You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jdo-commits@db.apache.org by ma...@apache.org on 2007/06/02 03:21:00 UTC

svn commit: r543689 - in /db/jdo/trunk/api20: src/java/javax/jdo/ test/java/javax/jdo/ test/schema/jdoconfig.xml/Negative7/ test/schema/jdoconfig.xml/Negative7/META-INF/ test/schema/jdoconfig.xml/Negative7/META-INF/services/ test/schema/jdoconfig.xml/N...

Author: madams
Date: Fri Jun  1 18:20:59 2007
New Revision: 543689

URL: http://svn.apache.org/viewvc?view=rev&rev=543689
Log:
JDO-482:  Enhanced JDOHelper PMF bootstrapping to use META-INF/services lookup

Added:
    db/jdo/trunk/api20/test/java/javax/jdo/JDOConfigTestClassLoader.java
    db/jdo/trunk/api20/test/schema/jdoconfig.xml/Negative7/
    db/jdo/trunk/api20/test/schema/jdoconfig.xml/Negative7/META-INF/
    db/jdo/trunk/api20/test/schema/jdoconfig.xml/Negative7/META-INF/services/
    db/jdo/trunk/api20/test/schema/jdoconfig.xml/Negative7/META-INF/services/javax.jdo.PersistenceManagerFactory
    db/jdo/trunk/api20/test/schema/jdoconfig.xml/Negative8/
    db/jdo/trunk/api20/test/schema/jdoconfig.xml/Negative8/META-INF/
    db/jdo/trunk/api20/test/schema/jdoconfig.xml/Negative8/META-INF/services/
    db/jdo/trunk/api20/test/schema/jdoconfig.xml/Negative8/META-INF/services/javax.jdo.PersistenceManagerFactory
    db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive3/
    db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive3/META-INF/
    db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive3/META-INF/jdoconfig.xml
      - copied, changed from r541701, db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive1/1a/META-INF/jdoconfig.xml
    db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive3/META-INF/services/
    db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive3/META-INF/services/javax.jdo.PersistenceManagerFactory
    db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive4/
    db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive4/META-INF/
    db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive4/META-INF/jdoconfig.xml
    db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive4/META-INF/services/
    db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive4/META-INF/services/javax.jdo.PersistenceManagerFactory
    db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive5/
    db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive5/META-INF/
    db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive5/META-INF/jdoconfig.xml
    db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive5/META-INF/services/
    db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive5/META-INF/services/javax.jdo.PersistenceManagerFactory
Modified:
    db/jdo/trunk/api20/src/java/javax/jdo/Bundle.properties
    db/jdo/trunk/api20/src/java/javax/jdo/Constants.java
    db/jdo/trunk/api20/src/java/javax/jdo/JDOHelper.java
    db/jdo/trunk/api20/test/java/javax/jdo/JDOHelperConfigTest.java

Modified: db/jdo/trunk/api20/src/java/javax/jdo/Bundle.properties
URL: http://svn.apache.org/viewvc/db/jdo/trunk/api20/src/java/javax/jdo/Bundle.properties?view=diff&rev=543689&r1=543688&r2=543689
==============================================================================
--- db/jdo/trunk/api20/src/java/javax/jdo/Bundle.properties (original)
+++ db/jdo/trunk/api20/src/java/javax/jdo/Bundle.properties Fri Jun  1 18:20:59 2007
@@ -25,7 +25,10 @@
 EXC_GetPMFUnexpectedException=Unexpected exception caught.
 EXC_GetPMFClassNotFound=Class {0} was not found.
 EXC_GetPMFIllegalAccess=Illegal Access for class {0}.
-EXC_GetPMFNoClassNameProperty=A property named javax.jdo.PersistenceManagerFactoryClass must be specified.
+EXC_GetPMFNoClassNameProperty=A property named javax.jdo.PersistenceManagerFactoryClass must be specified, \ 
+or the jar file with the default META-INF/services/javax.jdo.PersistenceManagerFactory entry must be in the classpath.
+EXC_IOExceptionDuringServiceLookup=IO error while attempting to lookup PMF name \
+via META-INF/services/javax.jdo.PersistenceManagerFactory
 MSG_FailedObject=FailedObject:
 MSG_NestedThrowables=NestedThrowables:
 MSG_NestedThrowablesStackTrace=NestedThrowablesStackTrace:

