Index: src/java/javax/jdo/Bundle.properties =================================================================== --- src/java/javax/jdo/Bundle.properties (revision 513879) +++ src/java/javax/jdo/Bundle.properties (working copy) @@ -77,3 +77,34 @@ EXC_DateStringConstructor: Error parsing Date string "{0}" at position {1} \ using date format "{2}". MSG_unknown: unknown +EXC_DuplicateRequestedPUFoundInDifferentConfigs: Duplicate persistence unit \ +name "{0}" found in {1} and {2}. +EXC_DuplicateRequestedPersistenceUnitFoundInSameConfig: Duplicate persistence \ +unit name "{0}" found in {1}. +EXC_UnableToInvokeCreateEMFMethod: Unable to invoke \ +javax.persistence.Persistence.createEntityManagerFactory(String) +EXC_UnableToCastEMFToPMF: Unable to cast EntityManagerFactory class {0} \ +to javax.jdo.PersistenceManagerFactory +ERR_NoDocumentBuilderFactory: Unable to instantiate \ +javax.xml.parsers.DocumentBuilderFactory +EXC_ParserConfigException: Encountered parser configuration exception while \ +getting javax.xml.parsers.DocumentBuilder +EXC_ParsingException: Exception parsing configuration {0} +EXC_DuplicatePropertyFound: Duplicate property name "{0}" found in persistence \ +unit name "{1}" found in {2}. +EXC_DuplicatePersistenceUnitNamePropertyFoundWithinUnitConfig: Duplicate \ +persistence unit name found in {2}: attribute is "{0}", element is "{1}" +EXC_PropertyElementHasNoNameAttribute: Found element with no \ +"name" attribute in {0} +EXC_PropertyElementNameAttributeHasNoValue: Found element name \ +attribute "{0}" with no value in {1} +EXC_DuplicatePropertyNameGivenInPropertyElement: Duplicate property name given \ +in property element: name {0} in {1} +EXC_MissingListenerAttribute: Required \ +attribute "listener" missing in {0} +EXC_MissingListenerAttributeValue: attribute \ +"listener" missing value in {0} +EXC_InvalidJDOConfigNoRoot: No root element found in {0} +EXC_NoPMFConfigurableViaPropertiesOrXML: No PersistenceManagerFactory \ +configurable via properties resource "{0}" or no persistence unit named "{0}" \ +found using resource loader {1} Index: src/java/javax/jdo/Constants.java =================================================================== --- src/java/javax/jdo/Constants.java (revision 0) +++ src/java/javax/jdo/Constants.java (revision 0) @@ -0,0 +1,654 @@ +/* + * 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. + */ + +package javax.jdo; + +/** + * Constant values used in JDO. + * @since 2.1 + */ +public interface Constants { + + /** + * The name of the standard JDO configuration resource file(s). + * @since 2.1 + */ + static String JDOCONFIG_RESOURCE_NAME = + "META-INF/jdoconfig.xml"; + + /** + * The standard JDO configuration schema namespace. + * @since 2.1 + */ + static String JDOCONFIG_XSD_NS = + "http://java.sun.com/xml/ns/jdo/jdoconfig"; + + /** + * The name of the persitence manager factory element in the JDO + * configuration file. + * @since 2.1 + */ + static String ELEMENT_PERSISTENCE_MANAGER_FACTORY + = "persistence-manager-factory"; + + /** + * The name of the persitence manager factory element's "class" attribute. + * @since 2.1 + */ + static String PMF_ATTRIBUTE_CLASS + = "class"; + /** + * The name of the persitence manager factory element's + * "persistence-unit-name" attribute. + * @since 2.1 + */ + static String PMF_ATTRIBUTE_PERSISTENCE_UNIT_NAME + = "persistence-unit-name"; + /** + * The name of the persitence manager factory element's "optimistic" + * attribute. + * @since 2.1 + */ + static String PMF_ATTRIBUTE_OPTIMISTIC + = "optimistic"; + /** + * The name of the persitence manager factory element's "retain-values" + * attribute. + * @since 2.1 + */ + static String PMF_ATTRIBUTE_RETAIN_VALUES + = "retain-values"; + /** + * The name of the persitence manager factory element's "restore-values" + * attribute. + * @since 2.1 + */ + static String PMF_ATTRIBUTE_RESTORE_VALUES + = "restore-values"; + /** + * The name of the persitence manager factory element's "ignore-cache" + * attribute. + * @since 2.1 + */ + static String PMF_ATTRIBUTE_IGNORE_CACHE + = "ignore-cache"; + /** + * The name of the persitence manager factory element's + * "nontransactional-read" attribute. + * @since 2.1 + */ + static String PMF_ATTRIBUTE_NONTRANSACTIONAL_READ + = "nontransactional-read"; + /** + * The name of the persitence manager factory element's + * "nontransactional-write" attribute. + * @since 2.1 + */ + static String PMF_ATTRIBUTE_NONTRANSACTIONAL_WRITE + = "nontransactional-write"; + /** + * The name of the persitence manager factory element's "multithreaded" + * attribute. + * @since 2.1 + */ + static String PMF_ATTRIBUTE_MULTITHREADED + = "multithreaded"; + /** + * The name of the persitence manager factory element's + * "connection-driver-name" attribute. + * @since 2.1 + */ + static String PMF_ATTRIBUTE_CONNECTION_DRIVER_NAME + = "connection-driver-name"; + /** + * The name of the persitence manager factory element's + * "connection-user-name" attribute. + * @since 2.1 + */ + static String PMF_ATTRIBUTE_CONNECTION_USER_NAME + = "connection-user-name"; + /** + * The name of the persitence manager factory element's + * "connection-password" attribute. + * @since 2.1 + */ + static String PMF_ATTRIBUTE_CONNECTION_PASSWORD + = "connection-password"; + /** + * The name of the persitence manager factory element's "connection-url" + * attribute. + * @since 2.1 + */ + static String PMF_ATTRIBUTE_CONNECTION_URL + = "connection-url"; + /** + * The name of the persitence manager factory element's "connection-factory-name" attribute. + * @since 2.1 + */ + static String PMF_ATTRIBUTE_CONNECTION_FACTORY_NAME + = "connection-factory-name"; + /** + * The name of the persitence manager factory element's "connection-factory2-name" attribute. + * @since 2.1 + */ + static String PMF_ATTRIBUTE_CONNECTION_FACTORY2_NAME + = "connection-factory2-name"; + /** + * The name of the persitence manager factory element's "detach-all-on-commit" attribute. + * @since 2.1 + */ + static String PMF_ATTRIBUTE_DETACH_ALL_ON_COMMIT + = "detach-all-on-commit"; + /** + * The name of the persitence manager factory element's "mapping" attribute. + * @since 2.1 + */ + static String PMF_ATTRIBUTE_MAPPING + = "mapping"; + + /** + * The name of the persitence manager factory property elements in the JDO + * configuration file. + */ + static String ELEMENT_PROPERTY + = "property"; + /** + * The name of the persitence manager factory property element's "name" + * attribute. + */ + static String PROPERTY_ATTRIBUTE_NAME + = "name"; + /** + * The name of the persitence manager factory property element's "value" + * attribute. + */ + static String PROPERTY_ATTRIBUTE_VALUE + = "value"; + + /** + * The name of the instance lifecycle listener element in the JDO + * configuration file. + */ + static String ELEMENT_INSTANCE_LIFECYCLE_LISTENER + = "instance-lifecycle-listener"; + + /** + * The name of the instance lifecycle listener element's "listener" + * attribute. + */ + static String INSTANCE_LIFECYCLE_LISTENER_ATTRIBUTE_LISTENER + = "listener"; + /** + * The name of the instance lifecycle listener element's "classes" + * attribute. + */ + static String INSTANCE_LIFECYCLE_LISTENER_ATTRIBUTE_CLASSES + = "classes"; + + /** + * "javax.jdo.option.TransientTransactional" + * @see {@link PersistenceManagerFactory#supportedOptions()} + * @since 2.1 + */ + static String OPTION_TRANSACTIONAL_TRANSIENT + = "javax.jdo.option.TransientTransactional"; + /** + * "javax.jdo.option.NontransactionalRead" + * @see {@link PersistenceManagerFactory#supportedOptions()} + * @since 2.1 + */ + static String OPTION_NONTRANSACTIONAL_READ + = "javax.jdo.option.NontransactionalRead"; + /** + * "javax.jdo.option.NontransactionalWrite" + * @see {@link PersistenceManagerFactory#supportedOptions()} + * @since 2.1 + */ + static String OPTION_NONTRANSACTIONAL_WRITE + = "javax.jdo.option.NontransactionalWrite"; + /** + * "javax.jdo.option.RetainValues" + * @see {@link PersistenceManagerFactory#supportedOptions()} + * @since 2.1 + */ + static String OPTION_RETAIN_VALUES + = "javax.jdo.option.RetainValues"; + /** + * "javax.jdo.option.Optimistic" + * @see {@link PersistenceManagerFactory#supportedOptions()} + * @since 2.1 + */ + static String OPTION_OPTIMISTIC + = "javax.jdo.option.Optimistic"; + /** + * "javax.jdo.option.ApplicationIdentity" + * @see {@link PersistenceManagerFactory#supportedOptions()} + * @since 2.1 + */ + static String OPTION_APPLICATION_IDENTITY + = "javax.jdo.option.ApplicationIdentity"; + /** + * "javax.jdo.option.DatastoreIdentity" + * @see {@link PersistenceManagerFactory#supportedOptions()} + * @since 2.1 + */ + static String OPTION_DATASTORE_IDENTITY + = "javax.jdo.option.DatastoreIdentity"; + /** + * "javax.jdo.option.NonDurableIdentity" + * @see {@link PersistenceManagerFactory#supportedOptions()} + * @since 2.1 + */ + static String OPTION_NONDURABLE_IDENTITY + = "javax.jdo.option.NonDurableIdentity"; + /** + * "javax.jdo.option.ArrayList" + * @see {@link PersistenceManagerFactory#supportedOptions()} + * @since 2.1 + */ + static String OPTION_ARRAYLIST + = "javax.jdo.option.ArrayList"; + /** + * "javax.jdo.option.LinkedList" + * @see {@link PersistenceManagerFactory#supportedOptions()} + * @since 2.1 + */ + static String OPTION_LINKEDLIST + = "javax.jdo.option.LinkedList"; + /** + * "javax.jdo.option.TreeMap" + * @see {@link PersistenceManagerFactory#supportedOptions()} + * @since 2.1 + */ + static String OPTION_TREEMAP + = "javax.jdo.option.TreeMap"; + /** + * "javax.jdo.option.TreeSet" + * @see {@link PersistenceManagerFactory#supportedOptions()} + * @since 2.1 + */ + static String OPTION_TREESET + = "javax.jdo.option.TreeSet"; + /** + * "javax.jdo.option.Vector" + * @see {@link PersistenceManagerFactory#supportedOptions()} + * @since 2.1 + */ + static String OPTION_VECTOR + = "javax.jdo.option.Vector"; + /** + * "javax.jdo.option.Array" + * @see {@link PersistenceManagerFactory#supportedOptions()} + * @since 2.1 + */ + static String OPTION_ARRAY + = "javax.jdo.option.Array"; + /** + * "javax.jdo.option.NullCollection" + * @see {@link PersistenceManagerFactory#supportedOptions()} + * @since 2.1 + */ + static String OPTION_NULL_COLLECTION + = "javax.jdo.option.NullCollection"; + /** + * "javax.jdo.option.ChangeApplicationIdentity" + * @see {@link PersistenceManagerFactory#supportedOptions()} + * @since 2.1 + */ + static String OPTION_CHANGE_APPLICATION_IDENTITY + = "javax.jdo.option.ChangeApplicationIdentity"; + /** + * "javax.jdo.option.BinaryCompatibility" + * @see {@link PersistenceManagerFactory#supportedOptions()} + * @since 2.1 + */ + static String OPTION_BINARY_COMPATIBILITY + = "javax.jdo.option.BinaryCompatibility"; + /** + * "javax.jdo.option.GetDataStoreConnection" + * @see {@link PersistenceManagerFactory#supportedOptions()} + * @since 2.1 + */ + static String OPTION_GET_DATASTORE_CONNECTION + = "javax.jdo.option.GetDataStoreConnection"; + /** + * "javax.jdo.option.GetJDBCConnection" + * @see {@link PersistenceManagerFactory#supportedOptions()} + * @since 2.1 + */ + static String OPTION_GET_JDBC_CONNECTION + = "javax.jdo.option.GetJDBCConnection"; + /** + * "javax.jdo.query.SQL" + * @see {@link PersistenceManagerFactory#supportedOptions()} + * @since 2.1 + */ + static String OPTION_QUERY_SQL + = "javax.jdo.query.SQL"; + /** + * "javax.jdo.option.UnconstrainedQueryVariables" + * @see {@link PersistenceManagerFactory#supportedOptions()} + * @since 2.1 + */ + static String OPTION_UNCONSTRAINED_QUERY_VARIABLES + = "javax.jdo.option.UnconstrainedQueryVariables"; + /** + * "javax.jdo.option.version.DateTime" + * @see {@link PersistenceManagerFactory#supportedOptions()} + * @since 2.1 + */ + static String OPTION_VERSION_DATETIME + = "javax.jdo.option.version.DateTime"; + /** + * "javax.jdo.option.version.StateImage" + * @see {@link PersistenceManagerFactory#supportedOptions()} + * @since 2.1 + */ + static String OPTION_VERSION_STATE_IMAGE + = "javax.jdo.option.version.StateImage"; + /** + * "javax.jdo.option.PreDirtyEvent" + * @see {@link PersistenceManagerFactory#supportedOptions()} + * @since 2.1 + */ + static String OPTION_PREDIRTY_EVENT + = "javax.jdo.option.PreDirtyEvent"; + /** + * "javax.jdo.option.mapping.HeterogeneousObjectType" + * @see {@link PersistenceManagerFactory#supportedOptions()} + * @since 2.1 + */ + static String OPTION_MAPPING_HETEROGENEOUS_OBJECT_TYPE + = "javax.jdo.option.mapping.HeterogeneousObjectType"; + /** + * "javax.jdo.option.mapping.HeterogeneousInterfaceType" + * @see {@link PersistenceManagerFactory#supportedOptions()} + * @since 2.1 + */ + static String OPTION_MAPPING_HETEROGENEOUS_INTERFACE_TYPE + = "javax.jdo.option.mapping.HeterogeneousInterfaceType"; + /** + * "javax.jdo.option.mapping.JoinedTablePerClass" + * @see {@link PersistenceManagerFactory#supportedOptions()} + * @since 2.1 + */ + static String OPTION_MAPPING_JOINED_TABLE_PER_CLASS + = "javax.jdo.option.mapping.JoinedTablePerClass"; + /** + * "javax.jdo.option.mapping.JoinedTablePerConcreteClass" + * @see {@link PersistenceManagerFactory#supportedOptions()} + * @since 2.1 + */ + static String OPTION_MAPPING_JOINED_TABLE_PER_CONCRETE_CLASS + = "javax.jdo.option.mapping.JoinedTablePerConcreteClass"; + /** + * "javax.jdo.option.mapping.NonJoinedTablePerConcreteClass" + * @see {@link PersistenceManagerFactory#supportedOptions()} + * @since 2.1 + */ + static String OPTION_MAPPING_NON_JOINED_TABLE_PER_CONCRETE_CLASS + = "javax.jdo.option.mapping.NonJoinedTablePerConcreteClass"; + /** + * "javax.jdo.option.mapping.RelationSubclassTable" + * @see {@link PersistenceManagerFactory#supportedOptions()} + * @since 2.1 + */ + static String OPTION_MAPPING_RELATION_SUBCLASS_TABLE + = "javax.jdo.option.mapping.RelationSubclassTable"; + + /** + * "javax.jdo.PersistenceManagerFactoryClass" + * @see {@link JDOHelper#getPersistenceManagerFactory(java.util.Map)} + * @since 2.1 + */ + static String PROPERTY_PERSISTENCE_MANAGER_FACTORY_CLASS + = "javax.jdo.PersistenceManagerFactoryClass"; + + /** + * "javax.jdo.option.Optimistic" + * @see {@link PersistenceManagerFactory#getOptimistic()} + * @since 2.1 + */ + static String PROPERTY_OPTIMISTIC + = "javax.jdo.option.Optimistic"; + /** + * "javax.jdo.option.RetainValues" + * @see {@link PersistenceManagerFactory#getRetainValues()} + * @since 2.1 + */ + static String PROPERTY_RETAIN_VALUES + = "javax.jdo.option.RetainValues"; + /** + * "javax.jdo.option.RestoreValues" + * @see {@link PersistenceManagerFactory#getRestoreValues()} + * @since 2.1 + */ + static String PROPERTY_RESTORE_VALUES + = "javax.jdo.option.RestoreValues"; + /** + * "javax.jdo.option.IgnoreCache" + * @see {@link PersistenceManagerFactory#getIgnoreCache()} + * @since 2.1 + */ + static String PROPERTY_IGNORE_CACHE + = "javax.jdo.option.IgnoreCache"; + /** + * "javax.jdo.option.NontransactionalRead" + * @see {@link PersistenceManagerFactory#getNontransactionalRead()} + * @since 2.1 + */ + static String PROPERTY_NONTRANSACTIONAL_READ + = "javax.jdo.option.NontransactionalRead"; + /** + * "javax.jdo.option.NontransactionalWrite" + * @see {@link PersistenceManagerFactory#getNontransactionalWrite()} + * @since 2.1 + */ + static String PROPERTY_NONTRANSACTIONAL_WRITE + = "javax.jdo.option.NontransactionalWrite"; + /** + * "javax.jdo.option.Multithreaded" + * @see {@link PersistenceManagerFactory#getMultithreaded()} + * @since 2.1 + */ + static String PROPERTY_MULTITHREADED + = "javax.jdo.option.Multithreaded"; + /** + * "javax.jdo.option.DetachAllOnCommit" + * @see {@link PersistenceManagerFactory#getDetachAllOnCommit()} + * @since 2.1 + */ + static String PROPERTY_DETACH_ALL_ON_COMMIT + = "javax.jdo.option.DetachAllOnCommit"; + /** + * "javax.jdo.option.ConnectionDriverName" + * @see {@link PersistenceManagerFactory#getConnectionDriverName()} + * @since 2.1 + */ + static String PROPERTY_CONNECTION_DRIVER_NAME + = "javax.jdo.option.ConnectionDriverName"; + /** + * "javax.jdo.option.ConnectionUserName" + * @see {@link PersistenceManagerFactory#getConnectionUserName()} + * @since 2.1 + */ + static String PROPERTY_CONNECTION_USER_NAME + = "javax.jdo.option.ConnectionUserName"; + /** + * "javax.jdo.option.Password" + * @since 2.1 + */ + static String PROPERTY_CONNECTION_PASSWORD + = "javax.jdo.option.ConnectionPassword"; + /** + * "javax.jdo.option.ConnectionURL" + * @see {@link PersistenceManagerFactory#getConnectionURL()} + * @since 2.1 + */ + static String PROPERTY_CONNECTION_URL + = "javax.jdo.option.ConnectionURL"; + /** + * "javax.jdo.option.ConnectionFactoryName" + * @see {@link PersistenceManagerFactory#getConnectionFactoryName()} + * @since 2.1 + */ + static String PROPERTY_CONNECTION_FACTORY_NAME + = "javax.jdo.option.ConnectionFactoryName"; + /** + * "javax.jdo.option.ConnectionFactory2Name" + * @see {@link PersistenceManagerFactory#getConnectionFactory2Name()} + * @since 2.1 + */ + static String PROPERTY_CONNECTION_FACTORY2_NAME + = "javax.jdo.option.ConnectionFactory2Name"; + /** + * "javax.jdo.option.Mapping" + * @see {@link PersistenceManagerFactory#getMapping()} + * @since 2.1 + */ + static String PROPERTY_MAPPING + = "javax.jdo.option.Mapping"; + /** + * "javax.jdo.option.PersistenceUnitName" + * @see {@link PersistenceManagerFactory#getPersistenceUnitName()} + * @since 2.1 + */ + static String PROPERTY_PERSISTENCE_UNIT_NAME + = "javax.jdo.option.PersistenceUnitName"; + + /** + * Prefix used to configure + * {@link javax.jdo.listener.InstanceLifecycleListener} instances + * externally. + * To configure an InstanceLifecycleListener via properties, + * create a property name with the prefix of + * this constant and append the fully qualified listener class name, then + * set its value to the comma- or whitespace-delimited list + * of persistence-capable classes whose instances are to be observed. + * Use no value to indicate that instances of + * all persistence-capable classes are to be observed.
+ * For example,
+ * javax.jdo.option.InstanceLifecycleListener.com.example.MyListener=com.example.Foo,com.example.Bar
+ * is equivalent to calling
+ * pmf.addInstanceLifecycleListener(new com.example.MyListener(), new Class[] {com.example.Foo.class, com.example.Bar.class});
+ * where pmf is an instance of type + * PersistenceManagerFactory. + * @see {@link javax.jdo.PersistenceManagerFactory#addInstanceLifecycleListener(javax.jdo.listener.InstanceLifecycleListener,Class[])} + * @since 2.1 + */ + static String PROPERTY_PREFIX_INSTANCE_LIFECYCLE_LISTENER + = "javax.jdo.option.InstanceLifecycleListener."; + + /** + * Mapping "javax.jdo.mapping.Catalog" + * @since 2.1 + */ + static String PROPERTY_MAPPING_CATALOG + = "javax.jdo.mapping.Catalog"; + /** + * Mapping "javax.jdo.mapping.Schema" + * @since 2.1 + */ + static String PROPERTY_MAPPING_SCHEMA + = "javax.jdo.mapping.Schema"; + + /** + * Nonconfigurable property constanct "VendorName" + * @see {@link PersistenceManagerFactory#getProperties()} + * @since 2.1 + */ + static String NONCONFIGURABLE_PROPERTY_VENDOR_NAME + = "VendorName"; + /** + * Nonconfigurable property constanct "VersionNumber" + * @see {@link PersistenceManagerFactory#getProperties()} + * @since 2.1 + */ + static String NONCONFIGURABLE_PROPERTY_VERSION_NUMBER + = "VersionNumber"; + + /** + * The value for TransactionType to specify that transactions + * are managed by the Java Transactions API, as documented in + * JSR-220. + * @since 2.1 + */ + static String JTA = "JTA"; + + /** + * The value for TransactionType to specify that transactions + * are managed by the javax.jdo.Transaction instance, similar + * to the usage as documented in JSR-220. + * @since 2.1 + */ + static String RESOURCE_LOCAL = "RESOURCE_LOCAL"; + + /** + * The name of the resource for the DTD of the standard JDO configuration + * file. + * @since 2.1 + */ + static String JDOCONFIG_DTD_RESOURCE = "javax/jdo/jdoconfig_2_1.dtd"; + + /** + * The name of the resource for the XML schema of the standard JDO + * configuration file. + * @since 2.1 + */ + static String JDOCONFIG_XSD_RESOURCE = "javax/jdo/jdoconfig_2_1.xsd"; + + /** + * The name of the resource for the DTD of the standard JDO metadata file. + * @since 2.1 + */ + static String JDO_DTD_RESOURCE = "javax/jdo/jdo_2_0.dtd"; + + /** + * The name of the resource for the XML schema of the standard JDO + * metadata file. + * @since 2.1 + */ + static String JDO_XSD_RESOURCE = "javax/jdo/jdo_2_0.xsd"; + + /** + * The name of the resource for the DTD of the standard JDO + * object-relational mapping metadata file. + * @since 2.1 + */ + static String ORM_DTD_RESOURCE = "javax/jdo/orm_2_0.dtd"; + + /** + * The name of the resource for the XML schema of the standard JDO + * object-relational mapping metadata file. + * @since 2.1 + */ + static String ORM_XSD_RESOURCE = "javax/jdo/orm_2_0.xsd"; + + /** + * The name of the resource for the DTD of the standard JDO query + * metadata file. + * @since 2.1 + */ + static String JDOQUERY_DTD_RESOURCE = "javax/jdo/jdoquery_2_0.dtd"; + + /** + * The name of the resource for the XML schema of the standard JDO query + * metadata file. + * @since 2.1 + */ + static String JDOQUERY_XSD_RESOURCE = "javax/jdo/jdoquery_2_0.xsd"; +} Index: src/java/javax/jdo/JDOHelper.java =================================================================== --- src/java/javax/jdo/JDOHelper.java (revision 513879) +++ src/java/javax/jdo/JDOHelper.java (working copy) @@ -22,6 +22,14 @@ package javax.jdo; +import org.xml.sax.SAXException; + +import org.w3c.dom.Document; +import org.w3c.dom.NodeList; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.Element; + import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -31,16 +39,20 @@ import java.lang.reflect.Method; import java.lang.reflect.InvocationTargetException; +import java.security.AccessController; +import java.security.PrivilegedAction; + +import java.net.URL; + +import java.util.Collection; import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Properties; +import java.util.HashMap; +import java.util.Enumeration; +import java.util.Collections; -import java.security.AccessController; -import java.security.PrivilegedAction; - import javax.jdo.spi.I18NHelper; import javax.jdo.spi.JDOImplHelper; import javax.jdo.spi.JDOImplHelper.StateInterrogationBooleanReturn; @@ -54,7 +66,12 @@ import javax.rmi.PortableRemoteObject; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.FactoryConfigurationError; + /** * This class can be used by a JDO-aware application to call the JDO behavior * of PersistenceCapable instances without declaring them to be @@ -69,13 +86,100 @@ * * @version 2.1 */ -public class JDOHelper extends Object { - +public class JDOHelper extends Object implements Constants { + + /** + * A mapping from jdoconfig.xsd element attributes to PMF properties. + */ + static final Map ATTRIBUTE_PROPERTY_XREF + = createAttributePropertyXref(); + + /** + * The standard XML schema type. + */ + protected static final String XSD_TYPE + = "http://www.w3.org/2001/XMLSchema"; + + /** + * The JAXP schema language property. + */ + protected static final String SCHEMA_LANGUAGE_PROP + = "http://java.sun.com/xml/jaxp/properties/schemaLanguage"; + + /** + * External schema location property. + */ + protected static final String SCHEMA_LOCATION_PROP + = "http://apache.org/xml/properties/schema/external-schemaLocation"; + /** 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_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); + + return Collections.unmodifiableMap(xref); + } + /** The JDOImplHelper instance used for handling non-binary-compatible * implementations. */ @@ -487,23 +591,35 @@ } } - /** Get a PersistenceManagerFactory based on a Properties + /** 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(String,ClassLoader) + */ + public static PersistenceManagerFactory getPersistenceManagerFactory() { + ClassLoader cl = getContextClassLoader(); + return getPersistenceManagerFactory ((String)null, cl); + } + + /** 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 + * @param props a Properties instance with properties of the * PersistenceManagerFactory. - * @see #getPersistenceManagerFactory(Map,ClassLoader) + * @see #getPersistenceManagerFactory(java.util.Map,ClassLoader) */ public static PersistenceManagerFactory getPersistenceManagerFactory (Map props) { ClassLoader cl = getContextClassLoader(); return getPersistenceManagerFactory (props, cl); } - + /** * Get a PersistenceManagerFactory based on a - * Properties instance and a class loader. + * Map instance and a class loader. * The following are standard key values: *
"javax.jdo.PersistenceManagerFactoryClass" *
"javax.jdo.option.Optimistic", @@ -520,8 +636,20 @@ *
"javax.jdo.option.ConnectionFactory2Name", *
"javax.jdo.option.Mapping", *
"javax.jdo.mapping.Catalog", - *
"javax.jdo.mapping.Schema". - *

JDO implementations + *
"javax.jdo.mapping.Schema", + *
"javax.jdo.option.PersistenceUnitName". + * + * 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 @@ -544,9 +672,9 @@ public static PersistenceManagerFactory getPersistenceManagerFactory (Map props, ClassLoader cl) { String pmfClassName = (String) props.get ( - "javax.jdo.PersistenceManagerFactoryClass"); //NOI18N + PROPERTY_PERSISTENCE_MANAGER_FACTORY_CLASS); //NOI18N if (pmfClassName == null) { - throw new JDOFatalUserException (msg.msg( + throw new JDOFatalUserException(msg.msg( "EXC_GetPMFNoClassNameProperty")); // NOI18N } try { @@ -584,93 +712,676 @@ } /** - * Returns a {@link PersistenceManagerFactory} configured based + * Returns a named {@link PersistenceManagerFactory} with the given persistence unit name or, + * if not found, a {@link PersistenceManagerFactory} configured based * on the properties stored in the resource at - * propsResource. This method is equivalent to + * name. This method is equivalent to * invoking {@link * #getPersistenceManagerFactory(String,ClassLoader)} with * Thread.currentThread().getContextClassLoader() as * the loader argument. + * If multiple persistence units with the name given are found, a {@link JDOFatalUserException} is thrown. * @since 2.0 - * @param propsResource the resource containing the Properties + * @param name the persistence unit name or resource containing the Properties * @return the PersistenceManagerFactory */ public static PersistenceManagerFactory getPersistenceManagerFactory - (String propsResource) { - return getPersistenceManagerFactory (propsResource, + (String name) { + return getPersistenceManagerFactory (name, getContextClassLoader()); } /** - * Returns a {@link PersistenceManagerFactory} configured based + * Returns a named {@link PersistenceManagerFactory} with the given persistence unit name or, + * if not found, a {@link PersistenceManagerFactory} configured based * on the properties stored in the resource at - * propsResource. Loads the resource via + * name. Loads the resource via * loader, and creates a {@link * PersistenceManagerFactory} with loader. Any * IOExceptions thrown during resource loading will * be wrapped in a {@link JDOFatalUserException}. + * If multiple persistence units with the name given are found, a {@link JDOFatalUserException} is thrown. * @since 2.0 - * @param propsResource the resource containing the Properties - * @param loader the class loader to use to load both the propsResource and + * @param name the persistence unit name or resource containing the Properties + * @param loader the class loader to use to load both the name and * the PersistenceManagerFactory class * @return the PersistenceManagerFactory */ public static PersistenceManagerFactory getPersistenceManagerFactory - (String propsResource, ClassLoader loader) { - return getPersistenceManagerFactory(propsResource, loader, loader); + (String name, ClassLoader loader) { + return getPersistenceManagerFactory(name, loader, loader); } /** - * Returns a {@link PersistenceManagerFactory} configured based + * Returns a named {@link PersistenceManagerFactory} with the given + * persistence unit name or, + * if not found, a {@link PersistenceManagerFactory} configured based * on the properties stored in the resource at - * propsResource. Loads the Properties via - * propsLoader, and creates a {@link + * name. Loads the Properties via + * resourceLoader, and creates a {@link * PersistenceManagerFactory} with pmfLoader. Any - * IOExceptions thrown during resource loading will + * exceptions thrown during resource loading will * be wrapped in a {@link JDOFatalUserException}. + * If multiple persistence units with the requested name are found, a + * {@link JDOFatalUserException} is thrown. * @since 2.0 - * @param propsResource the resource containing the Properties - * @param propsLoader the class loader to use to load the propsResource + * @param name the persistence unit name or resource containing the Properties + * @param resourceLoader the class loader to use to load the name * @param pmfLoader the class loader to use to load the * PersistenceManagerFactory class * @return the PersistenceManagerFactory */ public static PersistenceManagerFactory getPersistenceManagerFactory - (String propsResource, ClassLoader propsLoader, ClassLoader pmfLoader) { - - if (propsResource == null) + (String name, ClassLoader resourceLoader, ClassLoader pmfLoader) { + + if (resourceLoader == null) throw new JDOFatalUserException (msg.msg ( - "EXC_GetPMFNullResource")); //NOI18N - if (propsLoader == null) - throw new JDOFatalUserException (msg.msg ( "EXC_GetPMFNullPropsLoader")); //NOI18N if (pmfLoader == null) throw new JDOFatalUserException (msg.msg ( "EXC_GetPMFNullPMFLoader")); //NOI18N - Properties props = new Properties (); InputStream in = null; + if (name != null) { // then try to load resources from properties file + Properties props = new Properties (); + try { + in = resourceLoader.getResourceAsStream (name); + if (in != null) { + // then some kind of resource was found by the given name; + // assume that it's a properties file and proceed as usual + props.load (in); + return getPersistenceManagerFactory (props, pmfLoader); + } + } + catch (IOException ioe) { + throw new JDOFatalUserException (msg.msg ( + "EXC_GetPMFIOExceptionRsrc", name), ioe); //NOI18N + } + finally { + if (in != null) + try { + in.close (); + } catch (IOException ioe) { } + } + } + // JDO 2.1: else name was null or no resource found by given name; + // assume name represents name of PU + + PersistenceManagerFactory pmf = getPersistenceUnit( + name == null ? "" : name.trim(), + resourceLoader, + pmfLoader + ); + if (pmf != null) { + return pmf; + } + + // else no PU found + throw new JDOFatalUserException (msg.msg ( + "EXC_NoPMFConfigurableViaPropertiesOrXML", + name, + resourceLoader)); //NOI18N + } + + /** Find and return

    + *
  • a {@link PersistenceManagerFactory} with the given name,
  • + *
  • a JPA EntityManagerFactory cast to a + * {@link PersistenceManagerFactory}, or
  • + *
  • null if not found.
  • + * If name is null + * or blank, this method attempts to return the anonymous + * {@link PersistenceManagerFactory}. If multiple persistence units with + * the given name are found (including the anonymous persistence unit), + * this method will throw {@link JDOFatalUserException}. + * + * @param name The persistence unit name, or null, the empty string or a + * string only containing whitespace characters for the anonymous + * persistence unit. + * @param resourceLoader The ClassLoader used to load the standard JDO + * configuration file(s) given in the constant + * {@link Constants#JDOCONFIG_RESOURCE_NAME}. + * @param pmfLoader The loader used to load the + * {@link PersistenceManagerFactory} implementation class. + * @return A {@link PersistenceManagerFactory} corresponding to the + * persistence unit name if found, or null if not found. + * @throws JDOFatalUserException if multiple persistence units are found + * with the given name, or any other is encountered. + * @since 2.1 + */ + public static PersistenceManagerFactory getPersistenceUnit( + String name, + ClassLoader resourceLoader, + ClassLoader pmfLoader + ) { + Map properties = getPersistenceUnitProperties( + name, resourceLoader, pmfLoader, JDOCONFIG_RESOURCE_NAME); + + if (properties != null) { // found requested JDO persistence unit props + return getPersistenceManagerFactory(properties, pmfLoader); + } + + // else try to return PMF from JPA EMF + if ("".equals(name)) { // no such thing as an anonymous JPA EMF + return null; + } + + // else try to return PMF from named JPA EMF + return getPMFFromEMF(name, pmfLoader); + } + + protected static Map getPersistenceUnitProperties( + String name, + ClassLoader resourceLoader, + ClassLoader pmfLoader + ) { + return getPersistenceUnitProperties( + name, resourceLoader, pmfLoader, JDOCONFIG_RESOURCE_NAME); + } + + /** + * Find and return the named {@link PersistenceManagerFactory}, or null if + * not found. If name is null, return the anonymous + * {@link PersistenceManagerFactory}. If multiple persistence units with + * the given name are found (including anonymous), 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 JDOCONFIG_RESOURCE_NAME. + * + * @param name The persistence unit name, or null or blank for the + * anonymous persistence unit. + * @param resourceLoader The ClassLoader used to load the standard JDO + * configuration file. + * @param pmfLoader The loader used to load the PMF implementation class. + * @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 persistence units are found + * with the given name, or any other exception is encountered. + */ + protected static Map getPersistenceUnitProperties( + String name, + ClassLoader resourceLoader, + ClassLoader pmfLoader, + String jdoconfigResourceName + ) { + /* JDO 2.1: + Attempt to find & return named persistence unit here. + If name == null or name == "", then we're looking for the default PMF. + + If we can't find it, this method returns null. + */ + name = name == null ? "" : name.trim(); // for use as key in Maps + + // key is PU name, value is Map of PU properties + Map/**/ propertiesByNameInAllConfigs + = new HashMap/**/(); try { - in = propsLoader.getResourceAsStream (propsResource); - if (in == null) - throw new JDOFatalUserException (msg.msg ( - "EXC_GetPMFNoResource", propsResource, propsLoader)); //NOI18N - props.load (in); - } catch (IOException ioe) { + URL firstFoundConfigURL = null; + + // get all JDO configurations + Enumeration resources = + resourceLoader.getResources(jdoconfigResourceName); + + if (resources.hasMoreElements()) { + + // get ready to parse XML + DocumentBuilderFactory factory = null; + // TODO: ensure DBF is initialized properly + factory = DocumentBuilderFactory.newInstance(); + factory.setIgnoringComments(true); + factory.setNamespaceAware(true); + factory.setValidating(false); + factory.setIgnoringElementContentWhitespace(true); + factory.setExpandEntityReferences(true); + + do { + URL currentConfigURL = (URL) resources.nextElement(); + Map/**/ propertiesByNameInCurrentConfig = + readPersistenceUnitProperties( + 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_DuplicateRequestedPUFoundInDifferentConfigs", + "".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", propsResource), ioe); //NOI18N + "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); + } + + + /** + * Convenience method for retrieving the JPA persistence unit by the given + * name. This method is equivalent to + * calling {@link #getPMFFromEMF(String,ClassLoader)} with the context ClassLoader. + * @see {@link #getPMFFromEMF(String,ClassLoader)} + */ + protected static PersistenceManagerFactory getPMFFromEMF(String name) { + return getPMFFromEMF(name, getContextClassLoader()); + } + + /** + * Attempts to locate a javax.persistence.EntityManagerFactory + * via the javax.persistence.Persistence method + * createEntityManagerFactory(String) + * and casts it to a {@link PersistenceManagerFactory}. It is a user error + * if his chosen JPA vendor's EntityManagerFactory + * implementation class does not also implement + * {@link PersistenceManagerFactory}. + * @param name The persistence unit name. + * @param loader The classloader used to attempt loading of the class + * javax.persistence.Persistence + * and javax.persistence.PersistenceException. + * @return The EntityManagerFactory, cast as a + * PersistenceManagerFactory for the given + * persistence unit name, or null if any of the following + * conditions are true. + *
      + *
    • The attempt to load javax.persistence.Persistence or + * javax.persistence.Persistence fails for any + * reason.
    • + *
    • The named JPA persistence unit is not found.
    • + *
    + * @throws JDOFatalUserException This method will throw + * a {@link JDOFatalUserException} + * with the exception that caused the error + * if any of the following conditions are true. + *
      + *
    • The javax.persistence.Persistence method + * createEntityManagerFactory(String) + * cannot be invoked.
    • + *
    • The javax.persistence.EntityManagerFactory cannot be + * cast to a + * {@link PersistenceManagerFactory}.
    • + *
    + */ + protected static PersistenceManagerFactory getPMFFromEMF( + String name, ClassLoader loader + ) { + /* + This implementation uses reflection to try to get an EMF so that + javax.jdo, a Java SE API, does not introduce an unnecessary + dependency on a Java EE API, namely the + javax.persistence.Persistence class, while still + being compatible with JPA. + */ + + // First, get required classes & methods + Class persistenceClass = null; + Class persistenceExceptionClass = null; + Method createEntityManagerFactoryMethod = null; + try { + persistenceClass = Class.forName( + "javax.persistenceClass.Persistence", + true, + loader); + + createEntityManagerFactoryMethod = persistenceClass.getMethod( + "createEntityManagerFactory", + new Class[] { String.class }); + + persistenceExceptionClass = + Class.forName( + "javax.persistenceClass.PersistenceException", + true, + loader); + } + catch (Exception x) { + // may happen -- if it does, javax.persistence.Persistence or + // requisites not available + return null; + } + + // Now, try to invoke createEntityManagerFactory method + Object entityManagerFactory = null; + Throwable t = null; + try { + entityManagerFactory = + createEntityManagerFactoryMethod.invoke( + persistenceClass, new Object[] { name }); + } + catch (RuntimeException x) { + if (persistenceExceptionClass.isAssignableFrom(x.getClass())) { + // named persistence unit not found + return null; + } + // else something else went wrong + t = x; + } + catch (Exception x) { + t = x; + } + if (t != null) { // something went wrong -- throw + throw new JDOFatalUserException( + msg.msg("EXC_UnableToInvokeCreateEMFMethod"), t); + } + + // Last, try to cast to PMF & return + try { + return (PersistenceManagerFactory) entityManagerFactory; + } + catch (ClassCastException x) { // EMF impl doesn't also implement PMF + throw new JDOFatalUserException( + msg.msg( + "EXC_UnableToCastEMFToPMF", + entityManagerFactory.getClass().getName()), + x); + } + } + + /** 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 requestedPersistenceUnitName 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/**/ readPersistenceUnitProperties( + URL url, + String requestedPersistenceUnitName, + DocumentBuilderFactory factory + ) { + requestedPersistenceUnitName = requestedPersistenceUnitName == null + ? "" + : requestedPersistenceUnitName.trim(); + + Map propertiesByName = new HashMap(); + InputStream in = null; + try { + DocumentBuilder builder = factory.newDocumentBuilder(); + in = url.openStream(); + Document doc = builder.parse(in); + + Element root = doc.getDocumentElement(); + if (root == null) { + throw new JDOFatalUserException( + msg.msg("EXC_InvalidJDOConfigNoRoot", url.toExternalForm()) + ); + } + + // TODO: consider namespace?!?! + 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 PU name (or names) now + String puNameFromAtts = + pmfPropertiesFromAttributes.getProperty( + PROPERTY_PERSISTENCE_UNIT_NAME); + String puNameFromElem = + pmfPropertiesFromElements.getProperty( + PROPERTY_PERSISTENCE_UNIT_NAME); + + String puName = null; + if (nullOrBlank(puNameFromAtts)) { + // no PU name attribute given + if (!nullOrBlank(puNameFromElem)) { + // PU name element was given + puName = puNameFromElem; + } + else { + // PU name not given at all, means the "anonymous" PU + puName = ""; + } + } + else { + // PU name given in an attribute + if (!nullOrBlank(puNameFromElem)) { + // exception -- PU name given as both att & elem + throw new JDOFatalUserException( + msg.msg( + "EXC_DuplicatePersistenceUnitNamePropertyFoundWithinUnitConfig", + puNameFromAtts, + puNameFromElem, + url.toExternalForm())); + } + puName = puNameFromAtts; + } + puName = puName == null ? "" : puName.trim(); + + // check for duplicate properties among atts & elems + if (requestedPersistenceUnitName.equals(puName)) { + 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, + puName, + 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 PU name + if (puName.equals(requestedPersistenceUnitName) + && propertiesByName.containsKey(puName)) { + + throw new JDOFatalUserException(msg.msg( + "EXC_DuplicateRequestedPersistenceUnitFoundInSameConfig", + puName, + url.toExternalForm())); + } + propertiesByName.put(puName, pmfProps); + } + return propertiesByName; + } + catch (IOException ioe) { + throw new JDOFatalUserException( + msg.msg("EXC_GetPMFIOExceptionRsrc", url.toString()), + ioe); //NOI18N + } + catch (ParserConfigurationException e) { + throw new JDOFatalUserException( + msg.msg("EXC_ParserConfigException"), + e); + } + catch (SAXException e) { + throw new JDOFatalUserException( + msg.msg("EXC_ParsingException", url.toExternalForm()), + e); + } + catch (JDOException e) { + throw e; + } + catch (RuntimeException e) { + throw new JDOFatalUserException( + msg.msg("EXC_ParsingException", url.toExternalForm()), + e); + } finally { - if (in != null) + if (in != null) { try { - in.close (); - } catch (IOException ioe) { } + in.close(); + } + catch (IOException ioe) { /* gulp */ } + } } + } - return getPersistenceManagerFactory (props, pmfLoader); + 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 + ? null + : classesAtt.getNodeValue().trim(); + + p.put(listener, value); + } + } + return p; + } + + protected static boolean nullOrBlank(String s) { + return s == null || "".equals(s.trim()); + } + /** * Returns a {@link PersistenceManagerFactory} configured based * on the properties stored in the file at Index: src/java/javax/jdo/PersistenceManagerFactory.java =================================================================== --- src/java/javax/jdo/PersistenceManagerFactory.java (revision 513879) +++ src/java/javax/jdo/PersistenceManagerFactory.java (working copy) @@ -25,6 +25,8 @@ import java.util.Properties; import java.util.Collection; +import java.io.Serializable; + import javax.jdo.datastore.DataStoreCache; import javax.jdo.listener.InstanceLifecycleListener; @@ -54,21 +56,8 @@ * @version 2.1 */ -public interface PersistenceManagerFactory extends java.io.Serializable { +public interface PersistenceManagerFactory extends Serializable { - /** - * The value for TransactionType to specify that transactions - * are managed by the Java Transactions API, as documented in - * JSR-220. - */ - public static final String JTA = "JTA"; - - /** - * The value for TransactionType to specify that transactions - * are managed by the javax.jdo.Transaction instance, similar - * to the usage as documented in JSR-220. - */ - public static final String RESOURCE_LOCAL = "RESOURCE_LOCAL"; /** Close this PersistenceManagerFactory. Check for * JDOPermission("closePersistenceManagerFactory") and if not authorized, @@ -425,8 +414,8 @@ * This has the same semantics as the same-named property in * JSR-220 EntityManagerFactory. * @see #getTransactionType() - * @see #JTA - * @see #RESOURCE_LOCAL + * @see Constants#JTA + * @see Constants#RESOURCE_LOCAL * @since 2.1 * @param name the TransactionType * @throws JDOUserException if the parameter is not a permitted value Index: src/schema/javax/jdo/jdoconfig_2_1.dtd =================================================================== --- src/schema/javax/jdo/jdoconfig_2_1.dtd (revision 0) +++ src/schema/javax/jdo/jdoconfig_2_1.dtd (revision 0) @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Index: src/schema/javax/jdo/jdoconfig_2_1.xsd =================================================================== --- src/schema/javax/jdo/jdoconfig_2_1.xsd (revision 0) +++ src/schema/javax/jdo/jdoconfig_2_1.xsd (revision 0) @@ -0,0 +1,172 @@ + + + + + + + This is the XML Schema for the JDO configuration file. + + + + + + + + The root configuration element for JDO. + + + + + + + + Standard JDO PersistenceManagerFactory + configuration properties. + Vendor-specific properties are set using + additional vendor-specific attributes and/or + property elements. + + + + + + + + Vendor-specific properties. + + + + + + + + + + javax.jdo.listener.InstanceLifecycleListener + instance configuration. + There is one + instance-lifecycle-listener element + per listener instance. + Only one instance of the listener + class is supported in this + configuration file. + If multiple instances of the same + listener class is required, then the + API + PersistenceManagerFactory.addInstanceLifecycleListener(...) + must be used. + + If attribute "classes" is missing, + all persistence-capable instances + are observed, + otherwise it is a comma- or + whitespace-delimited list of + persistence-capable + classes whose instances' will be + observed. + + + + + + + + + + + + + + + + + + + + These are attributes corresponding to the standard properties + defined in JDO 2.1. + Any other attributes present, if unrecognized by a JDO + implementation, may be silently ignored. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Index: test/java/javax/jdo/ClasspathHelper.java =================================================================== --- test/java/javax/jdo/ClasspathHelper.java (revision 0) +++ test/java/javax/jdo/ClasspathHelper.java (revision 0) @@ -0,0 +1,72 @@ +/* + * 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. + */ + +package javax.jdo; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; + +public class ClasspathHelper { + + private static URLClassLoader SYSTEM_CLASSLOADER = (URLClassLoader) ClassLoader.getSystemClassLoader(); + private static Method METHOD; + static { + try { + METHOD = URLClassLoader.class.getDeclaredMethod("addURL", new Class[] { URL.class }); + METHOD.setAccessible(true); + } + catch (Throwable t) { + throw new RuntimeException(t); + } + } + + public static void addFile(String s) throws IOException { + addFile(s, null); + } + + public static void addFile(File f) throws IOException { + addFile(f, null); + } + + public static void addURL(URL u) throws IOException { + addURL(u, null); + } + + public static void addFile(String s, URLClassLoader loader) throws IOException { + addFile(new File(s), loader); + } + + public static void addFile(File f, URLClassLoader loader) throws IOException { + addURL(f.toURL(), loader); + } + + public static void addURL(URL u, URLClassLoader loader) throws IOException { + if (loader == null) { + loader = SYSTEM_CLASSLOADER; + } + try { + METHOD.invoke(loader, new Object[] { u }); + } + catch (Throwable t) { + throw new IOException("Could not add URL to system classloader: " + t.getMessage()); + } + } +} + Index: test/java/javax/jdo/JDOHelperConfigTest.java =================================================================== --- test/java/javax/jdo/JDOHelperConfigTest.java (revision 0) +++ test/java/javax/jdo/JDOHelperConfigTest.java (revision 0) @@ -0,0 +1,316 @@ +/* + * 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. + */ + +package javax.jdo; + +import junit.framework.TestSuite; + +import javax.jdo.util.AbstractTest; +import javax.jdo.util.BatchTestRunner; +import java.util.HashMap; +import java.util.Map; +import java.util.Iterator; +import java.util.Random; +import java.io.InputStream; +import java.io.IOException; + +/** + * Tests class javax.jdo.JDOHelper for META-INF/jdoconfig.xml compliance. + */ +public class JDOHelperConfigTest extends AbstractTest implements Constants { + + public static void main(String args[]) { + BatchTestRunner.run(JDOHelperConfigTest.class); + } + + public static TestSuite suite() { + return new TestSuite(JDOHelperConfigTest.class); + } + + protected static String JDOCONFIG_CLASSPATH_PREFIX + = "test/schema/jdoconfig.xml"; + + protected static Random RANDOM = new Random(System.currentTimeMillis()); + + /** + * Tests JDOHelper.getPersistenceUnitProperties using file + * Positive0-jdoconfig.xml and PU name + * "persistence-unit-name.positive0.pmf0" + */ + public void testGetNamedPMFProperties_positive0_pmf0() throws IOException { + + ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Positive0"); + + ClassLoader loader = getClass().getClassLoader(); + + Map expected = prepareInitialExpectedMap("positive0.pmf0", 2); + String name = (String) expected.get(PROPERTY_PERSISTENCE_UNIT_NAME); + + Map actual = JDOHelper.getPersistenceUnitProperties( + name, loader, loader); + + assertNotNull("No properties found", actual); + assertEqualProperties(expected, actual); + } + + /** + * Tests JDOHelper.getPersistenceUnitProperties using file + * Positive0-jdoconfig.xml and PU name + * "persistence-unit-name.positive0.pmf1" + */ + public void testGetNamedPMFProperties_positive0_pmf1() throws IOException { + ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Positive0"); + + ClassLoader loader = getClass().getClassLoader(); + + Map expected = prepareInitialExpectedMap("positive0.pmf1", 2); + String name = (String) expected.get(PROPERTY_PERSISTENCE_UNIT_NAME); + + Map actual = JDOHelper.getPersistenceUnitProperties( + name, loader, loader); + + assertNotNull("No properties found", actual); + assertEqualProperties(expected, actual); + } + + /** + * Tests JDOHelper.getPersistenceUnitProperties using file + * Positive0-jdoconfig.xml and PU name + * "persistence-unit-name.positive0.pmf2" + */ + public void testGetNamedPMFProperties_positive0_pmf2() throws IOException { + ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Positive0"); + + ClassLoader loader = getClass().getClassLoader(); + + Map expected = prepareInitialExpectedMap("positive0.pmf2", 2); + String name = (String) expected.get(PROPERTY_PERSISTENCE_UNIT_NAME); + + Map actual = JDOHelper.getPersistenceUnitProperties( + name, loader, loader); + + assertNotNull("No properties found", actual); + assertEqualProperties(expected, actual); + } + + /** + * Tests JDOHelper.getPersistenceUnitProperties using file + * Positive0-jdoconfig.xml and PU name + * "persistence-unit-name.positive0.pmf3" + */ + public void testGetNamedPMFProperties_positive0_pmf3() throws IOException { + ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Positive0"); + + ClassLoader loader = getClass().getClassLoader(); + + Map expected = prepareInitialExpectedMap("positive0.pmf3", 2, 2); + String name = (String) expected.get(PROPERTY_PERSISTENCE_UNIT_NAME); + + Map actual = JDOHelper.getPersistenceUnitProperties( + name, loader, loader); + + assertNotNull("No properties found", actual); + assertEqualProperties(expected, actual); + } + + /** + * Tests JDOHelper.getPersistenceUnitProperties using file + * Positive0-jdoconfig.xml and PU name + * "persistence-unit-name.positive0.pmf4" + */ + public void testGetNamedPMFProperties_positive0_pmf4() throws IOException { + ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Positive0"); + + ClassLoader loader = getClass().getClassLoader(); + + Map expected = prepareInitialExpectedMap("positive0.pmf4", 0, 2); + String name = (String) expected.get(PROPERTY_PERSISTENCE_UNIT_NAME); + + Map actual = JDOHelper.getPersistenceUnitProperties( + name, loader, loader); + + assertNotNull("No properties found", actual); + assertEqualProperties(expected, actual); + } + + public Map prepareInitialExpectedMap(String testVariant) { + return prepareInitialExpectedMap(testVariant, 0, 0); + } + public Map prepareInitialExpectedMap(String testVariant, int numListeners) { + return prepareInitialExpectedMap(testVariant, numListeners, 0); + } + public Map prepareInitialExpectedMap( + String testVariant, + int numListeners, + int numProperties + ) { + Map expected = new HashMap(); + + expected.put(PROPERTY_PERSISTENCE_MANAGER_FACTORY_CLASS, + "class." + testVariant); + expected.put( + PROPERTY_CONNECTION_DRIVER_NAME, + "connection-driver-name." + testVariant); + expected.put( + PROPERTY_CONNECTION_FACTORY_NAME, + "connection-factory-name." + testVariant); + expected.put( + PROPERTY_CONNECTION_FACTORY2_NAME, + "connection-factory2-name." + testVariant); + expected.put( + PROPERTY_CONNECTION_PASSWORD, + "connection-password." + testVariant); + expected.put( + PROPERTY_CONNECTION_URL, + "connection-url." + testVariant); + expected.put( + PROPERTY_CONNECTION_USER_NAME, + "connection-user-name." + testVariant); + expected.put( + PROPERTY_IGNORE_CACHE, + "ignore-cache." + testVariant); + expected.put( + PROPERTY_MAPPING, + "mapping." + testVariant); + expected.put( + PROPERTY_MULTITHREADED, + "multithreaded." + testVariant); + expected.put( + PROPERTY_NONTRANSACTIONAL_READ, + "nontransactional-read." + testVariant); + expected.put( + PROPERTY_NONTRANSACTIONAL_WRITE, + "nontransactional-write." + testVariant); + expected.put( + PROPERTY_OPTIMISTIC, + "optimistic." + testVariant); + expected.put( + PROPERTY_PERSISTENCE_UNIT_NAME, + "persistence-unit-name." + testVariant); + expected.put( + PROPERTY_RESTORE_VALUES, + "restore-values." + testVariant); + expected.put( + PROPERTY_RETAIN_VALUES, + "retain-values." + testVariant); + expected.put( + PROPERTY_DETACH_ALL_ON_COMMIT, + "detach-all-on-commit." + testVariant); + + // listeners + for (int i = 0; i < numListeners; i++) { + expected.put( + PROPERTY_PREFIX_INSTANCE_LIFECYCLE_LISTENER + + "listener." + testVariant + ".listener" + i, + "classes." + testVariant + ".classes" + i + ); + } + + // properties + for (int i = 0; i < numProperties; i++) { + expected.put( + "property." + testVariant + ".name" + i, + "property." + testVariant + ".value" + i + ); + } + + return expected; + } + + static void assertEqualProperties(Map expected, Map actual) { + Iterator i = expected.entrySet().iterator(); + while (i.hasNext()) { + Map.Entry entry = (Map.Entry) i.next(); + String key = (String) entry.getKey(); + String expectedValue = (String) entry.getValue(); + String actualValue = (String) actual.get(key); + + assertEquals( + "Actual property at [" + key + "] with value [" + + actualValue + "] not equal to expected value [" + + expectedValue + "]", + expectedValue, + actualValue); + } + } + + public void testNegative_NoResourcesFound() { + String resource = "" + RANDOM.nextLong(); + + InputStream in = + getClass().getClassLoader().getResourceAsStream(resource); + assertNull(in); + + // resource pretty much guaranteed not to exist + try { + JDOHelper.getPersistenceManagerFactory(resource); + fail("JDOHelper failed to throw JDOFatalUserException"); + } + catch (JDOFatalUserException x) { + // happy path + println("Caught expected exception!"); + println(x.getMessage()); + } + } + + public void testNegative0_EmptyJDOConfigXML() throws IOException { + try { + ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Negative0"); + + JDOHelper.getPersistenceManagerFactory(); + fail("JDOHelper failed to throw JDOFatalUserException"); + } + catch (JDOFatalUserException x) { + // happy path + println("Caught expected exception!"); + println(x.getMessage()); + } + } + + public void testNegative1_NoPersistenceUnitsDefined() throws IOException { + try { + ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Negative1"); + + JDOHelper.getPersistenceManagerFactory(); + fail("JDOHelper failed to throw JDOFatalUserException"); + } + catch (JDOFatalUserException x) { + // happy path + println("Caught expected exception!"); + println(x.getMessage()); + } + } + + public void testNegative2_DuplicateAnonymousPersistenceUnitsInSameConfig() + throws IOException + { + try { + ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Negative2"); + + JDOHelper.getPersistenceManagerFactory(); + fail("JDOHelper failed to throw JDOFatalUserException"); + } + catch (JDOFatalUserException x) { + // happy path + println("Caught expected exception!"); + println(x.getMessage()); + } + catch (IOException e) { + fail(e.getMessage()); + } + } +} Index: test/schema/jdoconfig.xml/Negative0/META-INF/jdoconfig.xml =================================================================== Index: test/schema/jdoconfig.xml/Negative0/META-INF/jdoconfig.xml =================================================================== Index: test/schema/jdoconfig.xml/Negative1/META-INF/jdoconfig.xml =================================================================== --- test/schema/jdoconfig.xml/Negative1/META-INF/jdoconfig.xml (revision 0) +++ test/schema/jdoconfig.xml/Negative1/META-INF/jdoconfig.xml (revision 0) @@ -0,0 +1,7 @@ + + + + + Index: test/schema/jdoconfig.xml/Negative1/META-INF/jdoconfig.xml =================================================================== --- test/schema/jdoconfig.xml/Negative1/META-INF/jdoconfig.xml (revision 0) +++ test/schema/jdoconfig.xml/Negative1/META-INF/jdoconfig.xml (revision 0) @@ -0,0 +1,7 @@ + + + + + Index: test/schema/jdoconfig.xml/Negative2/META-INF/jdoconfig.xml =================================================================== --- test/schema/jdoconfig.xml/Negative2/META-INF/jdoconfig.xml (revision 0) +++ test/schema/jdoconfig.xml/Negative2/META-INF/jdoconfig.xml (revision 0) @@ -0,0 +1,9 @@ + + + + + + + Index: test/schema/jdoconfig.xml/Negative2/META-INF/jdoconfig.xml =================================================================== --- test/schema/jdoconfig.xml/Negative2/META-INF/jdoconfig.xml (revision 0) +++ test/schema/jdoconfig.xml/Negative2/META-INF/jdoconfig.xml (revision 0) @@ -0,0 +1,9 @@ + + + + + + + Index: test/schema/jdoconfig.xml/Positive0/META-INF/jdoconfig.xml =================================================================== --- test/schema/jdoconfig.xml/Positive0/META-INF/jdoconfig.xml (revision 0) +++ test/schema/jdoconfig.xml/Positive0/META-INF/jdoconfig.xml (revision 0) @@ -0,0 +1,245 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Index: test/schema/jdoconfig.xml/Positive0/META-INF/jdoconfig.xml =================================================================== --- test/schema/jdoconfig.xml/Positive0/META-INF/jdoconfig.xml (revision 0) +++ test/schema/jdoconfig.xml/Positive0/META-INF/jdoconfig.xml (revision 0) @@ -0,0 +1,245 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +