You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by cs...@apache.org on 2015/05/19 11:47:53 UTC

svn commit: r1680218 [4/5] - in /aries/trunk/jpa: ./ examples/ examples/tasklist-blueprint/ examples/tasklist-blueprint/src/ examples/tasklist-blueprint/src/main/ examples/tasklist-blueprint/src/main/java/ examples/tasklist-blueprint/src/main/java/org/...

Added: aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/DSFTracker.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/DSFTracker.java?rev=1680218&view=auto
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/DSFTracker.java (added)
+++ aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/DSFTracker.java Tue May 19 09:47:49 2015
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIESOR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.jpa.container.impl;
+
+import java.sql.SQLException;
+import java.util.Properties;
+
+import javax.persistence.spi.PersistenceProvider;
+import javax.persistence.spi.PersistenceUnitTransactionType;
+import javax.sql.DataSource;
+
+import org.apache.aries.jpa.container.parser.impl.PersistenceUnit;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.jdbc.DataSourceFactory;
+import org.osgi.util.tracker.ServiceTracker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DSFTracker extends ServiceTracker<DataSourceFactory, ManagedEMF>{
+    private static final String JDBC_DRIVER = "javax.persistence.jdbc.driver";
+    private static final String JDBC_URL = "javax.persistence.jdbc.url";
+    private static final String JDBC_USER = "javax.persistence.jdbc.user";
+    private static final String JDBC_PASSWORD = "javax.persistence.jdbc.password";
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(DSFTracker.class);
+
+
+    private PersistenceProvider provider;
+    private PersistenceUnit punit;
+
+    public DSFTracker(BundleContext context, PersistenceProvider provider, PersistenceUnit punit) {
+        super(context, createFilter(context, punit), null);
+        this.provider = provider;
+        this.punit = punit;
+    }
+
+    static Filter createFilter(BundleContext context, PersistenceUnit punit) {
+        String driverName = getDriverName(punit);
+        if (driverName == null) {
+            throw new IllegalArgumentException("No javax.persistence.jdbc.driver supplied in persistence.xml");
+        }
+        String filter = String.format("(&(objectClass=%s)(%s=%s))",
+                                      DataSourceFactory.class.getName(),
+                                      DataSourceFactory.OSGI_JDBC_DRIVER_CLASS,
+                                      driverName);
+        LOGGER.info("Tracking DataSourceFactory for punit " + punit.getPersistenceUnitName() + " with filter " + filter);
+        try {
+            return context.createFilter(filter);
+        } catch (InvalidSyntaxException e) {
+            throw new IllegalArgumentException(e);
+        }
+    }
+
+    public static String getDriverName(PersistenceUnit punit) {
+        return (String)punit.getProperties().get(JDBC_DRIVER);
+    }
+
+    @Override
+    public ManagedEMF addingService(ServiceReference<DataSourceFactory> reference) {
+        LOGGER.info("Found DataSourceFactory for " + punit.getPersistenceUnitName() + " "
+                    + getDriverName(punit));
+        try {
+            DataSourceFactory dsf = context.getService(reference);
+            DataSource ds = createDataSource(dsf);
+            if (punit.getTransactionType() == PersistenceUnitTransactionType.JTA) {
+                punit.setJtaDataSource(ds);
+            } else {
+                punit.setNonJtaDataSource(ds);
+            }
+            BundleContext containerContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext();
+            return new ManagedEMF(containerContext, punit.getBundle(), provider, punit);
+        } catch (Exception e) {
+            LOGGER.error("Error creating DataSource for punit " + punit.getPersistenceUnitName(), e);
+            return null;
+        }
+    }
+
+    private DataSource createDataSource(DataSourceFactory dsf) {
+        try {
+            Properties props = new Properties();
+            put(props, DataSourceFactory.JDBC_URL, punit, JDBC_URL);
+            put(props, DataSourceFactory.JDBC_USER, punit, JDBC_USER);
+            put(props, DataSourceFactory.JDBC_PASSWORD, punit, JDBC_PASSWORD);
+            DataSource ds = dsf.createDataSource(props);
+            return ds;
+        } catch (SQLException e) {
+            throw new RuntimeException("Error creating DataSource for persistence unit " + punit + "."
+                                       + e.getMessage(), e);
+        }
+    }
+
+    private static void put(Properties props, String destKey, PersistenceUnit punit, String sourceKey) {
+        Object value = punit.getProperties().get(sourceKey);
+        if (value != null) {
+            props.put(destKey, value);
+        }
+    }
+
+    @Override
+    public void removedService(ServiceReference<DataSourceFactory> reference, ManagedEMF managedEMF) {
+        LOGGER.info("Lost DataSourceFactory for " + punit.getPersistenceUnitName() + " " + getDriverName(punit));
+        managedEMF.close();
+        super.removedService(reference, managedEMF);
+    }
+}

Added: aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/DataSourceTracker.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/DataSourceTracker.java?rev=1680218&view=auto
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/DataSourceTracker.java (added)
+++ aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/DataSourceTracker.java Tue May 19 09:47:49 2015
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIESOR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.jpa.container.impl;
+
+import static javax.persistence.spi.PersistenceUnitTransactionType.JTA;
+
+import javax.persistence.spi.PersistenceProvider;
+import javax.persistence.spi.PersistenceUnitTransactionType;
+import javax.sql.DataSource;
+
+import org.apache.aries.jpa.container.parser.impl.PersistenceUnit;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DataSourceTracker extends ServiceTracker<DataSource, ManagedEMF>{
+    private static final Logger LOGGER = LoggerFactory.getLogger(DataSourceTracker.class);
+
+    private PersistenceProvider provider;
+    private PersistenceUnit punit;
+
+    static final String DS_PREFIX = "osgi:service/javax.sql.DataSource";
+
+    public DataSourceTracker(BundleContext context, PersistenceProvider provider, PersistenceUnit punit) {
+        super(context, createFilter(context, punit), null);
+        this.provider = provider;
+        this.punit = punit;
+    }
+
+    static Filter createFilter(BundleContext context, PersistenceUnit punit) {
+        String dsName = getDsName(punit);
+        if (dsName == null) {
+            throw new IllegalArgumentException("No DataSource supplied in persistence.xml");
+        }
+        String subFilter = getSubFilter(dsName);
+        String filter = String.format("(&(objectClass=%s)%s)",
+                                      DataSource.class.getName(),
+                                      subFilter);
+        LOGGER.info("Tracking DataSource for punit " + punit.getPersistenceUnitName() + " with filter " + filter);
+        try {
+            return context.createFilter(filter);
+        } catch (InvalidSyntaxException e) {
+            throw new IllegalArgumentException(e);
+        }
+    }
+
+    private static String getSubFilter(String dsName) {
+        if (dsName.startsWith(DS_PREFIX)) {
+            return (dsName.length() > DS_PREFIX.length() +1) 
+                ? dsName.substring(DS_PREFIX.length()+1) 
+                : "(osgi.jndi.service.name=*)"; 
+        } else {
+            return "(osgi.jndi.service.name=" + dsName + ")";
+        }
+    }
+
+    private static String getDsName(PersistenceUnit punit) {
+        return punit.getTransactionType() == JTA ? punit.getJtaDataSourceName() : punit.getNonJtaDataSourceName();
+    }
+
+    @Override
+    public ManagedEMF addingService(ServiceReference<DataSource> reference) {
+        LOGGER.info("Found DataSource for " + punit.getPersistenceUnitName() + " " + getDsName(punit));
+        DataSource ds = context.getService(reference);
+        if (punit.getTransactionType() == PersistenceUnitTransactionType.JTA) {
+            punit.setJtaDataSource(ds);
+        } else {
+            punit.setNonJtaDataSource(ds);
+        }
+        BundleContext containerContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext();
+        return new ManagedEMF(containerContext, punit.getBundle(), provider, punit);
+    }
+
+
+    @Override
+    public void removedService(ServiceReference<DataSource> reference, ManagedEMF managedEMF) {
+        LOGGER.info("Lost DataSource for " + punit.getPersistenceUnitName() + " " + getDsName(punit));
+        managedEMF.close();
+        super.removedService(reference, managedEMF);
+    }
+
+}

