/*
$Header: /cvsroot/xorm/xorm/src/org/xorm/InterfaceManagerFactory.java,v 1.46 2003/09/26 20:22:11 wbiggs Exp $
This file is part of XORM.
XORM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
XORM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with XORM; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.xorm;
import java.io.InputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.security.AccessController;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;
import javax.jdo.JDOFatalException;
import javax.jdo.JDOUserException;
import javax.jdo.spi.JDOPermission;
import org.xorm.cache.DataCache;
import org.xorm.cache.LRUCache;
import org.xorm.datastore.DatastoreDriver;
import org.xorm.datastore.ConnectionInfo;
// These are used as defaults in certain circumstances.
import org.xorm.datastore.heap.HeapDatastore;
import org.xorm.datastore.heap.HeapConnectionInfo;
import org.xorm.datastore.sql.SQLConnectionInfo;
// TODO: make this class Serializable per the JDO spec
// TODO: implement connection factory support
/**
* Factory that allows the creation of InterfaceManager objects.
* Configured via a properties file.
*
* The properties file should always contain the following:
* <pre>
* javax.jdo.PersistenceManagerFactoryClass=org.xorm.InterfaceManagerFactory
* </pre>
*
* For use with relational databases, you should set at minimum:
* <pre>
* javax.jdo.option.ConnectionDriverName={name of JDBC driver class}
* javax.jdo.option.ConnectionURL={JDBC URL}
* </pre>
*
* For use as in an in-memory database, you may omit all properties.
*
* For use with other datastore backends, you will need to set
* <pre>
* org.xorm.option.ConnectionInfoClass={name of ConnectionInfo class}
* </pre>
*
* Refer to the XORM User's Guide for a full list of available properties.
*/
public final class InterfaceManagerFactory implements PersistenceManagerFactory, I15d, Serializable {
private static final Collection SUPPORTED_OPTIONS =
Collections.unmodifiableList(Arrays.asList(new String[] {
"javax.jdo.option.TransientTransactional",
"javax.jdo.option.NontransactionalRead",
"javax.jdo.query.JDOQL",
"javax.jdo.option.RetainValues",
"javax.jdo.option.DatastoreIdentity"
}));
// Note: the following options are NOT supported
/*
javax.jdo.option.NontransactionalWrite
javax.jdo.option.Optimistic
javax.jdo.option.ApplicationIdentity
javax.jdo.option.NonDatastoreIdentity
javax.jdo.option.ArrayList
javax.jdo.option.HashMap
javax.jdo.option.Hashtable
javax.jdo.option.LinkedList
javax.jdo.option.TreeMap
javax.jdo.option.TreeSet
javax.jdo.option.Vector
javax.jdo.option.Map
javax.jdo.option.List
javax.jdo.option.Array
javax.jdo.option.NullCollection
javax.jdo.option.ChangeApplicationIdentity
*/
// Instance variables
private ModelMapping mapping;
private Class cacheImpl;
private Class fetchGroupManagerImpl;
private transient DataCache dataCache;
private boolean multithreaded;
private boolean ignoreCache;
private Options jdoOptions;
private boolean threadLocalTransactions;
private ConnectionInfo connectionInfo;
private Properties properties;
private FetchGroupManager fetchGroupManager;
private Map samples = new HashMap();
private boolean closed;
/** Static factory method; delegates to the constructor. */
public static PersistenceManagerFactory getPersistenceManagerFactory(Properties properties) throws Throwable {
// TODO: should this return the same instance for multiple calls
// with the same properties object or properties.equals()?
try {
return new InterfaceManagerFactory(properties);
} catch (Throwable e) {
// Work around an annoyance with JDO 1.0 classes
e.printStackTrace();
throw e;
}
}
/**
* @deprecated This constructor is provided for compatibility with
* the JDO 1.0 TCK. Application code should always construct a
* PersistenceManagerFactory using either the JDOHelper static
* methods or the static helper methods on the org.xorm.XORM class.
*/
public InterfaceManagerFactory() {
this(new Properties());
}
/**
* Constructs a new InterfaceManagerFactory. Note that this method
* is private -- to get an instance of InterfaceManagerFactory, you
* must call the static factory method. See also the helper methods
* on the org.xorm.XORM class.
*/
private InterfaceManagerFactory(Properties properties) {
this.properties = properties;
// Set XORM default options
jdoOptions = new Options();
jdoOptions.setNontransactionalRead(true);
jdoOptions.setRetainValues(true);
// Default implementations for DataCache, FetchGroupManager
// and ConnectionInfo
cacheImpl = LRUCache.class;
fetchGroupManagerImpl = FetchGroupManager.class;
Class connectionInfoImpl = SQLConnectionInfo.class;
//
if ((properties.getProperty("javax.jdo.option.ConnectionDriverName") == null) && (properties.getProperty("org.xorm.datastore.ConnectionInfoClass") == null)) {
connectionInfoImpl = HeapConnectionInfo.class;
cacheImpl = HeapDatastore.class;
properties.setProperty("org.xorm.option.DefaultMapping", "true");
}
Iterator i = properties.entrySet().iterator();
while (i.hasNext()) {
Map.Entry entry = (Map.Entry) i.next();
String key = (String) entry.getKey();
String value = (String) entry.getValue();
if (key.equals("org.xorm.datastore.ConnectionInfoClass")) {
try {
connectionInfoImpl = Class.forName(value);
} catch (ClassNotFoundException e) {
throw new JDOFatalException(I18N.msg("E_no_connection_info_class", value));
}
} else if (key.equals("org.xorm.cache.DataCacheClass")) {
if ("none".equals(value)) {
cacheImpl = null;
} else {
try {
cacheImpl = Class.forName(value);
} catch (ClassNotFoundException e) {
throw new JDOFatalException(I18N.msg("E_no_cache_class", value));
}
}
} else if (key.equals("org.xorm.FetchGroupManagerClass")) {
try {
fetchGroupManagerImpl = Class.forName(value);
} catch (ClassNotFoundException e) {
throw new JDOFatalException(I18N.msg("E_no_cache_class", value));
}
} else if (key.equals("org.xorm.option.ThreadLocalTransactions")) {
threadLocalTransactions = Boolean.valueOf(value).booleanValue();
}
}
// Initialize the ConnectionInfo
connectionInfo = (ConnectionInfo) configureNewInstance
(connectionInfoImpl);
// Initialize the ModelMapping
mapping = (ModelMapping) configureNewInstance(ModelMapping.class);
// Initialize the FetchGroupManager
fetchGroupManager = (FetchGroupManager) configureNewInstance(fetchGroupManagerImpl);
// Initialize the DataCache
if (cacheImpl != null) {
dataCache = (DataCache) configureNewInstance(cacheImpl);
}
}
/**
* Initializes a new instance of the class, which should implement
* the org.xorm.Configurable interface, and calls its
* setProperties() method.
*/
private Configurable configureNewInstance(Class configurableClass) {
Configurable instance = null;
if (configurableClass != null) {
try {
instance = (Configurable) configurableClass.newInstance();
instance.setFactory(this);
instance.setProperties(properties);
} catch (InstantiationException e) {
throw new JDOFatalException(I18N.msg("E_instantiation", configurableClass.getName()));
} catch (IllegalAccessException e) {
throw new JDOFatalException(I18N.msg("E_illegal_access", configurableClass.getName()));
} catch (ClassCastException e) {
throw new JDOFatalException(I18N.msg("E_not_configurable", configurableClass.getName()));
}
}
return instance;
}
/**
* Creates a new PersistenceManager associated with this factory.
* The PersistenceManager inherits the JDO options set on the factory
* at the time of its creation.
*/
public PersistenceManager getPersistenceManager() {
if (closed) {
throw new JDOUserException(I18N.msg("E_PMF_closed"));
}
return new InterfaceManager
(this, (Options) jdoOptions.clone());
}
/**
* Factory method. Creates a new instance of the DatastoreDriver
* configured for this factory.
*/
DatastoreDriver newDatastoreDriver() {
return connectionInfo.getDriver();
}
// TODO this is not supposed to affect the default settings
public PersistenceManager getPersistenceManager(String userid, String password) {
setConnectionUserName(userid);
setConnectionPassword(password);
return getPersistenceManager();
}
// The JDO options get/set methods are wrapper pattern.
public void setNontransactionalRead(boolean value) {
jdoOptions.setNontransactionalRead(value);
}
public boolean getNontransactionalRead() {
return jdoOptions.getNontransactionalRead();
}
public void setNontransactionalWrite(boolean value) {
jdoOptions.setNontransactionalWrite(value);
}
public boolean getNontransactionalWrite() {
return jdoOptions.getNontransactionalWrite();
}
public void setOptimistic(boolean value) {
jdoOptions.setOptimistic(value);
}
public boolean getOptimistic() {
return jdoOptions.getOptimistic();
}
public void setRetainValues(boolean value) {
jdoOptions.setRetainValues(value);
}
public boolean getRetainValues() {
return jdoOptions.getRetainValues();
}
public void setRestoreValues(boolean restoreValues) {
jdoOptions.setRestoreValues(restoreValues);
}
public boolean getRestoreValues() {
return jdoOptions.getRestoreValues();
}
// These methods call through to the connectionInfo object
public void setConnectionUserName(String s) {
connectionInfo.setConnectionUserName(s);
}
public String getConnectionUserName() {
return connectionInfo.getConnectionUserName();
}
public void setConnectionPassword(String s) {
connectionInfo.setConnectionPassword(s);
}
public void setConnectionURL(String s) {
connectionInfo.setConnectionURL(s);
}
public String getConnectionURL() {
return connectionInfo.getConnectionURL();
}
public void setConnectionDriverName(String s) {
connectionInfo.setConnectionDriverName(s);
}
public String getConnectionDriverName() {
return connectionInfo.getConnectionDriverName();
}
public int getMaxPool() {
return connectionInfo.getMaxPool();
}
public void setMaxPool(int i) {
connectionInfo.setMaxPool(i);
}
public int getMinPool() {
return connectionInfo.getMinPool();
}
public void setMinPool(int i) {
connectionInfo.setMinPool(i);
}
public int getMsWait() {
return connectionInfo.getMsWait();
}
public void setMsWait(int i) {
connectionInfo.setMsWait(i);
}
public void setConnectionFactoryName(String s) {
connectionInfo.setConnectionFactoryName(s);
}
public String getConnectionFactoryName() {
return connectionInfo.getConnectionFactoryName();
}
public void setConnectionFactory(Object o) {
connectionInfo.setConnectionFactory(o);
}
public Object getConnectionFactory() {
return connectionInfo.getConnectionFactory();
}
public void setConnectionFactory2Name(String s) {
connectionInfo.setConnectionFactory2Name(s);
}
public String getConnectionFactory2Name() {
return connectionInfo.getConnectionFactory2Name();
}
public void setConnectionFactory2(Object o) {
connectionInfo.setConnectionFactory2(o);
}
public Object getConnectionFactory2() {
return connectionInfo.getConnectionFactory2();
}
public void setMultithreaded(boolean value) {
this.multithreaded = value;
}
public boolean getMultithreaded() {
return multithreaded;
}
public void setIgnoreCache(boolean value) {
this.ignoreCache = value;
}
public boolean getIgnoreCache() {
return ignoreCache;
}
/** Returns a listing of the JDO options supported. */
public Collection supportedOptions() {
return SUPPORTED_OPTIONS;
}
/** Returns XORM-specific properties information. */
public Properties getProperties() {
Properties props = new Properties();
props.setProperty("VendorName", "XORM");
props.setProperty("VersionNumber", XORM.getVersion());
return props;
}
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException {
in.defaultReadObject();
if (cacheImpl != null) {
dataCache = (DataCache) configureNewInstance(cacheImpl);
}
}
// The following package-scope methods are used by XORM
// implementation classes.
public DataCache getCache() {
return dataCache;
}
ModelMapping getModelMapping() {
return mapping;
}
boolean useThreadLocalTransactions() {
return threadLocalTransactions;
}
FetchGroupManager getFetchGroupManager() {
return fetchGroupManager;
}
void clearCache() {
dataCache = (DataCache) configureNewInstance(cacheImpl);
}
Object getSample(Class clazz) {
return samples.get(clazz);
}
void putSample(Class clazz, Object sample) {
samples.put(clazz, sample);
}
ConnectionInfo getConnectionInfo() {
return connectionInfo;
}
/**
* Closes resources associated with this factory, including
* any connection resources currently allocated.
*/
public void close() {
// Check for permission
AccessController.checkPermission(new JDOPermission("closePersistenceManagerFactory"));
// TODO: Close PMs
closed = true;
// Release resources
connectionInfo.close();
}
}