You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by hu...@apache.org on 2009/10/01 19:19:21 UTC

svn commit: r820722 [4/8] - in /incubator/aries/contrib: ./ ibm/ ibm/aries.image/ ibm/build/ ibm/build/buildtasks/ ibm/build/buildtasks/src/ ibm/build/buildtasks/src/com/ ibm/build/buildtasks/src/com/ibm/ ibm/build/buildtasks/src/com/ibm/aries/ ibm/bui...

Added: incubator/aries/contrib/ibm/com.ibm.osgi.jndi/src/com/ibm/osgi/jndi/DelegateContext.java
URL: http://svn.apache.org/viewvc/incubator/aries/contrib/ibm/com.ibm.osgi.jndi/src/com/ibm/osgi/jndi/DelegateContext.java?rev=820722&view=auto
==============================================================================
--- incubator/aries/contrib/ibm/com.ibm.osgi.jndi/src/com/ibm/osgi/jndi/DelegateContext.java (added)
+++ incubator/aries/contrib/ibm/com.ibm.osgi.jndi/src/com/ibm/osgi/jndi/DelegateContext.java Thu Oct  1 17:19:13 2009
@@ -0,0 +1,273 @@
+/*
+ * (C) Copyright IBM Corp. 2009
+ */
+package com.ibm.osgi.jndi;
+
+import java.util.Hashtable;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import javax.naming.Binding;
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NameClassPair;
+import javax.naming.NameParser;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+
+public class DelegateContext implements Context
+{
+  private Hashtable<Object, Object> env = new Hashtable<Object, Object>();
+  private Context defaultContext;
+  private static ConcurrentMap<String, Context> urlContexts = new ConcurrentHashMap<String, Context>();
+
+  public DelegateContext(Hashtable<?, ?> theEnv)
+  {
+    env.putAll(theEnv);
+  }
+  
+  public DelegateContext(Context ctx) throws NamingException
+	{
+
+  		defaultContext = ctx;
+			env.putAll(ctx.getEnvironment());
+
+	}
+
+	public Object addToEnvironment(String propName, Object propVal) throws NamingException
+  {
+    Context ctx = getDefaultContext();
+    
+    if (ctx != null) ctx.addToEnvironment(propName, propVal);
+    
+    return env.put(propName, propVal);
+  }
+
+  public void bind(Name name, Object obj) throws NamingException
+  {
+    findContext(name).bind(name, obj);
+  }
+
+  public void bind(String name, Object obj) throws NamingException
+  {
+    findContext(name).bind(name, obj);
+  }
+
+  public void close() throws NamingException
+  {
+    if (defaultContext != null) defaultContext.close();
+    env.clear();
+  }
+
+  public Name composeName(Name name, Name prefix) throws NamingException
+  {
+    return findContext(name).composeName(name, prefix);
+  }
+
+  public String composeName(String name, String prefix) throws NamingException
+  {
+    return findContext(name).composeName(name, prefix);
+  }
+
+  public Context createSubcontext(Name name) throws NamingException
+  {
+    return findContext(name).createSubcontext(name);
+  }
+
+  public Context createSubcontext(String name) throws NamingException
+  {
+    return findContext(name).createSubcontext(name);
+  }
+
+  public void destroySubcontext(Name name) throws NamingException
+  {
+    findContext(name).destroySubcontext(name);
+  }
+
+  public void destroySubcontext(String name) throws NamingException
+  {
+    findContext(name).destroySubcontext(name);
+  }
+
+  public Hashtable<?, ?> getEnvironment() throws NamingException
+  {
+    Hashtable<Object, Object> theEnv = new Hashtable<Object, Object>();
+    theEnv.putAll(env);
+    return theEnv;
+  }
+
+  public String getNameInNamespace() throws NamingException
+  {
+    return getDefaultContext().getNameInNamespace();
+  }
+
+  public NameParser getNameParser(Name name) throws NamingException
+  {
+    return findContext(name).getNameParser(name);
+  }
+
+  public NameParser getNameParser(String name) throws NamingException
+  {
+    return findContext(name).getNameParser(name);
+  }
+
+  public NamingEnumeration<NameClassPair> list(Name name) throws NamingException
+  {
+    return findContext(name).list(name);
+  }
+
+  public NamingEnumeration<NameClassPair> list(String name) throws NamingException
+  {
+    return findContext(name).list(name);
+  }
+
+  public NamingEnumeration<Binding> listBindings(Name name) throws NamingException
+  {
+    return findContext(name).listBindings(name);
+  }
+
+  public NamingEnumeration<Binding> listBindings(String name) throws NamingException
+  {
+    return findContext(name).listBindings(name);
+  }
+
+  public Object lookup(Name name) throws NamingException
+  {
+    return findContext(name).lookup(name);
+  }
+
+  public Object lookup(String name) throws NamingException
+  {
+    return findContext(name).lookup(name);
+  }
+
+  public Object lookupLink(Name name) throws NamingException
+  {
+    return findContext(name).lookupLink(name);
+  }
+
+  public Object lookupLink(String name) throws NamingException
+  {
+    return findContext(name).lookupLink(name);
+  }
+
+  public void rebind(Name name, Object obj) throws NamingException
+  {
+    findContext(name).rebind(name, obj);
+  }
+
+  public void rebind(String name, Object obj) throws NamingException
+  {
+    findContext(name).rebind(name, obj);
+  }
+
+  public Object removeFromEnvironment(String propName) throws NamingException
+  {
+    Context ctx = getDefaultContext();
+    
+    if (ctx != null) ctx.removeFromEnvironment(propName);
+    
+    return env.remove(propName);
+  }
+
+  public void rename(Name oldName, Name newName) throws NamingException
+  {
+    findContext(oldName).rename(oldName, newName);
+  }
+
+  public void rename(String oldName, String newName) throws NamingException
+  {
+    findContext(oldName).rename(oldName, newName);
+  }
+
+  public void unbind(Name name) throws NamingException
+  {
+    findContext(name).unbind(name);
+  }
+
+  public void unbind(String name) throws NamingException
+  {
+    findContext(name).unbind(name);
+  }
+
+  protected Context findContext(Name name) throws NamingException
+  {
+    return findContext(name.toString());
+  }
+
+  
+  protected Context findContext(String name) throws NamingException
+  {
+  	Context toReturn = null;
+  	
+  	if (name.contains(":")) {
+      toReturn = getURLContext(name);
+    } else {
+      toReturn =  getDefaultContext();
+    }
+    
+  	if (toReturn != null)
+  	{
+  		String packages = System.getProperty(Context.URL_PKG_PREFIXES, null);
+  		
+  		if (packages != null)
+  		{
+  			toReturn.addToEnvironment(Context.URL_PKG_PREFIXES, packages);	
+  		}
+  	}
+  	
+    return toReturn;
+  }
+
+  private Context getDefaultContext() throws NamingException
+  {
+    if (defaultContext == null) {
+      defaultContext = ContextHelper.createContext(env);
+    }
+    return defaultContext;
+  }
+
+  private Context getURLContext(String name) throws NamingException
+  {
+    Context ctx = null;
+    
+    int index = name.indexOf(':');
+    
+    if (index != -1) {
+      String scheme = name.substring(0, index);
+      
+      ctx = ContextHelper.createURLContext(scheme, env);
+    }
+    
+    if (ctx == null) {
+      ctx = getDefaultContext();
+    }
+    
+    return ctx;
+  }
+  
+  /**
+   * This method allows the caller to set the default context if one is to hand.
+   * Normally the context would be lazily constructed upon first use, but this
+   * if one already exists when this is created it can be pushed in.
+   * 
+   * @param ctx the context to use.
+   */
+  public void setDefaultContext(Context ctx)
+  {
+    defaultContext = ctx;
+  }
+  
+  /**
+   * This method allows URL contexts to be pushed in. We should probably be 
+   * pushing in references to the ObjectFactory for the url Object Factory, but
+   * for now lets just push the context itself in.
+   * 
+   * @param url
+   * @param ctx
+   */
+  public void setURLContext(String url, Context ctx)
+  {
+    urlContexts.put(url, ctx);
+  }
+}
\ No newline at end of file

Added: incubator/aries/contrib/ibm/com.ibm.osgi.jndi/src/com/ibm/osgi/jndi/DelegateContextFactory.java
URL: http://svn.apache.org/viewvc/incubator/aries/contrib/ibm/com.ibm.osgi.jndi/src/com/ibm/osgi/jndi/DelegateContextFactory.java?rev=820722&view=auto
==============================================================================
--- incubator/aries/contrib/ibm/com.ibm.osgi.jndi/src/com/ibm/osgi/jndi/DelegateContextFactory.java (added)
+++ incubator/aries/contrib/ibm/com.ibm.osgi.jndi/src/com/ibm/osgi/jndi/DelegateContextFactory.java Thu Oct  1 17:19:13 2009
@@ -0,0 +1,13 @@
+/*
+ * (C) Copyright IBM Corp. 2009
+ */
+package com.ibm.osgi.jndi;
+
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+
+public interface DelegateContextFactory {
+  public Context getInitialContext(Hashtable<?, ?> envmt) throws NamingException;
+}

