001: /*
002: $Header: /cvsroot/xorm/xorm/src/org/xorm/InterfaceManagerFactory.java,v 1.46 2003/09/26 20:22:11 wbiggs Exp $
003:
004: This file is part of XORM.
005:
006: XORM is free software; you can redistribute it and/or modify
007: it under the terms of the GNU General Public License as published by
008: the Free Software Foundation; either version 2 of the License, or
009: (at your option) any later version.
010:
011: XORM is distributed in the hope that it will be useful,
012: but WITHOUT ANY WARRANTY; without even the implied warranty of
013: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: GNU General Public License for more details.
015:
016: You should have received a copy of the GNU General Public License
017: along with XORM; if not, write to the Free Software
018: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: */
020: package org.xorm;
021:
022: import java.io.InputStream;
023: import java.io.IOException;
024: import java.io.ObjectInputStream;
025: import java.io.Serializable;
026:
027: import java.security.AccessController;
028:
029: import java.util.Arrays;
030: import java.util.Collection;
031: import java.util.Collections;
032: import java.util.HashMap;
033: import java.util.Iterator;
034: import java.util.Map;
035: import java.util.Map.Entry;
036: import java.util.Properties;
037:
038: import javax.jdo.PersistenceManager;
039: import javax.jdo.PersistenceManagerFactory;
040: import javax.jdo.JDOFatalException;
041: import javax.jdo.JDOUserException;
042: import javax.jdo.spi.JDOPermission;
043:
044: import org.xorm.cache.DataCache;
045: import org.xorm.cache.LRUCache;
046:
047: import org.xorm.datastore.DatastoreDriver;
048: import org.xorm.datastore.ConnectionInfo;
049:
050: // These are used as defaults in certain circumstances.
051: import org.xorm.datastore.heap.HeapDatastore;
052: import org.xorm.datastore.heap.HeapConnectionInfo;
053: import org.xorm.datastore.sql.SQLConnectionInfo;
054:
055: // TODO: make this class Serializable per the JDO spec
056: // TODO: implement connection factory support
057:
058: /**
059: * Factory that allows the creation of InterfaceManager objects.
060: * Configured via a properties file.
061: *
062: * The properties file should always contain the following:
063: * <pre>
064: * javax.jdo.PersistenceManagerFactoryClass=org.xorm.InterfaceManagerFactory
065: * </pre>
066: *
067: * For use with relational databases, you should set at minimum:
068: * <pre>
069: * javax.jdo.option.ConnectionDriverName={name of JDBC driver class}
070: * javax.jdo.option.ConnectionURL={JDBC URL}
071: * </pre>
072: *
073: * For use as in an in-memory database, you may omit all properties.
074: *
075: * For use with other datastore backends, you will need to set
076: * <pre>
077: * org.xorm.option.ConnectionInfoClass={name of ConnectionInfo class}
078: * </pre>
079: *
080: * Refer to the XORM User's Guide for a full list of available properties.
081: */
082: public final class InterfaceManagerFactory implements
083: PersistenceManagerFactory, I15d, Serializable {
084: private static final Collection SUPPORTED_OPTIONS = Collections
085: .unmodifiableList(Arrays.asList(new String[] {
086: "javax.jdo.option.TransientTransactional",
087: "javax.jdo.option.NontransactionalRead",
088: "javax.jdo.query.JDOQL",
089: "javax.jdo.option.RetainValues",
090: "javax.jdo.option.DatastoreIdentity" }));
091:
092: // Note: the following options are NOT supported
093: /*
094: javax.jdo.option.NontransactionalWrite
095: javax.jdo.option.Optimistic
096: javax.jdo.option.ApplicationIdentity
097: javax.jdo.option.NonDatastoreIdentity
098: javax.jdo.option.ArrayList
099: javax.jdo.option.HashMap
100: javax.jdo.option.Hashtable
101: javax.jdo.option.LinkedList
102: javax.jdo.option.TreeMap
103: javax.jdo.option.TreeSet
104: javax.jdo.option.Vector
105: javax.jdo.option.Map
106: javax.jdo.option.List
107: javax.jdo.option.Array
108: javax.jdo.option.NullCollection
109: javax.jdo.option.ChangeApplicationIdentity
110: */
111:
112: // Instance variables
113: private ModelMapping mapping;
114: private Class cacheImpl;
115: private Class fetchGroupManagerImpl;
116: private transient DataCache dataCache;
117: private boolean multithreaded;
118: private boolean ignoreCache;
119: private Options jdoOptions;
120: private boolean threadLocalTransactions;
121: private ConnectionInfo connectionInfo;
122: private Properties properties;
123: private FetchGroupManager fetchGroupManager;
124: private Map samples = new HashMap();
125: private boolean closed;
126:
127: /** Static factory method; delegates to the constructor. */
128: public static PersistenceManagerFactory getPersistenceManagerFactory(
129: Properties properties) throws Throwable {
130: // TODO: should this return the same instance for multiple calls
131: // with the same properties object or properties.equals()?
132: try {
133: return new InterfaceManagerFactory(properties);
134: } catch (Throwable e) {
135: // Work around an annoyance with JDO 1.0 classes
136: e.printStackTrace();
137: throw e;
138: }
139: }
140:
141: /**
142: * @deprecated This constructor is provided for compatibility with
143: * the JDO 1.0 TCK. Application code should always construct a
144: * PersistenceManagerFactory using either the JDOHelper static
145: * methods or the static helper methods on the org.xorm.XORM class.
146: */
147: public InterfaceManagerFactory() {
148: this (new Properties());
149: }
150:
151: /**
152: * Constructs a new InterfaceManagerFactory. Note that this method
153: * is private -- to get an instance of InterfaceManagerFactory, you
154: * must call the static factory method. See also the helper methods
155: * on the org.xorm.XORM class.
156: */
157: private InterfaceManagerFactory(Properties properties) {
158: this .properties = properties;
159:
160: // Set XORM default options
161: jdoOptions = new Options();
162: jdoOptions.setNontransactionalRead(true);
163: jdoOptions.setRetainValues(true);
164:
165: // Default implementations for DataCache, FetchGroupManager
166: // and ConnectionInfo
167: cacheImpl = LRUCache.class;
168: fetchGroupManagerImpl = FetchGroupManager.class;
169: Class connectionInfoImpl = SQLConnectionInfo.class;
170:
171: //
172: if ((properties
173: .getProperty("javax.jdo.option.ConnectionDriverName") == null)
174: && (properties
175: .getProperty("org.xorm.datastore.ConnectionInfoClass") == null)) {
176: connectionInfoImpl = HeapConnectionInfo.class;
177: cacheImpl = HeapDatastore.class;
178: properties.setProperty("org.xorm.option.DefaultMapping",
179: "true");
180: }
181:
182: Iterator i = properties.entrySet().iterator();
183: while (i.hasNext()) {
184: Map.Entry entry = (Map.Entry) i.next();
185: String key = (String) entry.getKey();
186: String value = (String) entry.getValue();
187: if (key.equals("org.xorm.datastore.ConnectionInfoClass")) {
188: try {
189: connectionInfoImpl = Class.forName(value);
190: } catch (ClassNotFoundException e) {
191: throw new JDOFatalException(I18N.msg(
192: "E_no_connection_info_class", value));
193: }
194: } else if (key.equals("org.xorm.cache.DataCacheClass")) {
195: if ("none".equals(value)) {
196: cacheImpl = null;
197: } else {
198: try {
199: cacheImpl = Class.forName(value);
200: } catch (ClassNotFoundException e) {
201: throw new JDOFatalException(I18N.msg(
202: "E_no_cache_class", value));
203: }
204: }
205: } else if (key.equals("org.xorm.FetchGroupManagerClass")) {
206: try {
207: fetchGroupManagerImpl = Class.forName(value);
208: } catch (ClassNotFoundException e) {
209: throw new JDOFatalException(I18N.msg(
210: "E_no_cache_class", value));
211: }
212: } else if (key
213: .equals("org.xorm.option.ThreadLocalTransactions")) {
214: threadLocalTransactions = Boolean.valueOf(value)
215: .booleanValue();
216: }
217: }
218:
219: // Initialize the ConnectionInfo
220: connectionInfo = (ConnectionInfo) configureNewInstance(connectionInfoImpl);
221:
222: // Initialize the ModelMapping
223: mapping = (ModelMapping) configureNewInstance(ModelMapping.class);
224:
225: // Initialize the FetchGroupManager
226: fetchGroupManager = (FetchGroupManager) configureNewInstance(fetchGroupManagerImpl);
227:
228: // Initialize the DataCache
229: if (cacheImpl != null) {
230: dataCache = (DataCache) configureNewInstance(cacheImpl);
231: }
232: }
233:
234: /**
235: * Initializes a new instance of the class, which should implement
236: * the org.xorm.Configurable interface, and calls its
237: * setProperties() method.
238: */
239: private Configurable configureNewInstance(Class configurableClass) {
240: Configurable instance = null;
241: if (configurableClass != null) {
242: try {
243: instance = (Configurable) configurableClass
244: .newInstance();
245: instance.setFactory(this );
246: instance.setProperties(properties);
247: } catch (InstantiationException e) {
248: throw new JDOFatalException(I18N.msg("E_instantiation",
249: configurableClass.getName()));
250: } catch (IllegalAccessException e) {
251: throw new JDOFatalException(I18N
252: .msg("E_illegal_access", configurableClass
253: .getName()));
254: } catch (ClassCastException e) {
255: throw new JDOFatalException(I18N.msg(
256: "E_not_configurable", configurableClass
257: .getName()));
258: }
259: }
260: return instance;
261: }
262:
263: /**
264: * Creates a new PersistenceManager associated with this factory.
265: * The PersistenceManager inherits the JDO options set on the factory
266: * at the time of its creation.
267: */
268: public PersistenceManager getPersistenceManager() {
269: if (closed) {
270: throw new JDOUserException(I18N.msg("E_PMF_closed"));
271: }
272: return new InterfaceManager(this , (Options) jdoOptions.clone());
273: }
274:
275: /**
276: * Factory method. Creates a new instance of the DatastoreDriver
277: * configured for this factory.
278: */
279: DatastoreDriver newDatastoreDriver() {
280: return connectionInfo.getDriver();
281: }
282:
283: // TODO this is not supposed to affect the default settings
284: public PersistenceManager getPersistenceManager(String userid,
285: String password) {
286: setConnectionUserName(userid);
287: setConnectionPassword(password);
288: return getPersistenceManager();
289: }
290:
291: // The JDO options get/set methods are wrapper pattern.
292:
293: public void setNontransactionalRead(boolean value) {
294: jdoOptions.setNontransactionalRead(value);
295: }
296:
297: public boolean getNontransactionalRead() {
298: return jdoOptions.getNontransactionalRead();
299: }
300:
301: public void setNontransactionalWrite(boolean value) {
302: jdoOptions.setNontransactionalWrite(value);
303: }
304:
305: public boolean getNontransactionalWrite() {
306: return jdoOptions.getNontransactionalWrite();
307: }
308:
309: public void setOptimistic(boolean value) {
310: jdoOptions.setOptimistic(value);
311: }
312:
313: public boolean getOptimistic() {
314: return jdoOptions.getOptimistic();
315: }
316:
317: public void setRetainValues(boolean value) {
318: jdoOptions.setRetainValues(value);
319: }
320:
321: public boolean getRetainValues() {
322: return jdoOptions.getRetainValues();
323: }
324:
325: public void setRestoreValues(boolean restoreValues) {
326: jdoOptions.setRestoreValues(restoreValues);
327: }
328:
329: public boolean getRestoreValues() {
330: return jdoOptions.getRestoreValues();
331: }
332:
333: // These methods call through to the connectionInfo object
334: public void setConnectionUserName(String s) {
335: connectionInfo.setConnectionUserName(s);
336: }
337:
338: public String getConnectionUserName() {
339: return connectionInfo.getConnectionUserName();
340: }
341:
342: public void setConnectionPassword(String s) {
343: connectionInfo.setConnectionPassword(s);
344: }
345:
346: public void setConnectionURL(String s) {
347: connectionInfo.setConnectionURL(s);
348: }
349:
350: public String getConnectionURL() {
351: return connectionInfo.getConnectionURL();
352: }
353:
354: public void setConnectionDriverName(String s) {
355: connectionInfo.setConnectionDriverName(s);
356: }
357:
358: public String getConnectionDriverName() {
359: return connectionInfo.getConnectionDriverName();
360: }
361:
362: public int getMaxPool() {
363: return connectionInfo.getMaxPool();
364: }
365:
366: public void setMaxPool(int i) {
367: connectionInfo.setMaxPool(i);
368: }
369:
370: public int getMinPool() {
371: return connectionInfo.getMinPool();
372: }
373:
374: public void setMinPool(int i) {
375: connectionInfo.setMinPool(i);
376: }
377:
378: public int getMsWait() {
379: return connectionInfo.getMsWait();
380: }
381:
382: public void setMsWait(int i) {
383: connectionInfo.setMsWait(i);
384: }
385:
386: public void setConnectionFactoryName(String s) {
387: connectionInfo.setConnectionFactoryName(s);
388: }
389:
390: public String getConnectionFactoryName() {
391: return connectionInfo.getConnectionFactoryName();
392: }
393:
394: public void setConnectionFactory(Object o) {
395: connectionInfo.setConnectionFactory(o);
396: }
397:
398: public Object getConnectionFactory() {
399: return connectionInfo.getConnectionFactory();
400: }
401:
402: public void setConnectionFactory2Name(String s) {
403: connectionInfo.setConnectionFactory2Name(s);
404: }
405:
406: public String getConnectionFactory2Name() {
407: return connectionInfo.getConnectionFactory2Name();
408: }
409:
410: public void setConnectionFactory2(Object o) {
411: connectionInfo.setConnectionFactory2(o);
412: }
413:
414: public Object getConnectionFactory2() {
415: return connectionInfo.getConnectionFactory2();
416: }
417:
418: public void setMultithreaded(boolean value) {
419: this .multithreaded = value;
420: }
421:
422: public boolean getMultithreaded() {
423: return multithreaded;
424: }
425:
426: public void setIgnoreCache(boolean value) {
427: this .ignoreCache = value;
428: }
429:
430: public boolean getIgnoreCache() {
431: return ignoreCache;
432: }
433:
434: /** Returns a listing of the JDO options supported. */
435: public Collection supportedOptions() {
436: return SUPPORTED_OPTIONS;
437: }
438:
439: /** Returns XORM-specific properties information. */
440: public Properties getProperties() {
441: Properties props = new Properties();
442: props.setProperty("VendorName", "XORM");
443: props.setProperty("VersionNumber", XORM.getVersion());
444: return props;
445: }
446:
447: private void readObject(ObjectInputStream in) throws IOException,
448: ClassNotFoundException {
449: in.defaultReadObject();
450: if (cacheImpl != null) {
451: dataCache = (DataCache) configureNewInstance(cacheImpl);
452: }
453: }
454:
455: // The following package-scope methods are used by XORM
456: // implementation classes.
457:
458: public DataCache getCache() {
459: return dataCache;
460: }
461:
462: ModelMapping getModelMapping() {
463: return mapping;
464: }
465:
466: boolean useThreadLocalTransactions() {
467: return threadLocalTransactions;
468: }
469:
470: FetchGroupManager getFetchGroupManager() {
471: return fetchGroupManager;
472: }
473:
474: void clearCache() {
475: dataCache = (DataCache) configureNewInstance(cacheImpl);
476: }
477:
478: Object getSample(Class clazz) {
479: return samples.get(clazz);
480: }
481:
482: void putSample(Class clazz, Object sample) {
483: samples.put(clazz, sample);
484: }
485:
486: ConnectionInfo getConnectionInfo() {
487: return connectionInfo;
488: }
489:
490: /**
491: * Closes resources associated with this factory, including
492: * any connection resources currently allocated.
493: */
494: public void close() {
495: // Check for permission
496: AccessController.checkPermission(new JDOPermission(
497: "closePersistenceManagerFactory"));
498: // TODO: Close PMs
499:
500: closed = true;
501:
502: // Release resources
503: connectionInfo.close();
504:
505: }
506: }
|