Added: aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/ManagedEMF.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/ManagedEMF.java?rev=1680218&view=auto
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/ManagedEMF.java (added)
+++ aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/ManagedEMF.java Tue May 19 09:47:49 2015
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIESOR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.jpa.container.impl;
+
+import static org.osgi.service.jpa.EntityManagerFactoryBuilder.JPA_UNIT_NAME;
+import static org.osgi.service.jpa.EntityManagerFactoryBuilder.JPA_UNIT_PROVIDER;
+import static org.osgi.service.jpa.EntityManagerFactoryBuilder.JPA_UNIT_VERSION;
+
+import java.io.Closeable;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.spi.PersistenceProvider;
+import javax.persistence.spi.PersistenceUnitInfo;
+import javax.persistence.spi.PersistenceUnitTransactionType;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+import org.osgi.service.jpa.EntityManagerFactoryBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Creates an EntityManagerFactory(EMF) for a persistence unit and publishes it as a service.
+ * Custom properties can be configured by supplying a config admin configuriation named like
+ * the JPA_CONFIGURATION_PREFIX.<persistence unit name>.
+ */
+public class ManagedEMF implements Closeable, ManagedService {
+	private static final Logger LOGGER = LoggerFactory.getLogger(ManagedEMF.class);
+
+    private static String JPA_CONFIGURATION_PREFIX = "org.apache.aries.jpa.";
+
+    private EntityManagerFactory emf;
+    private ServiceRegistration<EntityManagerFactory> reg;
+    private ServiceRegistration<EntityManagerFactoryBuilder> regBuilder;
+    private PersistenceProvider provider;
+    private PersistenceUnitInfo persistenceUnit;
+    private Bundle bundle;
+
+    public ManagedEMF(BundleContext containerContext, Bundle bundle, PersistenceProvider provider, PersistenceUnitInfo persistenceUnit) {
+        this.provider = provider;
+        this.persistenceUnit = persistenceUnit;
+        this.bundle = bundle;
+
+        Dictionary<String, Object> configuration = new Hashtable<String, Object>();
+        configuration.put(Constants.SERVICE_PID,
+                          JPA_CONFIGURATION_PREFIX + persistenceUnit.getPersistenceUnitName());
+        containerContext.registerService(ManagedService.class.getName(), this, configuration);
+    }
+
+    public void close() {
+        try {
+            reg.unregister();
+        } catch (Exception e) {
+            // Ignore. May happen if persistence unit bundle is unloaded/updated
+        }
+        try {
+            regBuilder.unregister();
+        } catch (Exception e) {
+            // Ignore. May happen if persistence unit bundle is unloaded/updated
+        }
+        if (emf != null) {
+            try {
+                emf.close();
+            } catch (Exception e) {
+                LOGGER.warn("EntityManagerFactory for " + persistenceUnit.getPersistenceUnitName() + " already close", e);
+            }
+        }
+        reg = null;
+        emf = null;
+    }
+
+    @Override
+    public void updated(Dictionary<String, ?> properties) throws ConfigurationException {
+        if (emf != null) {
+            close();
+        }
+        Map<String, Object> overrides = (properties != null) ? asMap(properties) : null;
+        LOGGER.info("Registering EntityManagerFactory for persistence unit " + persistenceUnit.getPersistenceUnitName());
+        if (LOGGER.isDebugEnabled()) {
+           LOGGER.debug("Using properties override " + overrides); 
+        }
+        emf = provider.createContainerEntityManagerFactory(persistenceUnit, overrides);
+        Dictionary<String, String> props = createProperties(persistenceUnit, bundle);
+        BundleContext uctx = bundle.getBundleContext();
+        reg = uctx.registerService(EntityManagerFactory.class, emf, props);
+    }
+
+    public static Dictionary<String, String> createProperties(PersistenceUnitInfo persistenceUnit, Bundle puBundle) {
+        Dictionary<String, String> props = new Hashtable<>();
+        props.put(JPA_UNIT_NAME, persistenceUnit.getPersistenceUnitName());
+        if (persistenceUnit.getPersistenceProviderClassName() != null) {
+            props.put(JPA_UNIT_PROVIDER, persistenceUnit.getPersistenceProviderClassName());
+        }
+        props.put(JPA_UNIT_VERSION, puBundle.getVersion().toString());
+        return props;
+    }
+
+    private Map<String, Object> asMap(Dictionary<String, ?> dict) {
+        Map<String, Object> map = new HashMap<String, Object>();
+        map.put(PersistenceUnitTransactionType.class.getName(), persistenceUnit.getTransactionType());
+        for (Enumeration<String> e = dict.keys(); e.hasMoreElements();) {
+            String key = e.nextElement();
+            map.put(key, dict.get(key));
+        }
+        return map;
+    }
+
+}

Added: aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleTracker.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleTracker.java?rev=1680218&view=auto
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleTracker.java (added)
+++ aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleTracker.java Tue May 19 09:47:49 2015
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIESOR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.aries.jpa.container.impl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+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.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.packageadmin.PackageAdmin;
+import org.osgi.util.tracker.BundleTrackerCustomizer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Looks for bundles containing a persistence.xml. For each persistence unit
+ * found a PersistenceProviderTracker is installed that tracks matching providers.
+ */
+@SuppressWarnings("deprecation")
+public class PersistenceBundleTracker implements BundleTrackerCustomizer<Bundle> {
+    private static final Logger LOGGER = LoggerFactory.getLogger(PersistenceBundleTracker.class);
+    Map<Bundle, Collection<PersistenceProviderTracker>> trackers;
+    private BundleContext context;
+
+    public PersistenceBundleTracker(BundleContext context) {
+        this.context = context;
+        trackers = new HashMap<Bundle, Collection<PersistenceProviderTracker>>();
+    }
+
+    public Bundle addingBundle(Bundle bundle, BundleEvent event) {
+        if (getTrackers(bundle).size() == 0) {
+            findPersistenceUnits(bundle);
+        }
+        return bundle;
+    }
+
+    public void removedBundle(Bundle bundle, BundleEvent event, Bundle object) {
+        Collection<PersistenceProviderTracker> providerTrackers = trackers.get(bundle);
+        if (providerTrackers != null) {
+            if (providerTrackers.size() > 0)  {
+                LOGGER.info("removing persistence units for " + bundle.getSymbolicName() + " " + getType(event));
+            }
+            for (PersistenceProviderTracker providerTracker : providerTrackers) {
+                providerTracker.close();
+            }
+            providerTrackers.clear();
+            trackers.remove(bundle);
+        }
+    }
+
+    private void findPersistenceUnits(Bundle bundle) {
+        ServiceReference<PackageAdmin> ref = context.getServiceReference(PackageAdmin.class);
+        PackageAdmin packageAdmin = context.getService(ref);
+        for (PersistenceUnit punit : PersistenceUnitParser.getPersistenceUnits(bundle)) {
+            punit.addAnnotated(packageAdmin);
+            trackProvider(bundle, punit);
+        }
+        context.ungetService(ref);
+    }
+
+    private void trackProvider(Bundle bundle, 
+                               PersistenceUnit punit) {
+        LOGGER.info(String.format("Found persistence unit %s in bundle %s with provider %s.",
+                                  punit.getPersistenceUnitName(), bundle.getSymbolicName(),
+                                  punit.getPersistenceProviderClassName()));
+        PersistenceProviderTracker tracker = new PersistenceProviderTracker(context, punit);
+        tracker.open();
+        getTrackers(bundle).add(tracker);
+    }
+
+    @Override
+    public void modifiedBundle(Bundle bundle, BundleEvent event, Bundle object) {
+    }
+
+    private static String getType(BundleEvent event) {
+        if (event == null) {
+            return "null";
+        }
+        int type = event.getType();
+        switch (type) {
+        case BundleEvent.INSTALLED:
+            return "INSTALLED";
+        case BundleEvent.LAZY_ACTIVATION:
+            return "LAZY_ACTIVATION";
+        case BundleEvent.RESOLVED:
+            return "RESOLVED";
+        case BundleEvent.STARTED:
+            return "STARTED";
+        case BundleEvent.STARTING:
+            return "Starting";
+        case BundleEvent.STOPPED:
+            return "STOPPED";
+        case BundleEvent.UNINSTALLED:
+            return "UNINSTALLED";
+        case BundleEvent.UNRESOLVED:
+            return "UNRESOLVED";
+        case BundleEvent.UPDATED:
+            return "UPDATED";
+        default:
+            return "unknown event type: " + type;
+        }
+    }
+    
+    private Collection<PersistenceProviderTracker> getTrackers(Bundle bundle) {
+        Collection<PersistenceProviderTracker> providerTrackers = trackers.get(bundle);
+        if (providerTrackers == null) {
+            providerTrackers = new ArrayList<>();
+            trackers.put(bundle, providerTrackers);
+        }
+        return providerTrackers;
+    }
+
+}