Added: incubator/aries/contrib/ibm/com.ibm.osgi.jndi/src/com/ibm/osgi/jndi/OSGiInitialContextFactoryBuilder.java
URL: http://svn.apache.org/viewvc/incubator/aries/contrib/ibm/com.ibm.osgi.jndi/src/com/ibm/osgi/jndi/OSGiInitialContextFactoryBuilder.java?rev=820722&view=auto
==============================================================================
--- incubator/aries/contrib/ibm/com.ibm.osgi.jndi/src/com/ibm/osgi/jndi/OSGiInitialContextFactoryBuilder.java (added)
+++ incubator/aries/contrib/ibm/com.ibm.osgi.jndi/src/com/ibm/osgi/jndi/OSGiInitialContextFactoryBuilder.java Thu Oct  1 17:19:13 2009
@@ -0,0 +1,59 @@
+/*
+ * (C) Copyright IBM Corp. 2009
+ */
+package com.ibm.osgi.jndi;
+
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.spi.InitialContextFactory;
+import javax.naming.spi.InitialContextFactoryBuilder;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+
+public class OSGiInitialContextFactoryBuilder implements InitialContextFactoryBuilder,
+  InitialContextFactory
+{
+	private BundleContext _context;
+	
+	public OSGiInitialContextFactoryBuilder(BundleContext context)
+	{
+		_context = context;
+	}
+	
+  public InitialContextFactory createInitialContextFactory(Hashtable<?, ?> environment)
+      throws NamingException
+  {
+    return this;
+  }
+  public Context getInitialContext(Hashtable<?, ?> environment) throws NamingException
+  {
+  	Context toReturn = null;
+  	
+  	ServiceReference ref = _context.getServiceReference(DelegateContextFactory.class.getName());
+  	
+  	//TODO: is the custom interface DelegateContextFactory the right way to go about things
+  	//  or is there a more generic way in RFC 142
+  	if (ref != null) {
+  	  try {
+    		DelegateContextFactory dcf = (DelegateContextFactory) _context.getService(ref);
+    		
+    		if (dcf != null) {
+    			toReturn = dcf.getInitialContext(environment);
+    		}
+  	  }
+  	  finally {
+  	    _context.ungetService(ref);
+  	  }
+  	}
+  	
+  	if (toReturn == null) {
+  		toReturn  = new DelegateContext(environment);
+  	}
+  	
+    return toReturn;
+  }
+}

Added: incubator/aries/contrib/ibm/com.ibm.osgi.jndi/src/com/ibm/osgi/jndi/OSGiObjectFactoryBuilder.java
URL: http://svn.apache.org/viewvc/incubator/aries/contrib/ibm/com.ibm.osgi.jndi/src/com/ibm/osgi/jndi/OSGiObjectFactoryBuilder.java?rev=820722&view=auto
==============================================================================
--- incubator/aries/contrib/ibm/com.ibm.osgi.jndi/src/com/ibm/osgi/jndi/OSGiObjectFactoryBuilder.java (added)
+++ incubator/aries/contrib/ibm/com.ibm.osgi.jndi/src/com/ibm/osgi/jndi/OSGiObjectFactoryBuilder.java Thu Oct  1 17:19:13 2009
@@ -0,0 +1,218 @@
+/*
+ * (C) Copyright IBM Corp. 2009
+ */
+package com.ibm.osgi.jndi;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.Referenceable;
+import javax.naming.StringRefAddr;
+import javax.naming.spi.ObjectFactory;
+import javax.naming.spi.ObjectFactoryBuilder;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+public class OSGiObjectFactoryBuilder implements ObjectFactoryBuilder, ObjectFactory
+{
+  /** The bundle context we use for accessing the SR */
+  private static BundleContext context;
+  
+  public static void setBundleContext(BundleContext ctx)
+  {
+    context = ctx;
+  }
+
+  public ObjectFactory createObjectFactory(Object obj, Hashtable<?, ?> environment)
+      throws NamingException
+  {
+    return this;
+  }
+
+  public Object getObjectInstance(Object obj, Name name, Context nameCtx,
+      Hashtable<?, ?> environment) throws Exception
+  {
+  	
+    Reference ref = null;
+
+    if (obj instanceof Reference) {
+      ref = (Reference) obj;
+    } else if (obj instanceof Referenceable) {
+      ref = ((Referenceable)obj).getReference();
+    }
+
+    Object result = ref;
+
+    if (ref != null) {
+      String className = ref.getFactoryClassName();
+
+      if (className != null) {
+        result = getObjectInstanceUsingClassName(obj, className, obj, name, nameCtx, environment);
+      } else {
+        result = getObjectInstanceUsingRefAddress(ref.getAll(), obj, name, nameCtx, environment);
+
+        if (result == null || result == obj) {
+          result = getObjectInstanceUsingAllObjectFactories(obj, name, nameCtx, environment);
+        }
+      }
+    }
+
+    if (result == null) result = ref;
+    
+    return result;
+  }
+
+  private Object getObjectInstanceUsingAllObjectFactories(Object obj, Name name, Context nameCtx,
+      Hashtable<?, ?> environment)
+  {
+    Object result = obj;
+    try {
+      ServiceReference[] refs = context.getAllServiceReferences(ObjectFactory.class.getName(), null);
+
+      if (refs != null) {
+        for (ServiceReference ref : refs) {
+          ObjectFactory factory = (ObjectFactory) context.getService(ref);
+  
+          if (factory != null) {
+            try {
+              result = factory.getObjectInstance(obj, name, nameCtx, environment);
+            } catch (Exception e) {
+              // TODO Auto-generated catch block
+              e.printStackTrace();
+            }
+  
+            context.ungetService(ref);
+  
+            // if the result comes back and is not null and not the reference
+            // object then we should return the result, so break out of the
+            // loop we are in.
+            if (result != null && result != obj) break;
+          }
+        }
+      }
+    } catch (InvalidSyntaxException e) {
+      // TODO Auto-generated catch block
+      e.printStackTrace();
+    }
+
+    if (result == null) result = obj;
+  	
+    return result;
+  }
+
+  private Object getObjectInstanceUsingRefAddress(Enumeration<RefAddr> addresses, Object obj, Name name,
+      Context nameCtx, Hashtable<?, ?> environment)
+  {
+    Object result = obj;
+
+    while (addresses.hasMoreElements()) {
+      RefAddr address = addresses.nextElement();
+      if (address instanceof StringRefAddr && "URL".equals(address.getType())) {
+        String urlScheme = (String)address.getContent();
+        ObjectFactory factory = null;
+        ServiceReference ref = null;
+        try {
+          ServiceReference[] services = context.getServiceReferences(ObjectFactory.class.getName(), "(|(osgi.jndi.urlScheme=" + urlScheme + ")(urlScheme=" + urlScheme + "))");
+
+          if (services != null) {
+            ref = services[0];
+            factory = (ObjectFactory) context.getService(ref);
+          }
+        } catch (InvalidSyntaxException e) {
+          e.printStackTrace();
+        }
+
+        if (factory != null) {
+          try {
+            result = factory.getObjectInstance(obj, name, nameCtx, environment);
+          } catch (Exception e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+          }
+        }
+
+        if (ref != null) context.ungetService(ref);
+        
+        // if the result is not null and references a different object from
+        // the obj then we have resolved the object, so we stop searching.
+        if (result != null && result != obj) break;
+      }
+    }
+
+    return result;
+  }
+
+  private Object getObjectInstanceUsingClassName(Object reference, String className, Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment)
+  {
+    Object result = obj;
+
+    ObjectFactory factory = null;
+    ServiceReference ref = null;
+
+    if (className != null) {
+      try {
+        ServiceReference[] refs = context.getAllServiceReferences(className, null);
+
+        if (refs != null) {
+          for (ServiceReference ref1 : refs) {
+            factory = (ObjectFactory) context.getService(ref1);
+
+            if (factory != null) {
+              ref = ref1;
+              break;
+            }
+          }
+        }
+      } catch (InvalidSyntaxException e) {
+        // TODO Auto-generated catch block
+        e.printStackTrace();
+      }
+    }
+
+    if (factory == null) {
+      try {
+        ServiceReference[] refs = context.getServiceReferences(ObjectFactoryBuilder.class.getName(), null);
+
+        if (refs != null) {
+          for (ServiceReference ofRef : refs) {
+            ObjectFactoryBuilder builder = (ObjectFactoryBuilder) context.getService(ofRef);
+            try {
+              factory = builder.createObjectFactory(reference, environment);
+            } catch (NamingException e) {
+              // TODO Auto-generated catch block
+              e.printStackTrace();
+            }
+
+            context.ungetService(ofRef);
+            if (factory != null) {
+              break;
+            }
+          }
+        }
+      } catch (InvalidSyntaxException e) {
+        // TODO Auto-generated catch block
+        e.printStackTrace();
+      }
+    }
+
+    if (factory != null) {
+      try {
+        result = factory.getObjectInstance(obj, name, nameCtx, environment);
+      } catch (Exception e) {
+        // TODO Auto-generated catch block
+        e.printStackTrace();
+      } finally {
+        if (ref != null) context.ungetService(ref);
+      }
+    }
+
+    return result;
+  }
+}
\ No newline at end of file

Added: incubator/aries/contrib/ibm/com.ibm.osgi.jndi/src/com/ibm/osgi/jndi/startup/Activator.java
URL: http://svn.apache.org/viewvc/incubator/aries/contrib/ibm/com.ibm.osgi.jndi/src/com/ibm/osgi/jndi/startup/Activator.java?rev=820722&view=auto
==============================================================================
--- incubator/aries/contrib/ibm/com.ibm.osgi.jndi/src/com/ibm/osgi/jndi/startup/Activator.java (added)
+++ incubator/aries/contrib/ibm/com.ibm.osgi.jndi/src/com/ibm/osgi/jndi/startup/Activator.java Thu Oct  1 17:19:13 2009
@@ -0,0 +1,47 @@
+/*
+ * (C) Copyright IBM Corp. 2009
+ */
+package com.ibm.osgi.jndi.startup;
+
+import javax.naming.NamingException;
+import javax.naming.spi.NamingManager;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+import com.ibm.osgi.jndi.ContextHelper;
+import com.ibm.osgi.jndi.OSGiInitialContextFactoryBuilder;
+import com.ibm.osgi.jndi.OSGiObjectFactoryBuilder;
+
+/**
+ * The activator for this bundle makes sure the static classes in it are
+ * driven so they can do their magic stuff properly.
+ */
+public class Activator implements BundleActivator
+{
+  public void start(BundleContext context)
+  {
+    ContextHelper.setBundleContext(context);
+    OSGiObjectFactoryBuilder.setBundleContext(context);
+  
+    try {
+      if (!!!NamingManager.hasInitialContextFactoryBuilder()) {
+        NamingManager.setInitialContextFactoryBuilder(new OSGiInitialContextFactoryBuilder(context));
+      }
+    } catch (NamingException e) {
+      // TODO Auto-generated catch block
+      e.printStackTrace();
+    }
+    
+    try {
+      NamingManager.setObjectFactoryBuilder(new OSGiObjectFactoryBuilder());
+    } catch (NamingException e) {
+      // TODO Auto-generated catch block
+      e.printStackTrace();
+    } catch (IllegalStateException e) {
+      e.printStackTrace();
+    }
+  }
+
+  public void stop(BundleContext context) {}
+}
\ No newline at end of file

Added: incubator/aries/contrib/ibm/com.ibm.osgi.jndi/unittest/com/ibm/ws/eba/jndi/test/ObjectFactoryTest.java
URL: http://svn.apache.org/viewvc/incubator/aries/contrib/ibm/com.ibm.osgi.jndi/unittest/com/ibm/ws/eba/jndi/test/ObjectFactoryTest.java?rev=820722&view=auto
==============================================================================
--- incubator/aries/contrib/ibm/com.ibm.osgi.jndi/unittest/com/ibm/ws/eba/jndi/test/ObjectFactoryTest.java (added)
+++ incubator/aries/contrib/ibm/com.ibm.osgi.jndi/unittest/com/ibm/ws/eba/jndi/test/ObjectFactoryTest.java Thu Oct  1 17:19:13 2009
@@ -0,0 +1,156 @@
+/*
+ * (C) Copyright IBM Corp. 2009
+ */
+package com.ibm.ws.eba.jndi.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+
+import java.lang.reflect.Field;
+import java.util.Hashtable;
+import java.util.Properties;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.Reference;
+import javax.naming.StringRefAddr;
+import javax.naming.spi.NamingManager;
+import javax.naming.spi.ObjectFactory;
+
+import mocks.BundleContextMock;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+
+import com.ibm.aries.unittest.mocks.MethodCall;
+import com.ibm.aries.unittest.mocks.Skeleton;
+import com.ibm.osgi.jndi.ContextHelper;
+import com.ibm.osgi.jndi.OSGiObjectFactoryBuilder;
+import com.ibm.osgi.jndi.startup.Activator;
+
+public class ObjectFactoryTest
+{
+  private BundleContext bc;
+
+  /**
+   * This method does the setup .
+   * @throws NoSuchFieldException 
+   * @throws SecurityException 
+   * @throws IllegalAccessException 
+   * @throws IllegalArgumentException 
+   */
+  @Before
+  public void setup() throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException
+  {
+    bc =  Skeleton.newMock(new BundleContextMock(), BundleContext.class);
+    new Activator().start(bc);
+    
+    Field f = ContextHelper.class.getDeclaredField("context");
+    f.setAccessible(true);
+    f.set(null, bc);
+    f = OSGiObjectFactoryBuilder.class.getDeclaredField("context");
+    f.setAccessible(true);
+    f.set(null, bc);
+
+  }
+
+  /**
+   * Make sure we clear the caches out before the next test.
+   */
+  @After
+  public void teardown()
+  {
+    new Activator().stop(bc);
+    BundleContextMock.clear();
+  }
+
+  @Test
+  public void testURLReferenceWithNoMatchingHandler() throws Exception
+  {
+    Reference ref = new Reference(null);
+    ref.add(new StringRefAddr("URL", "wibble"));
+    Object obj = NamingManager.getObjectInstance(ref, null, null, null);
+
+    assertSame("The naming manager should have returned the reference object", ref, obj);
+  }
+
+  @Test
+  public void testURLReferenceWithMatchingHandler() throws Exception
+  {
+    String testObject = "Test object";
+    ObjectFactory factory = Skeleton.newMock(ObjectFactory.class);
+    Skeleton.getSkeleton(factory).setReturnValue(new MethodCall(ObjectFactory.class, "getObjectInstance", Object.class, Name.class, Context.class, Hashtable.class), testObject);
+
+    Properties props = new Properties();
+    props.setProperty("osgi.jndi.urlScheme", "wibble");
+
+    bc.registerService(ObjectFactory.class.getName(), factory, props);
+
+    Reference ref = new Reference(null);
+    ref.add(new StringRefAddr("URL", "wibble"));
+    Object obj = NamingManager.getObjectInstance(ref, null, null, null);
+    
+    assertEquals("The naming manager should have returned the test object", testObject, obj);
+  }
+
+  @Test
+  public void testReferenceWithNoClassName() throws Exception
+  {
+    String testObject = "Test object";
+    ObjectFactory factory = Skeleton.newMock(ObjectFactory.class);
+    Skeleton.getSkeleton(factory).setReturnValue(new MethodCall(ObjectFactory.class, "getObjectInstance", Object.class, Name.class, Context.class, Hashtable.class), testObject);
+
+    bc.registerService(ObjectFactory.class.getName(), factory, null);
+
+    Reference ref = new Reference(null);
+    Object obj = NamingManager.getObjectInstance(ref, null, null, null);
+    
+    assertEquals("The naming manager should have returned the test object", testObject, obj);
+  }
+
+  @Test
+  public void testSpecifiedFactoryWithMatchingFactory() throws Exception
+  {
+    String testObject = "Test object";
+    ObjectFactory factory = Skeleton.newMock(ObjectFactory.class);
+    Skeleton.getSkeleton(factory).setReturnValue(new MethodCall(ObjectFactory.class, "getObjectInstance", Object.class, Name.class, Context.class, Hashtable.class), testObject);
+
+    Reference ref = new Reference("dummy.class.name", factory.getClass().getName(), "");
+
+    bc.registerService(new String[] {ObjectFactory.class.getName(), factory.getClass().getName()}, 
+                       factory, null);
+
+    Object obj = NamingManager.getObjectInstance(ref, null, null, null);
+    
+    assertEquals("The naming manager should have returned the test object", testObject, obj);
+  }
+
+  @Test
+  public void testSpecifiedFactoryWithRegisteredButNotMatchingFactory() throws Exception
+  {
+    String testObject = "Test object";
+    ObjectFactory factory = Skeleton.newMock(ObjectFactory.class);
+    Skeleton.getSkeleton(factory).setReturnValue(new MethodCall(ObjectFactory.class, "getObjectInstance", Object.class, Name.class, Context.class, Hashtable.class), testObject);
+
+    Reference ref = new Reference("dummy.class.name", "dummy.factory.class.name", "");
+
+    bc.registerService(new String[] {ObjectFactory.class.getName(), factory.getClass().getName()}, 
+                       factory, null);
+
+    Object obj = NamingManager.getObjectInstance(ref, null, null, null);
+
+    assertSame("The naming manager should have returned the reference object", ref, obj);
+  }
+
+  @Test
+  public void testSpecifiedFactoryWithNoMatchingFactory() throws Exception
+  {
+    Reference ref = new Reference("dummy.class.name");
+
+    Object obj = NamingManager.getObjectInstance(ref, null, null, null);
+
+    assertSame("The naming manager should have returned the reference object", ref, obj);
+  }
+}
\ No newline at end of file

Added: incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/.aries
URL: http://svn.apache.org/viewvc/incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/.aries?rev=820722&view=auto
==============================================================================
    (empty)

Added: incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/.classpath
URL: http://svn.apache.org/viewvc/incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/.classpath?rev=820722&view=auto
==============================================================================
--- incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/.classpath (added)
+++ incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/.classpath Thu Oct  1 17:19:13 2009
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="src" output="build/unittest/classes" path="unittest"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/unittest.framework"/>
+	<classpathentry kind="output" path="build/classes"/>
+</classpath>

Added: incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/.project
URL: http://svn.apache.org/viewvc/incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/.project?rev=820722&view=auto
==============================================================================
--- incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/.project (added)
+++ incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/.project Thu Oct  1 17:19:13 2009
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>com.ibm.osgi.jpa.unit.manager</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>