Modified: db/jdo/trunk/api20/src/java/javax/jdo/Constants.java
URL: http://svn.apache.org/viewvc/db/jdo/trunk/api20/src/java/javax/jdo/Constants.java?view=diff&rev=543689&r1=543688&r2=543689
==============================================================================
--- db/jdo/trunk/api20/src/java/javax/jdo/Constants.java (original)
+++ db/jdo/trunk/api20/src/java/javax/jdo/Constants.java Fri Jun  1 18:20:59 2007
@@ -25,6 +25,16 @@
 public interface Constants {
 
     /**
+     * The name of the standard service configuration resource text file containing
+     * the name of an implementation of {@link PersistenceManagerFactory}.
+     * Constant value is <code>META-INF/services/javax.jdo.PersistenceManagerFactory</code>.
+     *
+     * @since 2.1
+     */
+    static String SERVICE_LOOKUP_PMF_RESOURCE_NAME
+        = "META-INF/services/javax.jdo.PersistenceManagerFactory";
+
+    /**
      * The name of the standard JDO configuration resource file(s).
      * Constant value is <code>META-INF/jdoconfig.xml</code>.
      *

Modified: db/jdo/trunk/api20/src/java/javax/jdo/JDOHelper.java
URL: http://svn.apache.org/viewvc/db/jdo/trunk/api20/src/java/javax/jdo/JDOHelper.java?view=diff&rev=543689&r1=543688&r2=543689
==============================================================================
--- db/jdo/trunk/api20/src/java/javax/jdo/JDOHelper.java (original)
+++ db/jdo/trunk/api20/src/java/javax/jdo/JDOHelper.java Fri Jun  1 18:20:59 2007
@@ -22,55 +22,31 @@
  
 package javax.jdo;
 
+import org.w3c.dom.*;
 import org.xml.sax.SAXException;
 import org.xml.sax.SAXParseException;
 
-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;
-import java.io.InputStream;
-import java.io.IOException;
-
-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.Iterator;
-import java.util.Map;
-import java.util.Properties;
-import java.util.HashMap;
-import java.util.Enumeration;
-import java.util.Collections;
-
 import javax.jdo.spi.I18NHelper;
 import javax.jdo.spi.JDOImplHelper;
 import javax.jdo.spi.JDOImplHelper.StateInterrogationBooleanReturn;
 import javax.jdo.spi.JDOImplHelper.StateInterrogationObjectReturn;
 import javax.jdo.spi.PersistenceCapable;
 import javax.jdo.spi.StateInterrogation;
-
 import javax.naming.Context;
 import javax.naming.InitialContext;
 import javax.naming.NamingException;
-
 import javax.rmi.PortableRemoteObject;
-
-import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.FactoryConfigurationError;
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.*;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.*;
 
 
 /**
@@ -595,8 +571,9 @@
         }
     }
     
-    /** Get the anonymous <code>PersistenceManagerFactory</code> configured via the standard
-     * configuration file resource "META-INF/jdoconfig.xml", using the current thread's context class loader
+    /** Get the anonymous <code>PersistenceManagerFactory</code> 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 <code>PersistenceManagerFactory</code>.
      * @since 2.1
@@ -607,6 +584,40 @@
         return getPersistenceManagerFactory ((String)null, cl);
     }
 
+    /** Get the anonymous <code>PersistenceManagerFactory</code> configured via
+     * the standard
+     * configuration file resource "META-INF/jdoconfig.xml", using the given
+     * class loader
+     * to locate the configuration file resource(s).
+     * @return the anonymous <code>PersistenceManagerFactory</code>.
+     * @param cl the ClassLoader used to load resources and classes
+     * @since 2.1
+     * @see #getPersistenceManagerFactory(String,ClassLoader)
+     */
+    public static PersistenceManagerFactory getPersistenceManagerFactory(
+            ClassLoader cl
+    ) {
+        return getPersistenceManagerFactory((String)null, cl, cl);
+    }
+
+    /** Get the anonymous <code>PersistenceManagerFactory</code> configured via
+     * the standard
+     * configuration file resource "META-INF/jdoconfig.xml", using the given
+     * resource class loader & class loader
+     * to locate the configuration file resource(s).
+     * @return the anonymous <code>PersistenceManagerFactory</code>.
+     * @param resourceLoader the class loader to use to load resources
+     * @param pmfLoader the class loader to use to load the classes
+     * @since 2.1
+     * @see #getPersistenceManagerFactory(String,ClassLoader)
+     */
+    public static PersistenceManagerFactory getPersistenceManagerFactory(
+            ClassLoader resourceLoader,
+            ClassLoader pmfLoader
+    ) {
+        return getPersistenceManagerFactory((String)null, resourceLoader, pmfLoader);
+    }
+
     /** Get a <code>PersistenceManagerFactory</code> based on a <code>Properties</code>
      * instance, using the current thread's context class loader to locate the
      * <code>PersistenceManagerFactory</code> class.
@@ -678,8 +689,17 @@
         String pmfClassName = (String) props.get (
             PROPERTY_PERSISTENCE_MANAGER_FACTORY_CLASS); //NOI18N
         if (pmfClassName == null) {
-            throw new JDOFatalUserException(msg.msg(
-                "EXC_GetPMFNoClassNameProperty")); // NOI18N
+            try {
+                pmfClassName = getPMFClassNameViaServiceLookup(cl);
+            }
+            catch (IOException e) {
+                throw new JDOFatalInternalException(msg.msg(
+                    "EXC_IOExceptionDuringServiceLookup"), e); // NOI18N
+            }
+            if (pmfClassName == null) {
+                throw new JDOFatalUserException(msg.msg(
+                    "EXC_GetPMFNoClassNameProperty")); // NOI18N
+            }
         }
         try {
             Class pmfClass = cl.loadClass (pmfClassName);
@@ -699,7 +719,7 @@
                 "EXC_GetPMFNoSuchMethod"), nsme); //NOI18N
         } catch (InvocationTargetException ite) {
             Throwable nested = ite.getTargetException();
-            if  (nested instanceof JDOException) {
+            if (nested instanceof JDOException) {
                 throw (JDOException)nested;
             } else throw new JDOFatalInternalException (msg.msg(
                 "EXC_GetPMFUnexpectedException"), ite); //NOI18N
@@ -714,7 +734,66 @@
                 "EXC_GetPMFUnexpectedException"), e); //NOI18N
         }
     }
-    
+
+    /**
+     * Looks up a (@link PersistenceManagerFactory} implementation class name
+     * from the resource
+     * <code>META-INF/services/javax.jdo.PersistenceManagerFactory</code>,
+     * which should be a text file whose
+     * only contents are the fully qualified name of a class that implements
+     * {@link PersistenceManagerFactory}.
+     * Note that the method
+     * {@link java.lang.ClassLoader#getResourceAsStream(String)} is used to
+     * find the resource.
+     * Only the first implementation class name found in the resource is used. 
+     * @param cl The ClassLoader used to find the resource.
+     * @return The first non-blank, trimmed line found in the file; should be
+     * a PMF implementation class name, or null
+     * if no content was found.
+     * @throws IOException
+     */
+    protected static String getPMFClassNameViaServiceLookup(ClassLoader cl)
+            throws IOException
+    {
+        /*
+        Note:  not using sun.misc.Service because it's not a standard part of
+        the JDK (yet).
+         */
+        InputStream is = cl.getResourceAsStream(
+                SERVICE_LOOKUP_PMF_RESOURCE_NAME);
+
+        if (is == null) {
+            return null;
+        }
+        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+        String line = null;
+        try {
+            while ((line = reader.readLine()) != null) {
+                line = line.trim();
+                if (line.length() == 0 || line.startsWith("#")) {
+                    continue;
+                }
+                // else assume first line of text is the PMF class name
+                String[] tokens = line.split("\\s");
+                String pmfClassName = tokens[0];
+                int indexOfComment = pmfClassName.indexOf("#");
+                if (indexOfComment == -1) {
+                    return pmfClassName;
+                }
+                // else pmfClassName has a comment at the end of it -- remove
+                return pmfClassName.substring(0, indexOfComment);
+            }
+            return null;
+        } finally {
+            try {
+                reader.close();
+            }
+            catch (IOException x) {
+                // gulp
+            }
+        }
+    }
+
     /**
      * Returns a named {@link PersistenceManagerFactory} with the given persistence unit name or,
      * if not found, a {@link PersistenceManagerFactory} configured based

Added: db/jdo/trunk/api20/test/java/javax/jdo/JDOConfigTestClassLoader.java
URL: http://svn.apache.org/viewvc/db/jdo/trunk/api20/test/java/javax/jdo/JDOConfigTestClassLoader.java?view=auto&rev=543689
==============================================================================
--- db/jdo/trunk/api20/test/java/javax/jdo/JDOConfigTestClassLoader.java (added)
+++ db/jdo/trunk/api20/test/java/javax/jdo/JDOConfigTestClassLoader.java Fri Jun  1 18:20:59 2007
@@ -0,0 +1,34 @@
+package javax.jdo;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+
+/**
+ * A class loader used to ensure that classpath URLs added in JUnit tests
+ * aren't included in subsequent JUnit tests.
+ */
+public class JDOConfigTestClassLoader extends URLClassLoader {
+
+    public JDOConfigTestClassLoader(String partialPathToIgnore, URLClassLoader unparent) {
+        this(new String[]{partialPathToIgnore}, unparent);
+    }
+
+    public JDOConfigTestClassLoader(String[] partialPathsToIgnore, URLClassLoader unparent) {
+        super(new URL[]{}, null);
+        addNonTestURLs(partialPathsToIgnore == null ? new String[]{} : partialPathsToIgnore, unparent);
+    }
+
+    // HACK:  need to identify a better way of controlling test classpath
+    protected void addNonTestURLs(String[] partialPathsToIgnore, URLClassLoader unparent) {
+        URL[] urls = unparent.getURLs();
+        for (int i = 0; i < urls.length; i++) {
+            URL url = urls[i];
+            String urlString = url.toString();
+            for (int j = 0; j < partialPathsToIgnore.length; j++) {
+                if (urlString.indexOf(partialPathsToIgnore[j]) == -1) {
+                    addURL(url);
+                }
+            }
+        }
+    }
+}

Modified: db/jdo/trunk/api20/test/java/javax/jdo/JDOHelperConfigTest.java
URL: http://svn.apache.org/viewvc/db/jdo/trunk/api20/test/java/javax/jdo/JDOHelperConfigTest.java?view=diff&rev=543689&r1=543688&r2=543689
==============================================================================
--- db/jdo/trunk/api20/test/java/javax/jdo/JDOHelperConfigTest.java (original)
+++ db/jdo/trunk/api20/test/java/javax/jdo/JDOHelperConfigTest.java Fri Jun  1 18:20:59 2007
@@ -21,12 +21,13 @@
 
 import javax.jdo.util.AbstractTest;
 import javax.jdo.util.BatchTestRunner;
+import java.io.IOException;
+import java.io.InputStream;
 import java.util.HashMap;
-import java.util.Map;
 import java.util.Iterator;
+import java.util.Map;
 import java.util.Random;
-import java.io.InputStream;
-import java.io.IOException;
+import java.net.URLClassLoader;
 
 /**
  * Tests class javax.jdo.JDOHelper for META-INF/jdoconfig.xml compliance.
@@ -51,11 +52,12 @@
      * Positive0-jdoconfig.xml and PU name
      * "persistence-unit-name.positive0.pmf0"
      */
-    public void testGetNamedPMFProperties_positive0_pmf0() throws IOException {
+    public void testPositive00_PMF0_GetNamedPMFProperties() throws IOException {
 
-        ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Positive0");
-
-        ClassLoader loader = getClass().getClassLoader();
+        URLClassLoader loader = new JDOConfigTestClassLoader(
+                JDOCONFIG_CLASSPATH_PREFIX,
+                (URLClassLoader) getClass().getClassLoader());
+        ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Positive0", loader);
 
         Map expected = prepareInitialExpectedMap("positive0.pmf0", 2);
         String name = (String) expected.get(PROPERTY_PERSISTENCE_UNIT_NAME);
@@ -71,10 +73,11 @@
      * 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();
+    public void testPositive00_PMF1_GetNamedPMFProperties() throws IOException  {
+        URLClassLoader loader = new JDOConfigTestClassLoader(
+                JDOCONFIG_CLASSPATH_PREFIX,
+                (URLClassLoader) getClass().getClassLoader());
+        ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Positive0", loader);
 
         Map expected = prepareInitialExpectedMap("positive0.pmf1", 2);
         String name = (String) expected.get(PROPERTY_PERSISTENCE_UNIT_NAME);
@@ -90,10 +93,11 @@
      * 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();
+    public void testPositive00_PMF2_GetNamedPMFProperties() throws IOException  {
+        URLClassLoader loader = new JDOConfigTestClassLoader(
+                JDOCONFIG_CLASSPATH_PREFIX,
+                (URLClassLoader) getClass().getClassLoader());
+        ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Positive0", loader);
 
         Map expected = prepareInitialExpectedMap("positive0.pmf2", 2);
         String name = (String) expected.get(PROPERTY_PERSISTENCE_UNIT_NAME);
@@ -109,10 +113,11 @@
      * 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();
+    public void testPositive00_PMF3_GetNamedPMFProperties() throws IOException  {
+        URLClassLoader loader = new JDOConfigTestClassLoader(
+                JDOCONFIG_CLASSPATH_PREFIX,
+                (URLClassLoader) getClass().getClassLoader());
+        ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Positive0", loader);
 
         Map expected = prepareInitialExpectedMap("positive0.pmf3", 2, 2);
         String name = (String) expected.get(PROPERTY_PERSISTENCE_UNIT_NAME);
@@ -128,10 +133,11 @@
      * 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();
+    public void testPositive00_PMF4_GetNamedPMFProperties() throws IOException  {
+        URLClassLoader loader = new JDOConfigTestClassLoader(
+                JDOCONFIG_CLASSPATH_PREFIX,
+                (URLClassLoader) getClass().getClassLoader());
+        ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Positive0", loader);
 
         Map expected = prepareInitialExpectedMap("positive0.pmf4", 0, 2);
         String name = (String) expected.get(PROPERTY_PERSISTENCE_UNIT_NAME);
@@ -251,18 +257,70 @@
      * Positive0-jdoconfig.xml and PU name
      * "persistence-unit-name.positive0.pmf0"
      */
-    public void testDuplicatePUsInDifferentConfigFilesButNotRequested_positive1() throws IOException {
+    public void testPostiive01_DuplicatePUsInDifferentConfigFilesButNotRequested() throws IOException {
 
-        ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Positive1/1a");
-        ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Positive1/1b");
+        URLClassLoader loader = new JDOConfigTestClassLoader(
+                JDOCONFIG_CLASSPATH_PREFIX,
+                (URLClassLoader) getClass().getClassLoader());
+        ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Positive1/1a", loader);
+        ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Positive1/1b", loader);
 
-        ClassLoader loader = getClass().getClassLoader();
-
-        Map props = JDOHelper.getPersistenceUnitProperties(null);
+        Map props = JDOHelper.getPersistenceUnitProperties(null, loader);
         assertNotNull(props);
     }
 
-    public void testNegative_NoResourcesFound() {
+    /**
+     * Tests JDOHelper.getPMFClassNameViaServiceLookup
+     */
+    public void testPositive03_PMF0_PMFClassNameViaServicesLookup() throws IOException {
+
+        URLClassLoader loader = new JDOConfigTestClassLoader(
+                JDOCONFIG_CLASSPATH_PREFIX,
+                (URLClassLoader) getClass().getClassLoader());
+        ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Positive3", loader);
+
+        String expected = "class.positive3.pmf0";
+        String actual = JDOHelper.getPMFClassNameViaServiceLookup(loader);
+
+        assertNotNull("No PMF name found via services lookup", actual);
+        assertEquals(expected, actual);
+    }
+
+    /**
+     * Tests JDOHelper.getPMFClassNameViaServiceLookup
+     */
+    public void testPositive04_PMF0_PMFClassNameViaServicesLookup() throws IOException {
+
+        URLClassLoader loader = new JDOConfigTestClassLoader(
+                JDOCONFIG_CLASSPATH_PREFIX,
+                (URLClassLoader) getClass().getClassLoader());
+        ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Positive4", loader);
+
+        String expected = "class.positive4.pmf0";
+        String actual = JDOHelper.getPMFClassNameViaServiceLookup(loader);
+
+        assertNotNull("No PMF name found via services lookup", actual);
+        assertEquals(expected, actual);
+    }
+
+    /**
+     * Tests JDOHelper.getPMFClassNameViaServiceLookup
+     */
+    public void testPositive05_PMF0_PMFClassNameViaServicesLookup() throws IOException {
+
+        URLClassLoader loader = new JDOConfigTestClassLoader(
+                JDOCONFIG_CLASSPATH_PREFIX,
+                (URLClassLoader) getClass().getClassLoader());
+        ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Positive5", loader);
+
+        String expected = "class.positive5.pmf0";
+        String actual = JDOHelper.getPMFClassNameViaServiceLookup(loader);
+
+        assertNotNull("No PMF name found via services lookup", actual);
+        assertEquals(expected, actual);
+    }
+
+    public void testNegative08_NoResourcesFound() {
         String resource = "" + RANDOM.nextLong();
 
         InputStream in =
@@ -279,11 +337,14 @@
         }
     }
 
-    public void testNegative0_EmptyJDOConfigXML() throws IOException  {
+    public void testNegative00_EmptyJDOConfigXML() throws IOException  {
         try {
-            ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Negative0");
+            URLClassLoader loader = new JDOConfigTestClassLoader(
+                    JDOCONFIG_CLASSPATH_PREFIX,
+                    (URLClassLoader) getClass().getClassLoader());
+            ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Negative0", loader);
 
-            JDOHelper.getPersistenceManagerFactory();
+            JDOHelper.getPersistenceManagerFactory(loader);
             fail("JDOHelper failed to throw JDOFatalUserException");
         }
         catch (JDOFatalUserException x) {
@@ -291,11 +352,14 @@
         }
     }
     
-    public void testNegative1_NoPersistenceUnitsDefined() throws IOException  {
+    public void testNegative01_NoPersistenceUnitsDefined() throws IOException  {
         try {
-            ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Negative1");
+            URLClassLoader loader = new JDOConfigTestClassLoader(
+                    JDOCONFIG_CLASSPATH_PREFIX,
+                    (URLClassLoader) getClass().getClassLoader());
+            ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Negative1", loader);
 
-            JDOHelper.getPersistenceManagerFactory();
+            JDOHelper.getPersistenceManagerFactory(loader);
             fail("JDOHelper failed to throw JDOFatalUserException");
         }
         catch (JDOFatalUserException x) {
@@ -303,13 +367,16 @@
         }
     }
 
-    public void testNegative2_DuplicateAnonymousPersistenceUnitsInSameConfig()
+    public void testNegative02_DuplicateAnonymousPersistenceUnitsInSameConfig()
         throws IOException
     {
         try {
-            ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Negative2");
+            URLClassLoader loader = new JDOConfigTestClassLoader(
+                    JDOCONFIG_CLASSPATH_PREFIX,
+                    (URLClassLoader) getClass().getClassLoader());
+            ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Negative2", loader);
 
-            JDOHelper.getPersistenceManagerFactory();
+            JDOHelper.getPersistenceManagerFactory(loader);
             fail("JDOHelper failed to throw JDOFatalUserException");
         }
         catch (JDOFatalUserException x) {
@@ -317,14 +384,18 @@
         }
     }
 
-    public void testNegative3_DuplicateNamedPersistenceUnitsInSameConfig()
+    public void testNegative03_DuplicateNamedPersistenceUnitsInSameConfig()
         throws IOException
     {
         try {
-            ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Negative3");
+            URLClassLoader loader = new JDOConfigTestClassLoader(
+                    JDOCONFIG_CLASSPATH_PREFIX,
+                    (URLClassLoader) getClass().getClassLoader());
+            ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Negative3", loader);
 
             JDOHelper.getPersistenceManagerFactory(
-                "persistence-unit-name.negative3");
+                "persistence-unit-name.negative3",
+                loader);
 
             fail("JDOHelper failed to throw JDOFatalUserException");
         }
@@ -333,14 +404,18 @@
         }
     }
 
-    public void testNegative4_DuplicatePUNamePropertyInAttributeAndElement()
+    public void testNegative04_DuplicatePUNamePropertyInAttributeAndElement()
         throws IOException
     {
         try {
-            ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Negative4");
+            URLClassLoader loader = new JDOConfigTestClassLoader(
+                    JDOCONFIG_CLASSPATH_PREFIX,
+                    (URLClassLoader) getClass().getClassLoader());
+            ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Negative4", loader);
 
             JDOHelper.getPersistenceManagerFactory(
-                "persistence-unit-name.negative4.value0");
+                "persistence-unit-name.negative4.value0",
+                loader);
 
             fail("JDOHelper failed to throw JDOFatalUserException");
         }
@@ -349,13 +424,16 @@
         }
     }
 
-    public void testNegative5_DuplicatePropertyInAttributeAndElement()
+    public void testNegative05_DuplicatePropertyInAttributeAndElement()
         throws IOException
     {
         try {
-            ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Negative5");
+            URLClassLoader loader = new JDOConfigTestClassLoader(
+                    JDOCONFIG_CLASSPATH_PREFIX,
+                    (URLClassLoader) getClass().getClassLoader());
+            ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Negative5", loader);
 
-            JDOHelper.getPersistenceManagerFactory();
+            JDOHelper.getPersistenceManagerFactory(loader);
 
             fail("JDOHelper failed to throw JDOFatalUserException");
         }
@@ -364,14 +442,19 @@
         }
     }
 
-    public void testNegative6_DuplicatePUInDifferentConfigFiles()
+    public void testNegative06_DuplicatePUInDifferentConfigFiles()
         throws IOException
     {
         try {
-            ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Negative6/6a");
-            ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Negative6/6b");
+            URLClassLoader loader = new JDOConfigTestClassLoader(
+                    JDOCONFIG_CLASSPATH_PREFIX,
+                    (URLClassLoader) getClass().getClassLoader());
+            ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Negative6/6a", loader);
+            ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Negative6/6b", loader);
 
-            JDOHelper.getPersistenceManagerFactory("persistence-unit-name.negative6");
+            JDOHelper.getPersistenceManagerFactory(
+                    "persistence-unit-name.negative6",
+                    loader);
 
             fail("JDOHelper failed to throw JDOFatalUserException");
         }
@@ -379,5 +462,24 @@
             // happy path
         }
     }
-}
 
+    public void testNegative07_EmptyServicesFile()
+        throws IOException
+    {
+        URLClassLoader loader = (URLClassLoader) getClass().getClassLoader();
+        JDOConfigTestClassLoader testLoader = new JDOConfigTestClassLoader(new String[] {JDOCONFIG_CLASSPATH_PREFIX}, loader);
+        ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Negative7", testLoader);
+        String shouldBeNull = JDOHelper.getPMFClassNameViaServiceLookup(testLoader);
+        assertNull(shouldBeNull);
+    }
+
+    public void testNegative08_ServicesFileWithOnlyComments()
+        throws IOException
+    {
+        URLClassLoader loader = (URLClassLoader) getClass().getClassLoader();
+        JDOConfigTestClassLoader testLoader = new JDOConfigTestClassLoader(new String[] {JDOCONFIG_CLASSPATH_PREFIX}, loader);
+        ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Negative8", testLoader);
+        String shouldBeNull = JDOHelper.getPMFClassNameViaServiceLookup(testLoader);
+        assertNull(shouldBeNull);
+    }
+}

Added: db/jdo/trunk/api20/test/schema/jdoconfig.xml/Negative7/META-INF/services/javax.jdo.PersistenceManagerFactory
URL: http://svn.apache.org/viewvc/db/jdo/trunk/api20/test/schema/jdoconfig.xml/Negative7/META-INF/services/javax.jdo.PersistenceManagerFactory?view=auto&rev=543689
==============================================================================
    (empty)

Added: db/jdo/trunk/api20/test/schema/jdoconfig.xml/Negative8/META-INF/services/javax.jdo.PersistenceManagerFactory
URL: http://svn.apache.org/viewvc/db/jdo/trunk/api20/test/schema/jdoconfig.xml/Negative8/META-INF/services/javax.jdo.PersistenceManagerFactory?view=auto&rev=543689
==============================================================================
--- db/jdo/trunk/api20/test/schema/jdoconfig.xml/Negative8/META-INF/services/javax.jdo.PersistenceManagerFactory (added)
+++ db/jdo/trunk/api20/test/schema/jdoconfig.xml/Negative8/META-INF/services/javax.jdo.PersistenceManagerFactory Fri Jun  1 18:20:59 2007
@@ -0,0 +1,3 @@
+# there are
+# only comments
+# in this file
\ No newline at end of file

Copied: db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive3/META-INF/jdoconfig.xml (from r541701, db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive1/1a/META-INF/jdoconfig.xml)
URL: http://svn.apache.org/viewvc/db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive3/META-INF/jdoconfig.xml?view=diff&rev=543689&p1=db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive1/1a/META-INF/jdoconfig.xml&r1=541701&p2=db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive3/META-INF/jdoconfig.xml&r2=543689
==============================================================================
--- db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive1/1a/META-INF/jdoconfig.xml (original)
+++ db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive3/META-INF/jdoconfig.xml Fri Jun  1 18:20:59 2007
@@ -8,10 +8,6 @@
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:noNamespaceSchemaLocation="http://java.sun.com/xml/ns/jdo/jdoconfig">
 
-    <!-- Duplicate PUs in this file and another, but not requested -->
+    <!-- Anonymous PMF & with META-INF/services lookup for PMF class name -->
     <persistence-manager-factory/>
-
-    <persistence-manager-factory
-        persistence-unit-name="persistence-unit-name.positive1"/>
 </jdoconfig>
-

Added: db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive3/META-INF/services/javax.jdo.PersistenceManagerFactory
URL: http://svn.apache.org/viewvc/db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive3/META-INF/services/javax.jdo.PersistenceManagerFactory?view=auto&rev=543689
==============================================================================
--- db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive3/META-INF/services/javax.jdo.PersistenceManagerFactory (added)
+++ db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive3/META-INF/services/javax.jdo.PersistenceManagerFactory Fri Jun  1 18:20:59 2007
@@ -0,0 +1 @@
+class.positive3.pmf0
\ No newline at end of file

Added: db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive4/META-INF/jdoconfig.xml
URL: http://svn.apache.org/viewvc/db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive4/META-INF/jdoconfig.xml?view=auto&rev=543689
==============================================================================
--- db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive4/META-INF/jdoconfig.xml (added)
+++ db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive4/META-INF/jdoconfig.xml Fri Jun  1 18:20:59 2007
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Do not change any values in this file without also making changes to
+    JDOHelperConfigTest.java, as that file depends on the values in this one!
+-->
+<jdoconfig
+    xmlns="http://java.sun.com/xml/ns/jdo/jdoconfig"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:noNamespaceSchemaLocation="http://java.sun.com/xml/ns/jdo/jdoconfig">
+
+    <!-- Anonymous PMF & with META-INF/services lookup for PMF class name -->
+    <persistence-manager-factory/>
+</jdoconfig>

Added: db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive4/META-INF/services/javax.jdo.PersistenceManagerFactory
URL: http://svn.apache.org/viewvc/db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive4/META-INF/services/javax.jdo.PersistenceManagerFactory?view=auto&rev=543689
==============================================================================
--- db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive4/META-INF/services/javax.jdo.PersistenceManagerFactory (added)
+++ db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive4/META-INF/services/javax.jdo.PersistenceManagerFactory Fri Jun  1 18:20:59 2007
@@ -0,0 +1,3 @@
+
+#this is a comment
+class.positive4.pmf0 # this is another comment
\ No newline at end of file

Added: db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive5/META-INF/jdoconfig.xml
URL: http://svn.apache.org/viewvc/db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive5/META-INF/jdoconfig.xml?view=auto&rev=543689
==============================================================================
--- db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive5/META-INF/jdoconfig.xml (added)
+++ db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive5/META-INF/jdoconfig.xml Fri Jun  1 18:20:59 2007
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Do not change any values in this file without also making changes to
+    JDOHelperConfigTest.java, as that file depends on the values in this one!
+-->
+<jdoconfig
+    xmlns="http://java.sun.com/xml/ns/jdo/jdoconfig"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:noNamespaceSchemaLocation="http://java.sun.com/xml/ns/jdo/jdoconfig">
+
+    <!-- Anonymous PMF & with META-INF/services lookup for PMF class name -->
+    <persistence-manager-factory/>
+</jdoconfig>

Added: db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive5/META-INF/services/javax.jdo.PersistenceManagerFactory
URL: http://svn.apache.org/viewvc/db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive5/META-INF/services/javax.jdo.PersistenceManagerFactory?view=auto&rev=543689
==============================================================================
--- db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive5/META-INF/services/javax.jdo.PersistenceManagerFactory (added)
+++ db/jdo/trunk/api20/test/schema/jdoconfig.xml/Positive5/META-INF/services/javax.jdo.PersistenceManagerFactory Fri Jun  1 18:20:59 2007
@@ -0,0 +1 @@
+class.positive5.pmf0# this is a comment without whitespace separating it from the uncommented text
\ No newline at end of file