Added: aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceProviderTracker.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceProviderTracker.java?rev=1680218&view=auto
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceProviderTracker.java (added)
+++ aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceProviderTracker.java Tue May 19 09:47:49 2015
@@ -0,0 +1,156 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIESOR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.jpa.container.impl;
+
+import java.util.Dictionary;
+
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.spi.PersistenceProvider;
+import javax.sql.DataSource;
+
+import org.apache.aries.jpa.container.parser.impl.PersistenceUnit;
+import org.apache.aries.jpa.container.weaving.impl.DummyDataSource;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.jpa.EntityManagerFactoryBuilder;
+import org.osgi.util.tracker.ServiceTracker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Tracks matching persistence providers for a persistence unit.
+ * If a provider is found:
+ * - an EntityManagerFactoryBuilder is installed
+ * - A DataSourceTracker is installed if the JtaDataSource refers to an OSGi service 
+ */
+public class PersistenceProviderTracker extends ServiceTracker<PersistenceProvider, StoredPerProvider> {
+    private static final String JAVAX_PERSISTENCE_PROVIDER = "javax.persistence.provider";
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(PersistenceProviderTracker.class);
+
+    private PersistenceUnit punit;
+
+    public PersistenceProviderTracker(BundleContext context, PersistenceUnit punit) {
+        super(context, createFilter(context, punit), null);
+        this.punit = punit;
+    }
+
+    private static Filter createFilter(BundleContext context, PersistenceUnit punit) {
+        String filter = null;
+        if (punit.getPersistenceProviderClassName() != null) {
+            filter = String.format("(&(objectClass=%s)(%s=%s))",
+                                   PersistenceProvider.class.getName(),
+                                   JAVAX_PERSISTENCE_PROVIDER,
+                                   punit.getPersistenceProviderClassName());
+        } else {
+            filter = String.format("(objectClass=%s)", PersistenceProvider.class.getName());
+        }
+
+        try {
+            return context.createFilter(filter);
+        } catch (InvalidSyntaxException e) {
+            throw new IllegalArgumentException(e);
+        }
+    }
+
+    @Override
+    public StoredPerProvider addingService(ServiceReference<PersistenceProvider> reference) {
+        String providerName = (String)reference.getProperty(JAVAX_PERSISTENCE_PROVIDER);
+        // FIXME should be set when creating the EMF was successful
+        if (punit.getPersistenceProviderClassName() == null) {
+            punit.setProviderClassName(providerName);
+        }
+        StoredPerProvider stored = new StoredPerProvider();
+        LOGGER.info("Found provider for " + punit.getPersistenceUnitName() + " " + punit.getPersistenceProviderClassName());
+        PersistenceProvider provider = context.getService(reference);
+
+        createAndCloseDummyEMF(provider);
+
+        stored.dsTracker = createDataSourceTracker(stored, provider, providerName);
+        EntityManagerFactoryBuilder emfBuilder = new AriesEntityManagerFactoryBuilder(provider, punit);
+        Dictionary<String, ?> props = ManagedEMF.createProperties(punit, punit.getBundle());
+        stored.reg = context.registerService(EntityManagerFactoryBuilder.class, emfBuilder , props);
+        return stored;
+    }
+
+    /**
+     * Create and close a dummy EMF to give the PersistenceProvider a chance to call
+     * punit.addTransformer(). This has to occur as early as possible as weaving needs
+     * to be done before the first entity class is loaded. So we can not wait till the
+     * real DataSource is found.
+     */
+    private void createAndCloseDummyEMF(PersistenceProvider provider) {
+        DataSource dummyDataSource = new DummyDataSource();
+        punit.setJtaDataSource(dummyDataSource);
+        punit.setNonJtaDataSource(dummyDataSource);
+        try {
+            EntityManagerFactory emf = provider.createContainerEntityManagerFactory(punit, null);
+            emf.close();
+        } catch (Exception e) {
+            LOGGER.warn(e.getMessage(), e);
+        }
+        punit.setJtaDataSource(null);
+        punit.setNonJtaDataSource(null);
+    }
+
+    private ServiceTracker<?, ?> createDataSourceTracker(StoredPerProvider stored, PersistenceProvider provider, String providerName) {
+        if (usesDataSource()) {
+            if (!usesDataSourceService()) {
+                LOGGER.warn("Persistence unit " + punit.getPersistenceUnitName() + " refers to a non OSGi service DataSource");
+                return null;
+            }
+            DataSourceTracker dsTracker = new DataSourceTracker(context, provider, punit);
+            dsTracker.open();
+            return dsTracker;
+        } else if (usesDSF()) {
+            DSFTracker dsfTracker = new DSFTracker(context, provider, punit);
+            dsfTracker.open();
+            return dsfTracker;
+        } else {
+            LOGGER.debug("Persistence unit " + punit.getPersistenceUnitName() + " does not refer a DataSource. "
+                         +"It can only be used with EntityManagerFactoryBuilder.");
+            return null;
+        }
+    }
+
+    private boolean usesDataSource() {
+        return punit.getJtaDataSourceName() != null || punit.getNonJtaDataSourceName() != null;
+    }
+
+    private boolean usesDSF() {
+        return DSFTracker.getDriverName(punit) != null;
+    }
+
+    private boolean usesDataSourceService() {
+        return punit.getJtaDataSourceName() != null && punit.getJtaDataSourceName().startsWith(DataSourceTracker.DS_PREFIX)
+            || punit.getNonJtaDataSourceName() != null && punit.getNonJtaDataSourceName().startsWith(DataSourceTracker.DS_PREFIX);
+    }
+
+    @Override
+    public void removedService(ServiceReference<PersistenceProvider> reference, StoredPerProvider stored) {
+        LOGGER.info("Lost provider for " + punit.getPersistenceUnitName() + " " + punit.getPersistenceProviderClassName());
+        if (stored.dsTracker != null) {
+            stored.dsTracker.close();
+        }
+        stored.reg.unregister();
+        super.removedService(reference, stored);
+    }
+}

Copied: aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/StoredPerProvider.java (from r1680054, aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/InvalidPersistenceUnitException.java)
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/StoredPerProvider.java?p2=aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/StoredPerProvider.java&p1=aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/InvalidPersistenceUnitException.java&r1=1680054&r2=1680218&rev=1680218&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/InvalidPersistenceUnitException.java (original)
+++ aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/StoredPerProvider.java Tue May 19 09:47:49 2015
@@ -18,22 +18,11 @@
  */
 package org.apache.aries.jpa.container.impl;
 
-/**
- * This exception is thrown if an {@link EntityManagerFactoryManager} has
- * entered an invalid state and needs to be destroyed
- */
-public class InvalidPersistenceUnitException extends Exception {
-
-  /**
-   * For serialization
-   */
-  private static final long serialVersionUID = 6523462131213055375L;
-
-  public InvalidPersistenceUnitException(Exception e) {
-    super(e);
-  }
-
-  public InvalidPersistenceUnitException() {
-  }
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.jpa.EntityManagerFactoryBuilder;
+import org.osgi.util.tracker.ServiceTracker;
 
-}
+public class StoredPerProvider {
+    ServiceTracker<?, ?> dsTracker;
+    ServiceRegistration<EntityManagerFactoryBuilder> reg;
+}
\ No newline at end of file