Added: incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/META-INF/MANIFEST.MF
URL: http://svn.apache.org/viewvc/incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/META-INF/MANIFEST.MF?rev=820722&view=auto
==============================================================================
--- incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/META-INF/MANIFEST.MF (added)
+++ incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/META-INF/MANIFEST.MF Thu Oct  1 17:19:13 2009
@@ -0,0 +1,12 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Manager Plug-in
+Bundle-SymbolicName: com.ibm.osgi.jpa.unit.manager
+Bundle-Version: 1.0.0
+Bundle-Vendor: IBM
+Bundle-Activator: com.ibm.osgi.jpa.start.Activator
+Import-Package: com.ibm.osgi.util,
+ javax.persistence;version="[1.0.0, 2.0.0)",
+ javax.persistence.spi;version="[1.0.0, 2.0.0)",
+ org.osgi.framework;version="[1.5.0,2.0.0)"
+Export-Package: org.osgi.service.jpa;version="1.0.0";uses:="org.osgi.framework"

Added: incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/build.properties
URL: http://svn.apache.org/viewvc/incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/build.properties?rev=820722&view=auto
==============================================================================
--- incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/build.properties (added)
+++ incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/build.properties Thu Oct  1 17:19:13 2009
@@ -0,0 +1,4 @@
+source.. = src/
+output.. = build/classes/
+bin.includes = META-INF/,\
+               .

Added: incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/build.xml
URL: http://svn.apache.org/viewvc/incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/build.xml?rev=820722&view=auto
==============================================================================
--- incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/build.xml (added)
+++ incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/build.xml Thu Oct  1 17:19:13 2009
@@ -0,0 +1,18 @@
+<!-- (C) Copyright IBM Corp. 2009 -->
+
+<project name="com.ibm.osgi.jpa.unit.manager" default="build" basedir=".">
+  <property name="aries.image" value="true"/>
+  <import file="../build/imports/standard_imports.xml"/>
+  
+  <target name="unittest" depends="createJar, unittest.unittest"/>
+  <target name="createJar">
+    <jar destfile="${basedir}/unittest/resources/jarfile.jar" basedir="${basedir}/unittest/resources/jarfile"/>
+  	<!-- put some jar files in the file1 persistence unit root for testing the parser -->
+  	<copy tofile="${basedir}/unittest/resources/file1/bravoJarFile1.jar">
+  		<fileset dir="${basedir}/unittest/resources" includes="jarfile.jar"/>
+    </copy>
+  	<copy tofile="${basedir}/unittest/resources/file1/bravoJarFile2.jar">
+      <fileset dir="${basedir}/unittest/resources" includes="jarfile.jar"/>
+    </copy>
+  </target>  
+</project>

Added: incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/provider/PersistenceProviderFactory.java
URL: http://svn.apache.org/viewvc/incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/provider/PersistenceProviderFactory.java?rev=820722&view=auto
==============================================================================
--- incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/provider/PersistenceProviderFactory.java (added)
+++ incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/provider/PersistenceProviderFactory.java Thu Oct  1 17:19:13 2009
@@ -0,0 +1,68 @@
+/*
+ * (C) Copyright IBM Corp. 2009
+ */
+package com.ibm.osgi.jpa.provider;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.persistence.spi.PersistenceProvider;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * A factory for lazily creating PersistenceProvider Implementations
+ */
+public class PersistenceProviderFactory implements ServiceFactory
+{
+
+  /** The JPA provider's implementation class name */
+  private final String className;
+  
+  /** The bundle containing the JPA provider */
+  private final Bundle providerBundle;
+
+  /** The persistence provider object */
+  private final AtomicReference<PersistenceProvider> provider = new AtomicReference<PersistenceProvider>();
+  
+  /** Constructor
+   *
+   *@param b The Persistence Bundle
+   *@param providerClassName The provider's implementation class name
+   */
+  public PersistenceProviderFactory(Bundle b, String providerClassName)
+  {
+    className = providerClassName;
+    providerBundle = b;
+  }
+
+  @SuppressWarnings("unchecked")
+public PersistenceProvider getService(Bundle arg0, ServiceRegistration arg1)
+  {
+    if(provider.get() == null)
+    {
+      try {
+        Class<? extends PersistenceProvider> providerClass = providerBundle.loadClass(className);
+        provider.compareAndSet(null, providerClass.newInstance());
+      } catch (Exception e) {
+        try {
+          providerBundle.stop();
+        } catch (BundleException e1) {
+          // TODO Auto-generated catch block
+          e1.printStackTrace();
+        }
+        e.printStackTrace();
+      }
+    }
+    return provider.get();
+  }
+
+  public void ungetService(Bundle arg0, ServiceRegistration arg1, Object arg2)
+  {
+    // No-op. We never want to tidy this up as it doesn't consume many
+    // resources once instantiated.
+  }
+
+}

Added: incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/provider/PersistenceProviderManager.java
URL: http://svn.apache.org/viewvc/incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/provider/PersistenceProviderManager.java?rev=820722&view=auto
==============================================================================
--- incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/provider/PersistenceProviderManager.java (added)
+++ incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/provider/PersistenceProviderManager.java Thu Oct  1 17:19:13 2009
@@ -0,0 +1,153 @@
+/*
+ * (C) Copyright IBM Corp. 2009
+ */
+package com.ibm.osgi.jpa.provider;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import javax.persistence.spi.PersistenceProvider;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.framework.SynchronousBundleListener;
+
+/**
+ *  This class registers PersistenceProvider implementations on behalf
+ *  of JPA provider bundles.
+ */
+public class PersistenceProviderManager implements SynchronousBundleListener, BundleActivator
+{  
+  /** The Service Registrations for Persistence Providers */
+  private final ConcurrentMap<Bundle, ServiceRegistration> registrations = new ConcurrentHashMap<Bundle, ServiceRegistration>();
+  
+  private BundleContext ctx;
+  
+  public void start(BundleContext ctx) throws Exception 
+  {
+    this.ctx = ctx;
+    
+    ctx.addBundleListener(this);
+    Bundle[] bundles = ctx.getBundles();
+    
+    for (Bundle b : bundles) {
+      if (b.getState() == Bundle.STARTING ||
+          b.getState() == Bundle.ACTIVE) {
+        registerPotentialPersistenceProvider(b);
+      }
+    }
+  }
+  
+  /**
+   * This method determines whether a bundle is a persistence
+   * provider bundle
+   * 
+   * @param b
+   */
+  private void registerPotentialPersistenceProvider(Bundle b)
+  {
+    URL provider = b.getResource("META-INF/services/javax.persistence.spi.PersistenceProvider");
+    
+    if (provider != null) {
+      try {
+        BufferedReader reader = null;
+        String providerClassName = null;
+        try {
+          reader = new BufferedReader(new InputStreamReader(provider.openStream()));
+          providerClassName = reader.readLine();
+        } finally {
+          if(reader != null)reader.close();
+        }
+        
+        String[] classNames = new String[] {PersistenceProvider.class.getName(), providerClassName};
+        String version = b.getVersion().toString();
+        
+        if(!!!alreadyRegistered(b, providerClassName))
+        {
+          PersistenceProviderFactory ppf = new PersistenceProviderFactory(b, providerClassName);
+        
+          Dictionary<String, Object> props = new Hashtable<String, Object>();
+          props.put("osgi.jpa.provider.version", version);
+        
+          ServiceRegistration reg = b.getBundleContext().registerService(classNames, ppf, props);
+        
+          if(registrations.putIfAbsent(b,reg) != null)
+            reg.unregister();
+         }
+      } catch (IOException e) {
+        //TODO log this properly
+        e.printStackTrace();
+      }
+    }
+    
+  }
+  
+  /**
+   * Return true if the Bundle b has already registered a PersistenceProvider with the
+   * implementation class name providerClassName
+   * @param b
+   * @param providerClassName
+   * @return
+   */
+  private boolean alreadyRegistered(Bundle b, String providerClassName)
+  {
+    ServiceReference[] refs = b.getRegisteredServices();
+    
+    boolean registered = false;
+    
+    if(refs != null) {
+      Filter f;
+      try {
+        f = ctx.createFilter("(&(" + Constants.OBJECTCLASS + "=" + PersistenceProvider.class.getName() +
+            ")("  + Constants.OBJECTCLASS + "=" + providerClassName + "))");
+        
+        for(ServiceReference r : refs)
+        {
+          registered = f.match(r);
+          if(registered) break;
+        }
+      } catch (InvalidSyntaxException e) {
+        // TODO Auto-generated catch block
+        e.printStackTrace();
+      }
+    }
+    return registered;
+  }
+
+  public void bundleChanged(BundleEvent event)
+  {
+    int eventType = event.getType();
+    
+    if(eventType == BundleEvent.STARTING || eventType == BundleEvent.LAZY_ACTIVATION)
+      registerPotentialPersistenceProvider(event.getBundle());
+    else if (eventType == BundleEvent.STOPPING) {
+      ServiceRegistration reg = registrations.remove(event.getBundle());
+      if(reg != null)
+        reg.unregister();
+    }
+  }
+  
+  /**
+   * Destroy this PersistenceProviderManager
+   */
+  public void stop(BundleContext ctx) throws Exception 
+  {
+    ctx.removeBundleListener(this);
+    //We do not need to unregister the PersistenceProviders on behalf of the
+    //bundles. This will happen automatically when they shut down.
+  }
+
+}

