Avoid processing incompatible persistence bundles
diff --git a/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/Activator.java b/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/Activator.java
index 6f51d85..afa8df0 100644
--- a/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/Activator.java
+++ b/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/Activator.java
@@ -28,6 +28,7 @@
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
 import org.osgi.framework.hooks.weaving.WeavingHook;
+import org.osgi.framework.wiring.BundleWiring;
 import org.osgi.util.tracker.BundleTracker;
 
 public class Activator implements BundleActivator {
@@ -38,7 +39,7 @@
     public void start(BundleContext context) throws Exception {
         registerWeavingHook(context, TransformerRegistrySingleton.get());
 
-        PersistenceBundleTracker customizer = new PersistenceBundleTracker();
+        PersistenceBundleTracker customizer = new PersistenceBundleTracker(context.getBundle().adapt(BundleWiring.class));
         persistenceBundleManager = new BundleTracker<Bundle>(context, Bundle.STARTING | Bundle.ACTIVE, customizer);
         persistenceBundleManager.open();
     }
diff --git a/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleTracker.java b/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleTracker.java
index 6981256..da694f8 100644
--- a/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleTracker.java
+++ b/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleTracker.java
@@ -22,12 +22,17 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import org.apache.aries.jpa.container.parser.impl.PersistenceUnit;
 import org.apache.aries.jpa.container.parser.impl.PersistenceUnitParser;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleEvent;
+import org.osgi.framework.wiring.BundleCapability;
+import org.osgi.framework.wiring.BundleWire;
+import org.osgi.framework.wiring.BundleWiring;
+import org.osgi.service.jpa.EntityManagerFactoryBuilder;
 import org.osgi.util.tracker.BundleTrackerCustomizer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -37,12 +42,24 @@
  * found a PersistenceProviderTracker is installed that tracks matching providers.
  */
 public class PersistenceBundleTracker implements BundleTrackerCustomizer<Bundle> {
-    private static final Logger LOGGER = LoggerFactory.getLogger(PersistenceBundleTracker.class);
-    private final Map<Bundle, Collection<PersistenceProviderTracker>> trackers;
-    private Map<Integer, String> typeMap;
+	
+	private static final String OSGI_EXTENDER_NS = "osgi.extender";
+	
+	private static final String OSGI_CONTRACT_NS = "osgi.contract";
+	private static final String JAVA_JPA_CONTRACT = "JavaJPA";
 
-    public PersistenceBundleTracker() {
-        trackers = new HashMap<Bundle, Collection<PersistenceProviderTracker>>();
+	private static final String OSGI_PACKAGE_NS = "osgi.wiring.package";
+	private static final String JAVAX_PERSISTENCE_PKG = "javax.persistence";
+	private static final String JPA_SERVICE_PKG = "org.osgi.service.jpa";
+	
+	private static final Logger LOGGER = LoggerFactory.getLogger(PersistenceBundleTracker.class);
+    private final Map<Bundle, Collection<PersistenceProviderTracker>> trackers;
+    private final Map<Integer, String> typeMap;
+    private final BundleWiring wiring;
+
+    public PersistenceBundleTracker(BundleWiring bundleWiring) {
+        wiring = bundleWiring;
+		trackers = new HashMap<Bundle, Collection<PersistenceProviderTracker>>();
         this.typeMap = new HashMap<Integer, String>();
         this.typeMap.put(BundleEvent.INSTALLED, "INSTALLED");
         this.typeMap.put(BundleEvent.LAZY_ACTIVATION, "LAZY_ACTIVATION");
@@ -57,6 +74,21 @@
 
     @Override
     public synchronized Bundle addingBundle(Bundle bundle, BundleEvent event) {
+    	
+    	if(incompatibleExtender(bundle)) {
+    		// We must not process bundles that we aren't compatible with
+    		LOGGER.info("The bundle {} is wired to a different JPA Extender and must be ignored.", 
+    				bundle.getSymbolicName());
+    		return null;
+    	}
+    	
+    	if(incompatibleClassSpace(bundle)) {
+    		// We must not process bundles that we aren't compatible with
+    		LOGGER.warn("The bundle {} does not share a class space with the JPA Extender and must be ignored.", 
+    				bundle.getSymbolicName());
+    		return null;
+    	}
+    	
         if (event != null && event.getType() == BundleEvent.STOPPED) {
             // Avoid starting persistence units in state STOPPED.
             // TODO No idea why we are called at all in this state
@@ -68,7 +100,101 @@
         return bundle;
     }
 
-    @Override
+    private boolean incompatibleExtender(Bundle bundle) {
+    	
+		List<BundleWire> requiredWires = bundle.adapt(BundleWiring.class)
+				.getRequiredWires(OSGI_EXTENDER_NS);
+		
+		for(BundleWire bw : requiredWires) {
+			BundleCapability capability = bw.getCapability();
+			if(EntityManagerFactoryBuilder.JPA_CAPABILITY_NAME.equals(
+					capability.getAttributes().get(OSGI_EXTENDER_NS))) {
+				
+				// If the persistence bundle requires a different revision for the 
+				// JPA extender then we are incompatible, otherwise we are
+				return !capability.getRevision().equals(wiring.getRevision());
+			}
+		}
+		
+		// If there is no requirement then we must assume that it's safe
+		return false;
+	}
+
+    /**
+     * Sufficient Criteria for having/failing class space compatibility - 
+     * <ol>
+     *   <li>Sharing a contract for <code>JavaJPA</code></li>
+     *   <li>Sharing a provider of <code>javax.persistence</code></li>
+     *   <li>Sharing a provider of <code>org.osgi.service.jpa</code></li>
+     * </ol>
+     * 
+     * @param bundle
+     * @return
+     */
+	private boolean incompatibleClassSpace(Bundle bundle) {
+		BundleWiring pbWiring = bundle.adapt(BundleWiring.class);
+		
+		BundleCapability pbContract = getUsedCapability(pbWiring, OSGI_CONTRACT_NS, JAVA_JPA_CONTRACT);
+		
+		if(pbContract != null) {
+			LOGGER.debug("Matching JPA contract for possible persistence bundle {}", bundle.getSymbolicName());
+			
+			BundleCapability implContract = getUsedCapability(pbWiring, OSGI_CONTRACT_NS, JAVA_JPA_CONTRACT);
+			return !pbContract.equals(implContract);
+		}
+		
+		// No contract required by the persistence bundle, try javax.persistence
+		BundleCapability pbJavaxPersistence = getUsedCapability(pbWiring, 
+					OSGI_PACKAGE_NS, JAVAX_PERSISTENCE_PKG);
+			
+		if(pbJavaxPersistence != null) {
+			LOGGER.debug("Matching JPA API package for possible persistence bundle {}", bundle.getSymbolicName());
+			
+			BundleCapability implJavaxPersistence = getUsedCapability(pbWiring, 
+					OSGI_PACKAGE_NS, JAVAX_PERSISTENCE_PKG);
+			return !pbJavaxPersistence.equals(implJavaxPersistence);
+		}
+
+		// No jpa package required by the persistence bundle, try org.osgi.service.jpa
+		BundleCapability pbJpaService = getUsedCapability(pbWiring, 
+				OSGI_PACKAGE_NS, JPA_SERVICE_PKG);
+		
+		if(pbJpaService != null) {
+			LOGGER.debug("Matching JPA service package for possible persistence bundle {}", bundle.getSymbolicName());
+			
+			BundleCapability implJpaService = getUsedCapability(pbWiring, 
+					OSGI_PACKAGE_NS, JPA_SERVICE_PKG);
+			return !pbJpaService.equals(implJpaService);
+		}
+		
+		// If there is nothing to clash on then we must assume that it's safe
+		return false;
+	}
+
+	private BundleCapability getUsedCapability(BundleWiring toCheck, String ns, String attr) {
+		BundleCapability cap = null;
+		
+		for(BundleWire bw : toCheck.getRequiredWires(ns)) {
+			BundleCapability capability = bw.getCapability();
+			if(attr.equals(capability.getAttributes().get(ns))) {
+				cap = capability;
+				break;
+			}
+		}
+		
+		if(cap == null) {
+			for(BundleCapability capability : toCheck.getCapabilities(ns)) {
+				if(attr.equals(capability.getAttributes().get(ns))) {
+					cap = capability;
+					break;
+				}
+			}
+		}
+		
+		return cap;
+	}
+
+	@Override
     public synchronized void removedBundle(Bundle bundle, BundleEvent event, Bundle object) {
         Collection<PersistenceProviderTracker> providerTrackers = trackers.remove(bundle);
         if (providerTrackers == null || providerTrackers.isEmpty()) {