Index: test/schema/jdoconfig.xml/Negative0/META-INF/jdoconfig.xml =================================================================== 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/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/Negative3/META-INF/jdoconfig.xml =================================================================== --- test/schema/jdoconfig.xml/Negative3/META-INF/jdoconfig.xml (revision 0) +++ test/schema/jdoconfig.xml/Negative3/META-INF/jdoconfig.xml (revision 0) @@ -0,0 +1,18 @@ + + + + + + + + + + Index: test/schema/jdoconfig.xml/Negative4/META-INF/jdoconfig.xml =================================================================== --- test/schema/jdoconfig.xml/Negative4/META-INF/jdoconfig.xml (revision 0) +++ test/schema/jdoconfig.xml/Negative4/META-INF/jdoconfig.xml (revision 0) @@ -0,0 +1,19 @@ + + + + + + + + + + Index: test/schema/jdoconfig.xml/Negative5/META-INF/jdoconfig.xml =================================================================== --- test/schema/jdoconfig.xml/Negative5/META-INF/jdoconfig.xml (revision 0) +++ test/schema/jdoconfig.xml/Negative5/META-INF/jdoconfig.xml (revision 0) @@ -0,0 +1,19 @@ + + + + + + + + + + Index: test/schema/jdoconfig.xml/Negative6/6a/META-INF/jdoconfig.xml =================================================================== --- test/schema/jdoconfig.xml/Negative6/6a/META-INF/jdoconfig.xml (revision 0) +++ test/schema/jdoconfig.xml/Negative6/6a/META-INF/jdoconfig.xml (revision 0) @@ -0,0 +1,14 @@ + + + + + + + Index: test/schema/jdoconfig.xml/Negative6/6b/META-INF/jdoconfig.xml =================================================================== --- test/schema/jdoconfig.xml/Negative6/6b/META-INF/jdoconfig.xml (revision 0) +++ test/schema/jdoconfig.xml/Negative6/6b/META-INF/jdoconfig.xml (revision 0) @@ -0,0 +1,14 @@ + + + + + + + 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,379 @@ +/* + * 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); + + 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); + + 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); + + 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); + + 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); + + 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 [" + key + "] with value [" + + actualValue + "] not equal to expected value [" + + expectedValue + "]", + expectedValue, + actualValue); + } + } + + /** + * Tests JDOHelper.getPersistenceUnitProperties using file + * Positive0-jdoconfig.xml and PU name + * "persistence-unit-name.positive0.pmf0" + */ + public void testDuplicatePUsInDifferentConfigFilesButNotRequested_positive1() throws IOException { + + ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Positive1/1a"); + ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Positive1/1b"); + + ClassLoader loader = getClass().getClassLoader(); + + Map props = JDOHelper.getPersistenceUnitProperties(null); + assertNotNull(props); + } + + 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 + } + } + + 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 + } + } + + 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 + } + } + + 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 + } + } + + public void testNegative3_DuplicateNamedPersistenceUnitsInSameConfig() + throws IOException + { + try { + ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Negative3"); + + JDOHelper.getPersistenceManagerFactory( + "persistence-unit-name.negative3"); + + fail("JDOHelper failed to throw JDOFatalUserException"); + } + catch (JDOFatalUserException x) { + // happy path + } + } + + public void testNegative4_DuplicatePUNamePropertyInAttributeAndElement() + throws IOException + { + try { + ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Negative4"); + + JDOHelper.getPersistenceManagerFactory( + "persistence-unit-name.negative4.value0"); + + fail("JDOHelper failed to throw JDOFatalUserException"); + } + catch (JDOFatalUserException x) { + // happy path + } + } + + public void testNegative5_DuplicatePropertyInAttributeAndElement() + throws IOException + { + try { + ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Negative5"); + + JDOHelper.getPersistenceManagerFactory(); + + fail("JDOHelper failed to throw JDOFatalUserException"); + } + catch (JDOFatalUserException x) { + // happy path + } + } + + public void testNegative6_DuplicatePUInDifferentConfigFiles() + throws IOException + { + try { + ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Negative6/6a"); + ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Negative6/6b"); + + JDOHelper.getPersistenceManagerFactory("persistence-unit-name.negative6"); + + fail("JDOHelper failed to throw JDOFatalUserException"); + } + catch (JDOFatalUserException x) { + // happy path + } + } +} 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,174 @@ + + + + + + + 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: 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,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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/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,103 @@ * * @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); + xref.put( + PMF_ATTRIBUTE_SERVERTIMEZONEID, + PROPERTY_SERVER_TIMEZONE_ID); + + return Collections.unmodifiableMap(xref); + } + /** The JDOImplHelper instance used for handling non-binary-compatible * implementations. */ @@ -487,23 +594,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 +639,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 +675,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 +715,680 @@ } /** - * 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