You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by ti...@apache.org on 2010/08/05 13:13:56 UTC
svn commit: r982543 [1/2] - in /incubator/aries/trunk/jpa: ./
jpa-container-context/
jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/
jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction...
Author: timothyjward
Date: Thu Aug 5 11:13:55 2010
New Revision: 982543
URL: http://svn.apache.org/viewvc?rev=982543&view=rev
Log:
ARIES-374 - JPA Persistence context quiesce support
Added:
incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/QuiesceParticipantImpl.java
incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/DestroyCallback.java
incubator/aries/trunk/jpa/jpa-container-context/src/test/java/org/apache/aries/jpa/container/context/transaction/impl/TranSyncRegistryMock.java
incubator/aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/quiesce/
incubator/aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/quiesce/itest/
incubator/aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/quiesce/itest/QuiesceJPAContextTest.java
incubator/aries/trunk/jpa/jpa-container-testbundle/src/main/resources/META-INF/
incubator/aries/trunk/jpa/jpa-container-testbundle/src/main/resources/META-INF/persistence.xml
Removed:
incubator/aries/trunk/jpa/jpa-container-context/src/main/resources/OSGI-INF/
incubator/aries/trunk/jpa/jpa-container-testbundle/src/main/resources/OSGI-INF/
Modified:
incubator/aries/trunk/jpa/jpa-container-context/pom.xml
incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/GlobalPersistenceManager.java
incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/ManagedPersistenceContextFactory.java
incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/PersistenceContextManager.java
incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAEntityManager.java
incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAPersistenceContextRegistry.java
incubator/aries/trunk/jpa/jpa-container-context/src/test/java/org/apache/aries/jpa/container/context/impl/GlobalPersistenceManagerTest.java
incubator/aries/trunk/jpa/jpa-container-context/src/test/java/org/apache/aries/jpa/container/context/impl/PersistenceContextManagerTest.java
incubator/aries/trunk/jpa/jpa-container-context/src/test/java/org/apache/aries/jpa/container/context/transaction/impl/JTAPersistenceContextRegistryTest.java
incubator/aries/trunk/jpa/jpa-container-itest/pom.xml
incubator/aries/trunk/jpa/jpa-container-testbundle/pom.xml
incubator/aries/trunk/jpa/pom.xml
Modified: incubator/aries/trunk/jpa/jpa-container-context/pom.xml
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container-context/pom.xml?rev=982543&r1=982542&r2=982543&view=diff
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container-context/pom.xml (original)
+++ incubator/aries/trunk/jpa/jpa-container-context/pom.xml Thu Aug 5 11:13:55 2010
@@ -28,6 +28,13 @@
<name>Aries JPA Container Managed Contexts</name>
<packaging>bundle</packaging>
+ <properties>
+ <aries.osgi.activator>
+ org.apache.aries.jpa.container.context.impl.GlobalPersistenceManager
+ </aries.osgi.activator>
+
+ </properties>
+
<dependencies>
<dependency>
<groupId>org.osgi</groupId>
@@ -60,6 +67,11 @@
<scope>provided</scope>
</dependency>
<dependency>
+ <groupId>org.apache.aries.quiesce</groupId>
+ <artifactId>org.apache.aries.quiesce.api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
@@ -94,6 +106,8 @@
javax.persistence.criteria;version="[1.1.0,2.1.0)";resolution:=optional,
javax.persistence.metamodel;version="[1.1.0,2.1.0)";resolution:=optional,
org.apache.aries.jpa.container.context;version="[0.1.0,1.1.0)",
+ org.apache.aries.quiesce.manager;version="[0.2,0.3)";resolution:=optional,
+ org.apache.aries.quiesce.participant;version="[0.2,0.3)";resolution:=optional,
*
</Import-Package>
<_versionpolicy>[$(version;==;$(@)),$(version;+;$(@)))</_versionpolicy>
Modified: incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/GlobalPersistenceManager.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/GlobalPersistenceManager.java?rev=982543&r1=982542&r2=982543&view=diff
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/GlobalPersistenceManager.java (original)
+++ incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/GlobalPersistenceManager.java Thu Aug 5 11:13:55 2010
@@ -18,15 +18,22 @@
*/
package org.apache.aries.jpa.container.context.impl;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
+import java.util.Map.Entry;
import org.apache.aries.jpa.container.context.PersistenceContextProvider;
+import org.apache.aries.jpa.container.context.transaction.impl.DestroyCallback;
import org.apache.aries.jpa.container.context.transaction.impl.JTAPersistenceContextRegistry;
import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
+import org.osgi.framework.ServiceRegistration;
import org.osgi.framework.SynchronousBundleListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -34,7 +41,10 @@ import org.slf4j.LoggerFactory;
/**
* Class that coordinates PersistenceContextManagers across multiple (nested) OSGi frameworks.
*/
-public class GlobalPersistenceManager implements PersistenceContextProvider, SynchronousBundleListener {
+public class GlobalPersistenceManager implements PersistenceContextProvider, SynchronousBundleListener, BundleActivator {
+ /** The QuiesceParticipant implementation class name */
+ private static final String QUIESCE_PARTICIPANT_CLASS = "org.apache.aries.quiesce.participant.QuiesceParticipant";
+
/** Logger */
private static final Logger _logger = LoggerFactory.getLogger("org.apache.aries.jpa.container.context");
@@ -54,12 +64,14 @@ public class GlobalPersistenceManager im
*/
private Map<Bundle, Set<String>> persistenceContexts =
new HashMap<Bundle, Set<String>>();
-
- public void setRegistry(JTAPersistenceContextRegistry registry) {
- this.registry = registry;
- }
-
+ /** The registration for the quiesce participant */
+ private ServiceRegistration quiesceReg;
+ /** The registration for the persistence context manager */
+ private ServiceRegistration pcpReg;
+ /** Our bundle */
+ private Bundle bundle;
+
public void registerContext(String unitName, Bundle client, HashMap<String, Object> properties) {
if (_logger.isDebugEnabled()) {
_logger.debug("Registering bundle {} as a client of persistence unit {} with properties {}.",
@@ -167,4 +179,107 @@ public class GlobalPersistenceManager im
}
}
+ /**
+ * Quiesce the supplied bundle
+ * @param bundleToQuiesce
+ * @param callback
+ */
+ public void quiesceBundle(Bundle bundleToQuiesce, final DestroyCallback callback) {
+ //If this is our bundle then get all the managers to clean up everything
+ if(bundleToQuiesce == bundle) {
+ unregister(pcpReg);
+ pcpReg = null;
+ final Collection<Entry<Bundle, PersistenceContextManager>> mgrs = new ArrayList<Entry<Bundle, PersistenceContextManager>>();
+ synchronized (this) {
+ mgrs.addAll(managers.entrySet());
+ }
+
+ if(managers.isEmpty())
+ callback.callback();
+ else {
+ final GlobalPersistenceManager gpm = this;
+ //A special callback to say we're done when everyone has replied!
+ DestroyCallback destroy = new DestroyCallback() {
+ int count = mgrs.size();
+ public void callback() {
+ count--;
+ if(count == 0) {
+ for(Entry<Bundle, PersistenceContextManager> entry : mgrs){
+ BundleContext ctx = entry.getKey().getBundleContext();
+ if(ctx != null) {
+ ctx.removeBundleListener(gpm);
+ }
+ }
+ callback.callback();
+ }
+ }
+ };
+ for (Entry<Bundle, PersistenceContextManager> entry : mgrs)
+ entry.getValue().quiesceAllUnits(destroy);
+ }
+ } else {
+ //Just quiesce the one bundle
+ Bundle frameworkBundle = bundleToQuiesce.getBundleContext().getBundle(0);
+ PersistenceContextManager mgr = managers.get(frameworkBundle);
+
+ //If there is no manager for this framework, then we aren't managing the bundle
+ //and can stop now
+ if(mgr == null) {
+ callback.callback();
+ } else {
+ mgr.quiesceUnits(bundleToQuiesce, callback);
+ }
+ }
+ }
+
+ public void start(BundleContext context) throws Exception {
+
+ bundle = context.getBundle();
+ registry = new JTAPersistenceContextRegistry(context);
+
+ //Register our service
+ pcpReg = context.registerService(PersistenceContextProvider.class.getName(), this, null);
+
+ try{
+ context.getBundle().loadClass(QUIESCE_PARTICIPANT_CLASS);
+ //Class was loaded, register
+
+ quiesceReg = context.registerService(QUIESCE_PARTICIPANT_CLASS,
+ new QuiesceParticipantImpl(this), null);
+ } catch (ClassNotFoundException e) {
+ _logger.info("No quiesce support is available, so persistence contexts will not participate in quiesce operations", e);
+ }
+ }
+
+ public void stop(BundleContext context) throws Exception {
+ //Clean up
+ unregister(pcpReg);
+ unregister(quiesceReg);
+ Collection<PersistenceContextManager> mgrs = new ArrayList<PersistenceContextManager>();
+ synchronized (persistenceContexts) {
+ mgrs.addAll(managers.values());
+ }
+
+ for(PersistenceContextManager mgr : mgrs)
+ mgr.close();
+
+ registry.close();
+ }
+
+ /**
+ * Clean up a registration without throwing an exception
+ * @param reg
+ */
+ private void unregister(ServiceRegistration reg) {
+ if(reg != null)
+ try {
+ reg.unregister();
+ } catch (IllegalStateException ise) {
+ //we don't care
+ }
+ }
+
+ public Bundle getBundle() {
+ return bundle;
+ }
}
Modified: incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/ManagedPersistenceContextFactory.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/ManagedPersistenceContextFactory.java?rev=982543&r1=982542&r2=982543&view=diff
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/ManagedPersistenceContextFactory.java (original)
+++ incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/ManagedPersistenceContextFactory.java Thu Aug 5 11:13:55 2010
@@ -20,7 +20,9 @@ package org.apache.aries.jpa.container.c
import java.util.HashMap;
import java.util.Map;
-import java.util.Properties;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
import javax.persistence.Cache;
import javax.persistence.EntityManager;
@@ -31,6 +33,8 @@ import javax.persistence.criteria.Criter
import javax.persistence.metamodel.Metamodel;
import org.apache.aries.jpa.container.context.PersistenceContextProvider;
+import org.apache.aries.jpa.container.context.impl.PersistenceContextManager.QuiesceTidyUp;
+import org.apache.aries.jpa.container.context.transaction.impl.DestroyCallback;
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;
@@ -41,8 +45,10 @@ import org.slf4j.LoggerFactory;
* 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.
+ *
+ * Also this class receives a callback on cleanup
*/
-public class ManagedPersistenceContextFactory implements EntityManagerFactory {
+public class ManagedPersistenceContextFactory implements EntityManagerFactory, DestroyCallback {
/** Logger */
private static final Logger _logger = LoggerFactory.getLogger("org.apache.aries.jpa.container.context");
@@ -50,10 +56,15 @@ public class ManagedPersistenceContextFa
private final Map<String, Object> properties;
private final JTAPersistenceContextRegistry registry;
private final PersistenceContextType type;
-
- public ManagedPersistenceContextFactory(ServiceReference unit,
+ private final AtomicBoolean quiesce = new AtomicBoolean(false);
+ private final AtomicLong activeCount = new AtomicLong(0);
+ private final String unitName;
+
+ private final AtomicReference<QuiesceTidyUp> tidyUp = new AtomicReference<QuiesceTidyUp>();
+
+ public ManagedPersistenceContextFactory(String name, ServiceReference unit,
Map<String, Object> props, JTAPersistenceContextRegistry contextRegistry) {
-
+ unitName = name;
emf = unit;
//Take a copy of the Map so that we don't modify the original
properties = new HashMap<String, Object>(props);
@@ -70,7 +81,7 @@ public class ManagedPersistenceContextFa
EntityManagerFactory factory = (EntityManagerFactory) emf.getBundle().getBundleContext().getService(emf);
if(type == PersistenceContextType.TRANSACTION || type == null)
- return new JTAEntityManager(factory, properties, registry);
+ return new JTAEntityManager(factory, properties, registry, activeCount, this);
else {
_logger.error("There is currently no support for extended scope EntityManagers");
return null;
@@ -110,4 +121,25 @@ public class ManagedPersistenceContextFa
throw new UnsupportedOperationException();
}
+ /**
+ * Register an async Quiesce operation with this peristence context
+ * @param tidyUp
+ */
+ public void quiesce(QuiesceTidyUp tidyUp) {
+ this.tidyUp.set(tidyUp);
+ quiesce.set(true);
+ if(activeCount.get() == 0) {
+ tidyUp.unitQuiesced(unitName);
+ }
+ }
+
+ /**
+ * Quiesce this unit after the last context is destroyed
+ */
+ public void callback() {
+ if(quiesce.get() && activeCount.get() == 0) {
+ tidyUp.get().unitQuiesced(unitName);
+ }
+ }
+
}
Modified: incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/PersistenceContextManager.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/PersistenceContextManager.java?rev=982543&r1=982542&r2=982543&view=diff
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/PersistenceContextManager.java (original)
+++ incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/PersistenceContextManager.java Thu Aug 5 11:13:55 2010
@@ -18,17 +18,23 @@
*/
package org.apache.aries.jpa.container.context.impl;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.Map.Entry;
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.DestroyCallback;
import org.apache.aries.jpa.container.context.transaction.impl.JTAPersistenceContextRegistry;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
@@ -268,7 +274,7 @@ public class PersistenceContextManager e
}
//Create the service factory
- entityManagerServiceFactory = new ManagedPersistenceContextFactory(unit, props, persistenceContextRegistry);
+ entityManagerServiceFactory = new ManagedPersistenceContextFactory(name, unit, props, persistenceContextRegistry);
}
//Always register from outside a synchronized
@@ -397,4 +403,117 @@ public class PersistenceContextManager e
public void open() {
super.open(true);
}
+
+ /**
+ * Call this method to quiesce a given bundle
+ * @param bundleToQuiesce The bundle to quiesce
+ * @param callback A callback indicating that we have finished quiescing
+ */
+ public void quiesceUnits(Bundle bundleToQuiesce, DestroyCallback callback) {
+
+ //Find the units supplied by this bundle
+ List<String> units = new ArrayList<String>();
+ synchronized (this) {
+ Iterator<Entry<String, ServiceReference>> it = persistenceUnits.entrySet().iterator();
+ while(it.hasNext()) {
+ Entry<String, ServiceReference> entry = it.next();
+ ServiceReference value = entry.getValue();
+ //If the quiescing bundle supplies the unit then unget the unit and remove it
+ if(value.getBundle().equals(bundleToQuiesce)) {
+ units.add(entry.getKey());
+ context.ungetService(entry.getValue());
+ //remove it to prevent other units that start using it
+ it.remove();
+ }
+ }
+ }
+ //If there are no units then our work is done!
+ if(units.isEmpty()) {
+ callback.callback();
+ } else {
+ //Find the ManagedFactories for the persistence unit
+ List<ManagedPersistenceContextFactory> factoriesToQuiesce = new ArrayList<ManagedPersistenceContextFactory>();
+ synchronized (this) {
+ for(String name : units) {
+ ServiceRegistration reg = entityManagerRegistrations.get(name);
+ if(reg != null) {
+ ManagedPersistenceContextFactory fact = (ManagedPersistenceContextFactory) bundleToQuiesce.getBundleContext().getService(reg.getReference());
+ if(fact != null)
+ factoriesToQuiesce.add(fact);
+ }
+ }
+ }
+ //If no factories are registered then we're done
+ if(factoriesToQuiesce.isEmpty()) {
+ callback.callback();
+ } else {
+ //Create a new Tidy up helper and tell the factories to tidy up
+ QuiesceTidyUp tidyUp = new QuiesceTidyUp(units, callback);
+
+ for(ManagedPersistenceContextFactory fact : factoriesToQuiesce) {
+ fact.quiesce(tidyUp);
+ }
+ }
+ }
+ }
+
+ /**
+ * Quiesce all the persistence units managed by this {@link PersistenceContextManager}
+ * @param callback
+ */
+ public void quiesceAllUnits(final DestroyCallback callback) {
+
+ Collection<String> names = new ArrayList<String>();
+ Collection<ServiceRegistration> factoriesToQuiesce = new ArrayList<ServiceRegistration>();
+
+ //Get all the resources
+ synchronized (this) {
+ names.addAll(entityManagerRegistrations.keySet());
+ factoriesToQuiesce.addAll(entityManagerRegistrations.values());
+ }
+ //If there are no names or factories then we're done
+ if(names.isEmpty() || factoriesToQuiesce.isEmpty()) {
+ callback.callback();
+ } else {
+
+ //Register an async tidy up
+ QuiesceTidyUp tidyUp = new QuiesceTidyUp(names, callback);
+
+ for(ServiceRegistration reg : factoriesToQuiesce) {
+ ManagedPersistenceContextFactory fact = (ManagedPersistenceContextFactory) reg.getReference().getBundle().getBundleContext().getService(reg.getReference());
+ fact.quiesce(tidyUp);
+ }
+ }
+ }
+
+ /**
+ * An asynchronous tidy up operation
+ */
+ class QuiesceTidyUp {
+ //The units being tidied up
+ private final Set<String> units;
+ //The callback for when we're done
+ private final DestroyCallback dc;
+
+ public QuiesceTidyUp(Collection<String> units,
+ DestroyCallback callback) {
+ this.units = new HashSet<String>(units);
+ dc = callback;
+ }
+
+ public void unitQuiesced(String name) {
+ unregisterEM(name);
+ boolean winner;
+ synchronized(this) {
+ winner = units.remove(name) && units.isEmpty();
+ }
+
+ if(winner) {
+ dc.callback();
+ }
+ }
+ }
+
+
+
}
Added: incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/QuiesceParticipantImpl.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/QuiesceParticipantImpl.java?rev=982543&view=auto
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/QuiesceParticipantImpl.java (added)
+++ incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/QuiesceParticipantImpl.java Thu Aug 5 11:13:55 2010
@@ -0,0 +1,137 @@
+/**
+ * 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 java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.aries.jpa.container.context.transaction.impl.DestroyCallback;
+import org.apache.aries.quiesce.manager.QuiesceCallback;
+import org.apache.aries.quiesce.participant.QuiesceParticipant;
+import org.osgi.framework.Bundle;
+
+/**
+ * This class provides Quiesce Participant support for JPA managed contexts. It is the only
+ * class in this bundle that depends on the Quiesce API to make sure that the bundle can
+ * optionally depend on the API. If no Quiesce API is available then this class will not be
+ * loaded and no Quiesce support will be available.
+ */
+public class QuiesceParticipantImpl implements QuiesceParticipant, DestroyCallback {
+
+ /**
+ * A wrapper to protect our internals from the Quiesce API so that we can make it
+ * an optional dependency
+ */
+ private static final class QuiesceDelegatingCallback implements DestroyCallback {
+
+ /** The callback to delegate to */
+ private final QuiesceCallback callback;
+
+ /** The single bundle being quiesced by this DestroyCallback */
+ private final Bundle toQuiesce;
+
+ public QuiesceDelegatingCallback(QuiesceCallback cbk, Bundle b) {
+ callback = cbk;
+ toQuiesce = b;
+ }
+
+ public void callback() {
+ callback.bundleQuiesced(toQuiesce);
+ }
+
+ }
+
+ /**
+ * A runnable Quiesce operation for a single bundle
+ */
+ private static final class QuiesceBundle implements Runnable {
+
+ /** The callback when we're done */
+ private final DestroyCallback callback;
+ /** The bundle being quiesced */
+ private final Bundle bundleToQuiesce;
+ /** The GlobalPersistenceManager instance */
+ private final GlobalPersistenceManager mgr;
+
+ public QuiesceBundle(QuiesceCallback callback, Bundle bundleToQuiesce,
+ GlobalPersistenceManager mgr) {
+ super();
+ this.callback = new QuiesceDelegatingCallback(callback, bundleToQuiesce);
+ this.bundleToQuiesce = bundleToQuiesce;
+ this.mgr = mgr;
+ }
+
+ public void run() {
+ mgr.quiesceBundle(bundleToQuiesce, callback);
+ }
+ }
+
+ /**
+ * A Threadpool for running quiesce operations
+ */
+ private final ExecutorService executor = new ThreadPoolExecutor(0, 10, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new ThreadFactory() {
+
+ public Thread newThread(Runnable r) {
+ Thread t = new Thread(r, "JPA-Context-ThreadPool");
+ t.setDaemon(true);
+ return t;
+ }
+ });
+
+ /** The Global manager for persistence contexts */
+ private final GlobalPersistenceManager mgr;
+
+
+ public QuiesceParticipantImpl(GlobalPersistenceManager mgr) {
+ this.mgr = mgr;
+ }
+
+
+ public void quiesce(QuiesceCallback qc, List<Bundle> arg1) {
+ //Run a quiesce operation for each bundle being quiesced
+ for(Bundle b : arg1) {
+ try {
+ executor.execute(new QuiesceBundle(qc, b, mgr));
+ } catch (RejectedExecutionException re) {
+
+ }
+ //If we are quiescing, then we need to quiesce this threadpool!
+ if(b.equals(mgr.getBundle()))
+ executor.shutdown();
+ }
+ }
+
+ /**
+ * Close down this object
+ */
+ public void callback() {
+ executor.shutdown();
+ try {
+ executor.awaitTermination(10, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ //We don't care
+ }
+ executor.shutdownNow();
+ }
+}
Added: incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/DestroyCallback.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/DestroyCallback.java?rev=982543&view=auto
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/DestroyCallback.java (added)
+++ incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/DestroyCallback.java Thu Aug 5 11:13:55 2010
@@ -0,0 +1,26 @@
+/**
+ * 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;
+
+/**
+ * A callback to indicate that a destroy operation has completed
+ */
+public interface DestroyCallback {
+ public void callback();
+}
Modified: incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAEntityManager.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAEntityManager.java?rev=982543&r1=982542&r2=982543&view=diff
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAEntityManager.java (original)
+++ incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAEntityManager.java Thu Aug 5 11:13:55 2010
@@ -19,6 +19,7 @@
package org.apache.aries.jpa.container.context.transaction.impl;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
@@ -48,6 +49,12 @@ public class JTAEntityManager implements
private final Map<String, Object> props;
/** A registry for creating new persistence contexts */
private final JTAPersistenceContextRegistry reg;
+ /** The number of EntityManager instances that are open */
+ private final AtomicLong instanceCount;
+ /** A callback for when we're quiescing */
+ private final DestroyCallback callback;
+
+
/**
* The entity manager to use when there is no transaction. Note that there is one of these
* per injection site.
@@ -55,10 +62,13 @@ public class JTAEntityManager implements
private EntityManager detachedManager = null;
public JTAEntityManager(EntityManagerFactory factory,
- Map<String, Object> properties, JTAPersistenceContextRegistry registry) {
+ Map<String, Object> properties, JTAPersistenceContextRegistry registry, AtomicLong activeCount,
+ DestroyCallback onDestroy) {
emf = factory;
props = properties;
reg = registry;
+ instanceCount = activeCount;
+ callback = onDestroy;
}
/**
@@ -70,10 +80,10 @@ public class JTAEntityManager implements
private EntityManager getPersistenceContext(boolean forceTransaction)
{
if (forceTransaction) {
- return reg.getCurrentPersistenceContext(emf, props);
+ return reg.getCurrentPersistenceContext(emf, props, instanceCount, callback);
} else {
if (reg.isTransactionActive()) {
- return reg.getCurrentPersistenceContext(emf, props);
+ return reg.getCurrentPersistenceContext(emf, props, instanceCount, callback);
} else {
if(!!!reg.jtaIntegrationAvailable() && _logger.isDebugEnabled())
_logger.debug("No integration with JTA transactions is available. No transaction context is active.");
Modified: incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAPersistenceContextRegistry.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAPersistenceContextRegistry.java?rev=982543&r1=982542&r2=982543&view=diff
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAPersistenceContextRegistry.java (original)
+++ incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAPersistenceContextRegistry.java Thu Aug 5 11:13:55 2010
@@ -20,7 +20,8 @@ package org.apache.aries.jpa.container.c
import java.util.IdentityHashMap;
import java.util.Map;
-import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
@@ -28,14 +29,16 @@ import javax.persistence.TransactionRequ
import javax.transaction.Synchronization;
import javax.transaction.TransactionSynchronizationRegistry;
+import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class is used to manage the lifecycle of JTA peristence contexts
*/
-public final class JTAPersistenceContextRegistry {
+public final class JTAPersistenceContextRegistry extends ServiceTracker {
/** Logger */
private static final Logger _logger = LoggerFactory.getLogger("org.apache.aries.jpa.container.context");
/** The unique key we use to find our Map */
@@ -62,13 +65,15 @@ public final class JTAPersistenceContext
* The transaction synchronization registry, used to determine the currently
* active transaction, and to register for post-commit cleanup.
*/
- private TransactionSynchronizationRegistry tranRegistry;
+ private final AtomicReference<TransactionSynchronizationRegistry> tranRegistry = new AtomicReference<TransactionSynchronizationRegistry>();
- /**
- * 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();
+ /** The reference for our TSR service */
+ private AtomicReference<ServiceReference> tranRegistryRef = new AtomicReference<ServiceReference>();
+
+ public JTAPersistenceContextRegistry(BundleContext context) {
+ super(context, TransactionSynchronizationRegistry.class.getName(), null);
+ open();
+ }
/**
* Get a PersistenceContext for the current transaction. The persistence context will
@@ -77,13 +82,17 @@ public final class JTAPersistenceContext
* @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.
+ * @param activeCount The AtomicLong for counting instances
+ * @param cbk A callback called when the instance is destroyed
*
* @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
+ public final EntityManager getCurrentPersistenceContext(
+ EntityManagerFactory persistenceUnit, Map<?,?> properties, AtomicLong activeCount,
+ DestroyCallback cbk) 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.
@@ -98,11 +107,11 @@ public final class JTAPersistenceContext
}
}
EntityManager toReturn = null;
-
+ TransactionSynchronizationRegistry tsr = tranRegistry.get();
//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);
+ Map<EntityManagerFactory, EntityManager> contextsForTransaction = (Map<EntityManagerFactory, EntityManager>) tsr.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) {
@@ -110,10 +119,10 @@ public final class JTAPersistenceContext
} else {
contextsForTransaction = new IdentityHashMap<EntityManagerFactory, EntityManager>();
try {
- tranRegistry.putResource(EMF_MAP_KEY, contextsForTransaction);
+ tsr.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());
+ _logger.warn("Unable to create a persistence context for the transaction {} because the is not active", new Object[] {tsr.getTransactionKey()});
+ throw new TransactionRequiredException("Unable to assiociate resources with transaction " + tsr.getTransactionKey());
}
}
@@ -121,18 +130,19 @@ public final class JTAPersistenceContext
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()});
+ _logger.debug("Created a new persistence context {} for transaction {}.", new Object[] {toReturn, tsr.getTransactionKey()});
try {
- tranRegistry.registerInterposedSynchronization(new EntityManagerClearUp(toReturn));
+ tsr.registerInterposedSynchronization(new EntityManagerClearUp(toReturn, activeCount, cbk));
} 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()});
+ _logger.warn("No persistence context could be created as the JPA container could not register a synchronization with the transaction {}.", new Object[] {tsr.getTransactionKey()});
toReturn.close();
- throw new TransactionRequiredException("Unable to synchronize with transaction " + tranRegistry.getTransactionKey());
+ throw new TransactionRequiredException("Unable to synchronize with transaction " + tsr.getTransactionKey());
}
contextsForTransaction.put(persistenceUnit, toReturn);
+ activeCount.incrementAndGet();
} else {
if(_logger.isDebugEnabled())
- _logger.debug("Re-using a persistence context for transaction " + tranRegistry.getTransactionKey());
+ _logger.debug("Re-using a persistence context for transaction " + tsr.getTransactionKey());
}
return toReturn;
}
@@ -143,15 +153,8 @@ public final class JTAPersistenceContext
*/
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;
+ TransactionSynchronizationRegistry tsr = tranRegistry.get();
+ return tsr != null && tsr.getTransactionKey() != null;
}
/**
@@ -161,34 +164,93 @@ public final class JTAPersistenceContext
*/
public final boolean jtaIntegrationAvailable()
{
- return registryAvailable.get();
+ return tranRegistry.get() != null;
}
/**
- * Called by the blueprint container to indicate that a new {@link TransactionSynchronizationRegistry}
- * will be used by the runtime
+ * Called by service tracker to indicate that a new {@link TransactionSynchronizationRegistry}
+ * is available in 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});
+ @Override
+ public final Object addingService(ServiceReference ref) {
+
+ if(tranRegistryRef.compareAndSet(null, ref))
+ {
+ TransactionSynchronizationRegistry tsr = (TransactionSynchronizationRegistry) context.getService(ref);
+ if(tsr != null) {
+ if(tranRegistry.compareAndSet(null, tsr)) {
+ _logger.info("A TransactionSynchronizationRegistry service is now available in the runtime. Managed persistence contexts will now" +
+ "integrate with JTA transactions using {}.", new Object[] {ref});
+ }
+ else
+ {
+ tranRegistry.set(tsr);
+ _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 {
+ tranRegistryRef.compareAndSet(ref, null);
+ }
}
+ return 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.");
+ @Override
+ public final void removedService(ServiceReference reference, Object o) {
+ if(tranRegistryRef.get() == reference) {
+ //Our reference is going away, find a new one
+ ServiceReference[] refs = getServiceReferences();
+ ServiceReference chosenRef = null;
+ TransactionSynchronizationRegistry replacement = null;
+ if(refs != null) {
+ for(ServiceReference ref : refs) {
+ if(ref != reference) {
+ replacement = (TransactionSynchronizationRegistry) context.getService(ref);
+ if(replacement != null) {
+ chosenRef = ref;
+ break;
+ }
+ }
+ }
+ }
+
+ if(replacement == null) {
+ TransactionSynchronizationRegistry old = tranRegistry.get();
+ tranRegistryRef.set(null);
+ tranRegistry.compareAndSet(old, null);
+
+ _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.");
+ } else {
+ tranRegistryRef.set(chosenRef);
+ tranRegistry.set(replacement);
+ _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[] {chosenRef});
+ }
+ context.ungetService(reference);
+ //If there was no replacement before, check again. This closes the short window if
+ //add and remove happen simultaneously
+ if(replacement == null) {
+ ServiceReference[] retryRefs = getServiceReferences();
+ if(refs != null) {
+ for(ServiceReference r : retryRefs) {
+ if(r != reference) {
+ addingService(r);
+ if(tranRegistryRef.get() != null)
+ break;
+ }
+ }
+ }
+ }
+ }
}
/**
@@ -199,13 +261,19 @@ public final class JTAPersistenceContext
private final EntityManager context;
+ private final AtomicLong activeCount;
+
+ private final DestroyCallback callback;
+
/**
* Create a Synchronization to clear up our EntityManagers
* @param em
*/
- public EntityManagerClearUp(EntityManager em)
+ public EntityManagerClearUp(EntityManager em, AtomicLong instanceCount, DestroyCallback cbk)
{
context = em;
+ activeCount = instanceCount;
+ callback = cbk;
}
public final void beforeCompletion() {
@@ -217,10 +285,16 @@ public final class JTAPersistenceContext
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);
+ activeCount.decrementAndGet();
+ callback.callback();
+ } finally {
+ try{
+ context.close();
+ } catch (Exception e) {
+ _logger.warn("There was an error when the container closed an EntityManager", context);
+ }
}
}
}
+
}
Modified: incubator/aries/trunk/jpa/jpa-container-context/src/test/java/org/apache/aries/jpa/container/context/impl/GlobalPersistenceManagerTest.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container-context/src/test/java/org/apache/aries/jpa/container/context/impl/GlobalPersistenceManagerTest.java?rev=982543&r1=982542&r2=982543&view=diff
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container-context/src/test/java/org/apache/aries/jpa/container/context/impl/GlobalPersistenceManagerTest.java (original)
+++ incubator/aries/trunk/jpa/jpa-container-context/src/test/java/org/apache/aries/jpa/container/context/impl/GlobalPersistenceManagerTest.java Thu Aug 5 11:13:55 2010
@@ -45,7 +45,7 @@ public class GlobalPersistenceManagerTes
private Bundle framework;
@Before
- public void setup()
+ public void setup() throws Exception
{
framework = Skeleton.newMock(new BundleMock("framework", new Hashtable<Object, Object>()), Bundle.class);
@@ -59,8 +59,7 @@ public class GlobalPersistenceManagerTes
Skeleton.getSkeleton(otherClient).setReturnValue(new MethodCall(Bundle.class, "getBundleContext"), ctx);
sut = new GlobalPersistenceManager();
- sut.setRegistry(new JTAPersistenceContextRegistry());
-
+ sut.start(ctx);
Skeleton.getSkeleton(framework.getBundleContext()).setReturnValue(
new MethodCall(BundleContext.class, "getBundles"), new Bundle[] {framework, client, otherClient});
}
Modified: incubator/aries/trunk/jpa/jpa-container-context/src/test/java/org/apache/aries/jpa/container/context/impl/PersistenceContextManagerTest.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container-context/src/test/java/org/apache/aries/jpa/container/context/impl/PersistenceContextManagerTest.java?rev=982543&r1=982542&r2=982543&view=diff
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container-context/src/test/java/org/apache/aries/jpa/container/context/impl/PersistenceContextManagerTest.java (original)
+++ incubator/aries/trunk/jpa/jpa-container-context/src/test/java/org/apache/aries/jpa/container/context/impl/PersistenceContextManagerTest.java Thu Aug 5 11:13:55 2010
@@ -26,11 +26,16 @@ import java.util.HashMap;
import java.util.Hashtable;
import javax.persistence.EntityManagerFactory;
+import javax.transaction.TransactionSynchronizationRegistry;
import org.apache.aries.jpa.container.PersistenceUnitConstants;
import org.apache.aries.jpa.container.context.PersistenceContextProvider;
+import org.apache.aries.jpa.container.context.transaction.impl.DestroyCallback;
+import org.apache.aries.jpa.container.context.transaction.impl.JTAPersistenceContextRegistry;
+import org.apache.aries.jpa.container.context.transaction.impl.TranSyncRegistryMock;
import org.apache.aries.mocks.BundleContextMock;
import org.apache.aries.mocks.BundleMock;
+import org.apache.aries.unittest.mocks.MethodCall;
import org.apache.aries.unittest.mocks.Skeleton;
import org.junit.After;
import org.junit.Before;
@@ -65,7 +70,7 @@ public class PersistenceContextManagerTe
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 = new PersistenceContextManager(context, new JTAPersistenceContextRegistry(context));
mgr.open();
}
@@ -92,7 +97,7 @@ public class PersistenceContextManagerTe
mgr.registerContext(unitName, client1, new HashMap<String, Object>());
- assertContextRegistered(unitName);
+ assertUniqueContextRegistered(unitName);
}
/**
@@ -142,7 +147,7 @@ public class PersistenceContextManagerTe
reg1 = registerUnit(emf1, unitName, TRUE);
- assertContextRegistered(unitName);
+ assertUniqueContextRegistered(unitName);
}
/**
@@ -203,11 +208,11 @@ public class PersistenceContextManagerTe
mgr.registerContext("unit", client1, new HashMap<String, Object>());
- assertContextRegistered("unit");
+ assertUniqueContextRegistered("unit");
mgr.unregisterContext("context", client1);
- assertContextRegistered("unit");
+ assertUniqueContextRegistered("unit");
}
/**
@@ -220,9 +225,9 @@ public class PersistenceContextManagerTe
{
testAddDifferentContext();
reg2 = registerUnit(emf2, "context", TRUE);
- assertContextRegistered("context");
+ assertUniqueContextRegistered("context");
reg1.unregister();
- assertContextRegistered("context");
+ assertUniqueContextRegistered("context");
reg2.unregister();
assertNoContextRegistered();
}
@@ -237,15 +242,272 @@ public class PersistenceContextManagerTe
testContextThenUnit();
mgr.registerContext("unit", client2, new HashMap<String, Object>());
- assertContextRegistered("unit");
+ assertUniqueContextRegistered("unit");
mgr.unregisterContext("unit", client1);
- assertContextRegistered("unit");
+ assertUniqueContextRegistered("unit");
mgr.unregisterContext("unit", client2);
assertNoContextRegistered();
}
+ /**
+ * Test that we can quiesce an unused context
+ * @throws InvalidSyntaxException
+ */
+ @Test
+ public void testNoOpQuiesce() throws InvalidSyntaxException
+ {
+ DestroyCallback cbk = Skeleton.newMock(DestroyCallback.class);
+ Bundle b = context.getBundle();
+ mgr.quiesceUnits(b, cbk);
+
+ Skeleton.getSkeleton(cbk).assertCalledExactNumberOfTimes(new MethodCall(DestroyCallback.class,
+ "callback"), 1);
+
+ assertNoContextRegistered();
+ }
+
+ /**
+ * Test that we can quiesce an unused context
+ * @throws InvalidSyntaxException
+ */
+ @Test
+ public void testBasicQuiesce() throws InvalidSyntaxException
+ {
+ testContextThenUnit();
+ DestroyCallback cbk = Skeleton.newMock(DestroyCallback.class);
+ Bundle b = context.getBundle();
+ mgr.quiesceUnits(b, cbk);
+
+ Skeleton.getSkeleton(cbk).assertCalledExactNumberOfTimes(new MethodCall(DestroyCallback.class,
+ "callback"), 1);
+
+ assertNoContextRegistered();
+ }
+
+ /**
+ * Test that we can quiesce multiple contexts
+ * @throws InvalidSyntaxException
+ */
+ @Test
+ public void testMultipleContextQuiesce() throws InvalidSyntaxException
+ {
+ assertNoContextRegistered();
+
+ reg1 = registerUnit(emf1, "unit", TRUE);
+ mgr.registerContext("unit", client1, new HashMap<String, Object>());
+
+ reg2 = registerUnit(emf1, "unit2", TRUE);
+ mgr.registerContext("unit2", client2, new HashMap<String, Object>());
+
+ DestroyCallback cbk = Skeleton.newMock(DestroyCallback.class);
+ Bundle b = context.getBundle();
+ mgr.quiesceUnits(b, cbk);
+
+ Skeleton.getSkeleton(cbk).assertCalledExactNumberOfTimes(new MethodCall(DestroyCallback.class,
+ "callback"), 1);
+
+ assertNoContextRegistered();
+ }
+
+ /**
+ * Test that we can quiesce multiple contexts
+ * @throws InvalidSyntaxException
+ */
+ @Test
+ public void testActiveContextsQuiesce() throws InvalidSyntaxException
+ {
+ TranSyncRegistryMock backingTSR = new TranSyncRegistryMock();
+ TransactionSynchronizationRegistry tsr = Skeleton.newMock(backingTSR, TransactionSynchronizationRegistry.class);
+
+ context.registerService(TransactionSynchronizationRegistry.class.getName(), tsr, new Hashtable<String, Object>());
+
+ assertNoContextRegistered();
+
+ reg1 = registerUnit(emf1, "unit", TRUE);
+ mgr.registerContext("unit", client1, new HashMap<String, Object>());
+
+ reg2 = registerUnit(emf2, "unit2", TRUE);
+ mgr.registerContext("unit2", client2, new HashMap<String, Object>());
+
+ ServiceReference[] refs = context.getServiceReferences(EntityManagerFactory.class.getName(),"(&(" +
+ PersistenceContextProvider.PROXY_FACTORY_EMF_ATTRIBUTE + "=true)(osgi.unit.name=unit))");
+
+ assertEquals("Wrong number of services found", 1, refs.length);
+
+ ServiceReference[] refs2 = context.getServiceReferences(EntityManagerFactory.class.getName(),"(&(" +
+ PersistenceContextProvider.PROXY_FACTORY_EMF_ATTRIBUTE + "=true)(osgi.unit.name=unit2))");
+
+ assertEquals("Wrong number of services found", 1, refs2.length);
+
+ EntityManagerFactory emf = (EntityManagerFactory) context.getService(refs[0]);
+
+ EntityManagerFactory emf2 = (EntityManagerFactory) context.getService(refs2[0]);
+
+ backingTSR.setTransactionKey("new");
+
+ emf.createEntityManager().persist(new Object());
+ emf2.createEntityManager().persist(new Object());
+
+
+ DestroyCallback cbk = Skeleton.newMock(DestroyCallback.class);
+ Bundle b = context.getBundle();
+ mgr.quiesceUnits(b, cbk);
+
+ Skeleton.getSkeleton(cbk).assertNotCalled(new MethodCall(DestroyCallback.class,
+ "callback"));
+
+ backingTSR.setTransactionKey("new2");
+
+ emf2.createEntityManager().persist(new Object());
+
+ Skeleton.getSkeleton(cbk).assertNotCalled(new MethodCall(DestroyCallback.class,
+ "callback"));
+
+ backingTSR.afterCompletion("new");
+
+ Skeleton.getSkeleton(cbk).assertNotCalled(new MethodCall(DestroyCallback.class,
+ "callback"));
+
+ assertUniqueContextRegistered("unit2");
+
+ backingTSR.afterCompletion("new2");
+
+ Skeleton.getSkeleton(cbk).assertCalledExactNumberOfTimes(new MethodCall(DestroyCallback.class,
+ "callback"), 1);
+
+ assertNoContextRegistered();
+ }
+
+ /**
+ * Test that we can quiesce an unused context
+ * @throws InvalidSyntaxException
+ */
+ @Test
+ public void testNoOpQuiesceAll() throws InvalidSyntaxException
+ {
+ DestroyCallback cbk = Skeleton.newMock(DestroyCallback.class);
+ Bundle b = context.getBundle();
+ mgr.quiesceAllUnits(cbk);
+
+ Skeleton.getSkeleton(cbk).assertCalledExactNumberOfTimes(new MethodCall(DestroyCallback.class,
+ "callback"), 1);
+
+ assertNoContextRegistered();
+ }
+
+ /**
+ * Test that we can quiesce an unused context
+ * @throws InvalidSyntaxException
+ */
+ @Test
+ public void testBasicQuiesceAll() throws InvalidSyntaxException
+ {
+ testContextThenUnit();
+ DestroyCallback cbk = Skeleton.newMock(DestroyCallback.class);
+ Bundle b = context.getBundle();
+ mgr.quiesceAllUnits(cbk);
+
+ Skeleton.getSkeleton(cbk).assertCalledExactNumberOfTimes(new MethodCall(DestroyCallback.class,
+ "callback"), 1);
+
+ assertNoContextRegistered();
+ }
+
+ /**
+ * Test that we can quiesce multiple contexts
+ * @throws InvalidSyntaxException
+ */
+ @Test
+ public void testMultipleContextQuiesceAll() throws InvalidSyntaxException
+ {
+ assertNoContextRegistered();
+
+ reg1 = registerUnit(emf1, "unit", TRUE);
+ mgr.registerContext("unit", client1, new HashMap<String, Object>());
+
+ reg2 = registerUnit(emf1, "unit2", TRUE);
+ mgr.registerContext("unit2", client2, new HashMap<String, Object>());
+
+ DestroyCallback cbk = Skeleton.newMock(DestroyCallback.class);
+ Bundle b = context.getBundle();
+ mgr.quiesceAllUnits(cbk);
+
+ Skeleton.getSkeleton(cbk).assertCalledExactNumberOfTimes(new MethodCall(DestroyCallback.class,
+ "callback"), 1);
+
+ assertNoContextRegistered();
+ }
+
+ /**
+ * Test that we can quiesce multiple contexts
+ * @throws InvalidSyntaxException
+ */
+ @Test
+ public void testActiveContextsQuiesceAll() throws InvalidSyntaxException
+ {
+ TranSyncRegistryMock backingTSR = new TranSyncRegistryMock();
+ TransactionSynchronizationRegistry tsr = Skeleton.newMock(backingTSR, TransactionSynchronizationRegistry.class);
+
+ context.registerService(TransactionSynchronizationRegistry.class.getName(), tsr, new Hashtable<String, Object>());
+
+ assertNoContextRegistered();
+
+ reg1 = registerUnit(emf1, "unit", TRUE);
+ mgr.registerContext("unit", client1, new HashMap<String, Object>());
+
+ reg2 = registerUnit(emf2, "unit2", TRUE);
+ mgr.registerContext("unit2", client2, new HashMap<String, Object>());
+
+ ServiceReference[] refs = context.getServiceReferences(EntityManagerFactory.class.getName(),"(&(" +
+ PersistenceContextProvider.PROXY_FACTORY_EMF_ATTRIBUTE + "=true)(osgi.unit.name=unit))");
+
+ assertEquals("Wrong number of services found", 1, refs.length);
+
+ ServiceReference[] refs2 = context.getServiceReferences(EntityManagerFactory.class.getName(),"(&(" +
+ PersistenceContextProvider.PROXY_FACTORY_EMF_ATTRIBUTE + "=true)(osgi.unit.name=unit2))");
+
+ assertEquals("Wrong number of services found", 1, refs2.length);
+
+ EntityManagerFactory emf = (EntityManagerFactory) context.getService(refs[0]);
+
+ EntityManagerFactory emf2 = (EntityManagerFactory) context.getService(refs2[0]);
+
+ backingTSR.setTransactionKey("new");
+
+ emf.createEntityManager().persist(new Object());
+ emf2.createEntityManager().persist(new Object());
+
+
+ DestroyCallback cbk = Skeleton.newMock(DestroyCallback.class);
+ Bundle b = context.getBundle();
+ mgr.quiesceAllUnits(cbk);
+
+ Skeleton.getSkeleton(cbk).assertNotCalled(new MethodCall(DestroyCallback.class,
+ "callback"));
+
+ backingTSR.setTransactionKey("new2");
+
+ emf2.createEntityManager().persist(new Object());
+
+ Skeleton.getSkeleton(cbk).assertNotCalled(new MethodCall(DestroyCallback.class,
+ "callback"));
+
+ backingTSR.afterCompletion("new");
+
+ Skeleton.getSkeleton(cbk).assertNotCalled(new MethodCall(DestroyCallback.class,
+ "callback"));
+
+ assertUniqueContextRegistered("unit2");
+
+ backingTSR.afterCompletion("new2");
+
+ Skeleton.getSkeleton(cbk).assertCalledExactNumberOfTimes(new MethodCall(DestroyCallback.class,
+ "callback"), 1);
+
+ assertNoContextRegistered();
+ }
private ServiceRegistration registerUnit(EntityManagerFactory emf, String name, Boolean managed) {
@@ -270,7 +532,7 @@ public class PersistenceContextManagerTe
assertNull(refs);
}
- private void assertContextRegistered(String name) throws InvalidSyntaxException {
+ private void assertUniqueContextRegistered(String name) throws InvalidSyntaxException {
BundleContextMock.assertServiceExists(EntityManagerFactory.class.getName());
ServiceReference[] refs = context.getServiceReferences(EntityManagerFactory.class.getName(), "("+PersistenceContextProvider.PROXY_FACTORY_EMF_ATTRIBUTE+"=*)");
Modified: incubator/aries/trunk/jpa/jpa-container-context/src/test/java/org/apache/aries/jpa/container/context/transaction/impl/JTAPersistenceContextRegistryTest.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container-context/src/test/java/org/apache/aries/jpa/container/context/transaction/impl/JTAPersistenceContextRegistryTest.java?rev=982543&r1=982542&r2=982543&view=diff
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container-context/src/test/java/org/apache/aries/jpa/container/context/transaction/impl/JTAPersistenceContextRegistryTest.java (original)
+++ incubator/aries/trunk/jpa/jpa-container-context/src/test/java/org/apache/aries/jpa/container/context/transaction/impl/JTAPersistenceContextRegistryTest.java Thu Aug 5 11:13:55 2010
@@ -18,83 +18,30 @@
*/
package org.apache.aries.jpa.container.context.transaction.impl;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
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 java.util.concurrent.atomic.AtomicLong;
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;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
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;
@@ -103,11 +50,17 @@ public class JTAPersistenceContextRegist
private Map<Object,Object> props2;
private JTAPersistenceContextRegistry contexts;
+ private BundleContext ctx;
+ private TransactionSynchronizationRegistry tsr;
+
+ private ServiceReference ref;
@Before
public void setup()
{
reg = new TranSyncRegistryMock();
+ tsr = Skeleton.newMock(reg, TransactionSynchronizationRegistry.class);
+ ctx = Skeleton.newMock(BundleContext.class);
props1 = new HashMap<Object, Object>();
props1.put("prop1", "value1");
@@ -130,9 +83,11 @@ public class JTAPersistenceContextRegist
"createEntityManager", props2), Skeleton.newMock(EntityManager.class));
- contexts = new JTAPersistenceContextRegistry();
- contexts.setTranRegistry(Skeleton.newMock(reg, TransactionSynchronizationRegistry.class));
- contexts.addRegistry(null);
+ contexts = new JTAPersistenceContextRegistry(ctx);
+ ref = Skeleton.newMock(ServiceReference.class);
+ Skeleton.getSkeleton(ctx).setReturnValue(new MethodCall(BundleContext.class,
+ "getService", ref), tsr);
+ contexts.addingService(ref);
}
@Test
@@ -150,50 +105,65 @@ public class JTAPersistenceContextRegist
@Test
public void testMultiGetsOneTran()
{
+ AtomicLong useCount = new AtomicLong(0);
+ DestroyCallback cbk = Skeleton.newMock(DestroyCallback.class);
reg.setTransactionKey("");
- EntityManager em1a = contexts.getCurrentPersistenceContext(emf1, props1);
- EntityManager em1b = contexts.getCurrentPersistenceContext(emf1, props1);
+ EntityManager em1a = contexts.getCurrentPersistenceContext(emf1, props1, useCount, cbk);
+ EntityManager em1b = contexts.getCurrentPersistenceContext(emf1, props1, useCount, cbk);
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);
+ assertEquals("Expected only one creation", 1, useCount.get());
+ Skeleton.getSkeleton(cbk).assertSkeletonNotCalled();
- EntityManager em2a = contexts.getCurrentPersistenceContext(emf2, props1);
- EntityManager em2b = contexts.getCurrentPersistenceContext(emf2, props1);
+ EntityManager em2a = contexts.getCurrentPersistenceContext(emf2, props1, useCount, cbk);
+ EntityManager em2b = contexts.getCurrentPersistenceContext(emf2, props1, useCount, cbk);
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);
+ assertEquals("Expected a second creation", 2, useCount.get());
+ Skeleton.getSkeleton(cbk).assertSkeletonNotCalled();
reg.afterCompletion("");
Skeleton.getSkeleton(em1a).assertCalledExactNumberOfTimes(new MethodCall(EntityManager.class, "close"),1);
Skeleton.getSkeleton(em2a).assertCalledExactNumberOfTimes(new MethodCall(EntityManager.class, "close"),1);
+ assertEquals("Expected creations to be uncounted", 0, useCount.get());
+ Skeleton.getSkeleton(cbk).assertCalledExactNumberOfTimes(new MethodCall(DestroyCallback.class,
+ "callback"), 2);
}
@Test
public void testMultiGetsMultiTrans()
{
+ AtomicLong useCount = new AtomicLong(0);
+ DestroyCallback cbk = Skeleton.newMock(DestroyCallback.class);
+
reg.setTransactionKey("a");
- EntityManager em1a = contexts.getCurrentPersistenceContext(emf1, props1);
+ EntityManager em1a = contexts.getCurrentPersistenceContext(emf1, props1, useCount, cbk);
reg.setTransactionKey("b");
- EntityManager em1b = contexts.getCurrentPersistenceContext(emf1, props2);
+ EntityManager em1b = contexts.getCurrentPersistenceContext(emf1, props2, useCount, cbk);
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"));
+ assertEquals("Expected two creations", 2, useCount.get());
+ Skeleton.getSkeleton(cbk).assertSkeletonNotCalled();
+
reg.setTransactionKey("a");
- EntityManager em2a = contexts.getCurrentPersistenceContext(emf2, props1);
+ EntityManager em2a = contexts.getCurrentPersistenceContext(emf2, props1, useCount, cbk);
reg.setTransactionKey("b");
- EntityManager em2b = contexts.getCurrentPersistenceContext(emf2, props2);
+ EntityManager em2b = contexts.getCurrentPersistenceContext(emf2, props2, useCount, cbk);
Skeleton.getSkeleton(emf2).assertCalledExactNumberOfTimes(new MethodCall(EntityManagerFactory.class, "createEntityManager", props1), 1);
Skeleton.getSkeleton(emf2).assertCalledExactNumberOfTimes(new MethodCall(EntityManagerFactory.class, "createEntityManager", props2), 1);
@@ -203,6 +173,9 @@ public class JTAPersistenceContextRegist
Skeleton.getSkeleton(em2a).assertNotCalled(new MethodCall(EntityManager.class, "close"));
Skeleton.getSkeleton(em2b).assertNotCalled(new MethodCall(EntityManager.class, "close"));
+ assertEquals("Expected four creations", 4, useCount.get());
+ Skeleton.getSkeleton(cbk).assertSkeletonNotCalled();
+
reg.setTransactionKey("b");
reg.afterCompletion("b");
@@ -211,6 +184,10 @@ public class JTAPersistenceContextRegist
Skeleton.getSkeleton(em2a).assertNotCalled(new MethodCall(EntityManager.class, "close"));
Skeleton.getSkeleton(em2b).assertCalledExactNumberOfTimes(new MethodCall(EntityManager.class, "close"), 1);
+ assertEquals("Expected two uncreations", 2, useCount.get());
+ Skeleton.getSkeleton(cbk).assertCalledExactNumberOfTimes(new MethodCall(DestroyCallback.class,
+ "callback"), 2);
+
reg.setTransactionKey("a");
reg.afterCompletion("a");
@@ -218,41 +195,55 @@ public class JTAPersistenceContextRegist
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);
+ assertEquals("Expected no remaining instances", 0, useCount.get());
+ Skeleton.getSkeleton(cbk).assertCalledExactNumberOfTimes(new MethodCall(DestroyCallback.class,
+ "callback"), 4);
}
@Test
public void testNoTranSyncRegistry() {
- JTAPersistenceContextRegistry registry = new JTAPersistenceContextRegistry();
- //blueprint will still call our setter
- TransactionSynchronizationRegistry tranSyncReg = Skeleton.newMock(reg, TransactionSynchronizationRegistry.class);
- registry.setTranRegistry(tranSyncReg);
+ JTAPersistenceContextRegistry registry = new JTAPersistenceContextRegistry(ctx);
reg.setTransactionKey(null);
assertFalse(registry.jtaIntegrationAvailable());
assertFalse(registry.isTransactionActive());
- Skeleton.getSkeleton(tranSyncReg).assertSkeletonNotCalled();
+ Skeleton.getSkeleton(tsr).assertSkeletonNotCalled();
reg.setTransactionKey("");
assertFalse(registry.jtaIntegrationAvailable());
assertFalse(registry.isTransactionActive());
- Skeleton.getSkeleton(tranSyncReg).assertSkeletonNotCalled();
+ reg.setTransactionKey(null);
+ contexts.removedService(ref, ref);
+
+ assertFalse(contexts.jtaIntegrationAvailable());
+ assertFalse(contexts.isTransactionActive());
+
+ Skeleton.getSkeleton(tsr).assertSkeletonNotCalled();
+
+ reg.setTransactionKey("");
+
+ assertFalse(contexts.jtaIntegrationAvailable());
+ assertFalse(contexts.isTransactionActive());
+
+
+ Skeleton.getSkeleton(tsr).assertSkeletonNotCalled();
}
@Test(expected=TransactionRequiredException.class)
public void testGetNoTran() {
reg.setTransactionKey(null);
- contexts.getCurrentPersistenceContext(emf1, props1);
+ contexts.getCurrentPersistenceContext(emf1, props1, new AtomicLong(), Skeleton.newMock(DestroyCallback.class));
}
@Test(expected=TransactionRequiredException.class)
public void testGetNoTranSyncRegistry() {
reg.setTransactionKey("");
- contexts.removeRegistry(null);
- contexts.getCurrentPersistenceContext(emf1, props1);
+ contexts.removedService(ref, ref);
+ contexts.getCurrentPersistenceContext(emf1, props1, new AtomicLong(), Skeleton.newMock(DestroyCallback.class));
}
}
Added: incubator/aries/trunk/jpa/jpa-container-context/src/test/java/org/apache/aries/jpa/container/context/transaction/impl/TranSyncRegistryMock.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container-context/src/test/java/org/apache/aries/jpa/container/context/transaction/impl/TranSyncRegistryMock.java?rev=982543&view=auto
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container-context/src/test/java/org/apache/aries/jpa/container/context/transaction/impl/TranSyncRegistryMock.java (added)
+++ incubator/aries/trunk/jpa/jpa-container-context/src/test/java/org/apache/aries/jpa/container/context/transaction/impl/TranSyncRegistryMock.java Thu Aug 5 11:13:55 2010
@@ -0,0 +1,80 @@
+/**
+ * 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 java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.transaction.Status;
+import javax.transaction.Synchronization;
+
+public 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);
+ }
+}
\ No newline at end of file
Modified: incubator/aries/trunk/jpa/jpa-container-itest/pom.xml
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container-itest/pom.xml?rev=982543&r1=982542&r2=982543&view=diff
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container-itest/pom.xml (original)
+++ incubator/aries/trunk/jpa/jpa-container-itest/pom.xml Thu Aug 5 11:13:55 2010
@@ -180,6 +180,46 @@
<artifactId>org.apache.aries.jpa.blueprint.itest.bundle</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.aries.quiesce</groupId>
+ <artifactId>org.apache.aries.quiesce.api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.aries.transaction</groupId>
+ <artifactId>org.apache.aries.transaction.manager</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.aries.transaction</groupId>
+ <artifactId>org.apache.aries.transaction.testds</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.aries.jndi</groupId>
+ <artifactId>org.apache.aries.jndi.api</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.aries.jndi</groupId>
+ <artifactId>org.apache.aries.jndi.core</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.aries.jndi</groupId>
+ <artifactId>org.apache.aries.jndi.url</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.derby</groupId>
+ <artifactId>derby</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.servicemix.bundles</groupId>
+ <artifactId>org.apache.servicemix.bundles.cglib</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>