Added: incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/start/Activator.java
URL: http://svn.apache.org/viewvc/incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/start/Activator.java?rev=820722&view=auto
==============================================================================
--- incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/start/Activator.java (added)
+++ incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/start/Activator.java Thu Oct  1 17:19:13 2009
@@ -0,0 +1,57 @@
+/*
+ * (C) Copyright IBM Corp. 2009
+ */
+package com.ibm.osgi.jpa.start;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+import com.ibm.osgi.jpa.provider.PersistenceProviderManager;
+import com.ibm.osgi.jpa.unit.PersistenceBundleManager;
+
+public class Activator implements BundleActivator
+{
+  private PersistenceProviderManager providerMgr;
+  private PersistenceBundleManager bundleMgr;
+  
+  @Override
+  public void start(BundleContext ctx) throws Exception
+  {
+   try {
+     providerMgr = new PersistenceProviderManager();
+     providerMgr.start(ctx);
+   } catch (Exception e) {
+     //TODO log this error
+     e.printStackTrace();
+   }
+
+   try {
+     bundleMgr = new PersistenceBundleManager();
+     bundleMgr.start(ctx);
+   } catch (Exception e) {
+     //TODO log this error
+     e.printStackTrace();
+   }
+  }
+
+  @Override
+  public void stop(BundleContext ctx) throws Exception
+  {
+    Exception ex = null;
+    
+    try {
+      providerMgr.stop(ctx);
+    } catch (Exception e) {
+      ex = e;
+      //TODO FFDC
+    }
+    
+    try {
+      bundleMgr.stop(ctx);
+    } catch (Exception e) {
+      ex = e;
+      //TODO FFDC
+    }
+    if (ex != null) throw ex;
+  }
+}

Added: incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/unit/PersistenceBundleManager.java
URL: http://svn.apache.org/viewvc/incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/unit/PersistenceBundleManager.java?rev=820722&view=auto
==============================================================================
--- incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/unit/PersistenceBundleManager.java (added)
+++ incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/unit/PersistenceBundleManager.java Thu Oct  1 17:19:13 2009
@@ -0,0 +1,424 @@
+/*
+ * (C) Copyright IBM Corp. 2009
+ */
+
+package com.ibm.osgi.jpa.unit;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.validation.Schema;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.framework.SynchronousBundleListener;
+import org.osgi.framework.Version;
+import org.osgi.service.jpa.PersistenceUnitInfoService;
+
+import com.ibm.osgi.jpa.unit.parsing.EarlyParserReturn;
+import com.ibm.osgi.jpa.unit.parsing.JPAHandler;
+import com.ibm.osgi.jpa.unit.parsing.SchemaLocatingHandler;
+import com.ibm.osgi.jpa.util.PersistenceBundleHelper;
+import com.ibm.osgi.jpa.util.PersistenceLocationData;
+
+import com.ibm.osgi.util.FragmentBuilder;
+
+/**
+ * This class manages the fragments that need to be added to persistence bundles, and
+ * also registers the metadata for persistence units in the service registry.
+ */
+public class PersistenceBundleManager implements SynchronousBundleListener, BundleActivator
+{
+  /** The bundle context for this bundle */
+  private BundleContext ctx = null;
+  /** A map of bundles to generated fragments */
+  private final ConcurrentMap<Bundle, Bundle> hostToFragmentMap = new ConcurrentHashMap<Bundle, Bundle>();
+  /** A map of persistence bundles to sets of persistence metadata */
+  private final ConcurrentMap<Bundle, Set<ServiceRegistration>> hostToPersistenceUnitMap = new ConcurrentHashMap<Bundle, Set<ServiceRegistration>>();
+  //TODO pull this from config
+  /** The default JPA provider to use */
+  public static final String DEFAULT_JPA_PROVIDER ="org.apache.openjpa.persistence.PersistenceProviderImpl";
+
+  public void start(BundleContext ctx)
+  {
+    this.ctx = ctx;
+    ctx.addBundleListener(this);
+  }
+  
+  public void stop(BundleContext arg0) throws Exception {
+    
+    ctx.removeBundleListener(this);
+    //When we stop, tidy up all the fragments and services, the
+    //fragments only get detached when the host is unresolved,
+    //so JPA can continue gracefully in active bundles
+    //if the container wishes
+    for(Bundle b : hostToFragmentMap.keySet())
+      tidyUpPersistenceBundle(b);
+  }
+  
+  public void bundleChanged(BundleEvent event)
+  {
+    Bundle b = event.getBundle();
+    
+    //We don't look at fragments
+    if (b.getHeaders().get(Constants.FRAGMENT_HOST) == null)
+    {
+      // We need to remove fragments that are no longer useful
+      // and register fragments for those that need them.
+      // No action is needed on UNRESOLVED (a package refresh)
+      // as the bundle hasn't changed
+      // We shouldn't process multiple events on different
+      // threads for the same bundle at the same time, but the
+      // framework should protect us from this. Testing may also show
+      // that we need to prevent this call being reentrant.
+      // We absolutely cannot lock when calling these methods as
+      // it can cause deadlocks if listeners hold locks whilst
+      // interacting with the framework in a manner that fires
+      // events.
+      switch(event.getType()) {
+        case BundleEvent.UNINSTALLED : {
+          tidyUpPersistenceBundle(b);
+          break;
+        }
+        //This case should fall through to add a new
+        //fragment after update/refresh
+        case BundleEvent.UNRESOLVED :
+        case BundleEvent.UPDATED :
+          tidyUpPersistenceBundle(b);
+        case BundleEvent.INSTALLED :
+          processBundle(b);
+      }
+    }
+  }
+
+  /**
+   * If we have generated a resources for the supplied bundle, then
+   * tidy them  up.
+   * @param host
+   */
+  private void tidyUpPersistenceBundle(Bundle host)
+  {
+    
+    Bundle fragment = hostToFragmentMap.remove(host);
+    Set<ServiceRegistration> services = hostToPersistenceUnitMap.remove(host);
+    
+    if(services != null) {
+      for(ServiceRegistration reg : services)
+        reg.unregister();
+    }
+    
+    if(fragment != null){
+      try {
+        fragment.uninstall();
+      } catch (BundleException be) {
+        //TODO log this error, then hope that we don't try to
+        //recreate the fragment before restarting the framework!
+      }
+    }
+  }
+  
+  /**
+   * Process the supplied bundle for persistence units. If any are
+   * found then the bundle will be tied to a provider using a fragment
+   * @param b
+   */
+  private void processBundle(Bundle b)
+  {
+    Bundle fragment = null;
+    Collection <PersistenceLocationData> persistenceXmls = PersistenceBundleHelper.findPersistenceXmlFiles(b);
+    //If we have no persistence units then our job is done
+    if (!!!persistenceXmls.isEmpty())
+    {
+      //Get the persistence units defined, and a provider for them to use
+      Collection<PersistenceUnitImpl> parsedPersistenceUnits = parseXmlFiles(persistenceXmls, b);
+      ServiceReference providerRef = getProviderServiceReference(parsedPersistenceUnits);
+      
+      //If we can't find a provider then bomb out
+      if (providerRef != null)
+      {
+        try {
+          FragmentBuilder builder = new FragmentBuilder(b, ".jpa.fragment");
+          builder.addImportsFromExports(providerRef.getBundle());
+          fragment = builder.install(ctx);
+        
+          
+          hostToFragmentMap.put(b, fragment);
+          // If we successfully got a fragment then
+          // set the provider reference and register the units
+          Set<ServiceRegistration> registrations = new HashSet<ServiceRegistration>();
+          Hashtable<String, Object> props = new Hashtable<String, Object>();
+          
+          props.put(PersistenceUnitInfoService.PERSISTENCE_BUNDLE_SYMBOLIC_NAME, b.getSymbolicName());
+          props.put(PersistenceUnitInfoService.PERSISTENCE_BUNDLE_VERSION, b.getVersion());
+          
+          for(PersistenceUnitImpl unit : parsedPersistenceUnits){
+            Hashtable<String, Object> serviceProps = new Hashtable<String, Object>(props);
+            
+            String unitName = (String) unit.getPersistenceXmlMetadata().get(PersistenceUnitInfoService.UNIT_NAME);
+            if(unitName != null)
+              serviceProps.put(PersistenceUnitInfoService.PERSISTENCE_UNIT_NAME, unitName);
+            
+            unit.setProviderReference(providerRef);
+            registrations.add(ctx.registerService(PersistenceUnitInfoService.class.getName(), unit, serviceProps));
+          }
+          hostToPersistenceUnitMap.put(b, registrations);
+        }
+        catch (IOException e)
+        {
+          // TODO Fragment generation failed, log the error
+          // No clean up because we didn't register the bundle yet
+          e.printStackTrace();
+        }
+        catch (BundleException be) {
+          //TODO log the failure to install the fragment, but return null
+          // to show we didn't get a fragment installed
+          // No clean up because we didn't register the bundle yet
+        }
+      }
+    }
+  }
+
+  /**
+   * Parse the persistence.xml files referenced by the URLs in the collection
+   * @param persistenceXmls
+   * @param bundle  The bundle containing the persistence xml files
+   * @return A collection of parsed persistence units.
+   */
+  private Collection<PersistenceUnitImpl> parseXmlFiles(Collection<PersistenceLocationData> persistenceXmls, Bundle bundle)
+  {
+    Collection<PersistenceUnitImpl> persistenceUnits = new ArrayList<PersistenceUnitImpl>();
+    //Parse each xml file in turn
+    for(PersistenceLocationData datum : persistenceXmls) {
+      SAXParserFactory parserFactory = SAXParserFactory.newInstance();
+      InputStream is = null;
+      try {
+        SAXParser parser = parserFactory.newSAXParser();
+        is = datum.getPersistenceXML().openStream();
+        
+        try{
+          parser.parse(is, new SchemaLocatingHandler(ctx.getBundle()));
+        } catch (EarlyParserReturn epr) {
+          //This is not really an exception, but a way to work out which
+          //version of the persistence schema to use in validation
+          Schema s = epr.getSchema();
+          
+          if(s != null) {
+            parserFactory.setSchema(s);
+            parserFactory.setNamespaceAware(true);
+            parser = parserFactory.newSAXParser();
+           
+            //Get back to the beginning of the stream
+            is.close();
+            is = datum.getPersistenceXML().openStream();
+            
+            JPAHandler handler = new JPAHandler(datum, epr.getVersion());
+            parser.parse(is, handler);
+       
+            persistenceUnits.addAll(handler.getPersistenceUnits());
+          }
+        }
+      } catch (Exception e) {
+        //TODO Log this error in parsing
+        e.printStackTrace();
+      } finally {
+        if(is != null) try {
+          is.close();
+        } catch (IOException e) {
+          //TODO Log this
+          e.printStackTrace();
+        }
+      }
+    }
+    return persistenceUnits;
+  }
+
+  /**
+   * Get a persistence provider from the service registry described by the
+   * persistence units defined
+   * @param parsedPersistenceUnits
+   * @return A service reference or null if no suitable reference is available
+   */
+  private ServiceReference getProviderServiceReference(Collection<PersistenceUnitImpl> parsedPersistenceUnits)
+  {
+    Set<String> ppClassNames = new HashSet<String>();
+    Set<Filter> versionFilters = new HashSet<Filter>();
+    //Fill the set of class names and version Filters
+    for(PersistenceUnitImpl unit : parsedPersistenceUnits)
+    {
+      Map<String, Object> metadata = unit.getPersistenceXmlMetadata();
+      String provider = (String) metadata.get(PersistenceUnitInfoService.PROVIDER_CLASSNAME);
+      //get providers specified in the persistence units
+      if(provider != null && !!!provider.equals(""))
+      {
+        ppClassNames.add(provider);
+        
+        Properties props = (Properties) metadata.get(PersistenceUnitInfoService.PROPERTIES);
+        
+        if(props != null && props.containsKey(PersistenceUnitInfoService.JPA_PROVIDER_VERSION)) {
+         
+          try {
+            Filter f = getFilter(props.getProperty(PersistenceUnitInfoService.JPA_PROVIDER_VERSION, "0.0.0"));
+            versionFilters.add(f);
+          } catch (InvalidSyntaxException e) {
+            // TODO Log error and ignore, This should never happen
+            e.printStackTrace();
+          }
+        }
+      }
+    }
+    
+    //If we have too many provider class names specified then blow up
+    if(ppClassNames.size() > 1)
+    {
+      //TODO log this error (too many persistence providers specified)
+    } else {
+      //Get the best provider for the given filters
+      String provider = (ppClassNames.isEmpty()) ?
+          DEFAULT_JPA_PROVIDER : ppClassNames.iterator().next();
+          return getBestProvider(provider, versionFilters);
+    }
+    return null;
+  }
+ 
+  /**
+   * Locate the best provider for the given criteria
+   * @param providerClass
+   * @param matchingCriteria
+   * @return
+   */
+  private ServiceReference getBestProvider(String providerClass, Set<Filter> matchingCriteria)
+  {
+    ServiceReference[] array = null;
+    try {
+      array = ctx.getAllServiceReferences(providerClass, null);
+    } catch (InvalidSyntaxException e) {
+      //TODO this can never happen
+    }
+    
+    if(array != null) {
+      //A linked list is faster for large numbers of ServiceReferences
+      //Note we cannot use Arrays.asList() as we need to remove items
+      //via an iterator, and this would throw UnsupportedOperationException.
+      List<ServiceReference> refs = new LinkedList<ServiceReference>();
+      
+      for(ServiceReference reference : array)
+        refs.add(reference);
+      
+      Iterator<ServiceReference> it = refs.iterator();
+      
+      //Remove anything that doesn't match the filter
+      while(it.hasNext())
+      {
+        ServiceReference ref = it.next();
+        for(Filter f : matchingCriteria)
+        {
+          if(!!!f.match(ref)) {
+            it.remove();
+            break;
+          }
+        }
+      }
+      
+      if(!!!refs.isEmpty()) {
+        //Sort the list in DESCENDING ORDER
+        Collections.sort(refs, new Comparator<ServiceReference>() {
+
+          //TODO we may wish to use Ranking, then versions for equal ranks
+          @Override
+          public int compare(ServiceReference object1, ServiceReference object2)
+          {
+            Version v1 = object1.getBundle().getVersion();
+            Version v2 = object2.getBundle().getVersion();
+            return v2.compareTo(v1);
+          }
+        });
+        return refs.get(0);
+      } else {
+        //TODO no matching providers for matching criteria
+      }
+    } else {
+      //TODO log no matching Providers for impl class
+    }
+    
+    return null;
+  }
+  
+  /**
+   * Create a filter for the supplied version range string
+   * @param providerVersion
+   * @return
+   * @throws InvalidSyntaxException
+   */
+  private Filter getFilter(String providerVersion)
+      throws InvalidSyntaxException
+  {
+    String toReturn = null;
+    
+    //TODO NLS enable the messages in the exceptions below (Invalid version range specified...)
+    //Create a filter to match the required provider version range
+    if(providerVersion != null) {
+      if(!!!providerVersion.contains(","))
+        toReturn = ("(osgi.jpa.provider.version>=" + providerVersion + ")");
+      else {
+        String[] versionArray = providerVersion.split(",");
+        
+        if(versionArray.length == 2) {
+          
+          versionArray[0] = versionArray[0].trim();
+          versionArray[1] = versionArray[1].trim();
+          
+          char bracket1 = versionArray[0].charAt(0);
+          char bracket2 = versionArray[1].charAt(versionArray[1].length() - 1);
+          
+          String version1 = versionArray[0].substring(1);
+          String version2 = versionArray[1].substring(0, versionArray[1].length() -1);
+
+          if(version1.compareTo(version2) > 0)
+            throw new InvalidSyntaxException("Invalid version range specified. " + providerVersion, providerVersion);
+          
+          String compare1 = "(osgi.jpa.provider.version>=" + version1 + ")";
+          String compare2 = "(osgi.jpa.provider.version<=" + version2 + ")";
+          
+          if('(' == bracket1)
+             compare1 = compare1 + "(!(osgi.jpa.provider.version=" + version1 + "))";
+          else if('[' != bracket1) throw new InvalidSyntaxException("Invalid version range specified. " + providerVersion, providerVersion);
+          
+
+          if(')' == bracket2)
+            compare2 = compare2 + "(!(osgi.jpa.provider.version=" + version2 + "))";
+          else if(']' != bracket2) throw new InvalidSyntaxException("Invalid version range specified. " + providerVersion, providerVersion);
+         
+         
+          toReturn = "(&" + compare1 + compare2 + ")";
+        } else throw new InvalidSyntaxException("Invalid version range specified. " + providerVersion, providerVersion);
+        
+      }
+    }
+    return FrameworkUtil.createFilter(toReturn);
+  }
+}

