You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by zo...@apache.org on 2011/02/27 19:08:17 UTC
svn commit: r1075099 [3/7] - in /aries/tags/jpa-0.1-incubating: ./ jpa-api/
jpa-api/src/ jpa-api/src/main/ jpa-api/src/main/java/
jpa-api/src/main/java/org/ jpa-api/src/main/java/org/apache/
jpa-api/src/main/java/org/apache/aries/ jpa-api/src/main/java...
Added: aries/tags/jpa-0.1-incubating/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/ManagedPersistenceContextFactory.java
URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/ManagedPersistenceContextFactory.java?rev=1075099&view=auto
==============================================================================
--- aries/tags/jpa-0.1-incubating/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/ManagedPersistenceContextFactory.java (added)
+++ aries/tags/jpa-0.1-incubating/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/ManagedPersistenceContextFactory.java Sun Feb 27 18:08:10 2011
@@ -0,0 +1,113 @@
+/*
+ * 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.context.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.persistence.Cache;
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.PersistenceContextType;
+import javax.persistence.PersistenceUnitUtil;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.metamodel.Metamodel;
+
+import org.apache.aries.jpa.container.context.PersistenceContextProvider;
+import org.apache.aries.jpa.container.context.transaction.impl.JTAEntityManager;
+import org.apache.aries.jpa.container.context.transaction.impl.JTAPersistenceContextRegistry;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+/**
+ * A factory that can lazily create managed persistence contexts.
+ * This is registered in the Service registry to be looked up by blueprint.
+ * The EntityManagerFactory interface is used to ensure a shared class space
+ * with the client. Only the createEntityManager() method is supported.
+ */
+public class ManagedPersistenceContextFactory implements EntityManagerFactory {
+ /** Logger */
+ private static final Logger _logger = LoggerFactory.getLogger("org.apache.aries.jpa.container.context");
+
+ private final ServiceReference emf;
+ private final Map<String, Object> properties;
+ private final JTAPersistenceContextRegistry registry;
+ private final PersistenceContextType type;
+
+ public ManagedPersistenceContextFactory(ServiceReference unit,
+ Map<String, Object> props, JTAPersistenceContextRegistry contextRegistry) {
+
+ emf = unit;
+ //Take a copy of the Map so that we don't modify the original
+ properties = new HashMap<String, Object>(props);
+ registry = contextRegistry;
+ //Remove our internal property so that it doesn't get passed on the createEntityManager call
+ type = (PersistenceContextType) properties.remove(PersistenceContextProvider.PERSISTENCE_CONTEXT_TYPE);
+ }
+
+ public EntityManager createEntityManager() {
+ if(_logger.isDebugEnabled()) {
+ _logger.debug("Creating a container managed entity manager for the perstence unit {} with the following properties {}",
+ new Object[] {emf, properties});
+ }
+ EntityManagerFactory factory = (EntityManagerFactory) emf.getBundle().getBundleContext().getService(emf);
+
+ if(type == PersistenceContextType.TRANSACTION || type == null)
+ return new JTAEntityManager(factory, properties, registry);
+ else {
+ _logger.error("There is currently no support for extended scope EntityManagers");
+ return null;
+ }
+
+ }
+
+ public void close() {
+ throw new UnsupportedOperationException();
+ }
+
+ public EntityManager createEntityManager(Map arg0) {
+ throw new UnsupportedOperationException();
+ }
+
+ public Cache getCache() {
+ throw new UnsupportedOperationException();
+ }
+
+ public CriteriaBuilder getCriteriaBuilder() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Metamodel getMetamodel() {
+ throw new UnsupportedOperationException();
+ }
+
+ public PersistenceUnitUtil getPersistenceUnitUtil() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Map<String, Object> getProperties() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isOpen() {
+ throw new UnsupportedOperationException();
+ }
+
+}
Added: aries/tags/jpa-0.1-incubating/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/PersistenceContextManager.java
URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/PersistenceContextManager.java?rev=1075099&view=auto
==============================================================================
--- aries/tags/jpa-0.1-incubating/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/PersistenceContextManager.java (added)
+++ aries/tags/jpa-0.1-incubating/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/PersistenceContextManager.java Sun Feb 27 18:08:10 2011
@@ -0,0 +1,400 @@
+/*
+ * 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.context.impl;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
+
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.PersistenceContextType;
+
+import org.apache.aries.jpa.container.PersistenceUnitConstants;
+import org.apache.aries.jpa.container.context.PersistenceContextProvider;
+import org.apache.aries.jpa.container.context.transaction.impl.JTAPersistenceContextRegistry;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.util.tracker.ServiceTracker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class is responsible for managing all of the persistence contexts at a defined scope,
+ * i.e. for a single framework or composite. It will automatically manage the lifecycle of all
+ * registered persistence contexts.
+ */
+public class PersistenceContextManager extends ServiceTracker{
+ /** Logger */
+ private static final Logger _logger = LoggerFactory.getLogger("org.apache.aries.jpa.container.context");
+
+ /** The filter this tracker uses to select Persistence Units. */
+ private static final Filter filter;
+ static {
+ Filter f = null;
+ try {
+ //Create a filter to select container managed persistence units that
+ //are not proxies for managed persistence contexts
+ f = FrameworkUtil.createFilter("(&(" + Constants.OBJECTCLASS
+ + "=" + "javax.persistence.EntityManagerFactory" + ")(" +
+ PersistenceUnitConstants.CONTAINER_MANAGED_PERSISTENCE_UNIT + "=true)(!("
+ + PersistenceContextProvider.PROXY_FACTORY_EMF_ATTRIBUTE + "=*)))" );
+ } catch (InvalidSyntaxException e) {
+ _logger.error("There was an exception creating the EntityManagerFactory filter. This should never happen.", e);
+ throw new RuntimeException(e);
+ }
+ filter = f;
+ }
+ /** A Map of bundles that reference a particular persistence unit. Only access when synchronized on <code>this</code>.*/
+ private final Map<String, Set<Bundle>> persistenceContextConsumers = new HashMap<String, Set<Bundle>>();
+ /**
+ * A Map persistence unit names to persistenceContextDefinitions. We use HashMap in the generic definition to ensure that
+ * we get the correct deep <code>equals()</code> behaviour. Only access when synchronized on <code>this</code>.
+ */
+ private final Map<String, HashMap<String, Object>> persistenceContextDefinitions = new HashMap<String, HashMap<String,Object>>();
+ /** A Map of persistence units tracked by the tracker. Only access when synchronized on <code>this</code>. */
+ private final Map<String, ServiceReference> persistenceUnits = new HashMap<String, ServiceReference>();
+ /** A Map for storing the registered ManagedPersistenceContextServiceFactory. Only access when synchronized on <code>this</code>. */
+ private final Map<String, ServiceRegistration> entityManagerRegistrations = new HashMap<String, ServiceRegistration>();
+ private final JTAPersistenceContextRegistry persistenceContextRegistry;
+
+ /**
+ * Create a new PersistenceContextManager at a scope defined by the supplied {@link BundleContext}
+ * @param ctx the bundle context to use for tracking services. In order to prevent this
+ * object becoming prematurely invalid it is best to use the {@link BundleContext} of
+ * the system bundle (Bundle 0).
+ */
+ public PersistenceContextManager(BundleContext ctx, JTAPersistenceContextRegistry registry) {
+
+ super(ctx, filter, null);
+ persistenceContextRegistry = registry;
+ }
+
+ @Override
+ public void close() {
+ super.close();
+ for (ServiceRegistration reg : entityManagerRegistrations.values()) {
+ try {
+ reg.unregister();
+ } catch (IllegalStateException ise) {
+ //This is no worry, the framework has done our job for us
+ }
+ }
+ }
+
+ @Override
+ public Object addingService(ServiceReference reference) {
+
+ if(_logger.isDebugEnabled()) {
+ _logger.debug("A new managed persistence unit, {}, has been detected.", new Object[] {reference});
+ }
+
+ String unitName = (String) reference.getProperty(PersistenceUnitConstants.OSGI_UNIT_NAME);
+ if(unitName == null)
+ unitName = "";
+ boolean register;
+ //Use a synchronized block to ensure that we get an atomic view of the persistenceUnits
+ //and the persistenceContextDefinitions
+ synchronized (this) {
+ //If we already track a unit with the same name then we are in trouble!
+ //only one unit with a given name should exist at a single scope
+ if(persistenceUnits.containsKey(unitName)) {
+ _logger.warn("The persistence unit {} exists twice at the same framework scope. " +
+ "The second service will be ignored", new Object[] {reference});
+ return null;
+ }
+ //If this is a new unit, then add it, and check whether we have any waiting
+ //persistenceContextDefinitions
+ persistenceUnits.put(unitName, reference);
+ register = persistenceContextDefinitions.containsKey(unitName);
+ }
+ //If there are persistenceContexts then register them
+ if(register){
+ registerEM(unitName);
+ }
+ return reference;
+ }
+
+ public void removedService(ServiceReference ref, Object o)
+ {
+ if(_logger.isDebugEnabled()) {
+ _logger.debug("A managed persistence unit, {}, has been unregistered.", new Object[] {ref});
+ }
+
+ String unitName = (String) ref.getProperty(PersistenceUnitConstants.OSGI_UNIT_NAME);
+ if(unitName == null)
+ unitName = "";
+ //Remove the persistence Unit service to prevent other people from trying to use it
+ synchronized (this) {
+ persistenceUnits.remove(unitName);
+ }
+ //Unregister any dependent contexts
+ unregisterEM(unitName);
+ }
+
+ /**
+ * Register a persistence context definition with this manager
+ * @param name The name of the persistence unit for this context
+ * @param client The {@link Bundle} that uses this persistence context
+ * @param properties The Map of properties for this persistence context
+ * This must contain the {@link PersistenceContextType}
+ */
+ public void registerContext(String name, Bundle client, HashMap<String, Object> properties) {
+ if (_logger.isDebugEnabled()) {
+ _logger.debug("Registering bundle {} as a client of persistence unit {} with properties {}.",
+ new Object[] {client.getSymbolicName() + "_" + client.getVersion(), name, properties});
+ }
+ HashMap<String, Object> oldProps;
+ boolean register;
+ //Use a synchronized to get an atomic view
+ synchronized (this) {
+ //Add a new consumer for the context, including the Set if necessary
+ Set<Bundle> bundles = persistenceContextConsumers.get(name);
+ if(bundles == null) {
+ bundles = new HashSet<Bundle>();
+ persistenceContextConsumers.put(name, bundles);
+ }
+ bundles.add(client);
+
+ //Check that we don't have different properties to other clients.
+ //This would not make sense, as all clients should share the same
+ //context!
+ oldProps = persistenceContextDefinitions.put(name, properties);
+ if(oldProps != null) {
+ if(!!!oldProps.equals(properties)) {
+ _logger.warn("The bundle {} depends on a managed persistence context {} with properties {}, but the context already exists with properties {}. The existing properties will be used.",
+ new Object[] {client.getSymbolicName() + "_" + client.getVersion(), name, properties, oldProps});
+ persistenceContextDefinitions.put(name, oldProps);
+ }
+ }
+ //We should only register if our persistence unit exists
+ register = persistenceUnits.containsKey(name);
+ }
+
+ if(register) {
+ registerEM(name);
+ }
+ }
+
+ /**
+ * Unregister the supplied bundle as a client of the supplied persistence context
+ * @param name The name of the context
+ * @param client The bundle that is using the persistence context
+ */
+ public void unregisterContext(String name, Bundle client)
+ {
+ if (_logger.isDebugEnabled()) {
+ _logger.debug("Unregistering the bundle {} as a client of persistence unit {}.",
+ new Object[] {client.getSymbolicName() + "_" + client.getVersion(), name});
+ }
+ boolean unregister = false;
+ //Keep an atomic view of our state
+ synchronized (this) {
+ //Remove the client
+ Set<Bundle> clients = persistenceContextConsumers.get(name);
+ clients.remove(client);
+ //If no clients remain then tidy up the context
+ if(clients.isEmpty()) {
+ persistenceContextDefinitions.remove(name);
+ persistenceContextConsumers.remove(name);
+ unregister = true;
+ }
+ }
+ //Unregister the context if it is no longer used
+ if(unregister)
+ unregisterEM(name);
+ }
+
+ /**
+ * Register a {@link ManagedPersistenceContextFactory} for the named persistence context
+ *
+ * This must <b>never</b> be called from a <code>synchronized</code> block.
+ * @param name
+ */
+ private void registerEM(String name) {
+
+ EntityManagerFactory entityManagerServiceFactory;
+ ServiceReference unit;
+ ServiceRegistration reg = null;
+ boolean alreadyRegistered = false;
+ try
+ {
+ //Synchronize for an atomic view
+ synchronized (this) {
+ //Not our job to register if someone is already doing it, or has already done it
+ if(entityManagerRegistrations.containsKey(name)){
+ alreadyRegistered = true;
+ return;
+ }
+ if(_logger.isDebugEnabled()) {
+ _logger.debug("Registering a managed persistence context for persistence unit {}", new Object[] {name});
+ }
+ //Block other threads from trying to register by adding the key
+ entityManagerRegistrations.put(name, null);
+
+ //Get hold of the information we need to create the context
+ unit = persistenceUnits.get(name);
+ Map<String, Object> props = persistenceContextDefinitions.get(name);
+
+ //If either of these things is undefined then the context cannot be registered
+ if(props == null || unit == null) {
+ _logger.error("The managed persistence context {} cannot be registered for persistence unit {} and properties {}.",
+ new Object[] {name, unit, props});
+ //The finally block will clear the entityManagerRegistrations key
+ return;
+ }
+
+ //Create the service factory
+ entityManagerServiceFactory = new ManagedPersistenceContextFactory(unit, props, persistenceContextRegistry);
+ }
+
+ //Always register from outside a synchronized
+ Hashtable<String, Object> props = new Hashtable<String, Object>();
+
+ props.put(PersistenceUnitConstants.OSGI_UNIT_NAME, name);
+ props.put(PersistenceUnitConstants.OSGI_UNIT_VERSION, unit.getProperty(PersistenceUnitConstants.OSGI_UNIT_VERSION));
+ props.put(PersistenceUnitConstants.CONTAINER_MANAGED_PERSISTENCE_UNIT, Boolean.TRUE);
+ props.put(PersistenceUnitConstants.OSGI_UNIT_PROVIDER, unit.getProperty(PersistenceUnitConstants.OSGI_UNIT_PROVIDER));
+ props.put(PersistenceUnitConstants.EMPTY_PERSISTENCE_UNIT_NAME, "".equals(name));
+ props.put(PersistenceContextProvider.PROXY_FACTORY_EMF_ATTRIBUTE, "true");
+
+ BundleContext persistenceBundleContext = unit.getBundle().getBundleContext();
+ reg = persistenceBundleContext.registerService(
+ EntityManagerFactory.class.getName(), entityManagerServiceFactory, props);
+ } finally {
+ //As we have to register from outside a synchronized then someone may be trying to
+ //unregister us. They will try to wait for us to finish, but in order to prevent
+ //live-lock they may flag to us that we need to do the unregistration by removing
+ //the persistence context key.
+ boolean recoverFromLiveLock = false;
+
+ //Synchronize to get an atomic view
+ synchronized (this) {
+ //If we created a registration
+ if(reg != null) {
+ //If the key still exists then all is well
+ if(entityManagerRegistrations.containsKey(name)) {
+ entityManagerRegistrations.put(name, reg);
+ } else {
+ //Else we were in a potential live-lock and the service could not be unregistered
+ //earlier. This means we have to do it (but outside the synchronized. Make sure we
+ //also remove the registration key!
+ _logger.warn("Recovering from a potential live-lock registering a container managed peristence context for persistence unit {}.",
+ new Object[] {name});
+ entityManagerRegistrations.remove(name);
+ recoverFromLiveLock = true;
+ }
+ }
+ //There was no registration created. Remove the key if we were registering.
+ else {
+ if(!!!alreadyRegistered)
+ entityManagerRegistrations.remove(name);
+ }
+
+ //Notify any waiting unregistrations that they can proceed
+ this.notifyAll();
+ }
+ //If we were live-locked then unregister the registration here
+ if(recoverFromLiveLock)
+ reg.unregister();
+ }
+ }
+
+ /**
+ * Unregister the named persistence context. This code attempts to ensure that
+ * the calling thread performs the unregistration to ensure the calls are
+ * synchronous. If a potential live-lock is detected then the unregistration may
+ * occur on a different thread or at a different time.
+ *
+ * This must <b>never</b> be called from a <code>synchronized</code> block.
+ * @param unitName
+ *
+ */
+ private void unregisterEM(String unitName) {
+ ServiceRegistration reg = null;
+ //Look for the registration
+ synchronized (this) {
+ //We use a loop to prevent live-locking, we
+ //loop a maximum of 4 times before
+ boolean found = false;
+ int tries = 0;
+ while (!!!found && tries < 4) {
+ //If we contain the key then get the registration,
+ //If not, then we have nothing to unregister
+ if(entityManagerRegistrations.containsKey(unitName))
+ reg = entityManagerRegistrations.get(unitName);
+ else
+ return;
+
+ //It is possible that the registration is null. This means we are in
+ //the transient case where a registration is being created. If we wait
+ //then everything should be fine. If the registration is not null, then
+ //remove it from the map and escape the loop
+ if(reg != null) {
+ found = true;
+ entityManagerRegistrations.remove(unitName);
+ } else
+ //We didn't find it, wait and try again
+ try {
+ this.wait(500);
+ } catch (InterruptedException e) {
+ _logger.warn("The Aries JPA container was interrupted when waiting for managed persistence context {} to be unregistered", new Object[] {unitName});
+ }
+ //Increment the loop to prevent us from live-locking
+ tries++;
+ }
+ //If we didn't find the registration in the loop then still
+ //remove the key to warn the registering thread to unregister
+ //immediately.
+ if(!found) {
+ //Possible Live lock, just remove the key
+ entityManagerRegistrations.remove(unitName);
+ _logger.warn("The JPA container detected a possible live lock whilst unregistering the managed persistence context {}. The service cannot be unregistered immediately so the context may become unusable before being unregistered.",
+ new Object[] {unitName});
+ }
+ }
+ //If we found the registration then unregister it outside the synchronized.
+ if (reg != null) {
+ reg.unregister();
+ }
+ }
+
+ @Override
+ /**
+ * Open this <code>PersistenceContextManager</code> and begin tracking services.
+ *
+ * <p>
+ * This implementation calls <code>open(true)</code>.
+ *
+ * @throws java.lang.IllegalStateException If the <code>BundleContext</code>
+ * with which this <code>ServiceTracker</code> was created is no
+ * longer valid.
+ * @see #open(boolean)
+ */
+ public void open() {
+ super.open(true);
+ }
+}
Added: aries/tags/jpa-0.1-incubating/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAEntityManager.java
URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAEntityManager.java?rev=1075099&view=auto
==============================================================================
--- aries/tags/jpa-0.1-incubating/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAEntityManager.java (added)
+++ aries/tags/jpa-0.1-incubating/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAEntityManager.java Sun Feb 27 18:08:10 2011
@@ -0,0 +1,354 @@
+/*
+ * 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.context.transaction.impl;
+
+import java.util.Map;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.EntityTransaction;
+import javax.persistence.FlushModeType;
+import javax.persistence.LockModeType;
+import javax.persistence.Query;
+import javax.persistence.TransactionRequiredException;
+import javax.persistence.TypedQuery;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.metamodel.Metamodel;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A <code>PersistenceContextType.TRANSACTION</code> {@link EntityManager} instance
+ */
+public class JTAEntityManager implements EntityManager {
+ /** Logger */
+ private static final Logger _logger = LoggerFactory.getLogger("org.apache.aries.jpa.container.context");
+
+ /** The {@link EntityManagerFactory} that can create new {@link EntityManager} instances */
+ private final EntityManagerFactory emf;
+ /** The map of properties to pass when creating EntityManagers */
+ private final Map<String, Object> props;
+ /** A registry for creating new persistence contexts */
+ private final JTAPersistenceContextRegistry reg;
+ /**
+ * The entity manager to use when there is no transaction. Note that there is one of these
+ * per injection site.
+ */
+ private EntityManager detachedManager = null;
+
+ public JTAEntityManager(EntityManagerFactory factory,
+ Map<String, Object> properties, JTAPersistenceContextRegistry registry) {
+ emf = factory;
+ props = properties;
+ reg = registry;
+ }
+
+ /**
+ * Get the target persistence context
+ * @param forceTransaction Whether the returned entity manager needs to be bound to a transaction
+ * @throws TransactionRequiredException if forceTransaction is true and no transaction is available
+ * @return
+ */
+ private EntityManager getPersistenceContext(boolean forceTransaction)
+ {
+ if (forceTransaction) {
+ return reg.getCurrentPersistenceContext(emf, props);
+ } else {
+ if (reg.isTransactionActive()) {
+ return reg.getCurrentPersistenceContext(emf, props);
+ } else {
+ if(!!!reg.jtaIntegrationAvailable() && _logger.isDebugEnabled())
+ _logger.debug("No integration with JTA transactions is available. No transaction context is active.");
+
+ if (detachedManager == null) {
+ EntityManager temp = emf.createEntityManager(props);
+
+ synchronized (this) {
+ if (detachedManager == null) {
+ detachedManager = temp;
+ temp = null;
+ }
+ }
+
+ if (temp != null)
+ temp.close();
+ }
+ return detachedManager;
+ }
+ }
+ }
+
+ /**
+ * Called reflectively by blueprint
+ */
+ public void internalClose() {
+ EntityManager temp = null;
+
+ synchronized (this) {
+ temp = detachedManager;
+ detachedManager = null;
+ }
+
+ if (temp != null)
+ temp.close();
+ }
+
+ public void clear()
+ {
+ getPersistenceContext(false).clear();
+ }
+
+ public void close()
+ {
+ //TODO add a message here
+ throw new IllegalStateException("It is forbidden to call close on a container managed EntityManager");
+ }
+
+ public boolean contains(Object arg0)
+ {
+ return getPersistenceContext(false).contains(arg0);
+ }
+
+ public Query createNamedQuery(String arg0)
+ {
+ return getPersistenceContext(false).createNamedQuery(arg0);
+ }
+
+ public Query createNativeQuery(String arg0)
+ {
+ return getPersistenceContext(false).createNativeQuery(arg0);
+ }
+
+ @SuppressWarnings("unchecked")
+ public Query createNativeQuery(String arg0, Class arg1)
+ {
+ return getPersistenceContext(false).createNativeQuery(arg0, arg1);
+ }
+
+ public Query createNativeQuery(String arg0, String arg1)
+ {
+ return getPersistenceContext(false).createNativeQuery(arg0, arg1);
+ }
+
+ public Query createQuery(String arg0)
+ {
+ return getPersistenceContext(false).createQuery(arg0);
+ }
+
+ public <T> T find(Class<T> arg0, Object arg1)
+ {
+ return getPersistenceContext(false).find(arg0, arg1);
+ }
+
+ /**
+ * @throws TransactionRequiredException
+ */
+ public void flush()
+ {
+ getPersistenceContext(true).flush();
+ }
+
+ public Object getDelegate()
+ {
+ return getPersistenceContext(false).getDelegate();
+ }
+
+ public FlushModeType getFlushMode()
+ {
+ return getPersistenceContext(false).getFlushMode();
+ }
+
+ public <T> T getReference(Class<T> arg0, Object arg1)
+ {
+ return getPersistenceContext(false).getReference(arg0, arg1);
+ }
+
+ public EntityTransaction getTransaction()
+ {
+ throw new IllegalStateException("Transaction management is not available for container managed EntityManagers");
+ }
+
+ public boolean isOpen()
+ {
+ return true;
+ }
+
+ public void joinTransaction()
+ {
+ //This should be a no-op for a JTA entity manager
+ }
+
+ /**
+ * @throws TransactionRequiredException
+ */
+ public void lock(Object arg0, LockModeType arg1)
+ {
+ getPersistenceContext(true).lock(arg0, arg1);
+ }
+
+ /**
+ * @throws TransactionRequiredException
+ */
+ public <T> T merge(T arg0)
+ {
+ return getPersistenceContext(true).merge(arg0);
+ }
+
+ /**
+ * @throws TransactionRequiredException
+ */
+ public void persist(Object arg0)
+ {
+ getPersistenceContext(true).persist(arg0);
+ }
+
+ /**
+ * @throws TransactionRequiredException
+ */
+ public void refresh(Object arg0)
+ {
+ getPersistenceContext(true).refresh(arg0);
+ }
+
+ /**
+ * @throws TransactionRequiredException
+ */
+ public void remove(Object arg0)
+ {
+ getPersistenceContext(true).remove(arg0);
+ }
+
+ public void setFlushMode(FlushModeType arg0)
+ {
+ getPersistenceContext(false).setFlushMode(arg0);
+ }
+
+ public <T> TypedQuery<T> createNamedQuery(String arg0, Class<T> arg1)
+ {
+ return getPersistenceContext(false).createNamedQuery(arg0, arg1);
+ }
+
+ public <T> TypedQuery<T> createQuery(CriteriaQuery<T> arg0)
+ {
+ return getPersistenceContext(false).createQuery(arg0);
+ }
+
+ public <T> TypedQuery<T> createQuery(String arg0, Class<T> arg1)
+ {
+ return getPersistenceContext(false).createQuery(arg0, arg1);
+ }
+
+ public void detach(Object arg0)
+ {
+ getPersistenceContext(false).detach(arg0);
+ }
+
+ public <T> T find(Class<T> arg0, Object arg1, Map<String, Object> arg2)
+ {
+ return getPersistenceContext(false).find(arg0, arg1, arg2);
+ }
+
+ /**
+ * @throws TransactionRequiredException if lock mode is not NONE
+ */
+ public <T> T find(Class<T> arg0, Object arg1, LockModeType arg2)
+ {
+ return getPersistenceContext(arg2 != LockModeType.NONE).find(arg0, arg1, arg2);
+ }
+
+ /**
+ * @throws TransactionRequiredException if lock mode is not NONE
+ */
+ public <T> T find(Class<T> arg0, Object arg1, LockModeType arg2, Map<String, Object> arg3)
+ {
+ return getPersistenceContext(arg2 != LockModeType.NONE).find(arg0, arg1, arg2, arg3);
+ }
+
+ public CriteriaBuilder getCriteriaBuilder()
+ {
+ return getPersistenceContext(false).getCriteriaBuilder();
+ }
+
+ public EntityManagerFactory getEntityManagerFactory()
+ {
+ return emf;
+ }
+
+ /**
+ * @throws TransactionRequiredException
+ */
+ public LockModeType getLockMode(Object arg0)
+ {
+ return getPersistenceContext(true).getLockMode(arg0);
+ }
+
+ public Metamodel getMetamodel()
+ {
+ return getPersistenceContext(false).getMetamodel();
+ }
+
+ public Map<String, Object> getProperties()
+ {
+ return getPersistenceContext(false).getProperties();
+ }
+
+ /**
+ * @throws TransactionRequiredException
+ */
+ public void lock(Object arg0, LockModeType arg1, Map<String, Object> arg2)
+ {
+ getPersistenceContext(true).lock(arg0, arg1, arg2);
+ }
+
+ /**
+ * @throws TransactionRequiredException
+ */
+ public void refresh(Object arg0, Map<String, Object> arg1)
+ {
+ getPersistenceContext(true).refresh(arg0, arg1);
+ }
+
+ /**
+ * @throws TransactionRequiredException
+ */
+ public void refresh(Object arg0, LockModeType arg1)
+ {
+ getPersistenceContext(true).refresh(arg0, arg1);
+ }
+
+ /**
+ * @throws TransactionRequiredException
+ */
+ public void refresh(Object arg0, LockModeType arg1, Map<String, Object> arg2)
+ {
+ getPersistenceContext(true).refresh(arg0, arg1, arg2);
+ }
+
+ public void setProperty(String arg0, Object arg1)
+ {
+ getPersistenceContext(false).setProperty(arg0, arg1);
+ }
+
+ public <T> T unwrap(Class<T> arg0)
+ {
+ return getPersistenceContext(false).unwrap(arg0);
+ }
+}
Added: aries/tags/jpa-0.1-incubating/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAPersistenceContextRegistry.java
URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAPersistenceContextRegistry.java?rev=1075099&view=auto
==============================================================================
--- aries/tags/jpa-0.1-incubating/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAPersistenceContextRegistry.java (added)
+++ aries/tags/jpa-0.1-incubating/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAPersistenceContextRegistry.java Sun Feb 27 18:08:10 2011
@@ -0,0 +1,226 @@
+/*
+ * 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.context.transaction.impl;
+
+import java.util.IdentityHashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.TransactionRequiredException;
+import javax.transaction.Synchronization;
+import javax.transaction.TransactionSynchronizationRegistry;
+
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class is used to manage the lifecycle of JTA peristence contexts
+ */
+public final class JTAPersistenceContextRegistry {
+ /** Logger */
+ private static final Logger _logger = LoggerFactory.getLogger("org.apache.aries.jpa.container.context");
+ /** The unique key we use to find our Map */
+ private static final TSRKey EMF_MAP_KEY = new TSRKey();
+
+ /**
+ * A simple class to avoid key collisions in the TransactionSynchronizationRegistry.
+ * As recommended by {@link TransactionSynchronizationRegistry#putResource(Object, Object)}
+ */
+ private final static class TSRKey {
+
+ @Override
+ public final boolean equals(Object o) {
+ return (this == o);
+ }
+
+ @Override
+ public final int hashCode() {
+ return 0xDEADBEEF;
+ }
+ }
+
+ /**
+ * The transaction synchronization registry, used to determine the currently
+ * active transaction, and to register for post-commit cleanup.
+ */
+ private TransactionSynchronizationRegistry tranRegistry;
+
+ /**
+ * A flag to indicate whether the {@link TransactionSynchronizationRegistry} is available.
+ * The initial value is false, as defined by {@link AtomicBoolean#AtomicBoolean()}.
+ */
+ private final AtomicBoolean registryAvailable = new AtomicBoolean();
+
+ /**
+ * Get a PersistenceContext for the current transaction. The persistence context will
+ * automatically be closed when the transaction completes.
+ *
+ * @param persistenceUnit The peristence unit to create the persitence context from
+ * @param properties Any properties that should be passed on the call to {@code createEntityManager()}.
+ * The properties are NOT used for retrieving an already created persistence context.
+ *
+ * @return A persistence context associated with the current transaction. Note that this will
+ * need to be wrappered to obey the JPA spec by throwing the correct exceptions
+ * @throws {@link TransactionRequiredException} if there is no active transaction.
+ */
+ @SuppressWarnings("unchecked")
+ public final EntityManager getCurrentPersistenceContext(EntityManagerFactory persistenceUnit, Map<?,?> properties) throws TransactionRequiredException
+ {
+ //There will only ever be one thread associated with a transaction at a given time
+ //As a result, it is only the outer map that needs to be thread safe.
+
+ //Throw the error on to the client
+ if(!!!isTransactionActive()) {
+ if(jtaIntegrationAvailable())
+ throw new TransactionRequiredException("No transaction currently active");
+ else {
+ throw new TransactionRequiredException("No JTA transaction services implementation is currently available. As a result the" +
+ " JPA container cannot integrate with JTA transactions.");
+ }
+ }
+ EntityManager toReturn = null;
+
+ //Get hold of the Map. If there is no Map already registered then add one.
+ //We don't need to worry about a race condition, as no other thread will
+ //share our transaction and be able to access our Map
+ Map<EntityManagerFactory, EntityManager> contextsForTransaction = (Map<EntityManagerFactory, EntityManager>) tranRegistry.getResource(EMF_MAP_KEY);
+
+ //If we have a map then find an EntityManager, else create a new Map add it to the registry, and register for cleanup
+ if(contextsForTransaction != null) {
+ toReturn = contextsForTransaction.get(persistenceUnit);
+ } else {
+ contextsForTransaction = new IdentityHashMap<EntityManagerFactory, EntityManager>();
+ try {
+ tranRegistry.putResource(EMF_MAP_KEY, contextsForTransaction);
+ } catch (IllegalStateException e) {
+ _logger.warn("Unable to create a persistence context for the transaction {} because the is not active", new Object[] {tranRegistry.getTransactionKey()});
+ throw new TransactionRequiredException("Unable to assiociate resources with transaction " + tranRegistry.getTransactionKey());
+ }
+ }
+
+ //If we have no previously created EntityManager
+ if(toReturn == null) {
+ toReturn = (properties == null) ? persistenceUnit.createEntityManager() : persistenceUnit.createEntityManager(properties);
+ if(_logger.isDebugEnabled())
+ _logger.debug("Created a new persistence context {} for transaction {}.", new Object[] {toReturn, tranRegistry.getTransactionKey()});
+ try {
+ tranRegistry.registerInterposedSynchronization(new EntityManagerClearUp(toReturn));
+ } catch (IllegalStateException e) {
+ _logger.warn("No persistence context could be created as the JPA container could not register a synchronization with the transaction {}.", new Object[] {tranRegistry.getTransactionKey()});
+ toReturn.close();
+ throw new TransactionRequiredException("Unable to synchronize with transaction " + tranRegistry.getTransactionKey());
+ }
+ contextsForTransaction.put(persistenceUnit, toReturn);
+ } else {
+ if(_logger.isDebugEnabled())
+ _logger.debug("Re-using a persistence context for transaction " + tranRegistry.getTransactionKey());
+ }
+ return toReturn;
+ }
+
+ /**
+ * Determine whether there is an active transaction on the thread
+ * @return
+ */
+ public final boolean isTransactionActive()
+ {
+ return registryAvailable.get() && tranRegistry.getTransactionKey() != null;
+ }
+
+ /**
+ * Provide a {@link TransactionSynchronizationRegistry} to use
+ * @param tranRegistry
+ */
+ public final void setTranRegistry(TransactionSynchronizationRegistry tranRegistry) {
+ this.tranRegistry = tranRegistry;
+ }
+
+ /**
+ * Returns true if we have access to a {@link TransactionSynchronizationRegistry} and
+ * can manage persistence contexts
+ * @return
+ */
+ public final boolean jtaIntegrationAvailable()
+ {
+ return registryAvailable.get();
+ }
+
+ /**
+ * Called by the blueprint container to indicate that a new {@link TransactionSynchronizationRegistry}
+ * will be used by the runtime
+ * @param ref
+ */
+ public final void addRegistry(ServiceReference ref) {
+ boolean oldValue = registryAvailable.getAndSet(true);
+ if(oldValue) {
+ _logger.warn("The TransactionSynchronizationRegistry used to manage persistence contexts has been replaced." +
+ " The new TransactionSynchronizationRegistry, {}, will now be used to manage persistence contexts." +
+ " Managed persistence contexts may not work correctly unless the runtime uses the new JTA Transaction services implementation" +
+ " to manage transactions.", new Object[] {ref});
+ } else {
+ _logger.info("A TransactionSynchronizationRegistry service is now available in the runtime. Managed persistence contexts will now" +
+ "integrate with JTA transactions using {}.", new Object[] {ref});
+ }
+ }
+
+ public final void removeRegistry(ServiceReference ref) {
+ registryAvailable.set(false);
+ _logger.warn("The TransactionSynchronizationRegistry used to manage persistence contexts is no longer available." +
+ " Managed persistence contexts will no longer be able to integrate with JTA transactions, and will behave as if" +
+ " no there is no transaction context at all times until a new TransactionSynchronizationRegistry is available." +
+ " Applications using managed persistence contexts may not work correctly until a new JTA Transaction services" +
+ " implementation is available.");
+ }
+
+ /**
+ * This class is used to close EntityManager instances once the transaction has committed,
+ * and clear the persistenceContextRegistry of old persistence contexts.
+ */
+ private final static class EntityManagerClearUp implements Synchronization {
+
+ private final EntityManager context;
+
+ /**
+ * Create a Synchronization to clear up our EntityManagers
+ * @param em
+ */
+ public EntityManagerClearUp(EntityManager em)
+ {
+ context = em;
+ }
+
+ public final void beforeCompletion() {
+ //This is a no-op;
+ }
+
+ @SuppressWarnings("unchecked")
+ public final void afterCompletion(int arg0) {
+ if(_logger.isDebugEnabled())
+ _logger.debug("Clearing up EntityManager {} as the transaction has completed.", new Object[] {context});
+ try {
+ context.close();
+ } catch (Exception e) {
+ _logger.warn("There was an error when the container closed an EntityManager", context);
+ }
+ }
+ }
+}
Added: aries/tags/jpa-0.1-incubating/jpa-container-context/src/main/resources/OSGI-INF/blueprint/jpa.xml
URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-container-context/src/main/resources/OSGI-INF/blueprint/jpa.xml?rev=1075099&view=auto
==============================================================================
--- aries/tags/jpa-0.1-incubating/jpa-container-context/src/main/resources/OSGI-INF/blueprint/jpa.xml (added)
+++ aries/tags/jpa-0.1-incubating/jpa-container-context/src/main/resources/OSGI-INF/blueprint/jpa.xml Sun Feb 27 18:08:10 2011
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+
+ <service interface="org.apache.aries.jpa.container.context.PersistenceContextProvider" ref="persistenceManager"/>
+
+ <bean id="persistenceManager" class="org.apache.aries.jpa.container.context.impl.GlobalPersistenceManager">
+ <property name="registry" ref="JtaPersistenceContextRegistry" />
+ </bean>
+
+ <bean id="JtaPersistenceContextRegistry"
+ class="org.apache.aries.jpa.container.context.transaction.impl.JTAPersistenceContextRegistry">
+ <property name="tranRegistry">
+ <reference interface="javax.transaction.TransactionSynchronizationRegistry" availability="optional">
+ <reference-listener ref="JtaPersistenceContextRegistry" bind-method="addRegistry" unbind-method="removeRegistry"/>
+ </reference>
+ </property>
+ </bean>
+
+</blueprint>
\ No newline at end of file
Added: aries/tags/jpa-0.1-incubating/jpa-container-context/src/test/java/org/apache/aries/jpa/container/context/impl/PersistenceContextManagerTest.java
URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-container-context/src/test/java/org/apache/aries/jpa/container/context/impl/PersistenceContextManagerTest.java?rev=1075099&view=auto
==============================================================================
--- aries/tags/jpa-0.1-incubating/jpa-container-context/src/test/java/org/apache/aries/jpa/container/context/impl/PersistenceContextManagerTest.java (added)
+++ aries/tags/jpa-0.1-incubating/jpa-container-context/src/test/java/org/apache/aries/jpa/container/context/impl/PersistenceContextManagerTest.java Sun Feb 27 18:08:10 2011
@@ -0,0 +1,288 @@
+/*
+ * 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.context.impl;
+
+import static java.lang.Boolean.TRUE;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import java.util.HashMap;
+import java.util.Hashtable;
+
+import javax.persistence.EntityManagerFactory;
+
+import org.apache.aries.jpa.container.PersistenceUnitConstants;
+import org.apache.aries.jpa.container.context.PersistenceContextProvider;
+import org.apache.aries.mocks.BundleContextMock;
+import org.apache.aries.mocks.BundleMock;
+import org.apache.aries.unittest.mocks.Skeleton;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.framework.Version;
+
+
+public class PersistenceContextManagerTest {
+
+ private BundleContext context;
+ private PersistenceContextManager mgr;
+
+ private EntityManagerFactory emf1;
+ private EntityManagerFactory emf2;
+
+ private ServiceRegistration reg1;
+ private ServiceRegistration reg2;
+
+ private Bundle client1;
+ private Bundle client2;
+
+ @Before
+ public void setUp()
+ {
+ client1 = Skeleton.newMock(Bundle.class);
+ client2 = Skeleton.newMock(Bundle.class);
+ emf1 = Skeleton.newMock(EntityManagerFactory.class);
+ emf2 = Skeleton.newMock(EntityManagerFactory.class);
+ context = Skeleton.newMock(new BundleMock("system.bundle", new Hashtable<Object, Object>()), Bundle.class).getBundleContext();
+ mgr = new PersistenceContextManager(context, null);
+ mgr.open();
+ }
+
+ @After
+ public void tearDown()
+ {
+ BundleContextMock.clear();
+ }
+
+ /**
+ * A simple test to show we get a service registered when a unit
+ * is registered first.
+ *
+ * @throws InvalidSyntaxException
+ */
+ @Test
+ public void testUnitThenContext() throws InvalidSyntaxException
+ {
+ String unitName = "unit";
+
+ reg1 = registerUnit(emf1, unitName, TRUE);
+
+ assertNoContextRegistered();
+
+ mgr.registerContext(unitName, client1, new HashMap<String, Object>());
+
+ assertContextRegistered(unitName);
+ }
+
+ /**
+ * A simple test to show we get a service unregistered when a context
+ * is removed.
+ *
+ * @throws InvalidSyntaxException
+ */
+ @Test
+ public void testUnitThenContextThenRemoveContext() throws InvalidSyntaxException
+ {
+ testUnitThenContext();
+ mgr.unregisterContext("unit", client1);
+
+ assertNoContextRegistered();
+ }
+
+ /**
+ * A simple test to show we get a service unregistered when a unit
+ * is removed.
+ *
+ * @throws InvalidSyntaxException
+ */
+ @Test
+ public void testUnitThenContextThenRemoveUnit() throws InvalidSyntaxException
+ {
+ testUnitThenContext();
+ reg1.unregister();
+
+ assertNoContextRegistered();
+ }
+
+ /**
+ * A simple test to show we get a service registered when a context
+ * is registered first.
+ *
+ * @throws InvalidSyntaxException
+ */
+ @Test
+ public void testContextThenUnit() throws InvalidSyntaxException
+ {
+ String unitName = "unit";
+
+ mgr.registerContext(unitName, client1, new HashMap<String, Object>());
+
+ assertNoContextRegistered();
+
+ reg1 = registerUnit(emf1, unitName, TRUE);
+
+ assertContextRegistered(unitName);
+ }
+
+ /**
+ * A simple test to show we get a service unregistered when a context
+ * is removed.
+ *
+ * @throws InvalidSyntaxException
+ */
+ @Test
+ public void testContextThenUnitThenRemoveContext() throws InvalidSyntaxException
+ {
+ testContextThenUnit();
+ mgr.unregisterContext("unit", client1);
+
+ assertNoContextRegistered();
+ }
+
+ /**
+ * A simple test to show we get a service unregistered when a unit
+ * is removed.
+ *
+ * @throws InvalidSyntaxException
+ */
+ @Test
+ public void testContextThenUnitThenRemoveUnit() throws InvalidSyntaxException
+ {
+ testContextThenUnit();
+ reg1.unregister();
+
+ assertNoContextRegistered();
+ }
+
+ /**
+ * Test that we don't register a service when the unit and
+ * context don't match
+ */
+ @Test
+ public void testAddDifferentContext() throws InvalidSyntaxException
+ {
+ reg1 = registerUnit(emf1, "unit", TRUE);
+
+ assertNoContextRegistered();
+
+ mgr.registerContext("context", client1, new HashMap<String, Object>());
+
+ assertNoContextRegistered();
+ }
+
+ /**
+ * Test that we don't unregister a service when a different context is
+ * removed
+ * @throws InvalidSyntaxException
+ */
+ @Test
+ public void testRemoveDifferentContext() throws InvalidSyntaxException
+ {
+ testAddDifferentContext();
+
+ mgr.registerContext("unit", client1, new HashMap<String, Object>());
+
+ assertContextRegistered("unit");
+
+ mgr.unregisterContext("context", client1);
+
+ assertContextRegistered("unit");
+ }
+
+ /**
+ * Test that we don't unregister a service when a different unit is
+ * removed
+ * @throws InvalidSyntaxException
+ */
+ @Test
+ public void testRemoveDifferentUnit() throws InvalidSyntaxException
+ {
+ testAddDifferentContext();
+ reg2 = registerUnit(emf2, "context", TRUE);
+ assertContextRegistered("context");
+ reg1.unregister();
+ assertContextRegistered("context");
+ reg2.unregister();
+ assertNoContextRegistered();
+ }
+
+ /**
+ * Test that we cope when multiple clients consume the same context
+ * @throws InvalidSyntaxException
+ */
+ @Test
+ public void testMultipleClients() throws InvalidSyntaxException
+ {
+ testContextThenUnit();
+
+ mgr.registerContext("unit", client2, new HashMap<String, Object>());
+ assertContextRegistered("unit");
+
+ mgr.unregisterContext("unit", client1);
+ assertContextRegistered("unit");
+
+ mgr.unregisterContext("unit", client2);
+ assertNoContextRegistered();
+ }
+
+
+ private ServiceRegistration registerUnit(EntityManagerFactory emf, String name, Boolean managed) {
+
+ Hashtable<String, Object> props = new Hashtable<String, Object>();
+
+ if(name != null)
+ props.put(PersistenceUnitConstants.OSGI_UNIT_NAME, name);
+
+ if(managed)
+ props.put(PersistenceUnitConstants.CONTAINER_MANAGED_PERSISTENCE_UNIT, managed);
+
+ props.put(PersistenceUnitConstants.OSGI_UNIT_PROVIDER, "some.provider.Name");
+ props.put(PersistenceUnitConstants.OSGI_UNIT_VERSION, new Version("1.0.0"));
+
+ return context.registerService(
+ EntityManagerFactory.class.getName(), emf, props);
+ }
+
+ private void assertNoContextRegistered() throws InvalidSyntaxException {
+ ServiceReference[] refs = context.getServiceReferences(EntityManagerFactory.class.getName(), "("+PersistenceContextProvider.PROXY_FACTORY_EMF_ATTRIBUTE+"=*)");
+
+ assertNull(refs);
+ }
+
+ private void assertContextRegistered(String name) throws InvalidSyntaxException {
+ BundleContextMock.assertServiceExists(EntityManagerFactory.class.getName());
+
+ ServiceReference[] refs = context.getServiceReferences(EntityManagerFactory.class.getName(), "("+PersistenceContextProvider.PROXY_FACTORY_EMF_ATTRIBUTE+"=*)");
+
+ assertEquals("Too many EntityManagerFactories", 1, refs.length);
+
+ assertEquals("Wrong unit name", name, refs[0].getProperty(PersistenceUnitConstants.OSGI_UNIT_NAME));
+
+ assertEquals("Wrong provider name", "some.provider.Name", refs[0].getProperty(PersistenceUnitConstants.OSGI_UNIT_PROVIDER));
+
+ assertEquals("Wrong unit version", new Version("1.0.0"), refs[0].getProperty(PersistenceUnitConstants.OSGI_UNIT_VERSION));
+
+ assertEquals("Unit should be managed", Boolean.TRUE, refs[0].getProperty(PersistenceUnitConstants.CONTAINER_MANAGED_PERSISTENCE_UNIT));
+ }
+}
Added: aries/tags/jpa-0.1-incubating/jpa-container-context/src/test/java/org/apache/aries/jpa/container/context/transaction/impl/JTAPersistenceContextRegistryTest.java
URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-container-context/src/test/java/org/apache/aries/jpa/container/context/transaction/impl/JTAPersistenceContextRegistryTest.java?rev=1075099&view=auto
==============================================================================
--- aries/tags/jpa-0.1-incubating/jpa-container-context/src/test/java/org/apache/aries/jpa/container/context/transaction/impl/JTAPersistenceContextRegistryTest.java (added)
+++ aries/tags/jpa-0.1-incubating/jpa-container-context/src/test/java/org/apache/aries/jpa/container/context/transaction/impl/JTAPersistenceContextRegistryTest.java Sun Feb 27 18:08:10 2011
@@ -0,0 +1,258 @@
+/*
+ * 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.context.transaction.impl;
+
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.TransactionRequiredException;
+import javax.transaction.Status;
+import javax.transaction.Synchronization;
+import javax.transaction.TransactionSynchronizationRegistry;
+
+import org.apache.aries.unittest.mocks.MethodCall;
+import org.apache.aries.unittest.mocks.Skeleton;
+import org.junit.Before;
+import org.junit.Test;
+
+public class JTAPersistenceContextRegistryTest {
+
+ private static class TranSyncRegistryMock
+ {
+ private String key;
+
+ private Map<String, List<Synchronization>> syncs = new HashMap<String, List<Synchronization>>();
+
+ private Map<String, Map<Object,Object>> resources = new HashMap<String, Map<Object,Object>>();
+
+ public void setTransactionKey(String s)
+ {
+ key = s;
+ }
+
+ public Object getTransactionKey() {
+ return key;
+ }
+
+ public void registerInterposedSynchronization(Synchronization arg0) {
+ List<Synchronization> list = syncs.get(key);
+ if(list == null) {
+ list = new ArrayList<Synchronization>();
+ syncs.put(key, list);
+ }
+ list.add(arg0);
+ }
+
+ public Object getResource(Object o) {
+ Object toReturn = null;
+ Map<Object, Object> map = resources.get(key);
+ if(map != null)
+ toReturn = map.get(o);
+ return toReturn;
+ }
+
+ public void putResource(Object resourceKey, Object value) {
+ Map<Object, Object> map = resources.get(key);
+ if(map == null) {
+ map = new HashMap<Object, Object>();
+ resources.put(key, map);
+ }
+ map.put(resourceKey, value);
+ }
+
+
+ public void afterCompletion(String s)
+ {
+ for(Synchronization sync : syncs.get(s))
+ sync.afterCompletion(Status.STATUS_COMMITTED);
+
+ resources.remove(s);
+ }
+ }
+
+ private TranSyncRegistryMock reg;
+
+ private EntityManagerFactory emf1;
+ private Map<Object,Object> props1;
+ private EntityManagerFactory emf2;
+ private Map<Object,Object> props2;
+
+ private JTAPersistenceContextRegistry contexts;
+
+ @Before
+ public void setup()
+ {
+ reg = new TranSyncRegistryMock();
+
+ props1 = new HashMap<Object, Object>();
+ props1.put("prop1", "value1");
+
+ props2 = new HashMap<Object, Object>();
+ props2.put("prop2", "value2");
+
+ emf1 = Skeleton.newMock(EntityManagerFactory.class);
+
+ Skeleton.getSkeleton(emf1).setReturnValue(new MethodCall(EntityManagerFactory.class,
+ "createEntityManager", props1), Skeleton.newMock(EntityManager.class));
+ Skeleton.getSkeleton(emf1).setReturnValue(new MethodCall(EntityManagerFactory.class,
+ "createEntityManager", props2), Skeleton.newMock(EntityManager.class));
+
+ emf2 = Skeleton.newMock(EntityManagerFactory.class);
+
+ Skeleton.getSkeleton(emf2).setReturnValue(new MethodCall(EntityManagerFactory.class,
+ "createEntityManager", props1), Skeleton.newMock(EntityManager.class));
+ Skeleton.getSkeleton(emf2).setReturnValue(new MethodCall(EntityManagerFactory.class,
+ "createEntityManager", props2), Skeleton.newMock(EntityManager.class));
+
+
+ contexts = new JTAPersistenceContextRegistry();
+ contexts.setTranRegistry(Skeleton.newMock(reg, TransactionSynchronizationRegistry.class));
+ contexts.addRegistry(null);
+ }
+
+ @Test
+ public void testIsTranActive()
+ {
+ reg.setTransactionKey(null);
+
+ assertFalse(contexts.isTransactionActive());
+
+ reg.setTransactionKey("");
+
+ assertTrue(contexts.isTransactionActive());
+ }
+
+ @Test
+ public void testMultiGetsOneTran()
+ {
+ reg.setTransactionKey("");
+
+ EntityManager em1a = contexts.getCurrentPersistenceContext(emf1, props1);
+ EntityManager em1b = contexts.getCurrentPersistenceContext(emf1, props1);
+
+ Skeleton.getSkeleton(emf1).assertCalledExactNumberOfTimes(new MethodCall(EntityManagerFactory.class, "createEntityManager", props1), 1);
+ Skeleton.getSkeleton(emf1).assertNotCalled(new MethodCall(EntityManagerFactory.class, "createEntityManager"));
+ Skeleton.getSkeleton(em1a).assertNotCalled(new MethodCall(EntityManager.class, "close"));
+ assertSame("We should get the same delegate!", em1a, em1b);
+
+ EntityManager em2a = contexts.getCurrentPersistenceContext(emf2, props1);
+ EntityManager em2b = contexts.getCurrentPersistenceContext(emf2, props1);
+
+ Skeleton.getSkeleton(emf2).assertCalledExactNumberOfTimes(new MethodCall(EntityManagerFactory.class, "createEntityManager", props1), 1);
+ Skeleton.getSkeleton(emf2).assertNotCalled(new MethodCall(EntityManagerFactory.class, "createEntityManager"));
+ Skeleton.getSkeleton(em2a).assertNotCalled(new MethodCall(EntityManager.class, "close"));
+ assertSame("We should get the same delegate!", em2a, em2b);
+
+ reg.afterCompletion("");
+
+ Skeleton.getSkeleton(em1a).assertCalledExactNumberOfTimes(new MethodCall(EntityManager.class, "close"),1);
+ Skeleton.getSkeleton(em2a).assertCalledExactNumberOfTimes(new MethodCall(EntityManager.class, "close"),1);
+ }
+
+ @Test
+ public void testMultiGetsMultiTrans()
+ {
+ reg.setTransactionKey("a");
+ EntityManager em1a = contexts.getCurrentPersistenceContext(emf1, props1);
+ reg.setTransactionKey("b");
+ EntityManager em1b = contexts.getCurrentPersistenceContext(emf1, props2);
+
+ Skeleton.getSkeleton(emf1).assertCalledExactNumberOfTimes(new MethodCall(EntityManagerFactory.class, "createEntityManager", props1), 1);
+ Skeleton.getSkeleton(emf1).assertCalledExactNumberOfTimes(new MethodCall(EntityManagerFactory.class, "createEntityManager", props2), 1);
+
+ assertNotSame("We should not get the same delegate!", em1a, em1b);
+
+ Skeleton.getSkeleton(em1a).assertNotCalled(new MethodCall(EntityManager.class, "close"));
+ Skeleton.getSkeleton(em1b).assertNotCalled(new MethodCall(EntityManager.class, "close"));
+
+ reg.setTransactionKey("a");
+ EntityManager em2a = contexts.getCurrentPersistenceContext(emf2, props1);
+ reg.setTransactionKey("b");
+ EntityManager em2b = contexts.getCurrentPersistenceContext(emf2, props2);
+
+ Skeleton.getSkeleton(emf2).assertCalledExactNumberOfTimes(new MethodCall(EntityManagerFactory.class, "createEntityManager", props1), 1);
+ Skeleton.getSkeleton(emf2).assertCalledExactNumberOfTimes(new MethodCall(EntityManagerFactory.class, "createEntityManager", props2), 1);
+
+ assertNotSame("We should get the same delegate!", em2a, em2b);
+
+ Skeleton.getSkeleton(em2a).assertNotCalled(new MethodCall(EntityManager.class, "close"));
+ Skeleton.getSkeleton(em2b).assertNotCalled(new MethodCall(EntityManager.class, "close"));
+
+ reg.setTransactionKey("b");
+ reg.afterCompletion("b");
+
+ Skeleton.getSkeleton(em1a).assertNotCalled(new MethodCall(EntityManager.class, "close"));
+ Skeleton.getSkeleton(em1b).assertCalledExactNumberOfTimes(new MethodCall(EntityManager.class, "close"), 1);
+ Skeleton.getSkeleton(em2a).assertNotCalled(new MethodCall(EntityManager.class, "close"));
+ Skeleton.getSkeleton(em2b).assertCalledExactNumberOfTimes(new MethodCall(EntityManager.class, "close"), 1);
+
+ reg.setTransactionKey("a");
+ reg.afterCompletion("a");
+
+ Skeleton.getSkeleton(em1a).assertCalledExactNumberOfTimes(new MethodCall(EntityManager.class, "close"), 1);
+ Skeleton.getSkeleton(em1b).assertCalledExactNumberOfTimes(new MethodCall(EntityManager.class, "close"), 1);
+ Skeleton.getSkeleton(em2a).assertCalledExactNumberOfTimes(new MethodCall(EntityManager.class, "close"), 1);
+ Skeleton.getSkeleton(em2b).assertCalledExactNumberOfTimes(new MethodCall(EntityManager.class, "close"), 1);
+ }
+
+ @Test
+ public void testNoTranSyncRegistry() {
+ JTAPersistenceContextRegistry registry = new JTAPersistenceContextRegistry();
+ //blueprint will still call our setter
+ TransactionSynchronizationRegistry tranSyncReg = Skeleton.newMock(reg, TransactionSynchronizationRegistry.class);
+ registry.setTranRegistry(tranSyncReg);
+
+ reg.setTransactionKey(null);
+
+ assertFalse(registry.jtaIntegrationAvailable());
+ assertFalse(registry.isTransactionActive());
+
+ Skeleton.getSkeleton(tranSyncReg).assertSkeletonNotCalled();
+
+ reg.setTransactionKey("");
+
+ assertFalse(registry.jtaIntegrationAvailable());
+ assertFalse(registry.isTransactionActive());
+
+ Skeleton.getSkeleton(tranSyncReg).assertSkeletonNotCalled();
+ }
+
+ @Test(expected=TransactionRequiredException.class)
+ public void testGetNoTran() {
+ reg.setTransactionKey(null);
+ contexts.getCurrentPersistenceContext(emf1, props1);
+ }
+
+ @Test(expected=TransactionRequiredException.class)
+ public void testGetNoTranSyncRegistry() {
+ reg.setTransactionKey("");
+ contexts.removeRegistry(null);
+ contexts.getCurrentPersistenceContext(emf1, props1);
+ }
+
+}
Added: aries/tags/jpa-0.1-incubating/jpa-container-itest/pom.xml
URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-container-itest/pom.xml?rev=1075099&view=auto
==============================================================================
--- aries/tags/jpa-0.1-incubating/jpa-container-itest/pom.xml (added)
+++ aries/tags/jpa-0.1-incubating/jpa-container-itest/pom.xml Sun Feb 27 18:08:10 2011
@@ -0,0 +1,229 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>jpa</artifactId>
+ <groupId>org.apache.aries.jpa</groupId>
+ <version>0.1-incubating</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>org.apache.aries.jpa.container.itest</artifactId>
+ <name>Aries JPA iTests</name>
+ <!--
+
+ For adding EclipseLink as a provider
+
+ <repositories>
+ <repository>
+ <id>EclipseLink Repo</id>
+ <url>http://www.eclipse.org/downloads/download.php?r=1&nf=1&file=/rt/eclipselink/maven.repo</url>
+ </repository>
+ </repositories>
+ -->
+
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.logging</groupId>
+ <artifactId>pax-logging-api</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.logging</groupId>
+ <artifactId>pax-logging-service</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-container-default</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.aries</groupId>
+ <artifactId>org.apache.aries.util</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.aries.blueprint</groupId>
+ <artifactId>org.apache.aries.blueprint</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.url</groupId>
+ <artifactId>pax-url-mvn</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.configadmin</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.geronimo.specs</groupId>
+ <artifactId>geronimo-jpa_2.0_spec</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <artifactId>org.apache.aries.jpa.api</artifactId>
+ <groupId>org.apache.aries.jpa</groupId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.aries.jpa</groupId>
+ <artifactId>org.apache.aries.jpa.container</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.aries.jpa</groupId>
+ <artifactId>org.apache.aries.jpa.container.context</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.aries.jpa</groupId>
+ <artifactId>org.apache.aries.jpa.blueprint.aries</artifactId>
+ <!--<scope>test</scope>-->
+ </dependency>
+ <!--
+
+ For adding EclipseLink as a provider
+
+ <dependency>
+ <groupId>org.eclipse.persistence</groupId>
+ <artifactId>org.eclipse.persistence.jpa</artifactId>
+ <version>2.0.0</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.persistence</groupId>
+ <artifactId>org.eclipse.persistence.core</artifactId>
+ <version>2.0.0</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.persistence</groupId>
+ <artifactId>org.eclipse.persistence.asm</artifactId>
+ <version>2.0.0</version>
+ <scope>test</scope>
+ </dependency>
+ -->
+ <dependency>
+ <groupId>org.apache.openjpa</groupId>
+ <artifactId>openjpa</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.geronimo.specs</groupId>
+ <artifactId>geronimo-jta_1.1_spec</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>commons-lang</groupId>
+ <artifactId>commons-lang</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>commons-collections</groupId>
+ <artifactId>commons-collections</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>commons-pool</groupId>
+ <artifactId>commons-pool</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.servicemix.bundles</groupId>
+ <artifactId>org.apache.servicemix.bundles.serp</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.aries.jpa</groupId>
+ <artifactId>org.apache.aries.jpa.container.itest.bundle</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.aries.jpa</groupId>
+ <artifactId>org.apache.aries.jpa.blueprint.itest.bundle</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.servicemix.tooling</groupId>
+ <artifactId>depends-maven-plugin</artifactId>
+ <version>1.1</version>
+ <executions>
+ <execution>
+ <id>generate-depends-file</id>
+ <goals>
+ <goal>generate-depends-file</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>ci-build-profile</id>
+ <activation>
+ <property>
+ <name>maven.repo.local</name>
+ </property>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <!--
+ when the local repo location has been specified, we need
+ to pass on this information to PAX mvn url
+ -->
+ <argLine>-Dorg.ops4j.pax.url.mvn.localRepository=${maven.repo.local}
+ </argLine>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+</project>
Added: aries/tags/jpa-0.1-incubating/jpa-container-itest/src/test/java/org/apache/aries/jpa/blueprint/aries/itest/JPAInjectionTest.java
URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-container-itest/src/test/java/org/apache/aries/jpa/blueprint/aries/itest/JPAInjectionTest.java?rev=1075099&view=auto
==============================================================================
--- aries/tags/jpa-0.1-incubating/jpa-container-itest/src/test/java/org/apache/aries/jpa/blueprint/aries/itest/JPAInjectionTest.java (added)
+++ aries/tags/jpa-0.1-incubating/jpa-container-itest/src/test/java/org/apache/aries/jpa/blueprint/aries/itest/JPAInjectionTest.java Sun Feb 27 18:08:10 2011
@@ -0,0 +1,189 @@
+/* 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.blueprint.aries.itest;
+
+import static org.junit.Assert.assertTrue;
+import static org.ops4j.pax.exam.CoreOptions.equinox;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+import static org.ops4j.pax.exam.CoreOptions.wrappedBundle;
+import static org.ops4j.pax.exam.OptionUtils.combine;
+
+import org.apache.aries.jpa.blueprint.itest.JPATestBean;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.CoreOptions;
+import org.ops4j.pax.exam.Inject;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.ops4j.pax.exam.options.BootDelegationOption;
+import org.ops4j.pax.exam.options.MavenArtifactProvisionOption;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.Version;
+import org.osgi.util.tracker.ServiceTracker;
+
+@RunWith(JUnit4TestRunner.class)
+public class JPAInjectionTest {
+ public static final long DEFAULT_TIMEOUT = 30000;
+
+ @Inject
+ protected BundleContext bundleContext;
+
+ @Test
+ public void findResources() throws Exception {
+ JPATestBean bean = getOsgiService(JPATestBean.class);
+
+ assertTrue("No persistence unit injection", bean.pUnitAvailable());
+ assertTrue("No persistence context injection", bean.pContextAvailable());
+ }
+
+ @org.ops4j.pax.exam.junit.Configuration
+ public static Option[] configuration() {
+ Option[] options = options(
+ bootDelegation(),
+
+ // Log
+ mavenBundle("org.ops4j.pax.logging", "pax-logging-api"),
+ mavenBundle("org.ops4j.pax.logging", "pax-logging-service"),
+ // Felix Config Admin
+ mavenBundle("org.apache.felix", "org.apache.felix.configadmin"),
+ // Felix mvn url handler
+ mavenBundle("org.ops4j.pax.url", "pax-url-mvn"),
+
+ // this is how you set the default log level when using pax
+ // logging (logProfile)
+ systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("DEBUG"),
+
+ // Bundles
+ mavenBundle("org.osgi", "org.osgi.compendium"),
+ mavenBundle("org.apache.aries", "org.apache.aries.util"),
+ mavenBundle("org.apache.aries.blueprint", "org.apache.aries.blueprint"),
+ mavenBundle("org.apache.geronimo.specs", "geronimo-jpa_2.0_spec"),
+ mavenBundle("org.apache.aries.jpa", "org.apache.aries.jpa.api"),
+ mavenBundle("org.apache.aries.jpa", "org.apache.aries.jpa.container"),
+ mavenBundle("org.apache.aries.jpa", "org.apache.aries.jpa.container.context"),
+ mavenBundle("org.apache.aries.jpa", "org.apache.aries.jpa.blueprint.aries"),
+ mavenBundle("org.apache.geronimo.specs", "geronimo-jta_1.1_spec"),
+ mavenBundle("commons-lang", "commons-lang"),
+ mavenBundle("commons-collections", "commons-collections"),
+ mavenBundle("commons-pool", "commons-pool"),
+ mavenBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.serp"),
+ mavenBundle("org.apache.openjpa", "openjpa"),
+
+// mavenBundle("org.eclipse.persistence", "org.eclipse.persistence.jpa"),
+// mavenBundle("org.eclipse.persistence", "org.eclipse.persistence.core"),
+// mavenBundle("org.eclipse.persistence", "org.eclipse.persistence.asm"),
+
+ mavenBundle("org.apache.aries.jpa", "org.apache.aries.jpa.blueprint.itest.bundle"),
+
+ equinox().version("3.5.0"));
+ options = updateOptions(options);
+ return options;
+ }
+
+
+ protected Bundle getBundle(String symbolicName) {
+ return getBundle(symbolicName, null);
+ }
+
+ protected Bundle getBundle(String bundleSymbolicName, String version) {
+ Bundle result = null;
+ for (Bundle b : bundleContext.getBundles()) {
+ if (b.getSymbolicName().equals(bundleSymbolicName)) {
+ if (version == null
+ || b.getVersion().equals(Version.parseVersion(version))) {
+ result = b;
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
+ public static BootDelegationOption bootDelegation() {
+ return new BootDelegationOption("org.apache.aries.unittest.fixture");
+ }
+
+ public static MavenArtifactProvisionOption mavenBundle(String groupId,
+ String artifactId) {
+ return CoreOptions.mavenBundle().groupId(groupId).artifactId(artifactId)
+ .versionAsInProject();
+ }
+
+ protected static Option[] updateOptions(Option[] options) {
+ // We need to add pax-exam-junit here when running with the ibm
+ // jdk to avoid the following exception during the test run:
+ // ClassNotFoundException: org.ops4j.pax.exam.junit.Configuration
+ if ("IBM Corporation".equals(System.getProperty("java.vendor"))) {
+ Option[] ibmOptions = options(wrappedBundle(mavenBundle(
+ "org.ops4j.pax.exam", "pax-exam-junit")));
+ options = combine(ibmOptions, options);
+ }
+
+ return options;
+ }
+
+ protected <T> T getOsgiService(Class<T> type, long timeout) {
+ return getOsgiService(type, null, timeout);
+ }
+
+ protected <T> T getOsgiService(Class<T> type) {
+ return getOsgiService(type, null, DEFAULT_TIMEOUT);
+ }
+
+ protected <T> T getOsgiService(Class<T> type, String filter, long timeout) {
+ return getOsgiService(null, type, filter, timeout);
+ }
+
+ protected <T> T getOsgiService(BundleContext bc, Class<T> type,
+ String filter, long timeout) {
+ ServiceTracker tracker = null;
+ try {
+ String flt;
+ if (filter != null) {
+ if (filter.startsWith("(")) {
+ flt = "(&(" + Constants.OBJECTCLASS + "=" + type.getName() + ")"
+ + filter + ")";
+ } else {
+ flt = "(&(" + Constants.OBJECTCLASS + "=" + type.getName() + ")("
+ + filter + "))";
+ }
+ } else {
+ flt = "(" + Constants.OBJECTCLASS + "=" + type.getName() + ")";
+ }
+ Filter osgiFilter = FrameworkUtil.createFilter(flt);
+ tracker = new ServiceTracker(bc == null ? bundleContext : bc, osgiFilter,
+ null);
+ tracker.open();
+ // Note that the tracker is not closed to keep the reference
+ // This is buggy, has the service reference may change i think
+ Object svc = type.cast(tracker.waitForService(timeout));
+ if (svc == null) {
+ throw new RuntimeException("Gave up waiting for service " + flt);
+ }
+ return type.cast(svc);
+ } catch (InvalidSyntaxException e) {
+ throw new IllegalArgumentException("Invalid filter", e);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}