001/* 002 * jPOS Project [http://jpos.org] 003 * Copyright (C) 2000-2026 jPOS Software SRL 004 * 005 * This program is free software: you can redistribute it and/or modify 006 * it under the terms of the GNU Affero General Public License as 007 * published by the Free Software Foundation, either version 3 of the 008 * License, or (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU Affero General Public License for more details. 014 * 015 * You should have received a copy of the GNU Affero General Public License 016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 017 */ 018 019package org.jpos.space; 020 021import org.jpos.util.ConcurrentUtil; 022import org.jpos.util.NameRegistrar; 023 024import java.util.StringTokenizer; 025import java.util.concurrent.ScheduledThreadPoolExecutor; 026 027/** 028 * Creates a space based on a space URI. 029 * 030 * <p>A space URI has three parts: 031 * <ul> 032 * <li>scheme 033 * <li>name 034 * <li>optional parameter 035 * </ul> 036 * 037 * <p>Examples: 038 * 039 * <pre> 040 * // default unnamed space (tspace:default) 041 * Space sp = SpaceFactory.getSpace (); 042 * 043 * // transient space named "test" 044 * Space sp = SpaceFactory.getSpace ("transient:test"); 045 * 046 * // lspace (Loom-optimized) named "test" 047 * Space sp = SpaceFactory.getSpace ("lspace:test"); 048 * 049 * // persistent space named "test" 050 * Space sp = SpaceFactory.getSpace ("persistent:test"); 051 * 052 * // jdbm space named test 053 * Space sp = SpaceFactory.getSpace ("jdbm:test"); 054 * 055 * // jdbm space named test, storage located in /tmp/test 056 * Space sp = SpaceFactory.getSpace ("jdbm:test:/tmp/test"); 057 * </pre> 058 * 059 */ 060public class SpaceFactory { 061 /** Default constructor; no instance state to initialise. */ 062 public SpaceFactory() {} 063 /** Scheme constant for transient (in-memory) spaces. */ 064 public static final String TSPACE = "tspace"; 065 /** Scheme constant for L-space (Loom-optimized) transient spaces. */ 066 public static final String LSPACE = "lspace"; 067 /** Scheme alias for {@link #TSPACE}. */ 068 public static final String TRANSIENT = "transient"; 069 /** Scheme constant for persistent (jdbm-backed) spaces. */ 070 public static final String PERSISTENT = "persistent"; 071 /** Scheme constant used to look up an externally-registered spacelet. */ 072 public static final String SPACELET = "spacelet"; 073 /** Scheme constant for JDBM-backed spaces. */ 074 public static final String JDBM = "jdbm"; 075 /** Scheme constant for Berkeley DB (JE) backed spaces. */ 076 public static final String JE = "je"; 077 /** Default name used for unnamed spaces. */ 078 public static final String DEFAULT = "default"; 079 private static ScheduledThreadPoolExecutor gcExecutor = ConcurrentUtil.newScheduledThreadPoolExecutor(); 080 081 /** 082 * Returns the default transient space (equivalent to {@code tspace:default}). 083 * 084 * @return the default TransientSpace 085 */ 086 public static Space getSpace () { 087 return getSpace (TSPACE, DEFAULT, null); 088 } 089 090 /** 091 * Resolves a space URI of the form {@code scheme:name[:param]}. 092 * 093 * @param spaceUri space URI; {@code null} returns the default space 094 * @return Space for given URI or null 095 */ 096 public static Space getSpace (String spaceUri) { 097 if (spaceUri == null) 098 return getSpace (); 099 100 String scheme = null; 101 String name = null; 102 String param = null; 103 104 StringTokenizer st = new StringTokenizer (spaceUri, ":"); 105 int count = st.countTokens(); 106 if (count == 0) { 107 scheme = TSPACE; 108 name = DEFAULT; 109 } 110 else if (count == 1) { 111 scheme = TSPACE; 112 name = st.nextToken (); 113 } 114 else { 115 scheme = st.nextToken (); 116 name = st.nextToken (); 117 } 118 if (st.hasMoreTokens()) { 119 param = st.nextToken (); 120 } 121 return getSpace (scheme, name, param); 122 } 123 /** 124 * Resolves the space identified by {@code scheme}, {@code name}, and optional {@code param}, 125 * registering a newly-created space in {@link NameRegistrar} on first use. 126 * 127 * @param scheme space scheme (one of the {@code TSPACE}/{@code LSPACE}/... constants) 128 * @param name space name 129 * @param param optional scheme-specific parameter (e.g. file path for {@code jdbm:}) 130 * @return the resolved space 131 * @throws SpaceError if the scheme is unknown or registration fails 132 */ 133 public static Space getSpace (String scheme, String name, String param) { 134 Space sp = null; 135 String uri = normalize (scheme, name, param); 136 synchronized (SpaceFactory.class) { 137 try { 138 sp = (Space) NameRegistrar.get (uri); 139 } catch (NameRegistrar.NotFoundException e) { 140 if (SPACELET.equals (scheme) || "rspace".equals(scheme)) 141 throw new SpaceError (uri + " not found."); 142 143 sp = createSpace (scheme, name, param); 144 NameRegistrar.register (uri, sp); 145 } 146 } 147 if (sp == null) { 148 throw new SpaceError ("Invalid space: " + uri); 149 } 150 return sp; 151 } 152 /** 153 * Returns the shared executor used by spaces to run lease-expiry/GC tasks. 154 * 155 * @return the shared GC executor 156 */ 157 public static ScheduledThreadPoolExecutor getGCExecutor() { 158 return gcExecutor; 159 } 160 private static Space createSpace (String scheme, String name, String param) 161 { 162 Space sp = null; 163 if (TSPACE.equals (scheme) || TRANSIENT.equals (scheme)) { 164 sp = new TSpace(); 165 } else if (LSPACE.equals (scheme)) { 166 sp = new LSpace(); 167 } else if (JDBM.equals (scheme) || PERSISTENT.equals (scheme)) { 168 if (param != null) 169 sp = JDBMSpace.getSpace (name, param); 170 else 171 sp = JDBMSpace.getSpace (name); 172 } else if (JE.equals (scheme)) { 173 if (param != null) 174 sp = JESpace.getSpace (name, param); 175 else 176 sp = JESpace.getSpace (name); 177 } 178 return sp; 179 } 180 private static String normalize (String scheme, String name, String param) { 181 StringBuilder sb = new StringBuilder (scheme); 182 sb.append (':'); 183 sb.append (name); 184 if (param != null) { 185 sb.append (':'); 186 sb.append (param); 187 } 188 return sb.toString(); 189 } 190} 191