Added: incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/unit/PersistenceUnitImpl.java
URL: http://svn.apache.org/viewvc/incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/unit/PersistenceUnitImpl.java?rev=820722&view=auto
==============================================================================
--- incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/unit/PersistenceUnitImpl.java (added)
+++ incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/unit/PersistenceUnitImpl.java Thu Oct  1 17:19:13 2009
@@ -0,0 +1,229 @@
+/*
+ * (C) Copyright IBM Corp. 2009
+ */
+package com.ibm.osgi.jpa.unit;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.jpa.PersistenceUnitInfoService;
+
+import com.ibm.osgi.jpa.util.PersistenceLocationData;
+
+/**
+ * An implementation of PersistenceUnit for parsed persistence unit metadata
+ *
+ */
+@SuppressWarnings("unchecked")
+public class PersistenceUnitImpl implements PersistenceUnitInfoService
+{
+  /** A map to hold the metadata from the xml */
+  private final Map<String,Object> metadata = new HashMap<String, Object>();
+  /** Information about the location of this persistence unit */
+  private final PersistenceLocationData xmlLocationData;
+
+  /**
+   * The Service Reference for the provider to which this persistence
+   * unit is tied
+   */
+  private ServiceReference provider;
+
+  
+  /**
+   * Create a new persistence unit with the given name, transaction type, location and
+   * defining bundle
+   * 
+   * @param name         may be null
+   * @param transactionType  may be null
+   * @param location
+   * @param version    The version of the JPA schema used in persistence.xml
+   */
+  public PersistenceUnitImpl(String name, String transactionType, PersistenceLocationData location, String version)
+  {
+    xmlLocationData = location;
+    
+    metadata.put(SCHEMA_VERSION, version);
+
+    if (name != null)metadata.put(UNIT_NAME, name);
+    if (transactionType != null) metadata.put(TRANSACTION_TYPE, transactionType);
+
+  }
+  
+  
+  @Override
+  public Bundle getDefiningBundle()
+  {
+    return xmlLocationData.getPersistenceBundle();
+  }
+
+  @Override
+  public ServiceReference getProviderReference()
+  {
+    return provider;
+  }
+
+  @Override
+  public Map<String, Object> getPersistenceXmlMetadata()
+  {
+    Map<String, Object> data = new HashMap<String, Object>(metadata);
+    if(data.containsKey(MAPPING_FILES))
+      data.put(MAPPING_FILES, ((ArrayList) metadata.get(MAPPING_FILES)).clone());
+    if(data.containsKey(JAR_FILES))
+    data.put(JAR_FILES, ((ArrayList) metadata.get(JAR_FILES)).clone());
+    if(data.containsKey(MANAGED_CLASSES))
+    data.put(MANAGED_CLASSES, ((ArrayList) metadata.get(MANAGED_CLASSES)).clone());
+    if(data.containsKey(PROPERTIES))
+    data.put(PROPERTIES, ((Properties)metadata.get(PROPERTIES)).clone());
+    
+    return data;
+  }
+
+  @Override
+  public URL getPersistenceXmlLocation()
+  {
+    return xmlLocationData.getPersistenceXML();
+  }
+  
+  @Override
+  public URL getPersistenceUnitRoot()
+  {
+    return xmlLocationData.getPersistenceUnitRoot();
+  }
+
+  /**
+   * @param provider
+   */
+  public void setProviderClassName(String provider)
+  {
+    metadata.put(PROVIDER_CLASSNAME, provider);
+  }
+
+  /**
+   * @param jtaDataSource
+   */
+  public void setJtaDataSource(String jtaDataSource)
+  {
+    metadata.put(JTA_DATASOURCE, jtaDataSource);
+  }
+
+  /**
+   * @param nonJtaDataSource
+   */
+  public void setNonJtaDataSource(String nonJtaDataSource)
+  {
+    metadata.put(NON_JTA_DATASOURCE, nonJtaDataSource);
+  }
+
+  /**
+   * @param mappingFileName
+   */
+  public void addMappingFileName(String mappingFileName)
+  {
+    List<String> files = (List<String>) metadata.get(MAPPING_FILES);
+    if(files == null) {
+      files = new ArrayList<String>();
+      metadata.put(MAPPING_FILES, files);
+    }
+    files.add(mappingFileName);
+  }
+
+  /**
+   * @param jarFile
+   */
+  public void addJarFileName(String jarFile)
+  {
+    List<String> jars = (List<String>) metadata.get(JAR_FILES);
+    if(jars == null) {
+      jars = new ArrayList<String>();
+      metadata.put(JAR_FILES, jars);
+    }
+      
+    jars.add(jarFile);
+  }
+
+  /**
+   * @param className
+   */
+  public void addClassName(String className)
+  {
+    List<String> classes = (List<String>) metadata.get(MANAGED_CLASSES);
+    if(classes == null) {
+      classes = new ArrayList<String>();
+      metadata.put(MANAGED_CLASSES, classes);
+    }
+    classes.add(className);
+  }
+
+  /**
+   * @param exclude
+   */
+  public void setExcludeUnlisted(boolean exclude)
+  {
+    metadata.put(EXCLUDE_UNLISTED_CLASSES, exclude);
+  }
+
+  /**
+   * @param name
+   * @param value
+   */
+  public void addProperty(String name, String value)
+  {
+    Properties props = (Properties) metadata.get(PROPERTIES);
+    if(props == null) {
+      props = new Properties();
+      metadata.put(PROPERTIES, props);
+    }
+    props.setProperty(name, value);
+  }
+
+  /**
+   * @param providerRef
+   */
+  public void setProviderReference(ServiceReference providerRef)
+  {
+    provider = providerRef;
+  }
+
+  @Override
+  public ClassLoader getClassLoader()
+  {
+    return new BundleDelegatingClassLoader(getDefiningBundle());
+  }
+  
+  private static class BundleDelegatingClassLoader extends ClassLoader
+  {
+    private final Bundle bundle;
+    
+    public BundleDelegatingClassLoader(Bundle b)
+    {
+      super(ClassLoader.getSystemClassLoader());
+      bundle = b;
+    }
+    
+    @Override
+    protected Class<?> findClass(String name) throws ClassNotFoundException
+    {
+      return bundle.loadClass(name);
+    }
+    
+    @Override
+    protected URL findResource(String resName)
+    {
+      return bundle.getResource(resName);
+    }
+    
+    @Override
+    protected Enumeration<URL> findResources(String resName) throws IOException
+    {
+      return bundle.getResources(resName);
+    }
+  }
+}

