/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* JDOHelper.java
*
*/
package javax.jdo;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.jdo.spi.I18NHelper;
import javax.jdo.spi.JDOImplHelper;
import javax.jdo.spi.JDOImplHelper.StateInterrogationBooleanReturn;
import javax.jdo.spi.JDOImplHelper.StateInterrogationObjectReturn;
import javax.jdo.spi.PersistenceCapable;
import javax.jdo.spi.StateInterrogation;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
/**
* This class can be used by a JDO-aware application to call the JDO behavior
* of PersistenceCapable
instances without declaring them to be
* PersistenceCapable
.
* It is also used to acquire a PersistenceManagerFactory
via
* various methods.
*
This helper class defines static methods that allow a JDO-aware
* application to examine the runtime state of instances. For example,
* an application can discover whether the instance is persistent,
* transactional, dirty, new, deleted, or detached; and to get its associated
* PersistenceManager
if it has one.
*
* @version 2.1
*/
public class JDOHelper implements Constants {
/**
* A mapping from jdoconfig.xsd element attributes to PMF properties.
*/
static final Map ATTRIBUTE_PROPERTY_XREF
= createAttributePropertyXref();
/** The Internationalization message helper.
*/
private final static I18NHelper msg =
I18NHelper.getInstance ("javax.jdo.Bundle"); //NOI18N
/**
* Creates a map from jdoconfig.xsd element attributes to PMF properties.
* @return An unmodifiable Map of jdoconfig.xsd element attributes to PMF
* properties.
*/
static Map createAttributePropertyXref() {
Map xref = new HashMap();
xref.put(
PMF_ATTRIBUTE_CLASS,
PROPERTY_PERSISTENCE_MANAGER_FACTORY_CLASS);
xref.put(
PMF_ATTRIBUTE_CONNECTION_DRIVER_NAME,
PROPERTY_CONNECTION_DRIVER_NAME);
xref.put(
PMF_ATTRIBUTE_CONNECTION_FACTORY_NAME,
PROPERTY_CONNECTION_FACTORY_NAME);
xref.put(
PMF_ATTRIBUTE_CONNECTION_FACTORY2_NAME,
PROPERTY_CONNECTION_FACTORY2_NAME);
xref.put(
PMF_ATTRIBUTE_CONNECTION_PASSWORD,
PROPERTY_CONNECTION_PASSWORD);
xref.put(
PMF_ATTRIBUTE_CONNECTION_URL,
PROPERTY_CONNECTION_URL);
xref.put(
PMF_ATTRIBUTE_CONNECTION_USER_NAME,
PROPERTY_CONNECTION_USER_NAME);
xref.put(
PMF_ATTRIBUTE_IGNORE_CACHE,
PROPERTY_IGNORE_CACHE);
xref.put(
PMF_ATTRIBUTE_MAPPING,
PROPERTY_MAPPING);
xref.put(
PMF_ATTRIBUTE_MULTITHREADED,
PROPERTY_MULTITHREADED);
xref.put(
PMF_ATTRIBUTE_NONTRANSACTIONAL_READ,
PROPERTY_NONTRANSACTIONAL_READ);
xref.put(
PMF_ATTRIBUTE_NONTRANSACTIONAL_WRITE,
PROPERTY_NONTRANSACTIONAL_WRITE);
xref.put(
PMF_ATTRIBUTE_OPTIMISTIC,
PROPERTY_OPTIMISTIC);
xref.put(
PMF_ATTRIBUTE_PERSISTENCE_UNIT_NAME,
PROPERTY_PERSISTENCE_UNIT_NAME);
xref.put(
PMF_ATTRIBUTE_NAME,
PROPERTY_NAME);
xref.put(
PMF_ATTRIBUTE_RESTORE_VALUES,
PROPERTY_RESTORE_VALUES);
xref.put(
PMF_ATTRIBUTE_RETAIN_VALUES,
PROPERTY_RETAIN_VALUES);
xref.put(
PMF_ATTRIBUTE_DETACH_ALL_ON_COMMIT,
PROPERTY_DETACH_ALL_ON_COMMIT);
xref.put(
PMF_ATTRIBUTE_SERVER_TIME_ZONE_ID,
PROPERTY_SERVER_TIME_ZONE_ID);
xref.put(
PMF_ATTRIBUTE_DATASTORE_READ_TIMEOUT_MILLIS,
PROPERTY_DATASTORE_READ_TIMEOUT_MILLIS);
xref.put(
PMF_ATTRIBUTE_DATASTORE_WRITE_TIMEOUT_MILLIS,
PROPERTY_DATASTORE_WRITE_TIMEOUT_MILLIS);
return Collections.unmodifiableMap(xref);
}
/** The JDOImplHelper instance used for handling non-binary-compatible
* implementations.
*/
private static JDOImplHelper implHelper = (JDOImplHelper)
AccessController.doPrivileged(
new PrivilegedAction () {
public JDOImplHelper run () {
return JDOImplHelper.getInstance();
}
}
);
/** The singleton instance of JDOHelper.
* @since 2.1
*/
private static JDOHelper instance = new JDOHelper();
/**
* Return the singleton instance of JDOHelper. This instance is
* thread-safe.
* @since 2.1
* @return the thread-safe singleton JDOHelper
*/
public static JDOHelper getInstance() {
return instance;
}
/** Some applications might prefer to use instance
* methods instead of static methods.
* @since 2.1
*/
public JDOHelper() {}
/** The stateless instance used for handling non-binary-compatible
* implementations of getPersistenceManager.
*/
static StateInterrogationObjectReturn getPersistenceManager =
new StateInterrogationObjectReturn() {
public Object get(Object pc, StateInterrogation si) {
return si.getPersistenceManager(pc);
}
};
/** The stateless instance used for handling non-binary-compatible
* implementations of getObjectId.
*/
static StateInterrogationObjectReturn getObjectId =
new StateInterrogationObjectReturn() {
public Object get(Object pc, StateInterrogation si) {
return si.getObjectId(pc);
}
};
/** The stateless instance used for handling non-binary-compatible
* implementations of getTransactionalObjectId.
*/
static StateInterrogationObjectReturn getTransactionalObjectId =
new StateInterrogationObjectReturn() {
public Object get(Object pc, StateInterrogation si) {
return si.getTransactionalObjectId(pc);
}
};
/** The stateless instance used for handling non-binary-compatible
* implementations of getVersion.
*/
static StateInterrogationObjectReturn getVersion =
new StateInterrogationObjectReturn() {
public Object get(Object pc, StateInterrogation si) {
return si.getVersion(pc);
}
};
/** The stateless instance used for handling non-binary-compatible
* implementations of isPersistent.
*/
static StateInterrogationBooleanReturn isPersistent =
new StateInterrogationBooleanReturn() {
public Boolean is(Object pc, StateInterrogation si) {
return si.isPersistent(pc);
}
};
/** The stateless instance used for handling non-binary-compatible
* implementations of isTransactional.
*/
static StateInterrogationBooleanReturn isTransactional =
new StateInterrogationBooleanReturn() {
public Boolean is(Object pc, StateInterrogation si) {
return si.isTransactional(pc);
}
};
/** The stateless instance used for handling non-binary-compatible
* implementations of isDirty.
*/
static StateInterrogationBooleanReturn isDirty =
new StateInterrogationBooleanReturn() {
public Boolean is(Object pc, StateInterrogation si) {
return si.isDirty(pc);
}
};
/** The stateless instance used for handling non-binary-compatible
* implementations of isNew.
*/
static StateInterrogationBooleanReturn isNew =
new StateInterrogationBooleanReturn() {
public Boolean is(Object pc, StateInterrogation si) {
return si.isNew(pc);
}
};
/** The stateless instance used for handling non-binary-compatible
* implementations of isDeleted.
*/
static StateInterrogationBooleanReturn isDeleted =
new StateInterrogationBooleanReturn() {
public Boolean is(Object pc, StateInterrogation si) {
return si.isDeleted(pc);
}
};
/** The stateless instance used for handling non-binary-compatible
* implementations of isDetached.
*/
static StateInterrogationBooleanReturn isDetached =
new StateInterrogationBooleanReturn() {
public Boolean is(Object pc, StateInterrogation si) {
return si.isDetached(pc);
}
};
/** Return the associated PersistenceManager
if there is one.
* Transactional and persistent instances return the associated
* PersistenceManager
.
*
* Transient non-transactional instances and instances of classes
* that do not implement PersistenceCapable
return
* null
.
* @see PersistenceCapable#jdoGetPersistenceManager()
* @param pc the PersistenceCapable
instance.
* @return the PersistenceManager
associated with the parameter
* instance.
*/
public static PersistenceManager getPersistenceManager(Object pc) {
if (pc instanceof PersistenceCapable) {
return ((PersistenceCapable)pc).jdoGetPersistenceManager();
} else {
return (PersistenceManager)
implHelper.nonBinaryCompatibleGet(pc, getPersistenceManager);
}
}
/** Explicitly mark the parameter instance and field dirty.
* Normally, PersistenceCapable
classes are able to detect
* changes made to their fields. However, if a reference to an array is
* given to a method outside the class, and the array is modified, then the
* persistent instance is not aware of the change. This API allows the
* application to notify the instance that a change was made to a field.
*
*
Transient instances and instances of classes
* that do not implement PersistenceCapable
ignore this method.
* @see PersistenceCapable#jdoMakeDirty(String fieldName)
* @param pc the PersistenceCapable
instance.
* @param fieldName the name of the field to be marked dirty.
*/
public static void makeDirty(Object pc, String fieldName) {
if (pc instanceof PersistenceCapable) {
((PersistenceCapable)pc).jdoMakeDirty(fieldName);
} else {
implHelper.nonBinaryCompatibleMakeDirty(pc, fieldName);
}
}
/** Return a copy of the JDO identity associated with the parameter
* instance.
*
*
Persistent instances of PersistenceCapable
classes have a
* JDO identity managed by the PersistenceManager
. This method
* returns a copy of the ObjectId that represents the JDO identity.
*
*
Transient instances and instances of classes that do not implement
* PersistenceCapable
return null
.
*
*
The ObjectId may be serialized
* and later restored, and used with a PersistenceManager
from
* the same JDO implementation to locate a persistent instance with the same
* data store identity.
*
*
If the JDO identity is managed by the application, then the ObjectId
* may be used with a PersistenceManager
from any JDO
* implementation that supports the PersistenceCapable
class.
*
*
If the JDO identity is not managed by the application or the data
* store, then the ObjectId returned is only valid within the current
* transaction.
*
* @see PersistenceManager#getObjectId(Object pc)
* @see PersistenceCapable#jdoGetObjectId()
* @see PersistenceManager#getObjectById(Object oid, boolean validate)
* @param pc the PersistenceCapable instance.
* @return a copy of the ObjectId of the parameter instance as of the
* beginning of the transaction.
*/
public static Object getObjectId(Object pc) {
if (pc instanceof PersistenceCapable) {
return ((PersistenceCapable)pc).jdoGetObjectId();
} else {
return implHelper.nonBinaryCompatibleGet(pc, getObjectId);
}
}
/** Get object ids for a collection of instances. For each instance
* in the parameter, the getObjectId method is called. This method
* returns one identity instance for each element
* in the parameter. The order of iteration of the returned
* Collection exactly matches the order of iteration of the
* parameter Collection.
* @param pcs the persistence-capable instances
* @return the object ids of the parameters
* @see #getObjectId(Object pc)
* @see #getObjectIds(Object[] pcs)
* @since 2.0
*/
public static Collection getObjectIds(Collection> pcs) {
ArrayList result = new ArrayList();
for (Iterator> it = pcs.iterator(); it.hasNext();) {
result.add(getObjectId(it.next()));
}
return result;
}
/** Get object ids for an array of instances. For each instance
* in the parameter, the getObjectId method is called. This method
* returns one identity instance for each element
* in the parameter. The order of instances of the returned
* array exactly matches the order of instances of the
* parameter array.
* @param pcs the persistence-capable instances
* @return the object ids of the parameters
* @see #getObjectId(Object pc)
* @see #getObjectIds(Collection pcs)
* @since 2.0
*/
public static Object[] getObjectIds(Object[] pcs) {
Object[] result = new Object[pcs.length];
for (int i = 0; i < pcs.length; ++i) {
result[i] = getObjectId(pcs[i]);
}
return result;
}
/** Return a copy of the JDO identity associated with the parameter
* instance.
*
* @see PersistenceCapable#jdoGetTransactionalObjectId()
* @see PersistenceManager#getObjectById(Object oid, boolean validate)
* @param pc the PersistenceCapable
instance.
* @return a copy of the ObjectId of the parameter instance as modified in
* this transaction.
*/
public static Object getTransactionalObjectId(Object pc) {
if (pc instanceof PersistenceCapable) {
return ((PersistenceCapable)pc).jdoGetTransactionalObjectId();
} else {
return implHelper.nonBinaryCompatibleGet(
pc, getTransactionalObjectId);
}
}
/**
* Return the version of the instance.
* @since 2.0
* @param pc the instance
* @return the version of the instance
*/
public static Object getVersion (Object pc) {
if (pc instanceof PersistenceCapable) {
return ((PersistenceCapable)pc).jdoGetVersion();
} else {
return implHelper.nonBinaryCompatibleGet(pc, getVersion);
}
}
/** Tests whether the parameter instance is dirty.
*
* Instances that have been modified, deleted, or newly
* made persistent in the current transaction return true
.
*
*Transient instances and instances of classes that do not implement
* PersistenceCapable
return false
.
*
* @see javax.jdo.spi.StateManager#makeDirty(PersistenceCapable pc,
* String fieldName)
* @see PersistenceCapable#jdoIsDirty()
* @param pc the PersistenceCapable
instance.
* @return true
if the parameter instance has been modified in
* the current transaction.
*/
public static boolean isDirty(Object pc) {
if (pc instanceof PersistenceCapable) {
return ((PersistenceCapable)pc).jdoIsDirty();
} else {
return implHelper.nonBinaryCompatibleIs(pc, isDirty);
}
}
/** Tests whether the parameter instance is transactional.
*
* Instances whose state is associated with the current transaction
* return true.
*
*
Transient instances and instances of classes that do not implement
* PersistenceCapable
return false
.
* @see PersistenceCapable#jdoIsTransactional()
* @param pc the PersistenceCapable
instance.
* @return true
if the parameter instance is transactional.
*/
public static boolean isTransactional(Object pc) {
if (pc instanceof PersistenceCapable) {
return ((PersistenceCapable)pc).jdoIsTransactional();
} else {
return implHelper.nonBinaryCompatibleIs(pc, isTransactional);
}
}
/** Tests whether the parameter instance is persistent.
*
* Instances that represent persistent objects in the data store
* return true
.
*
*
Transient instances and instances of classes that do not implement
* PersistenceCapable
return false
.
*
* @see PersistenceManager#makePersistent(Object pc)
* @see PersistenceCapable#jdoIsPersistent()
* @param pc the PersistenceCapable
instance.
* @return true
if the parameter instance is persistent.
*/
public static boolean isPersistent(Object pc) {
if (pc instanceof PersistenceCapable) {
return ((PersistenceCapable)pc).jdoIsPersistent();
} else {
return implHelper.nonBinaryCompatibleIs(pc, isPersistent);
}
}
/** Tests whether the parameter instance has been newly made persistent.
*
* Instances that have been made persistent in the current transaction
* return true
.
*
*
Transient instances and instances of classes that do not implement
* PersistenceCapable
return false
.
*
* @see PersistenceManager#makePersistent(Object pc)
* @see PersistenceCapable#jdoIsNew()
* @param pc the PersistenceCapable
instance.
* @return true
if the parameter instance was made persistent
* in the current transaction.
*/
public static boolean isNew(Object pc) {
if (pc instanceof PersistenceCapable) {
return ((PersistenceCapable)pc).jdoIsNew();
} else {
return implHelper.nonBinaryCompatibleIs(pc, isNew);
}
}
/** Tests whether the parameter instance has been deleted.
*
* Instances that have been deleted in the current transaction return
* true
.
*
*
Transient instances and instances of classes that do not implement
* PersistenceCapable
return false
.
*
* @see PersistenceManager#deletePersistent(Object pc)
* @see PersistenceCapable#jdoIsDeleted()
* @param pc the PersistenceCapable
instance.
* @return true
if the parameter instance was deleted
* in the current transaction.
*/
public static boolean isDeleted(Object pc) {
if (pc instanceof PersistenceCapable) {
return ((PersistenceCapable)pc).jdoIsDeleted();
} else {
return implHelper.nonBinaryCompatibleIs(pc, isDeleted);
}
}
/**
* Tests whether the parameter instance has been detached.
*
* Instances that have been detached return true.
*
*
Transient instances return false.
*
* @see PersistenceCapable#jdoIsDetached()
* @return true
if this instance is detached.
* @since 2.0
* @param pc the instance
*/
public static boolean isDetached(Object pc) {
if (pc instanceof PersistenceCapable) {
return ((PersistenceCapable)pc).jdoIsDetached();
} else {
return implHelper.nonBinaryCompatibleIs(pc, isDetached);
}
}
/** Accessor for the state of the passed object.
* @param pc The object
* @return The object state
* @since 2.1
*/
public static ObjectState getObjectState(Object pc) {
if (pc == null) {
return null;
}
if (isDetached(pc)) {
if (isDirty(pc)) {
// Detached Dirty
return ObjectState.DETACHED_DIRTY;
}
else {
// Detached Not Dirty
return ObjectState.DETACHED_CLEAN;
}
}
else {
if (isPersistent(pc)) {
if (isTransactional(pc)) {
if (isDirty(pc)) {
if (isNew(pc)) {
if (isDeleted(pc)) {
// Persistent Transactional Dirty New Deleted
return ObjectState.PERSISTENT_NEW_DELETED;
} else {
// Persistent Transactional Dirty New Not Deleted
return ObjectState.PERSISTENT_NEW;
}
} else {
if (isDeleted(pc)) {
// Persistent Transactional Dirty Not New Deleted
return ObjectState.PERSISTENT_DELETED;
} else {
// Persistent Transactional Dirty Not New Not Deleted
return ObjectState.PERSISTENT_DIRTY;
}
}
} else {
// Persistent Transactional Not Dirty
return ObjectState.PERSISTENT_CLEAN;
}
}
else {
if (isDirty(pc)) {
// Persistent Nontransactional Dirty
return ObjectState.PERSISTENT_NONTRANSACTIONAL_DIRTY;
}
else {
// Persistent Nontransactional Not Dirty
return ObjectState.HOLLOW_PERSISTENT_NONTRANSACTIONAL;
}
}
}
else {
if (isTransactional(pc)) {
if (isDirty(pc)) {
// Not Persistent Transactional Dirty
return ObjectState.TRANSIENT_DIRTY;
} else {
// Not Persistent Transactional Not Dirty
return ObjectState.TRANSIENT_CLEAN;
}
}
else {
// Not Persistent Not Transactional
return ObjectState.TRANSIENT;
}
}
}
}
/** Get the anonymous PersistenceManagerFactory
configured via
* the standard configuration file resource "META-INF/jdoconfig.xml", using
* the current thread's context class loader
* to locate the configuration file resource(s).
* @return the anonymous PersistenceManagerFactory
.
* @since 2.1
* @see #getPersistenceManagerFactory(Map,String,ClassLoader,ClassLoader)
*/
public static PersistenceManagerFactory getPersistenceManagerFactory() {
ClassLoader cl = getContextClassLoader();
return getPersistenceManagerFactory(
null, ANONYMOUS_PERSISTENCE_MANAGER_FACTORY_NAME, cl, cl);
}
/** Get the anonymous PersistenceManagerFactory
configured via
* the standard configuration file resource "META-INF/jdoconfig.xml", using
* the given class loader.
* @return the anonymous PersistenceManagerFactory
.
* @param pmfClassLoader the ClassLoader used to load resources and classes
* @since 2.1
* @see #getPersistenceManagerFactory(Map,String,ClassLoader,ClassLoader)
*/
public static PersistenceManagerFactory getPersistenceManagerFactory(
ClassLoader pmfClassLoader) {
return getPersistenceManagerFactory(
null,
ANONYMOUS_PERSISTENCE_MANAGER_FACTORY_NAME,
pmfClassLoader, pmfClassLoader);
}
/** Get a PersistenceManagerFactory
based on a Properties
* instance, using the current thread's context class loader to locate the
* PersistenceManagerFactory
class.
* @return the PersistenceManagerFactory
.
* @param props a Properties
instance with properties of the
* PersistenceManagerFactory
.
* @see #getPersistenceManagerFactory(java.util.Map,ClassLoader)
*/
public static PersistenceManagerFactory getPersistenceManagerFactory
(Map, ?> props) {
return getPersistenceManagerFactory(
null, props, getContextClassLoader());
}
/** Get a PersistenceManagerFactory
based on a
* Map
and a class loader.
* This method delegates to the getPersistenceManagerFactory
* method that takes a Map of overrides and a Map of properties,
* passing null as the overrides parameter.
* @see #getPersistenceManagerFactory(java.util.Map, java.util.Map, ClassLoader)
* @return the PersistenceManagerFactory
.
* @param props a Map
with properties of the
* PersistenceManagerFactory
.
* @param pmfClassLoader the class loader used to load the
* PersistenceManagerFactory
class
* @since 1.0
*/
public static PersistenceManagerFactory getPersistenceManagerFactory
(Map, ?> props, ClassLoader pmfClassLoader) {
return getPersistenceManagerFactory(
null, props, pmfClassLoader);
}
/**
* Get a PersistenceManagerFactory
based on a
* Map
of overrides, a Map
of
* properties, and a class loader.
* The following are standard key names:
* "javax.jdo.PersistenceManagerFactoryClass"
* "javax.jdo.option.Optimistic",
* "javax.jdo.option.RetainValues",
* "javax.jdo.option.RestoreValues",
* "javax.jdo.option.IgnoreCache",
* "javax.jdo.option.NontransactionalRead",
* "javax.jdo.option.NontransactionalWrite",
* "javax.jdo.option.Multithreaded",
* "javax.jdo.option.ConnectionUserName",
* "javax.jdo.option.ConnectionPassword",
* "javax.jdo.option.ConnectionURL",
* "javax.jdo.option.ConnectionFactoryName",
* "javax.jdo.option.ConnectionFactory2Name",
* "javax.jdo.option.Mapping",
* "javax.jdo.mapping.Catalog",
* "javax.jdo.mapping.Schema",
* "javax.jdo.option.PersistenceUnitName",
* "javax.jdo.option.DetachAllOnCommit",
* "javax.jdo.option.CopyOnAttach",
* "javax.jdo.option.ReadOnly",
* "javax.jdo.option.TransactionIsolationLevel",
* "javax.jdo.option.TransactionType",
* "javax.jdo.option.ServerTimeZoneID",
* "javax.jdo.option.DatastoreReadTimeoutMillis",
* "javax.jdo.option.DatastoreWriteTimeoutMillis",
* "javax.jdo.option.Name".
*
* and properties of the form
* javax.jdo.option.InstanceLifecycleListener.{listenerClass}[=[{pcClasses}]]
* where {listenerClass}
is the fully qualified name of a
* class that implements
* {@link javax.jdo.listener.InstanceLifecycleListener}, and
* {pcClasses}
is an optional comma- or whitespace-delimited
* list of persistence-capable classes to be observed; the absence of a
* value for a property of this form means that instances of all
* persistence-capable classes will be observed by an instance of the given
* listener class.
*
JDO implementations
* are permitted to define key values of their own. Any key values not
* recognized by the implementation must be ignored. Key values that are
* recognized but not supported by an implementation must result in a
* JDOFatalUserException
thrown by the method.
*
The returned PersistenceManagerFactory
is not
* configurable (the setXXX
methods will throw an
* exception).
*
JDO implementations might manage a map of instantiated
* PersistenceManagerFactory
instances based on specified
* property key values, and return a previously instantiated
* PersistenceManagerFactory
instance. In this case, the
* properties of the returned instance must exactly match the requested
* properties.
* @return the PersistenceManagerFactory
.
* @param props a Properties
instance with properties of the
* PersistenceManagerFactory
.
* @param pmfClassLoader the class loader to use to load the
* PersistenceManagerFactory
class
* @throws JDOFatalUserException if
*
the pmfClassLoader passed is invalid; or
* a valid class name cannot be obtained from
* either props
or system resources
* (an entry in META-INF/services/javax.jdo.PersistenceManagerFactory); or
* all implementations throw an exception.
*
* @since 2.1
*/
protected static PersistenceManagerFactory getPersistenceManagerFactory
(Map, ?> overrides, Map, ?> props, ClassLoader pmfClassLoader) {
List exceptions = new ArrayList();
if (pmfClassLoader == null)
throw new JDOFatalUserException (msg.msg (
"EXC_GetPMFNullLoader")); //NOI18N
JDOImplHelper.assertOnlyKnownStandardProperties(overrides);
JDOImplHelper.assertOnlyKnownStandardProperties(props);
// first try to get the class name from the properties object.
String pmfClassName = (String) props.get (
PROPERTY_PERSISTENCE_MANAGER_FACTORY_CLASS);
if (!isNullOrBlank(pmfClassName)) {
// a valid name was returned from the properties.
return invokeGetPersistenceManagerFactoryOnImplementation(
pmfClassName, overrides, props, pmfClassLoader);
} else {
/*
* If you have a jar file that provides the jdo implementation,
* a file naming the implementation goes into the file
* packaged into the jar file, called
* META-INF/services/javax.jdo.PersistenceManagerFactory.
* The contents of the file is a string that is the PMF class name,
* null or blank.
* For each file in pmfClassLoader named
* META-INF/services/javax.jdo.PersistenceManagerFactory,
* this method will try to invoke the getPersistenceManagerFactory
* method of the implementation class.
* Return the factory if a valid class name is extracted from
* resources and the invocation returns an instance.
* Otherwise add the exception thrown to
* an exception list.
*/
Enumeration urls = null;
try {
urls = getResources(pmfClassLoader,
SERVICE_LOOKUP_PMF_RESOURCE_NAME);
} catch (Throwable ex) {
exceptions.add(ex);
}
if (urls != null){
while (urls.hasMoreElements()) {
try {
pmfClassName = getClassNameFromURL(
(URL) urls.nextElement());
// return the implementation that is valid.
PersistenceManagerFactory pmf =
invokeGetPersistenceManagerFactoryOnImplementation(
pmfClassName, overrides, props, pmfClassLoader);
return pmf;
} catch (Throwable ex) {
// remember exceptions from failed pmf invocations
exceptions.add(ex);
}
}
}
}
// no PMF class name in props and no services.
throw new JDOFatalUserException(msg.msg(
"EXC_GetPMFNoPMFClassNamePropertyOrPUNameProperty"),
(Throwable[])
exceptions.toArray(new Throwable[exceptions.size()]));
}
/** Get a class name from a URL. The URL is from getResources with
* e.g. META-INF/services/javax.jdo.PersistenceManagerFactory as the
* parameter. Parse the file, removing blank lines, comment lines,
* and comments.
* @param url the URL of the services file
* @return the name of the class contained in the file
* @throws java.io.IOException
* @since 2.1
*/
protected static String getClassNameFromURL (URL url)
throws IOException {
InputStream is = openStream(url);
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = null;
try {
while ((line = reader.readLine()) != null) {
line = line.trim();
if (line.length() == 0 || line.startsWith("#")) {
continue;
}
// else assume first line of text is the PMF class name
String[] tokens = line.split("\\s");
String pmfClassName = tokens[0];
int indexOfComment = pmfClassName.indexOf("#");
if (indexOfComment == -1) {
return pmfClassName;
}
// else pmfClassName has a comment at the end of it -- remove
return pmfClassName.substring(0, indexOfComment);
}
return null;
} finally {
try {
reader.close();
}
catch (IOException x) {
// gulp
}
}
}
/**
* Returns a named {@link PersistenceManagerFactory} or persistence
* unit.
*
* @since 2.1
* @see #getPersistenceManagerFactory(Map,String,ClassLoader,ClassLoader)
*/
public static PersistenceManagerFactory getPersistenceManagerFactory
(String name) {
ClassLoader cl = getContextClassLoader();
return getPersistenceManagerFactory(null, name, cl, cl);
}
/**
* Returns a named {@link PersistenceManagerFactory} or persistence
* unit.
*
* @since 1.0
* @see #getPersistenceManagerFactory(Map,String,ClassLoader,ClassLoader)
*/
public static PersistenceManagerFactory getPersistenceManagerFactory
(String name, ClassLoader loader) {
return getPersistenceManagerFactory(null, name, loader, loader);
}
/**
* Returns a named {@link PersistenceManagerFactory} or persistence
* unit.
*
* @since 2.0
* @see #getPersistenceManagerFactory(Map,String,ClassLoader,ClassLoader)
*/
public static PersistenceManagerFactory getPersistenceManagerFactory
(String name, ClassLoader resourceLoader, ClassLoader pmfLoader) {
return getPersistenceManagerFactory(
null, name, resourceLoader, pmfLoader);
}
/**
* Returns a named {@link PersistenceManagerFactory} or persistence
* unit.
*
* @since 2.1
* @see #getPersistenceManagerFactory(Map,String,ClassLoader,ClassLoader)
*/
public static PersistenceManagerFactory getPersistenceManagerFactory
(Map, ?> overrides, String name) {
ClassLoader cl = getContextClassLoader();
return getPersistenceManagerFactory(overrides, name, cl, cl);
}
/**
* Returns a named {@link PersistenceManagerFactory} or persistence
* unit.
*
* @since 2.1
* @see #getPersistenceManagerFactory(Map,String,ClassLoader,ClassLoader)
*/
public static PersistenceManagerFactory getPersistenceManagerFactory
(Map, ?> overrides, String name, ClassLoader resourceLoader) {
return getPersistenceManagerFactory(
overrides, name, resourceLoader, resourceLoader);
}
/**
* Returns a {@link PersistenceManagerFactory} configured based
* on the properties stored in the resource at
* name
, or, if not found, returns a
* {@link PersistenceManagerFactory} with the given
* name or, if not found, returns a
* javax.persistence.EntityManagerFactory
cast to a
* {@link PersistenceManagerFactory}. If the name given is null or consists
* only of whitespace, it is interpreted as
* {@link Constants#ANONYMOUS_PERSISTENCE_MANAGER_FACTORY_NAME}.
* The following are standard key names:
* "javax.jdo.PersistenceManagerFactoryClass"
* "javax.jdo.option.Optimistic",
* "javax.jdo.option.RetainValues",
* "javax.jdo.option.RestoreValues",
* "javax.jdo.option.IgnoreCache",
* "javax.jdo.option.NontransactionalRead",
* "javax.jdo.option.NontransactionalWrite",
* "javax.jdo.option.Multithreaded",
* "javax.jdo.option.ConnectionUserName",
* "javax.jdo.option.ConnectionPassword",
* "javax.jdo.option.ConnectionURL",
* "javax.jdo.option.ConnectionFactoryName",
* "javax.jdo.option.ConnectionFactory2Name",
* "javax.jdo.option.Mapping",
* "javax.jdo.mapping.Catalog",
* "javax.jdo.mapping.Schema",
* "javax.jdo.option.PersistenceUnitName".
* "javax.jdo.option.DetachAllOnCommit".
* "javax.jdo.option.CopyOnAttach".
* "javax.jdo.option.TransactionType".
* "javax.jdo.option.ServerTimeZoneID".
* "javax.jdo.option.DatastoreReadTimeoutMillis",
* "javax.jdo.option.DatastoreWriteTimeoutMillis",
* "javax.jdo.option.Name".
*
* and properties of the form
* javax.jdo.option.InstanceLifecycleListener.{listenerClass}[=[{pcClasses}]]
* where {listenerClass}
is the fully qualified name of a
* class that implements
* {@link javax.jdo.listener.InstanceLifecycleListener}, and
* {pcClasses}
is an optional comma- or whitespace-delimited
* list of persistence-capable classes to be observed; the absence of a
* value for a property of this form means that instances of all
* persistence-capable classes will be observed by an instance of the given
* listener class.
* JDO implementations
* are permitted to define key values of their own. Any key values not
* recognized by the implementation must be ignored. Key values that are
* recognized but not supported by an implementation must result in a
* JDOFatalUserException
thrown by the method.
*
The returned PersistenceManagerFactory
is not
* configurable (the setXXX
methods will throw an
* exception).
*
* This method loads the properties found at name
, if any, via
* resourceLoader
, and creates a {@link
* PersistenceManagerFactory} with pmfLoader
. Any
* exceptions thrown during resource loading will
* be wrapped in a {@link JDOFatalUserException}.
* If multiple PMFs with the requested name are found, a
* {@link JDOFatalUserException} is thrown.
* @since 2.1
* @param overrides a Map containing properties that override properties
* defined in any resources loaded according to the "name" parameter
* @param name interpreted as the name of the resource containing the PMF
* properties, the name of the PMF, or the persistence unit name, in that
* order; if name is null, blank or whitespace, it is interpreted as
* indicating the anonymous {@link PersistenceManagerFactory}.
* @param resourceLoader the class loader to use to load properties file
* resources; must be non-null if name
is non-null or blank
* @param pmfLoader the class loader to use to load the
* {@link PersistenceManagerFactory} or
* javax.persistence.EntityManagerFactory
classes
* @return the {@link PersistenceManagerFactory} with properties in the
* given resource, with the given name, or with the given persitence unit
* name
* @see Constants#ANONYMOUS_PERSISTENCE_MANAGER_FACTORY_NAME
*/
public static PersistenceManagerFactory getPersistenceManagerFactory(
Map, ?> overrides,
String name,
ClassLoader resourceLoader,
ClassLoader pmfLoader) {
if (pmfLoader == null)
throw new JDOFatalUserException (msg.msg (
"EXC_GetPMFNullPMFLoader")); //NOI18N
if (resourceLoader == null) {
throw new JDOFatalUserException(msg.msg(
"EXC_GetPMFNullPropsLoader")); //NOI18N
}
Map props = null;
// trim spaces from name and ensure non-null
name = (name == null?ANONYMOUS_PERSISTENCE_MANAGER_FACTORY_NAME:name.trim());
if (!ANONYMOUS_PERSISTENCE_MANAGER_FACTORY_NAME.equals(name)) {
props = loadPropertiesFromResource(resourceLoader, name);
}
if (props != null) {
// add the SPI property to inform the implementation that
// the PMF was configured by the given resource name
// and not via named PMF for proper deserialization
props.put(PROPERTY_SPI_RESOURCE_NAME, name);
props.remove(PROPERTY_NAME);
return getPersistenceManagerFactory(overrides, props, pmfLoader);
}
// props were null; try getting from jdoconfig.xml
props = getPropertiesFromJdoconfig(name, pmfLoader);
if (props != null) {
// inform the impl that the config came from a jdoconfig.xml
// element with the given name
props.put(PROPERTY_NAME, name);
props.remove(PROPERTY_SPI_RESOURCE_NAME);
// we have loaded a Properties, delegate to implementation
return getPersistenceManagerFactory(overrides, props, pmfLoader);
}
// no properties found; last try to see if name is a JPA PU name
if (!ANONYMOUS_PERSISTENCE_MANAGER_FACTORY_NAME.equals(name)) {
props = new Properties();
props.put(PROPERTY_PERSISTENCE_UNIT_NAME, name);
return getPersistenceManagerFactory(overrides, props, pmfLoader);
}
// no PMF found; give up
throw new JDOFatalUserException (msg.msg (
"EXC_NoPMFConfigurableViaPropertiesOrXML", name)); //NOI18N
}
/** Invoke the getPersistenceManagerFactory method on the implementation.
* If the overrides parameter to this method is not null, the static method
* with Map overrides, Map properties parameters will be invoked.
* If the overrides parameter to this method is null, the static method
* with Map properties parameter will be invoked.
* @param pmfClassName the name of the implementation factory class
* @param overrides a Map of overrides
* @param properties a Map of properties
* @param cl the class loader to use to load the implementation class
* @return the PersistenceManagerFactory
*/
protected static PersistenceManagerFactory
invokeGetPersistenceManagerFactoryOnImplementation(
String pmfClassName, Map, ?> overrides, Map, ?> properties, ClassLoader cl) {
if (overrides != null) {
// overrides is not null; use getPersistenceManagerFactory(Map overrides, Map props)
try {
Class> implClass = forName(pmfClassName, true, cl);
Method m = getMethod(implClass,
"getPersistenceManagerFactory", //NOI18N
new Class[]{Map.class, Map.class});
PersistenceManagerFactory pmf =
(PersistenceManagerFactory) invoke(m,
null, new Object[]{overrides, properties});
if (pmf == null) {
throw new JDOFatalInternalException(msg.msg (
"EXC_GetPMFNullPMF", pmfClassName)); //NOI18N
}
return pmf;
} catch (ClassNotFoundException e) {
throw new JDOFatalUserException(msg.msg(
"EXC_GetPMFClassNotFound", pmfClassName), e); //NOI18N
} catch (NoSuchMethodException e) {
throw new JDOFatalInternalException(msg.msg(
"EXC_GetPMFNoSuchMethod2", pmfClassName), e); //NOI18N
} catch (NullPointerException e) {
throw new JDOFatalInternalException (msg.msg(
"EXC_GetPMFNullPointerException", pmfClassName), e); //NOI18N
} catch (IllegalAccessException e) {
throw new JDOFatalUserException(msg.msg(
"EXC_GetPMFIllegalAccess", pmfClassName), e); //NOI18N
} catch (ClassCastException e) {
throw new JDOFatalInternalException (msg.msg(
"EXC_GetPMFClassCastException", pmfClassName), e); //NOI18N
} catch (InvocationTargetException ite) {
Throwable nested = ite.getTargetException();
if (nested instanceof JDOException) {
throw (JDOException)nested;
} else throw new JDOFatalInternalException (msg.msg(
"EXC_GetPMFUnexpectedException"), ite); //NOI18N
}
} else {
// overrides is null; use getPersistenceManagerFactory(Map props)
try {
Class> implClass = forName(pmfClassName, true, cl);
Method m = getMethod(implClass,
"getPersistenceManagerFactory", //NOI18N
new Class[]{Map.class});
PersistenceManagerFactory pmf =
(PersistenceManagerFactory) invoke(m,
null, new Object[]{properties});
if (pmf == null) {
throw new JDOFatalInternalException(msg.msg (
"EXC_GetPMFNullPMF", pmfClassName)); //NOI18N
}
return pmf;
} catch (ClassNotFoundException e) {
throw new JDOFatalUserException(msg.msg(
"EXC_GetPMFClassNotFound", pmfClassName), e); //NOI18N
} catch (NoSuchMethodException e) {
throw new JDOFatalInternalException(msg.msg(
"EXC_GetPMFNoSuchMethod", pmfClassName), e); //NOI18N
} catch (NullPointerException e) {
throw new JDOFatalInternalException (msg.msg(
"EXC_GetPMFNullPointerException", pmfClassName), e); //NOI18N
} catch (IllegalAccessException e) {
throw new JDOFatalUserException(msg.msg(
"EXC_GetPMFIllegalAccess", pmfClassName), e); //NOI18N
} catch (ClassCastException e) {
throw new JDOFatalInternalException (msg.msg(
"EXC_GetPMFClassCastException", pmfClassName), e); //NOI18N
} catch (InvocationTargetException ite) {
Throwable nested = ite.getTargetException();
if (nested instanceof JDOException) {
throw (JDOException)nested;
} else throw new JDOFatalInternalException (msg.msg(
"EXC_GetPMFUnexpectedException"), ite); //NOI18N
}
}
}
/** Load a Properties instance by name from the class loader.
*
* @param resourceLoader the class loader from which to load the properties
* @param name the name of the resource
* @return a Properties instance or null if no resource is found
*/
protected static Map loadPropertiesFromResource(
ClassLoader resourceLoader, String name) {
InputStream in = null;
Properties props = null;
// try to load resources from properties file
try {
in = getResourceAsStream(resourceLoader, name);
if (in != null) {
// then some kind of resource was found by the given name;
// assume that it's a properties file
props = new Properties();
((Properties) props).load(in);
}
} catch (IOException ioe) {
throw new JDOFatalUserException(msg.msg(
"EXC_GetPMFIOExceptionRsrc", name), ioe); //NOI18N
} finally {
if (in != null) {
try {
in.close();
} catch (IOException ioe) {
}
}
}
return props;
}
/**
* @see #getNamedPMFProperties(String,ClassLoader,String)
* @since 2.1
*/
protected static Map getPropertiesFromJdoconfig(
String name,
ClassLoader resourceLoader) {
return getNamedPMFProperties(
name, resourceLoader, JDOCONFIG_RESOURCE_NAME);
}
/**
* Find and return the named {@link PersistenceManagerFactory}'s properties,
* or null if not found.
* If multiple named PMF property sets with
* the given name are found (including anonymous ones), throw
* {@link JDOFatalUserException}.
* This method is here only to facilitate testing; the parameter
* "jdoconfigResourceName" in public usage should always have the value
* given in the constant {@link Constants#JDOCONFIG_RESOURCE_NAME}.
*
* @param name The persistence unit name; null is disallowed.
* @param resourceLoader The ClassLoader used to load the standard JDO
* configuration file.
* @param jdoconfigResourceName The name of the configuration file to read.
* In public usage, this should always be the value of
* {@link Constants#JDOCONFIG_RESOURCE_NAME}.
* @return The named PersistenceManagerFactory
properties if
* found, null if not.
* @since 2.1
* @throws JDOFatalUserException if multiple named PMF property sets are
* found with the given name, or any other exception is encountered.
*/
protected static Map getNamedPMFProperties(
String name,
ClassLoader resourceLoader,
String jdoconfigResourceName) {
// key is PU name, value is Map of PU properties
Map> propertiesByNameInAllConfigs
= new HashMap>();
try {
URL firstFoundConfigURL = null;
// get all JDO configurations
Enumeration resources =
getResources(resourceLoader, jdoconfigResourceName);
if (resources.hasMoreElements()) {
ArrayList processedResources = new ArrayList();
// get ready to parse XML
DocumentBuilderFactory factory = getDocumentBuilderFactory();
do {
URL currentConfigURL = resources.nextElement();
if (processedResources.contains(currentConfigURL)) {
continue;
}
else {
processedResources.add(currentConfigURL);
}
Map> propertiesByNameInCurrentConfig =
readNamedPMFProperties(
currentConfigURL,
name,
factory);
// try to detect duplicate requested PU
if (propertiesByNameInCurrentConfig.containsKey(name)) {
// possible dup -- check for it
if (firstFoundConfigURL == null) {
firstFoundConfigURL = currentConfigURL;
}
if (propertiesByNameInAllConfigs.containsKey(name))
throw new JDOFatalUserException (msg.msg(
"EXC_DuplicateRequestedNamedPMFFoundInDifferentConfigs",
"".equals(name)
? "(anonymous)"
: name,
firstFoundConfigURL.toExternalForm(),
currentConfigURL.toExternalForm())); //NOI18N
}
// no dups -- add found PUs to all PUs and keep going
propertiesByNameInAllConfigs
.putAll(propertiesByNameInCurrentConfig);
} while (resources.hasMoreElements());
}
}
catch (FactoryConfigurationError e) {
throw new JDOFatalUserException(
msg.msg("ERR_NoDocumentBuilderFactory"), e);
}
catch (IOException ioe) {
throw new JDOFatalUserException (msg.msg (
"EXC_GetPMFIOExceptionRsrc", name), ioe); //NOI18N
}
// done with reading all config resources;
// return what we found, which may very well be null
return (Map) propertiesByNameInAllConfigs.get(name);
}
protected static DocumentBuilderFactory getDocumentBuilderFactory() {
@SuppressWarnings("static-access")
DocumentBuilderFactory factory =
implHelper.getRegisteredDocumentBuilderFactory();
if (factory == null) {
factory = getDefaultDocumentBuilderFactory();
}
return factory;
}
protected static DocumentBuilderFactory getDefaultDocumentBuilderFactory() {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setIgnoringComments(true);
factory.setNamespaceAware(true);
factory.setValidating(false);
factory.setIgnoringElementContentWhitespace(true);
factory.setExpandEntityReferences(true);
return factory;
}
protected static ErrorHandler getErrorHandler() {
@SuppressWarnings("static-access")
ErrorHandler handler = implHelper.getRegisteredErrorHandler();
if (handler == null) {
handler = getDefaultErrorHandler();
}
return handler;
}
protected static ErrorHandler getDefaultErrorHandler() {
return new ErrorHandler() {
public void error(SAXParseException exception)
throws SAXException {
throw exception;
}
public void fatalError(SAXParseException exception)
throws SAXException {
throw exception;
}
public void warning(SAXParseException exception)
throws SAXException {
// gulp: ignore warnings
}
};
}
/** Reads JDO configuration file, creates a Map for each
* persistence-manager-factory, then returns the map.
* @param url URL of a JDO configuration file compliant with
* javax/jdo/jdoconfig.xsd.
* @param requestedPMFName The name of the requested
* persistence unit (allows for fail-fast).
* @param factory The DocumentBuilderFactory
to use for XML
* parsing.
* @return a Map holding persistence unit configurations; for
* the anonymous persistence unit, the
* value of the String key is the empty string, "".
*/
protected static Map> readNamedPMFProperties(
URL url,
String requestedPMFName,
DocumentBuilderFactory factory) {
requestedPMFName = requestedPMFName == null
? ""
: requestedPMFName.trim();
Map>
propertiesByName = new HashMap>();
InputStream in = null;
try {
DocumentBuilder builder = factory.newDocumentBuilder();
builder.setErrorHandler(getErrorHandler());
in = openStream(url);
Document doc = builder.parse(in);
Element root = doc.getDocumentElement();
if (root == null) {
throw new JDOFatalUserException(
msg.msg("EXC_InvalidJDOConfigNoRoot", url.toExternalForm())
);
}
NodeList pmfs = root.getElementsByTagName(
ELEMENT_PERSISTENCE_MANAGER_FACTORY);
for(int i = 0; i < pmfs.getLength(); i++) {
Node pmfElement = pmfs.item(i);
Properties pmfPropertiesFromAttributes
= readPropertiesFromPMFElementAttributes(pmfElement);
Properties pmfPropertiesFromElements
= readPropertiesFromPMFSubelements(pmfElement, url);
// for informative error handling, get name (or names) now
String pmfNameFromAtts =
pmfPropertiesFromAttributes.getProperty(PROPERTY_NAME);
String pmfNameFromElem =
pmfPropertiesFromElements.getProperty(PROPERTY_NAME);
String pmfName = null;
if (isNullOrBlank(pmfNameFromAtts)) {
// no PMF name attribute given
if (!isNullOrBlank(pmfNameFromElem)) {
// PMF name element was given
pmfName = pmfNameFromElem;
}
else {
// PMF name not given at all, means the "anonymous" PMF
pmfName = ANONYMOUS_PERSISTENCE_MANAGER_FACTORY_NAME;
}
}
else {
// PMF name given in an attribute
if (!isNullOrBlank(pmfNameFromElem)) {
// exception -- PMF name given as both att & elem
throw new JDOFatalUserException(
msg.msg(
"EXC_DuplicatePMFNamePropertyFoundWithinConfig",
pmfNameFromAtts,
pmfNameFromElem,
url.toExternalForm()));
}
pmfName = pmfNameFromAtts;
}
pmfName = pmfName == null ? "" : pmfName.trim();
// check for duplicate properties among atts & elems
if (requestedPMFName.equals(pmfName)) {
Iterator> it =
pmfPropertiesFromAttributes.keySet().iterator();
while (it.hasNext()) {
String property = (String) it.next();
if (pmfPropertiesFromElements.contains(property)) {
throw new JDOFatalUserException(
msg.msg(
"EXC_DuplicatePropertyFound",
property,
pmfName,
url.toExternalForm()));
}
}
}
// at this point, we're guaranteed not to have duplicate
// properties -- merge them
Properties pmfProps = new Properties();
pmfProps.putAll(pmfPropertiesFromAttributes);
pmfProps.putAll(pmfPropertiesFromElements);
// check for duplicate requested PMF name
if (pmfName.equals(requestedPMFName)
&& propertiesByName.containsKey(pmfName)) {
throw new JDOFatalUserException(msg.msg(
"EXC_DuplicateRequestedNamedPMFFoundInSameConfig",
pmfName,
url.toExternalForm()));
}
propertiesByName.put(pmfName, pmfProps);
}
return propertiesByName;
}
catch (IOException ioe) {
throw new JDOFatalUserException(
msg.msg("EXC_GetPMFIOExceptionRsrc", url.toString()),
ioe); //NOI18N
}
catch (ParserConfigurationException e) {
throw new JDOFatalInternalException(
msg.msg("EXC_ParserConfigException"),
e);
}
catch (SAXParseException e) {
throw new JDOFatalUserException(
msg.msg(
"EXC_SAXParseException",
url.toExternalForm(),
new Integer(e.getLineNumber()),
new Integer(e.getColumnNumber())),
e);
}
catch (SAXException e) {
throw new JDOFatalUserException(
msg.msg("EXC_SAXException", url.toExternalForm()),
e);
}
catch (JDOException e) {
throw e;
}
catch (RuntimeException e) {
throw new JDOFatalUserException(
msg.msg("EXC_SAXException", url.toExternalForm()),
e);
}
finally {
if (in != null) {
try {
in.close();
}
catch (IOException ioe) { /* gulp */ }
}
}
}
protected static Properties readPropertiesFromPMFElementAttributes(
Node pmfElement) {
Properties p = new Properties();
NamedNodeMap attributes = pmfElement.getAttributes();
if (attributes == null) {
return p;
}
for(int i = 0; i < attributes.getLength(); i++) {
Node att = attributes.item(i);
String attName = att.getNodeName();
String attValue = att.getNodeValue().trim();
String jdoPropertyName =
(String) ATTRIBUTE_PROPERTY_XREF.get(attName);
p.put(
jdoPropertyName != null
? jdoPropertyName
: attName,
attValue);
}
return p;
}
protected static Properties readPropertiesFromPMFSubelements(
Node pmfElement, URL url) {
Properties p = new Properties();
NodeList elements = pmfElement.getChildNodes();
if (elements == null) {
return p;
}
for(int i = 0; i < elements.getLength(); i++) {
Node element = elements.item(i);
if (element.getNodeType() != Node.ELEMENT_NODE) {
continue;
}
String elementName = element.getNodeName();
NamedNodeMap attributes = element.getAttributes();
if (ELEMENT_PROPERTY.equalsIgnoreCase(elementName)) {
//
// get the "name" attribute's value (required)
Node nameAtt = attributes.getNamedItem(PROPERTY_ATTRIBUTE_NAME);
if (nameAtt == null) {
throw new JDOFatalUserException(
msg.msg("EXC_PropertyElementHasNoNameAttribute", url));
}
String name = nameAtt.getNodeValue().trim();
if ("".equals(name)) {
throw new JDOFatalUserException(
msg.msg(
"EXC_PropertyElementNameAttributeHasNoValue",
name,
url));
}
// The next call allows users to use either the
// attribute names or the
// "javax.jdo" property names in element "name"
// attributes. Handy-dandy.
String jdoPropertyName =
(String) ATTRIBUTE_PROPERTY_XREF.get(name);
String propertyName = jdoPropertyName != null
? jdoPropertyName
: name;
if (p.containsKey(propertyName)) {
throw new JDOFatalUserException(
msg.msg(
"EXC_DuplicatePropertyNameGivenInPropertyElement",
propertyName,
url));
}
// get the "value" attribute's value (optional)
Node valueAtt = attributes.getNamedItem(
PROPERTY_ATTRIBUTE_VALUE);
String value = valueAtt == null
? null
: valueAtt.getNodeValue().trim();
p.put(propertyName, value);
}
else if (ELEMENT_INSTANCE_LIFECYCLE_LISTENER.equals(elementName)) {
//
// get the "listener" attribute's value
Node listenerAtt = attributes.getNamedItem(
INSTANCE_LIFECYCLE_LISTENER_ATTRIBUTE_LISTENER);
if (listenerAtt == null) {
throw new JDOFatalUserException(
msg.msg(
"EXC_MissingListenerAttribute",
url));
}
String listener = listenerAtt.getNodeValue().trim();
if ("".equals(listener)) {
throw new JDOFatalUserException(
msg.msg(
"EXC_MissingListenerAttributeValue",
url));
}
// listener properties are of the form
// "javax.jdo.option.InstanceLifecycleListener." + listener
listener =
PROPERTY_PREFIX_INSTANCE_LIFECYCLE_LISTENER + listener;
// get the "classes" attribute's value (optional)
Node classesAtt = attributes.getNamedItem(
INSTANCE_LIFECYCLE_LISTENER_ATTRIBUTE_CLASSES);
String value = classesAtt == null
? ""
: classesAtt.getNodeValue().trim();
p.put(listener, value);
}
}
return p;
}
protected static boolean isNullOrBlank(String s) {
return s == null || "".equals(s.trim());
}
/**
* Returns a {@link PersistenceManagerFactory} configured based
* on the properties stored in the file at
* propsFile
. This method is equivalent to
* invoking {@link
* #getPersistenceManagerFactory(File,ClassLoader)} with
* Thread.currentThread().getContextClassLoader()
as
* the loader
argument.
* @since 2.0
* @param propsFile the file containing the Properties
* @return the PersistenceManagerFactory
*/
public static PersistenceManagerFactory getPersistenceManagerFactory
(File propsFile) {
return getPersistenceManagerFactory(
propsFile, getContextClassLoader());
}
/**
* Returns a {@link PersistenceManagerFactory} configured based
* on the properties stored in the file at
* propsFile
. Creates a {@link
* PersistenceManagerFactory} with loader
. Any
* IOException
s or
* FileNotFoundException
s thrown during resource
* loading will be wrapped in a {@link JDOFatalUserException}.
* @since 2.0
* @param propsFile the file containing the Properties
* @param loader the class loader to use to load the
* PersistenceManagerFactory
class
* @return the PersistenceManagerFactory
*/
public static PersistenceManagerFactory getPersistenceManagerFactory
(File propsFile, ClassLoader loader) {
if (propsFile == null)
throw new JDOFatalUserException (msg.msg (
"EXC_GetPMFNullFile")); //NOI18N
InputStream in = null;
try {
in = new FileInputStream(propsFile);
return getPersistenceManagerFactory(in, loader);
} catch (FileNotFoundException fnfe) {
throw new JDOFatalUserException (msg.msg (
"EXC_GetPMFNoFile", propsFile), fnfe); //NOI18N
} finally {
if (in != null)
try {
in.close ();
} catch (IOException ioe) { }
}
}
/**
* Returns a {@link PersistenceManagerFactory} at the JNDI
* location specified by jndiLocation
in the context
* context
. If context
is
* null
, new InitialContext()
will be
* used. This method is equivalent to invoking {@link
* #getPersistenceManagerFactory(String,Context,ClassLoader)}
* with Thread.currentThread().getContextClassLoader()
as
* the loader
argument.
* @since 2.0
* @param jndiLocation the JNDI location containing the
* PersistenceManagerFactory
* @param context the context in which to find the named
* PersistenceManagerFactory
* @return the PersistenceManagerFactory
*/
public static PersistenceManagerFactory getPersistenceManagerFactory
(String jndiLocation, Context context) {
return getPersistenceManagerFactory (jndiLocation, context,
getContextClassLoader());
}
/**
* Returns a {@link PersistenceManagerFactory} at the JNDI
* location specified by jndiLocation
in the context
* context
. If context
is
* null
, new InitialContext()
will be
* used. Creates a {@link PersistenceManagerFactory} with
* loader
. Any NamingException
s thrown
* will be wrapped in a {@link JDOFatalUserException}.
* @since 2.0
* @param jndiLocation the JNDI location containing the
* PersistenceManagerFactory
* @param context the context in which to find the named
* PersistenceManagerFactory
* @param loader the class loader to use to load the
* PersistenceManagerFactory
class
* @return the PersistenceManagerFactory
*/
public static PersistenceManagerFactory getPersistenceManagerFactory
(String jndiLocation, Context context, ClassLoader loader) {
if (jndiLocation == null)
throw new JDOFatalUserException (msg.msg (
"EXC_GetPMFNullJndiLoc")); //NOI18N
if (loader == null)
throw new JDOFatalUserException (msg.msg (
"EXC_GetPMFNullLoader")); //NOI18N
try {
if (context == null)
context = new InitialContext ();
Object o = context.lookup (jndiLocation);
return (PersistenceManagerFactory) PortableRemoteObject.narrow
(o, PersistenceManagerFactory.class);
} catch (NamingException ne) {
throw new JDOFatalUserException (msg.msg (
"EXC_GetPMFNamingException", jndiLocation, loader), ne); //NOI18N
}
}
/**
* Returns a {@link PersistenceManagerFactory} configured based
* on the Properties stored in the input stream at
* stream
. This method is equivalent to
* invoking {@link
* #getPersistenceManagerFactory(InputStream,ClassLoader)} with
* Thread.currentThread().getContextClassLoader()
as
* the loader
argument.
* @since 2.0
* @param stream the stream containing the Properties
* @return the PersistenceManagerFactory
*/
public static PersistenceManagerFactory getPersistenceManagerFactory
(InputStream stream) {
return getPersistenceManagerFactory(
stream, getContextClassLoader());
}
/**
* Returns a {@link PersistenceManagerFactory} configured based
* on the Properties stored in the input stream at
* stream
. Creates a {@link
* PersistenceManagerFactory} with loader
. Any
* IOException
s thrown during resource
* loading will be wrapped in a {@link JDOFatalUserException}.
* @since 2.0
* @param stream the stream containing the Properties
* @param loader the class loader to use to load the
* PersistenceManagerFactory
class
* @return the PersistenceManagerFactory
*/
public static PersistenceManagerFactory getPersistenceManagerFactory
(InputStream stream, ClassLoader loader) {
if (stream == null)
throw new JDOFatalUserException (msg.msg (
"EXC_GetPMFNullStream")); //NOI18N
Properties props = new Properties ();
try {
props.load (stream);
} catch (IOException ioe) {
throw new JDOFatalUserException
(msg.msg ("EXC_GetPMFIOExceptionStream"), ioe); //NOI18N
}
return getPersistenceManagerFactory (props, loader);
}
/**
* Get a JDOEnhancer
using the available enhancer(s) specified in
* "META-INF/services/JDOEnhancer" using the context class loader.
* @return the JDOEnhancer
.
* @throws JDOFatalUserException if no available enhancer
* @since 3.0
*/
public static JDOEnhancer getEnhancer() {
return getEnhancer(getContextClassLoader());
}
/**
* Get a JDOEnhancer
using the available enhancer(s) specified in
* "META-INF/services/JDOEnhancer"
* @param loader the loader to use for loading the JDOEnhancer class (if any)
* @return the JDOEnhancer
.
* @throws JDOFatalUserException if no available enhancer
* @since 3.0
*/
public static JDOEnhancer getEnhancer(ClassLoader loader) {
ClassLoader ctrLoader = loader;
if (ctrLoader == null) {
ctrLoader = Thread.currentThread().getContextClassLoader();
}
/*
* If you have a jar file that provides the jdo enhancer implementation,
* a file naming the implementation goes into the file
* packaged into the jar file, called "META-INF/services/javax.jdo.JDOEnhancer".
* The contents of the file is a string that is the enhancer class name.
* For each file in the class loader named "META-INF/services/javax.jdo.JDOEnhancer",
* this method will invoke the default constructor of the implementation class.
* Return the enhancer if a valid class name is extracted from resources and
* the invocation returns an instance.
* Otherwise add the exception thrown to an exception list.
*/
ArrayList exceptions = new ArrayList();
int numberOfJDOEnhancers = 0;
try {
Enumeration urls = getResources(loader, SERVICE_LOOKUP_ENHANCER_RESOURCE_NAME);
if (urls != null) {
while (urls.hasMoreElements()) {
numberOfJDOEnhancers++;
try {
String enhancerClassName = getClassNameFromURL((URL)urls.nextElement());
Class> enhancerClass = forName(enhancerClassName, true, ctrLoader);
JDOEnhancer enhancer = (JDOEnhancer)enhancerClass.newInstance();
return enhancer;
} catch (Throwable ex) {
// remember exceptions from failed enhancer invocations
exceptions.add(ex);
}
}
}
} catch (Throwable ex) {
exceptions.add(ex);
}
throw new JDOFatalUserException(msg.msg("EXC_GetEnhancerNoValidEnhancerAvailable", numberOfJDOEnhancers),
(Throwable[])exceptions.toArray(new Throwable[exceptions.size()]));
}
/** Get the context class loader associated with the current thread.
* This is done in a doPrivileged block because it is a secure method.
* @return the current thread's context class loader.
* @since 2.0
*/
private static ClassLoader getContextClassLoader() {
return AccessController.doPrivileged(
new PrivilegedAction () {
public ClassLoader run () {
return Thread.currentThread().getContextClassLoader();
}
}
);
}
/** Get the named resource as a stream from the resource loader.
* Perform this operation in a doPrivileged block.
*/
private static InputStream getResourceAsStream(
final ClassLoader resourceLoader, final String name) {
return AccessController.doPrivileged(
new PrivilegedAction() {
public InputStream run() {
return resourceLoader.getResourceAsStream(name);
}
}
);
}
/** Get the named Method from the named class.
* Perform this operation in a doPrivileged block.
*
* @param implClass the class
* @param methodName the name of the method
* @param parameterTypes the parameter types of the method
* @return the Method instance
*/
private static Method getMethod(
final Class> implClass,
final String methodName,
final Class>[] parameterTypes)
throws NoSuchMethodException {
try {
return AccessController.doPrivileged(
new PrivilegedExceptionAction() {
public Method run() throws NoSuchMethodException {
return implClass.getMethod(methodName, parameterTypes);
}
}
);
} catch (PrivilegedActionException ex) {
throw (NoSuchMethodException)ex.getException();
}
}
/** Invoke the method.
* Perform this operation in a doPrivileged block.
*/
private static Object invoke(final Method method,
final Object instance, final Object[] parameters)
throws IllegalAccessException, InvocationTargetException {
try {
return (Object) AccessController.doPrivileged(
new PrivilegedExceptionAction() {
public Object run()
throws IllegalAccessException,
InvocationTargetException {
return method.invoke (instance, parameters);
}
}
);
} catch (PrivilegedActionException ex) {
Exception cause = (Exception)ex.getException();
if (cause instanceof IllegalAccessException)
throw (IllegalAccessException)cause;
else //if (cause instanceof InvocationTargetException)
throw (InvocationTargetException)cause;
}
}
/** Get resources of the resource loader.
* Perform this operation in a doPrivileged block.
* @param resourceLoader
* @param resourceName
* @return the resources
*/
protected static Enumeration getResources(
final ClassLoader resourceLoader,
final String resourceName)
throws IOException {
try {
return AccessController.doPrivileged(
new PrivilegedExceptionAction>() {
public Enumeration run() throws IOException {
return resourceLoader.getResources(resourceName);
}
}
);
} catch (PrivilegedActionException ex) {
throw (IOException)ex.getException();
}
}
/** Get the named class.
* Perform this operation in a doPrivileged block.
*
* @param name the name of the class
* @param init whether to initialize the class
* @param loader which class loader to use
* @return the class
*/
private static Class> forName(
final String name,
final boolean init,
final ClassLoader loader)
throws ClassNotFoundException {
try {
return AccessController.doPrivileged(
new PrivilegedExceptionAction>() {
public Class> run() throws ClassNotFoundException {
return Class.forName(name, init, loader);
}
}
);
} catch (PrivilegedActionException ex) {
throw (ClassNotFoundException)ex.getException();
}
}
/** Open an input stream on the url.
* Perform this operation in a doPrivileged block.
*
* @param url
* @return the input stream
*/
private static InputStream openStream(final URL url)
throws IOException {
try {
return AccessController.doPrivileged(
new PrivilegedExceptionAction() {
public InputStream run() throws IOException {
return url.openStream();
}
}
);
} catch (PrivilegedActionException ex) {
throw (IOException)ex.getException();
}
}
}