Added: aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/parser/impl/JPAAnnotationScanner.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/parser/impl/JPAAnnotationScanner.java?rev=1680218&view=auto
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/parser/impl/JPAAnnotationScanner.java (added)
+++ aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/parser/impl/JPAAnnotationScanner.java Tue May 19 09:47:49 2015
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIESOR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.jpa.container.parser.impl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import javax.persistence.Embeddable;
+import javax.persistence.Entity;
+import javax.persistence.MappedSuperclass;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.wiring.BundleWiring;
+
+@SuppressWarnings("deprecation")
+class JPAAnnotationScanner {
+    public static Collection<String> findJPAAnnotatedClasses(Bundle b) {
+        BundleWiring bw = b.adapt(BundleWiring.class);
+        Collection<String> resources = bw.listResources("/", "*.class", 
+            BundleWiring.LISTRESOURCES_LOCAL | BundleWiring.LISTRESOURCES_RECURSE);
+        
+        Collection<String> classes = new ArrayList<String>(); 
+        ClassLoader cl = new TempBundleDelegatingClassLoader(b, JPAAnnotationScanner.class.getClassLoader());
+        for(String s : resources) {
+          s = s.replace('/', '.').substring(0, s.length() - 6);
+          try {
+            Class<?> clazz = Class.forName(s, false, cl);
+            
+            if(clazz.isAnnotationPresent(Entity.class) ||
+               clazz.isAnnotationPresent(MappedSuperclass.class) ||
+               clazz.isAnnotationPresent(Embeddable.class)) {
+              classes.add(s);
+            }
+            
+          } catch (ClassNotFoundException cnfe) {
+            
+          } catch (NoClassDefFoundError ncdfe) {
+            
+          }
+        }
+        return classes;
+      }
+}