Added: incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/unit/parsing/EarlyParserReturn.java
URL: http://svn.apache.org/viewvc/incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/unit/parsing/EarlyParserReturn.java?rev=820722&view=auto
==============================================================================
--- incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/unit/parsing/EarlyParserReturn.java (added)
+++ incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/unit/parsing/EarlyParserReturn.java Thu Oct  1 17:19:13 2009
@@ -0,0 +1,49 @@
+/*
+ * (C) Copyright IBM Corp. 2009
+ */
+package com.ibm.osgi.jpa.unit.parsing;
+
+import javax.xml.validation.Schema;
+
+import org.xml.sax.SAXException;
+
+/**
+ * A convenience mechanism for finding the schema to validate with
+ */
+public class EarlyParserReturn extends SAXException
+{
+  /** This class is serializable */
+  private static final long serialVersionUID = 6173561765417524327L;
+  /** The schema to use */
+  private final Schema schema;
+  /** The value of the version attribute in the xml */
+  private final String jpaVersion;
+
+  /**
+   * @return The schema that was used in the xml document
+   */
+  public Schema getSchema()
+  {
+    return schema;
+  }
+  
+  /**
+   * @return The version of the JPA schema used
+   */
+  public String getVersion()
+  {
+    return jpaVersion;
+  }
+
+  /**
+   * @param s  The schema used
+   * @param version The version of the schema used
+   */
+  public EarlyParserReturn(Schema s, String version)
+  {
+    schema = s;
+    jpaVersion = version;
+  }
+  
+  
+}

Added: incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/unit/parsing/JPAHandler.java
URL: http://svn.apache.org/viewvc/incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/unit/parsing/JPAHandler.java?rev=820722&view=auto
==============================================================================
--- incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/unit/parsing/JPAHandler.java (added)
+++ incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/unit/parsing/JPAHandler.java Thu Oct  1 17:19:13 2009
@@ -0,0 +1,114 @@
+/*
+ * (C) Copyright IBM Corp. 2009
+ */
+package com.ibm.osgi.jpa.unit.parsing;
+
+import java.util.Collection;
+import java.util.Stack;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import com.ibm.osgi.jpa.unit.PersistenceUnitImpl;
+import com.ibm.osgi.jpa.util.PersistenceLocationData;
+
+/**
+ *  This code is responsible for parsing the persistence.xml into PersistenceUnits
+ */
+public class JPAHandler extends DefaultHandler
+{
+  /** The Persistence Units that we have parsed */
+  private final Stack<PersistenceUnitImpl> persistenceUnits = new Stack<PersistenceUnitImpl>();
+  /** The name of the current element */
+  private String elementName;
+  /** The persistence xml location data */
+  private final PersistenceLocationData xmlLocationData;
+  /** The version of the persistence.xml file */
+  private final String jpaVersion;
+  /** A StringBuilder for caching the information from getCharacters */
+  private StringBuilder builder = new StringBuilder();
+  
+  /**
+   * Create a new JPA Handler for the given peristence.xml
+   * @param data
+   * @param version  the version of the JPA schema used in the xml
+   */
+  public JPAHandler(PersistenceLocationData data, String version){
+    xmlLocationData = data;
+    jpaVersion = version;
+  }
+  
+  /**
+   * Collect up the characters, as element's characters may be split across multiple
+   * calls. Isn't SAX lovely...
+   */
+  @Override
+  public void characters(char[] ch, int start, int length) throws SAXException
+  {
+    builder.append(ch, start, length);
+  }
+
+  @Override
+  public void startElement(String uri, String localName, String name, Attributes attributes)
+      throws SAXException
+  {
+    //Do this setting first as we use it later.
+    elementName = (localName == null || "".equals(localName))? name : localName;
+
+    if("persistence-unit".equals(elementName)) {
+      persistenceUnits.push(new PersistenceUnitImpl(attributes.getValue("name"), attributes.getValue("transaction-type"), xmlLocationData, jpaVersion));
+    } else if("exclude-unlisted-classes".equals(elementName))
+      persistenceUnits.peek().setExcludeUnlisted(true);
+    else if("property".equals(elementName))
+      persistenceUnits.peek().addProperty(attributes.getValue("name"), attributes.getValue("value"));
+    
+  }
+  
+
+  @Override
+  public void endElement(String uri, String localName, String name) throws SAXException
+  {
+    String s = builder.toString().trim();
+    //This step is VERY important, otherwise we pollute subsequent
+    //elements
+    builder = new StringBuilder();
+    
+    if("".equals(s)) return;
+    
+    PersistenceUnitImpl pu = persistenceUnits.peek();
+    
+    if("provider".equals(elementName))
+      pu.setProviderClassName(s);
+    else if("jta-data-source".equals(elementName))
+      pu.setJtaDataSource(s);
+    else if("non-jta-data-source".equals(elementName))
+      pu.setNonJtaDataSource(s);
+    else if("mapping-file".equals(elementName))
+      pu.addMappingFileName(s);
+    else if("jar-file".equals(elementName)) {
+      pu.addJarFileName(s);
+    } else if("class".equals(elementName))
+      pu.addClassName(s);
+    else if("exclude-unlisted-classes".equals(elementName))
+      pu.setExcludeUnlisted(Boolean.parseBoolean(s));
+  }
+
+  @Override
+  public void error(SAXParseException spe) throws SAXException
+  {
+    // We throw this exception to be caught further up and logged
+    // as an error there
+    throw spe;
+  }
+
+  /**
+   * @return The collection of persistence units that we have parsed
+   */
+  public Collection<PersistenceUnitImpl> getPersistenceUnits()
+  {
+    return persistenceUnits;
+  }
+
+}

