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 * <p>
037 * <p>
038 *
039 * Examples:
040 *
041 * <pre>
042 *   // default unnamed space (tspace:default)
043 *   Space sp = SpaceFactory.getSpace ();
044 *
045 *   // transient space named "test"
046 *   Space sp = SpaceFactory.getSpace ("transient:test");
047 *
048 *   // lspace (Loom-optimized) named "test"
049 *   Space sp = SpaceFactory.getSpace ("lspace:test");
050 *
051 *   // persistent space named "test"
052 *   Space sp = SpaceFactory.getSpace ("persistent:test");
053 *
054 *   // jdbm space named test
055 *   Space sp = SpaceFactory.getSpace ("jdbm:test");
056 *
057 *   // jdbm space named test, storage located in /tmp/test
058 *   Space sp = SpaceFactory.getSpace ("jdbm:test:/tmp/test");
059 * </pre>
060 *
061 */
062public class SpaceFactory {
063    public static final String TSPACE     = "tspace";
064    public static final String LSPACE     = "lspace";
065    public static final String TRANSIENT  = "transient";
066    public static final String PERSISTENT = "persistent";
067    public static final String SPACELET   = "spacelet";
068    public static final String JDBM       = "jdbm";
069    public static final String JE         = "je";
070    public static final String DEFAULT    = "default";
071    private static ScheduledThreadPoolExecutor gcExecutor = ConcurrentUtil.newScheduledThreadPoolExecutor();
072
073    /**
074     * @return the default TransientSpace
075     */
076    public static Space getSpace () {
077        return getSpace (TSPACE, DEFAULT, null);
078    }
079
080    /**
081     * @param spaceUri 
082     * @return Space for given URI or null
083     */
084    public static Space getSpace (String spaceUri) {
085        if (spaceUri == null)
086            return getSpace ();
087
088        String scheme = null;
089        String name   = null;
090        String param  = null;
091
092        StringTokenizer st = new StringTokenizer (spaceUri, ":");
093        int count = st.countTokens();
094        if (count == 0) {
095            scheme = TSPACE;
096            name   = DEFAULT;
097        }
098        else if (count == 1) {
099            scheme = TSPACE;
100            name   = st.nextToken ();
101        }
102        else {
103            scheme = st.nextToken ();
104            name   = st.nextToken ();
105        }
106        if (st.hasMoreTokens()) {
107            param  = st.nextToken ();
108        }
109        return getSpace (scheme, name, param);
110    }
111    public static Space getSpace (String scheme, String name, String param) {
112        Space sp = null;
113        String uri = normalize (scheme, name, param);
114        synchronized (SpaceFactory.class) {
115            try {
116                sp = (Space) NameRegistrar.get (uri);
117            } catch (NameRegistrar.NotFoundException e) {
118                if (SPACELET.equals (scheme) || "rspace".equals(scheme))
119                    throw new SpaceError (uri + " not found.");
120
121                sp = createSpace (scheme, name, param);
122                NameRegistrar.register (uri, sp);
123            }
124        }
125        if (sp == null) {
126            throw new SpaceError ("Invalid space: " + uri);
127        }
128        return sp;
129    }
130    public static ScheduledThreadPoolExecutor getGCExecutor() {
131        return gcExecutor;
132    }
133    private static Space createSpace (String scheme, String name, String param)
134    {
135        Space sp = null;
136        if (TSPACE.equals (scheme) || TRANSIENT.equals (scheme)) {
137            sp = new TSpace();
138        } else if (LSPACE.equals (scheme)) {
139            sp = new LSpace();
140        } else if (JDBM.equals (scheme) || PERSISTENT.equals (scheme)) {
141            if (param != null)
142                sp = JDBMSpace.getSpace (name, param);
143            else
144                sp = JDBMSpace.getSpace (name);
145        } else if (JE.equals (scheme)) {
146            if (param != null)
147                sp = JESpace.getSpace (name, param);
148            else
149                sp = JESpace.getSpace (name);
150        }
151        return sp;
152    }
153    private static String normalize (String scheme, String name, String param) {
154        StringBuilder sb = new StringBuilder (scheme);
155        sb.append (':');
156        sb.append (name);
157        if (param != null) {
158            sb.append (':');
159            sb.append (param);
160        }
161        return sb.toString();
162    }
163}
164