Added: aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/parser/impl/JPAAnnotationScannerXbean.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/parser/impl/JPAAnnotationScannerXbean.java?rev=1680218&view=auto
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/parser/impl/JPAAnnotationScannerXbean.java (added)
+++ aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/parser/impl/JPAAnnotationScannerXbean.java Tue May 19 09:47:49 2015
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIESOR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.jpa.container.parser.impl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.persistence.Embeddable;
+import javax.persistence.Entity;
+import javax.persistence.MappedSuperclass;
+
+import org.apache.xbean.finder.Annotated;
+import org.apache.xbean.finder.BundleAnnotationFinder;
+import org.osgi.framework.Bundle;
+import org.osgi.service.packageadmin.PackageAdmin;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@SuppressWarnings("deprecation")
+class JPAAnnotationScannerXbean {
+    private static Logger LOGGER = LoggerFactory.getLogger(JPAAnnotationScannerXbean.class);
+
+    public static Collection<String> findJPAAnnotatedClasses(Bundle bundle, PackageAdmin packageAdmin) {
+        Collection<String> classes = new ArrayList<String>();
+        try {
+            BundleAnnotationFinder finder = new BundleAnnotationFinder(packageAdmin, bundle);
+            Set<Annotated<Class<?>>> annotatedSet = new HashSet<Annotated<Class<?>>>();
+            annotatedSet.addAll(finder.findMetaAnnotatedClasses(Entity.class));
+            annotatedSet.addAll(finder.findMetaAnnotatedClasses(MappedSuperclass.class));
+            annotatedSet.addAll(finder.findMetaAnnotatedClasses(Embeddable.class));
+            LOGGER.info("Searching for entities");
+            for (Annotated<Class<?>> annotated : annotatedSet) {
+                LOGGER.info("Found entity " + annotated.get().getName());
+                classes.add(annotated.get().getName());
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return classes;
+    }
+
+}
\ No newline at end of file

Added: aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/parser/impl/JPAHandler.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/parser/impl/JPAHandler.java?rev=1680218&view=auto
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/parser/impl/JPAHandler.java (added)
+++ aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/parser/impl/JPAHandler.java Tue May 19 09:47:49 2015
@@ -0,0 +1,127 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIESOR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.jpa.container.parser.impl;
+
+import java.util.Collection;
+import java.util.Stack;
+
+import javax.persistence.SharedCacheMode;
+import javax.persistence.ValidationMode;
+import javax.persistence.spi.PersistenceUnitTransactionType;
+
+import org.osgi.framework.Bundle;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * 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<PersistenceUnit> persistenceUnits = new Stack<PersistenceUnit>();
+    /** The name of the current element */
+    private String elementName;
+    /** The version of the persistence.xml file */
+    /** A StringBuilder for caching the information from getCharacters */
+    private StringBuilder builder = new StringBuilder();
+    /** The bundle that contains this persistence descriptor */
+    private Bundle bundle;
+
+    /**
+     * Create a new JPA Handler for a bundle
+     * 
+     * @param bundle
+     */
+    public JPAHandler(Bundle bundle) {
+        this.bundle = bundle;
+    }
+
+    /**
+     * 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)) {
+            String tranTypeSt = attributes.getValue("transaction-type");
+            PersistenceUnitTransactionType tranType = tranTypeSt == null ? null : PersistenceUnitTransactionType.valueOf(tranTypeSt);
+            persistenceUnits.push(new PersistenceUnit(bundle, 
+                                                      attributes.getValue("name"), 
+                                                      tranType));
+        } 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;
+
+        PersistenceUnit pu = persistenceUnits.peek();
+
+        if ("provider".equals(elementName))
+            pu.setProviderClassName(s);
+        else if ("jta-data-source".equals(elementName))
+            pu.setJtaDataSourceName(s);
+        else if ("non-jta-data-source".equals(elementName))
+            pu.setNonJtaDataSourceName(s);
+        else if ("class".equals(elementName))
+            pu.addClassName(s);
+        else if ("exclude-unlisted-classes".equals(elementName))
+            pu.setExcludeUnlisted(Boolean.parseBoolean(s));
+        else if ("shared-cache-mode".equals(elementName))
+            pu.setSharedCacheMode(SharedCacheMode.valueOf(s));
+          else if ("validation-mode".equals(elementName))
+            pu.setValidationMode(ValidationMode.valueOf(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<PersistenceUnit> getPersistenceUnits() {
+        return persistenceUnits;
+    }
+
+}

Added: aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/parser/impl/PersistenceUnit.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/parser/impl/PersistenceUnit.java?rev=1680218&view=auto
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/parser/impl/PersistenceUnit.java (added)
+++ aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/parser/impl/PersistenceUnit.java Tue May 19 09:47:49 2015
@@ -0,0 +1,229 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIESOR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.jpa.container.parser.impl;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.persistence.SharedCacheMode;
+import javax.persistence.ValidationMode;
+import javax.persistence.spi.ClassTransformer;
+import javax.persistence.spi.PersistenceUnitInfo;
+import javax.persistence.spi.PersistenceUnitTransactionType;
+import javax.sql.DataSource;
+
+import org.apache.aries.jpa.container.weaving.impl.TransformerRegistry;
+import org.apache.aries.jpa.container.weaving.impl.TransformerRegistrySingleton;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.wiring.BundleWiring;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+public class PersistenceUnit implements PersistenceUnitInfo {
+
+    private Bundle bundle;
+    private ClassLoader classLoader;
+    private Set<String> classNames;
+    private boolean excludeUnlisted;
+    private DataSource jtaDataSource;
+    private String jtaDataSourceName;
+    private DataSource nonJtaDataSource;
+    private String nonJtaDataSourceName;
+    private String persistenceProviderClassName;
+    private String persistenceUnitName;
+    private String persistenceXMLSchemaVersion;
+    private Properties props;
+    private SharedCacheMode sharedCacheMode = SharedCacheMode.UNSPECIFIED;
+    private PersistenceUnitTransactionType transactionType;
+    private ValidationMode validationMode = ValidationMode.NONE;
+
+    public PersistenceUnit(Bundle bundle, String persistenceUnitName,
+                           PersistenceUnitTransactionType transactionType) {
+        this.bundle = bundle;
+        this.persistenceUnitName = persistenceUnitName;
+        this.transactionType = transactionType;
+        this.props = new Properties();
+        this.classLoader = bundle.adapt(BundleWiring.class).getClassLoader();
+        this.classNames = new HashSet<>();
+    }
+
+    public void addClassName(String className) {
+        this.classNames.add(className);
+    }
+
+    public void addProperty(String name, String value) {
+        props.put(name, value);
+    }
+
+    @Override
+    public void addTransformer(ClassTransformer transformer) {
+        TransformerRegistry reg = TransformerRegistrySingleton.get();
+        reg.addTransformer(bundle, transformer);
+    }
+
+    @Override
+    public boolean excludeUnlistedClasses() {
+        return this.excludeUnlisted;
+    }
+
+    public Bundle getBundle() {
+        return bundle;
+    }
+
+    @Override
+    public ClassLoader getClassLoader() {
+        return this.classLoader;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public List<URL> getJarFileUrls() {
+        return Collections.EMPTY_LIST;
+    }
+
+    @Override
+    public DataSource getJtaDataSource() {
+        return this.jtaDataSource;
+    }
+
+    public String getJtaDataSourceName() {
+        return jtaDataSourceName;
+    }
+
+    @Override
+    public List<String> getManagedClassNames() {
+        ArrayList<String> names = new ArrayList<>();
+        names.addAll(classNames);
+        return names;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public List<String> getMappingFileNames() {
+        return Collections.EMPTY_LIST;
+    }
+
+    public String getName() {
+        return persistenceUnitName;
+    }
+
+    @Override
+    public ClassLoader getNewTempClassLoader() {
+        return new TempBundleDelegatingClassLoader(bundle, classLoader);
+    }
+
+    @Override
+    public DataSource getNonJtaDataSource() {
+        return this.nonJtaDataSource;
+    }
+
+    public String getNonJtaDataSourceName() {
+        return nonJtaDataSourceName;
+    }
+
+    @Override
+    public String getPersistenceProviderClassName() {
+        return this.persistenceProviderClassName;
+    }
+
+    @Override
+    public String getPersistenceUnitName() {
+        return this.persistenceUnitName;
+    }
+
+    @Override
+    public URL getPersistenceUnitRootUrl() {
+        return bundle.getResource("/");
+    }
+
+    @Override
+    public String getPersistenceXMLSchemaVersion() {
+        return this.persistenceXMLSchemaVersion;
+    }
+
+    @Override
+    public Properties getProperties() {
+        return this.props;
+    }
+
+    @Override
+    public SharedCacheMode getSharedCacheMode() {
+        return this.sharedCacheMode;
+    }
+
+    @Override
+    public PersistenceUnitTransactionType getTransactionType() {
+        return transactionType;
+    }
+
+    @Override
+    public ValidationMode getValidationMode() {
+        return this.validationMode;
+    }
+
+    public boolean isExcludeUnlisted() {
+        return excludeUnlisted;
+    }
+
+    public void setExcludeUnlisted(boolean excludeUnlisted) {
+        this.excludeUnlisted = excludeUnlisted;
+    }
+
+    public void setJtaDataSource(DataSource jtaDataSource) {
+        this.jtaDataSource = jtaDataSource;
+    }
+
+    public void setJtaDataSourceName(String jtaDataSourceName) {
+        this.jtaDataSourceName = jtaDataSourceName;
+    }
+
+    public void setNonJtaDataSource(DataSource nonJtaDataSource) {
+        this.nonJtaDataSource = nonJtaDataSource;
+    }
+
+    public void setNonJtaDataSourceName(String nonJtaDataSourceName) {
+        this.nonJtaDataSourceName = nonJtaDataSourceName;
+    }
+
+    public void setProviderClassName(String providerClassName) {
+        this.persistenceProviderClassName = providerClassName;
+    }
+
+    public void setSharedCacheMode(SharedCacheMode sharedCacheMode) {
+        this.sharedCacheMode = sharedCacheMode;
+    }
+
+    public void setValidationMode(ValidationMode validationMode) {
+        this.validationMode = validationMode;
+    }
+
+    public void addAnnotated(PackageAdmin packageAdmin) {
+        if (!excludeUnlistedClasses()) {
+            Collection<String> detected = JPAAnnotationScanner.findJPAAnnotatedClasses(bundle);
+            for (String name : detected) {
+                addClassName(name);
+            }
+        }
+    }
+}

Added: aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/parser/impl/PersistenceUnitParser.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/parser/impl/PersistenceUnitParser.java?rev=1680218&view=auto
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/parser/impl/PersistenceUnitParser.java (added)
+++ aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/parser/impl/PersistenceUnitParser.java Tue May 19 09:47:49 2015
@@ -0,0 +1,187 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.jpa.container.parser.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+
+import javax.persistence.spi.PersistenceUnitTransactionType;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.osgi.framework.Bundle;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This helper can be used to locate persistence.xml files in a bundle
+ */
+public class PersistenceUnitParser {
+    private static final String DEFAULT_PERSISTENCE_LOCATION = "META-INF/persistence.xml";
+    private static final Logger _logger = LoggerFactory.getLogger("org.apache.aries.jpa.container");
+    public static final String PERSISTENCE_UNIT_HEADER = "Meta-Persistence";
+
+    /**
+     * This method locates persistence descriptor files based on a combination of the default location
+     * "META-INF/persistence.xml" and the Meta-Persistence header. Note that getEntry is used to ensure we do
+     * not alter the state of the bundle Note also that web application bundles will never return persistence
+     * descriptors
+     * @param context 
+     * 
+     * @param bundle The bundle to search
+     * @param packageAdmin 
+     * @return
+     */
+    public static Collection<PersistenceUnit> getPersistenceUnits(Bundle bundle) {
+        Collection<PersistenceUnit> punits = new ArrayList<PersistenceUnit>();
+        Dictionary<String, String> headers = bundle.getHeaders();
+        String metaPersistence = headers.get(PERSISTENCE_UNIT_HEADER);
+
+        Set<String> locations = new HashSet<String>();
+        if (metaPersistence == null) {
+            return punits;
+        }
+
+        if (!metaPersistence.isEmpty()) {
+            // Split apart the header to get the individual entries
+            for (String s : metaPersistence.split(",")) {
+                locations.add(s.trim());
+            }
+        }
+        
+        if (!locations.contains(DEFAULT_PERSISTENCE_LOCATION)) {
+            locations.add(DEFAULT_PERSISTENCE_LOCATION);
+        }
+
+        // Find the file and add it to our list
+        for (String location : locations) {
+            try {
+                InputStream is = locateFile(bundle, location);
+                if (is != null) {
+                    parse(bundle, location, is, punits);
+                }
+            } catch (Exception e) {
+                _logger.error("exception.while.locating.descriptor", e);
+                return Collections.emptySet();
+            }
+        }
+        
+        return punits;
+    }
+
+    private static void parse(Bundle bundle, String location, InputStream is, Collection<PersistenceUnit> punits) {
+        SAXParserFactory parserFactory = SAXParserFactory.newInstance();
+        try {
+            SAXParser parser = parserFactory.newSAXParser();
+            JPAHandler handler = new JPAHandler(bundle);
+            parser.parse(is, handler);
+            punits.addAll(handler.getPersistenceUnits());
+//            for (PersistenceUnit punit : punits) {
+                //validate(punit);
+//            }
+        } catch (Exception e) {
+            throw new RuntimeException("persistence.description.parse.error", e);
+        } finally {
+            safeClose(is);
+        }
+    }
+
+    private static void validate(PersistenceUnit punit) {
+        if (punit.getTransactionType() == null) {
+            throw new IllegalArgumentException("No transaction type specified for persistence unit " + punit.getName());
+        }
+        if (punit.getTransactionType() == PersistenceUnitTransactionType.JTA) {
+            if (punit.getJtaDataSourceName() == null) {
+                throw new IllegalArgumentException("Must specify jta-data-source for persistence unit " + punit.getName());
+            }
+        }
+        if (punit.getTransactionType() == PersistenceUnitTransactionType.RESOURCE_LOCAL) {
+            if (punit.getNonJtaDataSourceName() == null) {
+                throw new IllegalArgumentException("Must specify non-jta-data-source for persistence unit " + punit.getName());
+            }
+        }
+    }
+
+    private static void safeClose(InputStream is) {
+        if (is != null) {
+            try {
+                is.close();
+            } catch (IOException e) {
+                // No logging necessary, just consume
+            }
+        }
+    }
+
+    /**
+     * Locate a persistence descriptor file in a bundle based on a String name.
+     * 
+     * @param bundle
+     * @param persistenceXmlFiles
+     * @param jarLocation
+     * @throws IOException
+     */
+    private static InputStream locateFile(Bundle bundle, String location) throws IOException {
+        // There is nothing for an empty location
+        InputStream is = null;
+        if ("".equals(location)) {
+            return null;
+        }
+
+        // If there is a '!' then we have to look in a jar
+        int bangIndex = location.indexOf('!');
+        // No '!', getEntry will do
+        if (bangIndex == -1) {
+            URL url = bundle.getEntry(location);
+
+            if (url != null)
+                is = url.openStream();
+
+        } else {
+            // There was a '!', find the jar
+            URL url = bundle.getEntry(location.substring(0, bangIndex));
+
+            if (url != null) {
+                // Remember to trim off the "!/"
+                String toLocate = location.substring(bangIndex + 2);
+
+                @SuppressWarnings("resource")
+                JarInputStream jis = new JarInputStream(url.openStream());
+                JarEntry entry = jis.getNextJarEntry();
+
+                while (entry != null) {
+                    if (entry.getName().equals(toLocate)) {
+                        is = jis;
+                        break;
+                    }
+                    entry = jis.getNextJarEntry();
+                }
+            }
+        }
+        return is;
+    }
+}

Copied: aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/parser/impl/TempBundleDelegatingClassLoader.java (from r1680054, aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/TempBundleDelegatingClassLoader.java)
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/parser/impl/TempBundleDelegatingClassLoader.java?p2=aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/parser/impl/TempBundleDelegatingClassLoader.java&p1=aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/TempBundleDelegatingClassLoader.java&r1=1680054&r2=1680218&rev=1680218&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/TempBundleDelegatingClassLoader.java (original)
+++ aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/parser/impl/TempBundleDelegatingClassLoader.java Tue May 19 09:47:49 2015
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.aries.jpa.container.unit.impl;
+package org.apache.aries.jpa.container.parser.impl;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;

Added: aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/weaving/impl/DummyDataSource.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/weaving/impl/DummyDataSource.java?rev=1680218&view=auto
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/weaving/impl/DummyDataSource.java (added)
+++ aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/weaving/impl/DummyDataSource.java Tue May 19 09:47:49 2015
@@ -0,0 +1,97 @@
+package org.apache.aries.jpa.container.weaving.impl;
+
+import java.io.PrintWriter;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+
+import javax.sql.DataSource;
+
+/**
+ * DummyDataSource to be able to create the EMF before DataSource is ready
+ */
+public final class DummyDataSource implements DataSource {
+    
+    /**
+     * Simply tries to avoid that calling code runs into NPE
+     */
+    private final class DummyHandler implements InvocationHandler {
+        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+            ClassLoader classLoader = this.getClass().getClassLoader();
+            if (method.getReturnType() == DatabaseMetaData.class) {
+                Class<?>[] ifAr = new Class[] {
+                    DatabaseMetaData.class
+                };
+                return Proxy.newProxyInstance(classLoader, ifAr, this);
+            }
+            if (method.getReturnType() == int.class) {
+                return new Integer(0);
+            }
+            if (method.getReturnType() == boolean.class) {
+                return new Boolean(false);
+            }
+            if (method.getReturnType() == String.class) {
+                return "";
+            }
+            if (method.getReturnType() == ResultSet.class) {
+                Class<?>[] ifAr = new Class[] {
+                    ResultSet.class
+                };
+                return Proxy.newProxyInstance(classLoader, ifAr, this);
+            }
+            return null;
+        }
+    }
+    
+    @Override
+    public <T> T unwrap(Class<T> iface) throws SQLException {
+        return null;
+    }
+
+    @Override
+    public boolean isWrapperFor(Class<?> iface) throws SQLException {
+        return false;
+    }
+
+    @Override
+    public void setLoginTimeout(int seconds) throws SQLException {
+    }
+
+    @Override
+    public void setLogWriter(PrintWriter out) throws SQLException {
+    }
+
+    @Override
+    public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException {
+        return null;
+    }
+
+    @Override
+    public int getLoginTimeout() throws SQLException {
+        return 0;
+    }
+
+    @Override
+    public PrintWriter getLogWriter() throws SQLException {
+        return null;
+    }
+
+    @Override
+    public Connection getConnection(String username, String password) throws SQLException {
+        InvocationHandler handler = new DummyHandler();
+        ClassLoader classLoader = this.getClass().getClassLoader();
+        return (Connection)Proxy.newProxyInstance(classLoader, new Class[] {
+            Connection.class
+        }, handler);
+    }
+
+    @Override
+    public Connection getConnection() throws SQLException {
+        return getConnection(null, null);
+    }
+}

Modified: aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/weaving/impl/JPAWeavingHook.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/weaving/impl/JPAWeavingHook.java?rev=1680218&r1=1680217&r2=1680218&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/weaving/impl/JPAWeavingHook.java (original)
+++ aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/weaving/impl/JPAWeavingHook.java Tue May 19 09:47:49 2015
@@ -20,112 +20,115 @@ package org.apache.aries.jpa.container.w
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.LinkedHashSet;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
+import java.util.Map;
 
 import javax.persistence.spi.ClassTransformer;
 
-import org.apache.aries.jpa.container.impl.NLS;
 import org.osgi.framework.Bundle;
-import org.osgi.framework.ServiceReference;
 import org.osgi.framework.hooks.weaving.WeavingException;
 import org.osgi.framework.hooks.weaving.WeavingHook;
 import org.osgi.framework.hooks.weaving.WovenClass;
 import org.osgi.framework.wiring.BundleWiring;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
- * This weaving hook delegates to any registered {@link ClassTransformer} instances
- * for a given bundle
+ * This weaving hook delegates to any registered {@link ClassTransformer} instances for a given bundle
  */
 public class JPAWeavingHook implements WeavingHook, TransformerRegistry {
+    private static final Logger LOGGER = LoggerFactory.getLogger(JPAWeavingHook.class);
 
-  /**
-   * This constructor should not be called directly, the {@link JPAWeavingHookFactory} 
-   * should be used to ensure that Weaving support is available.
-   */
-  JPAWeavingHook() { }
-  
-  /** 
-   * With luck we will only have one persistence unit per bundle, but
-   * if we don't we'll need to call them until one of them does a transform
-   * or we run out.
-   */
-  private final ConcurrentMap<Bundle, LinkedHashSet<WrappingTransformer>> registeredTransformers
-      = new ConcurrentHashMap<Bundle, LinkedHashSet<WrappingTransformer>>();
-  
-  public void weave(WovenClass wovenClass) {
-    
-    BundleWiring wiring = wovenClass.getBundleWiring();
-    
-    Collection<WrappingTransformer> transformers = registeredTransformers.get(
-        wiring.getBundle());
-    
-    if(transformers != null) {
-      Collection<WrappingTransformer> transformersToTry;
-      synchronized (transformers) {
-        transformersToTry = new ArrayList<WrappingTransformer>(transformers);
-      }
-      for(WrappingTransformer transformer : transformersToTry) {
+    /**
+     * This constructor should not be called directly, the {@link JPAWeavingHookFactory} should be used to
+     * ensure that Weaving support is available.
+     */
+    JPAWeavingHook() {
+    }
+
+    /**
+     * With luck we will only have one persistence unit per bundle, but if we don't we'll need to call them
+     * until one of them does a transform or we run out.
+     */
+    private final Map<Bundle, LinkedHashSet<ClassTransformer>> registeredTransformers = new HashMap<Bundle, LinkedHashSet<ClassTransformer>>();
+
+    public void weave(WovenClass wovenClass) {
+        BundleWiring wiring = wovenClass.getBundleWiring();
+        Bundle bundle = wiring.getBundle();
+        ClassLoader cl = wiring.getClassLoader();
+        Collection<ClassTransformer> transformersToTry = getTransformers(bundle);
+        if (transformersToTry.size() == 0 && wovenClass.getClassName().endsWith("Car")) {
+            LOGGER.error("Loading " + wovenClass.getClassName() + " before transformer is present");
+            //for (StackTraceElement el : Thread.currentThread().getStackTrace()) {
+//                LOGGER.info(el.toString());
+//            }
+        }
+        for (ClassTransformer transformer : transformersToTry) {
+
+            if (transformClass(wovenClass, cl, transformer)) {
+                LOGGER.info("Weaving " + wovenClass.getClassName() + " using " + transformer.getClass().getName());
+                break;
+            };
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private synchronized Collection<ClassTransformer> getTransformers(Bundle bundle) {
+        LinkedHashSet<ClassTransformer> transformers = registeredTransformers.get(bundle);
+        return transformers != null ? new ArrayList<ClassTransformer>(transformers) : Collections.EMPTY_LIST;
+    }
+
+    private boolean transformClass(WovenClass wovenClass, ClassLoader cl, ClassTransformer transformer)
+        throws ThreadDeath, OutOfMemoryError {
         try {
-          byte[] result = transformer.transform(wiring.getClassLoader(), 
-              wovenClass.getClassName(), wovenClass.getDefinedClass(), 
-              wovenClass.getProtectionDomain(), wovenClass.getBytes());
-          if(result != null) {
-            wovenClass.setBytes(result);
-            wovenClass.getDynamicImports().addAll(transformer.getPackagesToAdd());
-            break;
-          }
+            byte[] result = transformer
+                .transform(cl, 
+                           wovenClass.getClassName(),
+                           wovenClass.getDefinedClass(), 
+                           wovenClass.getProtectionDomain(),
+                           wovenClass.getBytes());
+            if (result != null) {
+                wovenClass.setBytes(result);
+                wovenClass.getDynamicImports().add("org.eclipse.persistence.*");
+                wovenClass.getDynamicImports().add("org.apache.openjpa.*");
+                
+                return true;
+            }
         } catch (Throwable t) {
-          if(t instanceof ThreadDeath)
-            throw (ThreadDeath)t;
-          else if (t instanceof OutOfMemoryError)
-            throw (OutOfMemoryError) t;
-          else {
-            Bundle b = wovenClass.getBundleWiring().getBundle();
-            throw new WeavingException(NLS.MESSAGES.getMessage("jpa.weaving.failure", wovenClass.getClassName(), b.getSymbolicName(), b.getVersion(), transformer), t);
-          }
-        }
-      }
-    }
-  }
-  
-  public void addTransformer(Bundle pBundle, ClassTransformer transformer, ServiceReference<?> provider) {
-    
-    //Optimised for single adds
-    
-    LinkedHashSet<WrappingTransformer> set = new LinkedHashSet<WrappingTransformer>();
-    WrappingTransformer wt = new WrappingTransformer(transformer, provider);
-    set.add(wt);
-    
-    LinkedHashSet<WrappingTransformer> existingSet = registeredTransformers.putIfAbsent(pBundle, set);
-    
-    if(existingSet != null) {
-      synchronized (existingSet) {
-        existingSet.add(wt);
-      }
-    }
-  }
-   
-  public void removeTransformer(Bundle pBundle, ClassTransformer transformer) {
-    LinkedHashSet<WrappingTransformer> set = registeredTransformers.get(pBundle);
-    
-    if(set == null || !!!safeRemove(set, transformer))
-      throw new IllegalStateException(NLS.MESSAGES.getMessage("jpa.weaving.transformer.not.registered", transformer));
-    
-    if(set.isEmpty())
-      registeredTransformers.remove(pBundle);
-  }
-
-  /**
-   * Perform a remove on the collection while synchronized on it
-   * @param set
-   * @param t
-   * @return
-   */
-  private boolean safeRemove(Collection<WrappingTransformer> set, ClassTransformer t) {
-    synchronized(set) {
-        return set.remove(new WrappingTransformer(t));
-      }
-  }
+            if (t instanceof ThreadDeath)
+                throw (ThreadDeath)t;
+            else if (t instanceof OutOfMemoryError)
+                throw (OutOfMemoryError)t;
+            else {
+                Bundle b = wovenClass.getBundleWiring().getBundle();
+                String msg = String.format("Weaving failure", wovenClass.getClassName(),
+                                           b.getSymbolicName(), b.getVersion(), transformer);
+                throw new WeavingException(msg, t);
+            }
+        }
+        return false;
+    }
+
+    public synchronized void addTransformer(Bundle pBundle, ClassTransformer transformer) {
+        LOGGER.info("Adding transformer " + transformer.getClass().getName());
+        LinkedHashSet<ClassTransformer> transformers = registeredTransformers.get(pBundle);
+        if (transformers == null) {
+            transformers = new LinkedHashSet<ClassTransformer>();
+            registeredTransformers.put(pBundle, transformers);
+        }
+        transformers.add(transformer);
+    }
+
+    public synchronized void removeTransformer(Bundle pBundle, ClassTransformer transformer) {
+        LinkedHashSet<ClassTransformer> set = registeredTransformers.get(pBundle);
+        if (set == null || !set.remove(transformer)) {
+            throw new IllegalStateException("Transformer " + transformer + " not registered");
+        }
+        if (set.isEmpty()) {
+            registeredTransformers.remove(pBundle);
+        }
+    }
+
 }

Modified: aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/weaving/impl/TransformerRegistry.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/weaving/impl/TransformerRegistry.java?rev=1680218&r1=1680217&r2=1680218&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/weaving/impl/TransformerRegistry.java (original)
+++ aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/weaving/impl/TransformerRegistry.java Tue May 19 09:47:49 2015
@@ -21,11 +21,10 @@ package org.apache.aries.jpa.container.w
 import javax.persistence.spi.ClassTransformer;
 
 import org.osgi.framework.Bundle;
-import org.osgi.framework.ServiceReference;
 
 /**
  * {@link ClassTransformer} instances should be registered with the
- * instance of this interface returned by {@link TransformerRegistryFactory#getTransformerRegistry()}
+ * instance of this interface returned by {@link TransformerRegistrySingleton#getTransformerRegistry()}
  */
 public interface TransformerRegistry {
 
@@ -36,7 +35,7 @@ public interface TransformerRegistry {
    * @param transformer  The transformer to weave with
    * @param provider The provider to provide packages from
    */
-  public void addTransformer(Bundle pBundle, ClassTransformer transformer, ServiceReference<?> provider);
+  public void addTransformer(Bundle pBundle, ClassTransformer transformer);
   
   
   /**

Copied: aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/weaving/impl/TransformerRegistrySingleton.java (from r1680054, aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/quiesce/impl/DestroyCallback.java)
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/weaving/impl/TransformerRegistrySingleton.java?p2=aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/weaving/impl/TransformerRegistrySingleton.java&p1=aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/quiesce/impl/DestroyCallback.java&r1=1680054&r2=1680218&rev=1680218&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/quiesce/impl/DestroyCallback.java (original)
+++ aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/weaving/impl/TransformerRegistrySingleton.java Tue May 19 09:47:49 2015
@@ -16,11 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.aries.jpa.container.quiesce.impl;
+package org.apache.aries.jpa.container.weaving.impl;
+
 
 /**
- * An asynchronous callback for destroying something
+ * This class is used to get hold of the active {@link TransformerRegistry} for this bundle.
  */
-public interface DestroyCallback {
-  public void callback();
+public class TransformerRegistrySingleton {
+    private static TransformerRegistry _instance;
+
+    public static TransformerRegistry get() {
+        if (_instance == null) {
+            _instance = new JPAWeavingHook();
+        }
+        return _instance;
+    }
 }

Modified: aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/weaving/impl/WrappingTransformer.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/weaving/impl/WrappingTransformer.java?rev=1680218&r1=1680217&r2=1680218&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/weaving/impl/WrappingTransformer.java (original)
+++ aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/weaving/impl/WrappingTransformer.java Tue May 19 09:47:49 2015
@@ -25,7 +25,6 @@ import java.util.HashSet;
 
 import javax.persistence.spi.ClassTransformer;
 
-import org.apache.aries.jpa.container.impl.NLS;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceReference;
@@ -34,65 +33,63 @@ import org.osgi.framework.wiring.BundleR
 import org.osgi.framework.wiring.BundleWiring;
 
 class WrappingTransformer implements ClassTransformer {
-  private final ClassTransformer delegate;
-  private final Collection<String> packageImportsToAdd = new HashSet<String>();
-  
-  public WrappingTransformer(ClassTransformer delegate,
-      ServiceReference<?> persistenceProvider) {
-
-    if(delegate == null) 
-      throw new NullPointerException(NLS.MESSAGES.getMessage("jpa.weaving.null.transformer"));
-    
-    if(persistenceProvider == null) {
-      throw new NullPointerException(NLS.MESSAGES.getMessage("jpa.weaving.null.provider"));
-    }
-    
-    this.delegate = delegate;
-    
-    Object packages = persistenceProvider.getProperty("org.apache.aries.jpa.container.weaving.packages");
-    
-    if(packages instanceof String[]) {
-      for(String s : (String[]) packages) {
-        packageImportsToAdd.add(s);
-      }
-    } else {
-      Bundle provider = persistenceProvider.getBundle();
-      String suffix = ";" + Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE + "=" +
-      provider.getSymbolicName() + ";" + Constants.BUNDLE_VERSION_ATTRIBUTE 
-      + "=" + provider.getVersion();
-
-      BundleRevision br = provider.adapt(BundleWiring.class).getRevision();
-      for(BundleCapability bc : br.getDeclaredCapabilities(BundleRevision.PACKAGE_NAMESPACE)) {
-        packageImportsToAdd.add(bc.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE) + suffix);
-      }
-    }
-  }
-
-  public WrappingTransformer(ClassTransformer transformer) {
-    delegate = transformer;
-  }
-
-  public byte[] transform(ClassLoader arg0, String arg1, Class<?> arg2,
-      ProtectionDomain arg3, byte[] arg4) throws IllegalClassFormatException {
-    return delegate.transform(arg0, arg1, arg2, arg3, arg4);
-  }
-  
-  public Collection<String> getPackagesToAdd() {
-    return packageImportsToAdd;
-  }
-  
-  public int hashCode() {
-    return delegate.hashCode();
-  }
-  
-  public boolean equals(Object o) {
-    if(o instanceof WrappingTransformer)
-      return delegate == ((WrappingTransformer) o).delegate;
-
-    return false;
-  }
-  
-  public String toString() {
-    return "Transformer: " + delegate.toString() + " Packages to add: " + packageImportsToAdd;
-  }
-}
\ No newline at end of file
+    private final ClassTransformer delegate;
+    private final Collection<String> packageImportsToAdd = new HashSet<String>();
+
+    public WrappingTransformer(ClassTransformer delegate, ServiceReference<?> persistenceProvider) {
+
+        if (delegate == null)
+            throw new NullPointerException("Transformer delegate may not be null");
+
+        if (persistenceProvider == null) {
+            throw new NullPointerException("PersistenceProvider may not be null");
+        }
+
+        this.delegate = delegate;
+
+        Object packages = persistenceProvider.getProperty("org.apache.aries.jpa.container.weaving.packages");
+
+        if (packages instanceof String[]) {
+            for (String s : (String[])packages) {
+                packageImportsToAdd.add(s);
+            }
+        } else {
+            Bundle provider = persistenceProvider.getBundle();
+            String suffix = ";" + Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE + "=" + provider.getSymbolicName()
+                            + ";" + Constants.BUNDLE_VERSION_ATTRIBUTE + "=" + provider.getVersion();
+
+            BundleRevision br = provider.adapt(BundleWiring.class).getRevision();
+            for (BundleCapability bc : br.getDeclaredCapabilities(BundleRevision.PACKAGE_NAMESPACE)) {
+                packageImportsToAdd.add(bc.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE) + suffix);
+            }
+        }
+    }
+
+    public WrappingTransformer(ClassTransformer transformer) {
+        delegate = transformer;
+    }
+
+    public byte[] transform(ClassLoader arg0, String arg1, Class<?> arg2, ProtectionDomain arg3, byte[] arg4)
+        throws IllegalClassFormatException {
+        return delegate.transform(arg0, arg1, arg2, arg3, arg4);
+    }
+
+    public Collection<String> getPackagesToAdd() {
+        return packageImportsToAdd;
+    }
+
+    public int hashCode() {
+        return delegate.hashCode();
+    }
+
+    public boolean equals(Object o) {
+        if (o instanceof WrappingTransformer)
+            return delegate == ((WrappingTransformer)o).delegate;
+
+        return false;
+    }
+
+    public String toString() {
+        return "Transformer: " + delegate.toString() + " Packages to add: " + packageImportsToAdd;
+    }
+}

Added: aries/trunk/jpa/jpa-container/src/test/java/org/apache/aries/jpa/container/impl/DataSourceTrackerTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/test/java/org/apache/aries/jpa/container/impl/DataSourceTrackerTest.java?rev=1680218&view=auto
==============================================================================
--- aries/trunk/jpa/jpa-container/src/test/java/org/apache/aries/jpa/container/impl/DataSourceTrackerTest.java (added)
+++ aries/trunk/jpa/jpa-container/src/test/java/org/apache/aries/jpa/container/impl/DataSourceTrackerTest.java Tue May 19 09:47:49 2015
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIESOR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.jpa.container.impl;
+
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import javax.persistence.spi.PersistenceUnitTransactionType;
+
+import org.apache.aries.jpa.container.impl.DataSourceTracker;
+import org.apache.aries.jpa.container.parser.impl.PersistenceUnit;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+
+public class DataSourceTrackerTest {
+    
+    @Test
+    public void testCreateFilterFull() throws InvalidSyntaxException {
+        PersistenceUnit punit = mock(PersistenceUnit.class);
+        when(punit.getJtaDataSourceName()).thenReturn("osgi:service/javax.sql.DataSource/(osgi.jndi.service.name=tasklist)");
+        when(punit.getTransactionType()).thenReturn(PersistenceUnitTransactionType.JTA);
+        BundleContext context = mock(BundleContext.class);
+        
+        DataSourceTracker.createFilter(context, punit);
+
+        verify(context, atLeastOnce()).createFilter(Mockito.eq("(&(objectClass=javax.sql.DataSource)(osgi.jndi.service.name=tasklist))"));
+    }
+    
+    @Test
+    public void testCreateFilterSimple() throws InvalidSyntaxException {
+        PersistenceUnit punit = mock(PersistenceUnit.class);
+        when(punit.getJtaDataSourceName()).thenReturn("tasklist");
+        when(punit.getTransactionType()).thenReturn(PersistenceUnitTransactionType.JTA);
+        BundleContext context = mock(BundleContext.class);
+        
+        DataSourceTracker.createFilter(context, punit);
+
+        verify(context, atLeastOnce()).createFilter(Mockito.eq("(&(objectClass=javax.sql.DataSource)(osgi.jndi.service.name=tasklist))"));
+    }
+}