Added: incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/unit/parsing/SchemaLocatingHandler.java
URL: http://svn.apache.org/viewvc/incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/unit/parsing/SchemaLocatingHandler.java?rev=820722&view=auto
==============================================================================
--- incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/unit/parsing/SchemaLocatingHandler.java (added)
+++ incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/unit/parsing/SchemaLocatingHandler.java Thu Oct  1 17:19:13 2009
@@ -0,0 +1,100 @@
+/*
+ * (C) Copyright IBM Corp. 2009
+ */
+package com.ibm.osgi.jpa.unit.parsing;
+
+import java.net.URL;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import javax.xml.XMLConstants;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+
+import org.osgi.framework.Bundle;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * This parser provides a quick mechanism for determining the JPA schema level,
+ * and throws an EarlyParserReturn with the Schema to validate with
+ */
+public class SchemaLocatingHandler extends DefaultHandler
+{
+  /** The RFC 143 bundle object */
+  private final Bundle extender;
+  
+  /**
+   * A static cache of schemas in use in the runtime
+   */
+  private static final ConcurrentMap<String, Schema> schemaCache = new ConcurrentHashMap<String, Schema>();
+  
+  /**
+   * Create a new SchemaLocatingHandler
+   * @param bundle The bundle object for the RFC 143 bundle
+   */
+  public SchemaLocatingHandler(Bundle bundle)
+  {
+    extender = bundle;
+  }
+
+  @Override
+  public void startElement(String uri, String localName, String name, Attributes attributes)
+      throws SAXException
+  {
+    
+    Schema s = null;
+    String version = null;
+    if("persistence".equals(name)) {
+      version = attributes.getValue(uri, "version");
+       s = validate(version);
+    }
+    throw new EarlyParserReturn(s, version);
+  }
+  
+  /**
+   * Find the schema for the version of JPA we're using
+   * @param type  The value of the version attribute in the xml
+   * @return
+   * @throws SAXException
+   */
+  private final Schema validate(String type) throws SAXException
+  {
+    Schema toReturn = (type == null)? null : schemaCache.get(type);
+    
+    if(toReturn == null) {
+      toReturn = getSchema(type);
+      if(toReturn != null) schemaCache.putIfAbsent(type, toReturn);
+    }
+    
+    return toReturn;
+  }
+
+  /**
+   * Locate the schema document
+   * @param type The schema version to find
+   * @return
+   * @throws SAXException
+   */
+  private final Schema getSchema(String type) throws SAXException
+  {
+    SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+    URL schemaURL = null;
+    Schema schema = null;
+    if("1.0".equals(type)) {
+      try{
+        schemaURL = new URL("http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd");
+      }catch(Exception e){
+    	//will not occur with fixed url above.
+      }
+    }
+    //TODO handle JPA 2.0
+    if(schemaURL != null){
+      schema = schemaFactory.newSchema(schemaURL);
+    }
+    
+    return schema;
+  }
+  
+}

Added: incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/util/PersistenceBundleHelper.java
URL: http://svn.apache.org/viewvc/incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/util/PersistenceBundleHelper.java?rev=820722&view=auto
==============================================================================
--- incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/util/PersistenceBundleHelper.java (added)
+++ incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/util/PersistenceBundleHelper.java Thu Oct  1 17:19:13 2009
@@ -0,0 +1,122 @@
+/*
+ * (C) Copyright IBM Corp. 2009
+ */
+package com.ibm.osgi.jpa.util;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+
+/**
+ * This helper can be used to locate persistence.xml files in a bundle
+ */
+public class PersistenceBundleHelper
+{
+  /** The persistence xml location */
+  private static final String PERSISTENCE_XML = "META-INF/persistence.xml";
+
+  /**
+   * This method locates persistence xml files in the following
+   * locations:
+   * META-INF
+   * WEB-INF/classes
+   * the META-INF of any jar in WEB-INF/lib
+   * the META-INF of any jar on the Bundle-ClassPath
+   * 
+   * Note that getEntry and getEntryPaths are used to ensure
+   * we do not transition the bundle to RESOLVED
+   * 
+   * @param bundle
+   * @return
+   */
+  public static Collection<PersistenceLocationData> findPersistenceXmlFiles(Bundle bundle)
+  {
+    
+    Collection<PersistenceLocationData> persistenceXmlFiles = new ArrayList<PersistenceLocationData>();
+    
+    addLocationToCollectionIfFound(persistenceXmlFiles, "", bundle);
+    
+    addLocationToCollectionIfFound(persistenceXmlFiles, "WEB-INF/classes", bundle);
+   
+    @SuppressWarnings("unchecked")
+    Enumeration<String> webInfLibJars = bundle.getEntryPaths("WEB-INF/lib");
+    
+    if(webInfLibJars != null) {
+      
+      List<String> paths = Collections.list(webInfLibJars);
+      Iterator<String> it = paths.iterator();
+      
+      while(it.hasNext()){
+        String s = it.next();
+        // We want to process jars in WEB-INF/lib/ so it should end
+        // .jar, and not contain any / separators after character 11
+        if(s.endsWith(".jar") && s.lastIndexOf('/') < 12) {
+          processNestedJar(bundle, persistenceXmlFiles, s);
+        }
+      }
+    }
+    
+    String bundleClassPath = (String) bundle.getHeaders().get(Constants.BUNDLE_CLASSPATH);
+
+    if(bundleClassPath != null) {
+      String[] cpEntries = bundleClassPath.split(",");
+      
+      for (String s : cpEntries) {
+        s = s.trim();
+        if(s.endsWith(".jar")) {
+          processNestedJar(bundle, persistenceXmlFiles, s);
+        }
+      }
+    }
+      return persistenceXmlFiles;
+  }
+
+  /**
+   * Check to see if a nested jar contains a "META-INF/persistence.xml" file
+   * and add it to the list if it does
+   * 
+   * @param bundle
+   * @param persistenceXmlFiles
+   * @param jarLocation
+   */
+  private static void processNestedJar(Bundle bundle,
+      Collection<PersistenceLocationData> persistenceXmlFiles, String jarLocation)
+  {
+    URL jar = bundle.getEntry(jarLocation);
+    if(jar != null) {
+    ClassLoader cl = new URLClassLoader(new URL[] {jar});
+    URL xml = cl.getResource(PERSISTENCE_XML);
+
+    if(xml != null)
+      persistenceXmlFiles.add(new PersistenceLocationData(xml, jar, bundle));
+    }
+  }
+  
+  /**
+   * This method will attempt to find an entry for a given path in a given bundle
+   * and add it to the collection if the entry exists
+   * @param collection
+   * @param rootPath
+   * @param bundle
+   */
+  private static void addLocationToCollectionIfFound(Collection<PersistenceLocationData> collection, String rootPath, Bundle bundle)
+  {
+    rootPath = (rootPath.endsWith("/")) ? rootPath : rootPath + "/";
+    URL root = bundle.getEntry(rootPath);
+    if(root != null) {
+      String xmlPath = rootPath + PERSISTENCE_XML;
+      URL xml = bundle.getEntry(xmlPath);
+      if(xml != null)
+        collection.add(new PersistenceLocationData(xml, root, bundle));
+    }
+  }
+  
+}

Added: incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/util/PersistenceLocationData.java
URL: http://svn.apache.org/viewvc/incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/util/PersistenceLocationData.java?rev=820722&view=auto
==============================================================================
--- incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/util/PersistenceLocationData.java (added)
+++ incubator/aries/contrib/ibm/com.ibm.osgi.jpa.unit.manager/src/com/ibm/osgi/jpa/util/PersistenceLocationData.java Thu Oct  1 17:19:13 2009
@@ -0,0 +1,60 @@
+/*
+ * (C) Copyright IBM Corp. 2009
+ */
+package com.ibm.osgi.jpa.util;
+
+import java.net.URL;
+
+import org.osgi.framework.Bundle;
+
+/**
+ * A bean to hold metadata about the location of a persistence.xml file
+ */
+public class PersistenceLocationData
+{
+  /** The location of the persistence.xml file */
+  private final URL persistenceXML;
+  /** The location of the persistence unit root */
+  private final URL persistenceUnitRoot;
+  /** The persistence Bundle object */
+  private final Bundle persistenceBundle;
+  
+  /**
+   * Construct a new PersistenceLocationData
+   * @param persistenceXML
+   * @param persistenceUnitRoot
+   * @param persistenceBundle
+   */
+  public PersistenceLocationData(URL persistenceXML, URL persistenceUnitRoot,
+      Bundle persistenceBundle)
+  {
+    this.persistenceXML = persistenceXML;
+    this.persistenceUnitRoot = persistenceUnitRoot;
+    this.persistenceBundle = persistenceBundle;
+  }
+  
+  /**
+   * @return A URL to the persistence.xml file
+   */
+  public URL getPersistenceXML()
+  {
+    return persistenceXML;
+  }
+  
+  /**
+   * @return A URL to the persistence unit root
+   */
+  public URL getPersistenceUnitRoot()
+  {
+    return persistenceUnitRoot;
+  }
+  
+  /**
+   * @return The Bundle that defines this persistence unit
+   */
+  public Bundle getPersistenceBundle()
+  {
+    return persistenceBundle;
+  }
+  
+}