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/06 16:59:50 UTC
svn commit: r983007 [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-itest/src/test/java/org/apache/aries/jpa/container/itest/
jpa-container-ite...
Author: timothyjward
Date: Fri Aug 6 14:59:49 2010
New Revision: 983007
URL: http://svn.apache.org/viewvc?rev=983007&view=rev
Log:
ARIES-374 - JPA Persistence container quiesce support
Added:
incubator/aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/quiesce/itest/QuiesceJPATest.java
- copied, changed from r982543, incubator/aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/quiesce/itest/QuiesceJPAContextTest.java
incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/CoundownCallback.java
incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/CountingEntityManagerFactory.java
incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/DestroyCallback.java
incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/EntityManagerWrapper.java
incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/QuiesceParticipantImpl.java
incubator/aries/trunk/jpa/jpa-container/src/test/resources/testProps.props
Removed:
incubator/aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/quiesce/itest/QuiesceJPAContextTest.java
incubator/aries/trunk/jpa/jpa-container/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/ManagedPersistenceContextFactory.java
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-itest/src/test/java/org/apache/aries/jpa/container/itest/JPAContainerTest.java
incubator/aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/context/itest/JPAContextTest.java
incubator/aries/trunk/jpa/jpa-container/pom.xml
incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/EntityManagerFactoryManager.java
incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleManager.java
incubator/aries/trunk/jpa/jpa-container/src/test/java/org/apache/aries/jpa/container/PersistenceBundleLifecycleTest.java
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=983007&r1=983006&r2=983007&view=diff
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container-context/pom.xml (original)
+++ incubator/aries/trunk/jpa/jpa-container-context/pom.xml Fri Aug 6 14:59:49 2010
@@ -106,7 +106,7 @@
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.manager;version="[0.2,1.0)";resolution:=optional,
org.apache.aries.quiesce.participant;version="[0.2,0.3)";resolution:=optional,
*
</Import-Package>
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=983007&r1=983006&r2=983007&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 Fri Aug 6 14:59:49 2010
@@ -56,7 +56,6 @@ public class ManagedPersistenceContextFa
private final Map<String, Object> properties;
private final JTAPersistenceContextRegistry registry;
private final PersistenceContextType type;
- private final AtomicBoolean quiesce = new AtomicBoolean(false);
private final AtomicLong activeCount = new AtomicLong(0);
private final String unitName;
@@ -126,8 +125,7 @@ public class ManagedPersistenceContextFa
* @param tidyUp
*/
public void quiesce(QuiesceTidyUp tidyUp) {
- this.tidyUp.set(tidyUp);
- quiesce.set(true);
+ this.tidyUp.compareAndSet(null, tidyUp);
if(activeCount.get() == 0) {
tidyUp.unitQuiesced(unitName);
}
@@ -137,7 +135,7 @@ public class ManagedPersistenceContextFa
* Quiesce this unit after the last context is destroyed
*/
public void callback() {
- if(quiesce.get() && activeCount.get() == 0) {
+ if(tidyUp.get() != null && 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/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=983007&r1=983006&r2=983007&view=diff
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/QuiesceParticipantImpl.java (original)
+++ incubator/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/QuiesceParticipantImpl.java Fri Aug 6 14:59:49 2010
@@ -19,6 +19,7 @@
package org.apache.aries.jpa.container.context.impl;
import java.util.List;
+import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
@@ -102,6 +103,8 @@ public class QuiesceParticipantImpl impl
/** The Global manager for persistence contexts */
private final GlobalPersistenceManager mgr;
+ /** Some events that we need to tidy up */
+ private final BlockingQueue<DestroyCallback> unhandledQuiesces = new LinkedBlockingQueue<DestroyCallback>();
public QuiesceParticipantImpl(GlobalPersistenceManager mgr) {
this.mgr = mgr;
@@ -114,7 +117,7 @@ public class QuiesceParticipantImpl impl
try {
executor.execute(new QuiesceBundle(qc, b, mgr));
} catch (RejectedExecutionException re) {
-
+ unhandledQuiesces.add(new QuiesceDelegatingCallback(qc, b));
}
//If we are quiescing, then we need to quiesce this threadpool!
if(b.equals(mgr.getBundle()))
@@ -128,7 +131,9 @@ public class QuiesceParticipantImpl impl
public void callback() {
executor.shutdown();
try {
- executor.awaitTermination(10, TimeUnit.SECONDS);
+ for(DestroyCallback cbk : unhandledQuiesces)
+ cbk.callback();
+ executor.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
//We don't care
}
Modified: incubator/aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/container/itest/JPAContainerTest.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/container/itest/JPAContainerTest.java?rev=983007&r1=983006&r2=983007&view=diff
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/container/itest/JPAContainerTest.java (original)
+++ incubator/aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/container/itest/JPAContainerTest.java Fri Aug 6 14:59:49 2010
@@ -79,7 +79,6 @@ public class JPAContainerTest {
// 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"),
Modified: incubator/aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/context/itest/JPAContextTest.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/context/itest/JPAContextTest.java?rev=983007&r1=983006&r2=983007&view=diff
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/context/itest/JPAContextTest.java (original)
+++ incubator/aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/context/itest/JPAContextTest.java Fri Aug 6 14:59:49 2010
@@ -105,7 +105,6 @@ public class JPAContextTest {
// 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"),
Copied: incubator/aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/quiesce/itest/QuiesceJPATest.java (from r982543, incubator/aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/quiesce/itest/QuiesceJPAContextTest.java)
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/quiesce/itest/QuiesceJPATest.java?p2=incubator/aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/quiesce/itest/QuiesceJPATest.java&p1=incubator/aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/quiesce/itest/QuiesceJPAContextTest.java&r1=982543&r2=983007&rev=983007&view=diff
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/quiesce/itest/QuiesceJPAContextTest.java (original)
+++ incubator/aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/quiesce/itest/QuiesceJPATest.java Fri Aug 6 14:59:49 2010
@@ -29,6 +29,7 @@ import static org.ops4j.pax.exam.contain
import java.util.Collections;
import java.util.HashMap;
+import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceContextType;
import javax.transaction.UserTransaction;
@@ -58,7 +59,7 @@ import org.osgi.framework.Version;
import org.osgi.util.tracker.ServiceTracker;
@RunWith(JUnit4TestRunner.class)
-public class QuiesceJPAContextTest {
+public class QuiesceJPATest {
private static class TestQuiesceCallback implements QuiesceCallback{
@@ -87,13 +88,17 @@ public class QuiesceJPAContextTest {
b.stop();
b.start();
+ b = getBundle("org.apache.aries.jpa.container");
+ b.stop();
+ b.start();
+
b = getBundle("org.apache.aries.jpa.container.context");
b.stop();
b.start();
}
@Test
- public void testSimpleQuiesce() throws Exception {
+ public void testSimpleContextQuiesce() throws Exception {
PersistenceContextProvider provider = getOsgiService(PersistenceContextProvider.class);
@@ -113,7 +118,7 @@ public class QuiesceJPAContextTest {
participant.quiesce(callback, Collections.singletonList(getBundle(
"org.apache.aries.jpa.org.apache.aries.jpa.container.itest.bundle")));
- Thread.sleep(5000);
+ Thread.sleep(1000);
assertTrue("Quiesce not finished", callback.bundleClearedUp());
@@ -125,7 +130,7 @@ public class QuiesceJPAContextTest {
}
@Test
- public void testComplexQuiesce() throws Exception {
+ public void testComplexContextQuiesce() throws Exception {
PersistenceContextProvider provider = getOsgiService(PersistenceContextProvider.class);
@@ -151,9 +156,9 @@ public class QuiesceJPAContextTest {
participant.quiesce(callback, Collections.singletonList(getBundle(
"org.apache.aries.jpa.org.apache.aries.jpa.container.itest.bundle")));
- Thread.sleep(5000);
+ Thread.sleep(1000);
- assertFalse("Quiesce not finished", callback.bundleClearedUp());
+ assertFalse("Quiesce finished", callback.bundleClearedUp());
emf = getOsgiService(EntityManagerFactory.class, "(&(osgi.unit.name=test-unit)("
+ PersistenceUnitConstants.CONTAINER_MANAGED_PERSISTENCE_UNIT + "=true)" +
@@ -171,7 +176,7 @@ public class QuiesceJPAContextTest {
}
@Test
- public void testRuntimeQuiesce() throws Exception {
+ public void testContextRuntimeQuiesce() throws Exception {
PersistenceContextProvider provider = getOsgiService(PersistenceContextProvider.class);
@@ -197,7 +202,7 @@ public class QuiesceJPAContextTest {
participant.quiesce(callback, Collections.singletonList(getBundle(
"org.apache.aries.jpa.container.context")));
- Thread.sleep(5000);
+ Thread.sleep(1000);
assertFalse("Quiesce not finished", callback.bundleClearedUp());
@@ -216,6 +221,96 @@ public class QuiesceJPAContextTest {
assertNull("No context should exist",refs);
}
+ @Test
+ public void testSimpleUnitQuiesce() throws Exception {
+
+
+ EntityManagerFactory emf = getOsgiService(EntityManagerFactory.class, "(&(osgi.unit.name=test-unit)("
+ + PersistenceUnitConstants.CONTAINER_MANAGED_PERSISTENCE_UNIT + "=true))", DEFAULT_TIMEOUT);
+
+ QuiesceParticipant participant = getParticipant("org.apache.aries.jpa.container");
+
+ TestQuiesceCallback callback = new TestQuiesceCallback();
+
+ participant.quiesce(callback, Collections.singletonList(getBundle(
+ "org.apache.aries.jpa.org.apache.aries.jpa.container.itest.bundle")));
+
+ Thread.sleep(1000);
+
+ assertTrue("Quiesce not finished", callback.bundleClearedUp());
+
+ ServiceReference[] refs = bundleContext.getAllServiceReferences(EntityManagerFactory.class.getName(), "(&(osgi.unit.name=test-unit)("
+ + PersistenceUnitConstants.CONTAINER_MANAGED_PERSISTENCE_UNIT + "=true))");
+
+ assertNull("No context should exist",refs);
+ }
+
+ @Test
+ public void testComplexUnitQuiesce() throws Exception {
+
+
+ EntityManagerFactory emf = getOsgiService(EntityManagerFactory.class, "(&(osgi.unit.name=test-unit)("
+ + PersistenceUnitConstants.CONTAINER_MANAGED_PERSISTENCE_UNIT + "=true))", DEFAULT_TIMEOUT);
+
+ EntityManager em = emf.createEntityManager();
+
+ QuiesceParticipant participant = getParticipant("org.apache.aries.jpa.container");
+
+ TestQuiesceCallback callback = new TestQuiesceCallback();
+
+ participant.quiesce(callback, Collections.singletonList(getBundle(
+ "org.apache.aries.jpa.org.apache.aries.jpa.container.itest.bundle")));
+
+ Thread.sleep(1000);
+
+ assertFalse("Quiesce finished", callback.bundleClearedUp());
+
+ emf = getOsgiService(EntityManagerFactory.class, "(&(osgi.unit.name=test-unit)("
+ + PersistenceUnitConstants.CONTAINER_MANAGED_PERSISTENCE_UNIT + "=true))", DEFAULT_TIMEOUT);
+
+ em.close();
+
+ assertTrue("Quiesce not finished", callback.bundleClearedUp());
+
+ ServiceReference[] refs = bundleContext.getAllServiceReferences(EntityManagerFactory.class.getName(), "(&(osgi.unit.name=test-unit)("
+ + PersistenceUnitConstants.CONTAINER_MANAGED_PERSISTENCE_UNIT + "=true))");
+
+ assertNull("No context should exist",refs);
+ }
+
+ @Test
+ public void testContainerRuntimeQuiesce() throws Exception {
+
+ EntityManagerFactory emf = getOsgiService(EntityManagerFactory.class, "(&(osgi.unit.name=test-unit)("
+ + PersistenceUnitConstants.CONTAINER_MANAGED_PERSISTENCE_UNIT + "=true))", DEFAULT_TIMEOUT);
+
+
+ EntityManager em = emf.createEntityManager();
+
+ QuiesceParticipant participant = getParticipant("org.apache.aries.jpa.container");
+
+ TestQuiesceCallback callback = new TestQuiesceCallback();
+
+ participant.quiesce(callback, Collections.singletonList(getBundle(
+ "org.apache.aries.jpa.container")));
+
+ Thread.sleep(1000);
+
+ assertFalse("Quiesce finished early", callback.bundleClearedUp());
+
+ emf = getOsgiService(EntityManagerFactory.class, "(&(osgi.unit.name=test-unit)("
+ + PersistenceUnitConstants.CONTAINER_MANAGED_PERSISTENCE_UNIT + "=true))", DEFAULT_TIMEOUT);
+
+ em.close();
+
+ assertTrue("Quiesce not finished", callback.bundleClearedUp());
+
+ ServiceReference[] refs = bundleContext.getAllServiceReferences(EntityManagerFactory.class.getName(), "(&(osgi.unit.name=test-unit)("
+ + PersistenceUnitConstants.CONTAINER_MANAGED_PERSISTENCE_UNIT + "=true))");
+
+ assertNull("No context should exist",refs);
+ }
+
private QuiesceParticipant getParticipant(String bundleName) throws InvalidSyntaxException {
ServiceReference[] refs = bundleContext.getServiceReferences(QuiesceParticipant.class.getName(), null);
Modified: incubator/aries/trunk/jpa/jpa-container/pom.xml
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container/pom.xml?rev=983007&r1=983006&r2=983007&view=diff
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container/pom.xml (original)
+++ incubator/aries/trunk/jpa/jpa-container/pom.xml Fri Aug 6 14:59:49 2010
@@ -27,6 +27,13 @@
<artifactId>org.apache.aries.jpa.container</artifactId>
<packaging>bundle</packaging>
<name>Aries JPA Container</name>
+
+ <properties>
+ <aries.osgi.activator>
+ org.apache.aries.jpa.container.impl.PersistenceBundleManager
+ </aries.osgi.activator>
+ </properties>
+
<dependencies>
<dependency>
<groupId>org.osgi</groupId>
@@ -43,6 +50,11 @@
<groupId>org.apache.aries.jpa</groupId>
</dependency>
<dependency>
+ <groupId>org.apache.aries.quiesce</groupId>
+ <artifactId>org.apache.aries.quiesce.api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
<artifactId>org.apache.aries.util</artifactId>
<groupId>org.apache.aries</groupId>
<scope>provided</scope>
@@ -90,6 +102,8 @@
javax.persistence.metamodel;version="[1.1.0,2.1.0)";resolution:=optional,
org.apache.aries.jpa.container;version="[0.1.0,1.1.0)",
org.apache.aries.jpa.container.parsing;version="[0.1.0,1.1.0)",
+ org.apache.aries.quiesce.manager;version="[0.2,1.0)";resolution:=optional,
+ org.apache.aries.quiesce.participant;version="[0.2,0.3)";resolution:=optional,
*
</Import-Package>
<_versionpolicy>[$(version;==;$(@)),$(version;+;$(@)))</_versionpolicy>
Added: incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/CoundownCallback.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/CoundownCallback.java?rev=983007&view=auto
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/CoundownCallback.java (added)
+++ incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/CoundownCallback.java Fri Aug 6 14:59:49 2010
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIESOR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.jpa.container.impl;
+
+/**
+ * A {@link DestroyCallback} that delegates after the correct
+ * number of calls
+ */
+public final class CoundownCallback implements DestroyCallback {
+ private final DestroyCallback callback;
+ private int counter;
+
+ public CoundownCallback(int count,
+ DestroyCallback callback) {
+ this.callback = callback;
+ counter = count;
+ }
+
+ public void callback() {
+ if(--counter == 0)
+ callback.callback();
+ }
+}
\ No newline at end of file
Added: incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/CountingEntityManagerFactory.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/CountingEntityManagerFactory.java?rev=983007&view=auto
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/CountingEntityManagerFactory.java (added)
+++ incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/CountingEntityManagerFactory.java Fri Aug 6 14:59:49 2010
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIESOR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.jpa.container.impl;
+
+
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.persistence.Cache;
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.PersistenceUnitUtil;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.metamodel.Metamodel;
+
+import org.apache.aries.jpa.container.impl.EntityManagerFactoryManager.NamedCallback;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * An {@link EntityManagerFactory} that keeps track of the number of active instances
+ * so that it can be quiesced
+ */
+public class CountingEntityManagerFactory implements EntityManagerFactory, DestroyCallback {
+ /** Number of open EntityManagers */
+ private final AtomicLong count = new AtomicLong(0);
+ /** The real EMF */
+ private final EntityManagerFactory delegate;
+ /** The name of this unit */
+ private final String name;
+ /** A quiesce callback to call */
+ private final AtomicReference<NamedCallback> callback = new AtomicReference<NamedCallback>();
+ /** The service registration to unregister if we can quiesce */
+ private final AtomicReference<ServiceRegistration> reg = new AtomicReference<ServiceRegistration>();
+
+
+ public CountingEntityManagerFactory(
+ EntityManagerFactory containerEntityManagerFactory, String name) {
+ delegate = containerEntityManagerFactory;
+ this.name = name;
+ }
+
+ public void close() {
+ delegate.close();
+ }
+
+ public EntityManager createEntityManager() {
+ EntityManager em = delegate.createEntityManager();
+ count.incrementAndGet();
+ return new EntityManagerWrapper(em, this);
+ }
+
+ public EntityManager createEntityManager(Map arg0) {
+ EntityManager em = delegate.createEntityManager(arg0);
+ count.incrementAndGet();
+ return new EntityManagerWrapper(em, this);
+ }
+
+ public Cache getCache() {
+ return delegate.getCache();
+ }
+
+ public CriteriaBuilder getCriteriaBuilder() {
+ return delegate.getCriteriaBuilder();
+ }
+
+ public Metamodel getMetamodel() {
+ return delegate.getMetamodel();
+ }
+
+ public PersistenceUnitUtil getPersistenceUnitUtil() {
+ return delegate.getPersistenceUnitUtil();
+ }
+
+ public Map<String, Object> getProperties() {
+ return delegate.getProperties();
+ }
+
+ public boolean isOpen() {
+ return delegate.isOpen();
+ }
+
+ public void quiesce(NamedCallback callback, ServiceRegistration reg) {
+ this.reg.compareAndSet(null, reg);
+ this.callback.compareAndSet(null, callback);
+ if(count.get() == 0) {
+ PersistenceBundleManager.unregister(this.reg.getAndSet(null));
+ callback.callback(name);
+ }
+ }
+
+ public void callback() {
+ if(count.decrementAndGet() == 0 && callback.get() != null) {
+ PersistenceBundleManager.unregister(reg.getAndSet(null));
+ callback.get().callback(name);
+ }
+
+ }
+
+}
Added: incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/DestroyCallback.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/DestroyCallback.java?rev=983007&view=auto
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/DestroyCallback.java (added)
+++ incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/DestroyCallback.java Fri Aug 6 14:59:49 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 WARRANTIESOR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.jpa.container.impl;
+
+/**
+ * An asynchronous callback for destroying something
+ */
+public interface DestroyCallback {
+ public void callback();
+}
Modified: incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/EntityManagerFactoryManager.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/EntityManagerFactoryManager.java?rev=983007&r1=983006&r2=983007&view=diff
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/EntityManagerFactoryManager.java (original)
+++ incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/EntityManagerFactoryManager.java Fri Aug 6 14:59:49 2010
@@ -21,9 +21,13 @@ package org.apache.aries.jpa.container.i
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
+import java.util.Set;
import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import javax.persistence.EntityManagerFactory;
import javax.persistence.spi.PersistenceProvider;
@@ -44,6 +48,27 @@ import org.slf4j.LoggerFactory;
*/
public class EntityManagerFactoryManager {
+ /**
+ * A callback for a named persistence units
+ */
+ class NamedCallback {
+ private final Set<String> names;
+ private final DestroyCallback callback;
+ public NamedCallback(Collection<String> names, DestroyCallback countdown) {
+ this.names = new HashSet<String>(names);
+ callback = countdown;
+ }
+
+ public void callback(String name) {
+ boolean winner;
+ synchronized (this) {
+ winner = !!!names.isEmpty() && names.remove(name) && names.isEmpty();
+ }
+ if(winner)
+ callback.callback();
+ }
+ }
+
/** The container's {@link BundleContext} */
private final BundleContext containerContext;
/** The persistence bundle */
@@ -55,9 +80,11 @@ public class EntityManagerFactoryManager
/** The original parsed data */
private Collection<ParsedPersistenceUnit> parsedData;
/** A Map of created {@link EntityManagerFactory}s */
- private Map<String, EntityManagerFactory> emfs = null;
+ private Map<String, CountingEntityManagerFactory> emfs = null;
/** The {@link ServiceRegistration} objects for the {@link EntityManagerFactory}s */
- private Collection<ServiceRegistration> registrations = null;
+ private ConcurrentMap<String, ServiceRegistration> registrations = null;
+ /** Quiesce this Manager */
+ private boolean quiesce = false;
/** Logger */
private static final Logger _logger = LoggerFactory.getLogger("org.apache.aries.jpa.container");
@@ -98,7 +125,7 @@ public class EntityManagerFactoryManager
*/
public synchronized boolean providerRemoved(ServiceReference ref) {
- boolean toReturn = ref == provider;
+ boolean toReturn = provider.equals(ref);
if(toReturn)
destroy();
@@ -146,7 +173,7 @@ public class EntityManagerFactoryManager
private void unregisterEntityManagerFactories() {
//If we have registrations then unregister them
if(registrations != null) {
- for(ServiceRegistration reg : registrations) {
+ for(ServiceRegistration reg : registrations.values()) {
try {
reg.unregister();
} catch (Exception e) {
@@ -168,11 +195,11 @@ public class EntityManagerFactoryManager
private void registerEntityManagerFactories() throws InvalidPersistenceUnitException {
//Only register if there is a provider and we are not
//already registered
- if(provider != null && registrations == null) {
+ if(provider != null && registrations == null && !quiesce) {
//Make sure the EntityManagerFactories are instantiated
createEntityManagerFactories();
- registrations = new ArrayList<ServiceRegistration>();
+ registrations = new ConcurrentHashMap<String, ServiceRegistration>();
String providerName = (String) provider.getProperty("javax.persistence.provider");
if(providerName == null) {
_logger.warn("The PersistenceProvider for bundle {} did not specify a provider name in the \"javax.persistence.provider\" service property. " +
@@ -182,7 +209,7 @@ public class EntityManagerFactoryManager
new Object[] {bundle.getSymbolicName() + "_" + bundle.getVersion(), provider});
}
//Register each EMF
- for(Entry<String, EntityManagerFactory> entry : emfs.entrySet())
+ for(Entry<String, ? extends EntityManagerFactory> entry : emfs.entrySet())
{
Properties props = new Properties();
String unitName = entry.getKey();
@@ -194,7 +221,7 @@ public class EntityManagerFactoryManager
props.put(PersistenceUnitConstants.CONTAINER_MANAGED_PERSISTENCE_UNIT, Boolean.TRUE);
props.put(PersistenceUnitConstants.EMPTY_PERSISTENCE_UNIT_NAME, "".equals(unitName));
try {
- registrations.add(bundle.getBundleContext().registerService(EntityManagerFactory.class.getCanonicalName(), entry.getValue(), props));
+ registrations.put(unitName, bundle.getBundleContext().registerService(EntityManagerFactory.class.getCanonicalName(), entry.getValue(), props));
} catch (Exception e) {
_logger.error("There was an error registering the persistence unit "
+ unitName + " defined by the bundle " + bundle.getSymbolicName() + "_" + bundle.getVersion(), e);
@@ -212,9 +239,9 @@ public class EntityManagerFactoryManager
private void createEntityManagerFactories() throws InvalidPersistenceUnitException {
//Only try if we have a provider and EMFs
if(provider != null) {
- if(emfs == null) {
+ if(emfs == null && !quiesce) {
try {
- emfs = new HashMap<String, EntityManagerFactory>();
+ emfs = new HashMap<String, CountingEntityManagerFactory>();
//Get hold of the provider
PersistenceProvider providerService = (PersistenceProvider) containerContext.getService(provider);
@@ -229,9 +256,9 @@ public class EntityManagerFactoryManager
for(ManagedPersistenceUnitInfo info : persistenceUnits){
PersistenceUnitInfo pUnitInfo = info.getPersistenceUnitInfo();
- emfs.put(pUnitInfo.getPersistenceUnitName(),
+ emfs.put(pUnitInfo.getPersistenceUnitName(), new CountingEntityManagerFactory(
providerService.createContainerEntityManagerFactory(
- pUnitInfo, info.getContainerProperties()));
+ pUnitInfo, info.getContainerProperties()), pUnitInfo.getPersistenceUnitName()));
}
} finally {
//Remember to unget the provider
@@ -292,7 +319,7 @@ public class EntityManagerFactoryManager
if(registrations != null)
unregisterEntityManagerFactories();
if(emfs != null) {
- for(Entry<String, EntityManagerFactory> entry : emfs.entrySet()) {
+ for(Entry<String, ? extends EntityManagerFactory> entry : emfs.entrySet()) {
try {
entry.getValue().close();
} catch (Exception e) {
@@ -312,5 +339,31 @@ public class EntityManagerFactoryManager
{
return parsedData;
}
+ /** Quiesce this Manager */
+ public void quiesce(DestroyCallback countdown) {
+
+ //Find the EMFs to quiesce, and their Service registrations
+ Map<CountingEntityManagerFactory, ServiceRegistration> entries = new HashMap<CountingEntityManagerFactory, ServiceRegistration>();
+ Collection<String> names = new ArrayList<String>();
+ synchronized(this) {
+ quiesce = true;
+ if(emfs != null) {
+ for(String key : emfs.keySet()) {
+ entries.put(emfs.get(key), registrations != null ? registrations.get(key) : null);
+ names.add(key);
+ }
+ }
+ }
+ //Quiesce as necessary
+ if(entries.isEmpty())
+ countdown.callback();
+ else {
+ NamedCallback callback = new NamedCallback(names, countdown);
+ for(Entry<CountingEntityManagerFactory, ServiceRegistration> entry : entries.entrySet()) {
+ CountingEntityManagerFactory emf = entry.getKey();
+ emf.quiesce(callback, entry.getValue());
+ }
+ }
+ }
}
Added: incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/EntityManagerWrapper.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/EntityManagerWrapper.java?rev=983007&view=auto
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/EntityManagerWrapper.java (added)
+++ incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/EntityManagerWrapper.java Fri Aug 6 14:59:49 2010
@@ -0,0 +1,211 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIESOR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.jpa.container.impl;
+
+import java.util.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.TypedQuery;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.metamodel.Metamodel;
+
+/**
+ * Wrapper an EntityManager so that we know when it has been closed
+ */
+public class EntityManagerWrapper implements EntityManager {
+
+ private final EntityManager delegate;
+ /** Call this when the EntityManager is closed */
+ private final DestroyCallback callback;
+
+ public EntityManagerWrapper(EntityManager em, DestroyCallback callback) {
+ delegate = em;
+ this.callback = callback;
+ }
+
+ public void clear() {
+ delegate.clear();
+ }
+
+ public void close() {
+ delegate.close();
+ //This will only ever be called once, the second time there
+ //will be an IllegalStateException from the line above
+ callback.callback();
+ }
+
+ public boolean contains(Object arg0) {
+ return delegate.contains(arg0);
+ }
+
+ public <T> TypedQuery<T> createNamedQuery(String arg0, Class<T> arg1) {
+ return delegate.createNamedQuery(arg0, arg1);
+ }
+
+ public Query createNamedQuery(String arg0) {
+ return delegate.createNamedQuery(arg0);
+ }
+
+ public Query createNativeQuery(String arg0, Class arg1) {
+ return delegate.createNativeQuery(arg0, arg1);
+ }
+
+ public Query createNativeQuery(String arg0, String arg1) {
+ return delegate.createNativeQuery(arg0, arg1);
+ }
+
+ public Query createNativeQuery(String arg0) {
+ return delegate.createNativeQuery(arg0);
+ }
+
+ public <T> TypedQuery<T> createQuery(CriteriaQuery<T> arg0) {
+ return delegate.createQuery(arg0);
+ }
+
+ public <T> TypedQuery<T> createQuery(String arg0, Class<T> arg1) {
+ return delegate.createQuery(arg0, arg1);
+ }
+
+ public Query createQuery(String arg0) {
+ return delegate.createQuery(arg0);
+ }
+
+ public void detach(Object arg0) {
+ delegate.detach(arg0);
+ }
+
+ public <T> T find(Class<T> arg0, Object arg1, LockModeType arg2,
+ Map<String, Object> arg3) {
+ return delegate.find(arg0, arg1, arg2, arg3);
+ }
+
+ public <T> T find(Class<T> arg0, Object arg1, LockModeType arg2) {
+ return delegate.find(arg0, arg1, arg2);
+ }
+
+ public <T> T find(Class<T> arg0, Object arg1, Map<String, Object> arg2) {
+ return delegate.find(arg0, arg1, arg2);
+ }
+
+ public <T> T find(Class<T> arg0, Object arg1) {
+ return delegate.find(arg0, arg1);
+ }
+
+ public void flush() {
+ delegate.flush();
+ }
+
+ public CriteriaBuilder getCriteriaBuilder() {
+ return delegate.getCriteriaBuilder();
+ }
+
+ public Object getDelegate() {
+ return delegate.getDelegate();
+ }
+
+ public EntityManagerFactory getEntityManagerFactory() {
+ return delegate.getEntityManagerFactory();
+ }
+
+ public FlushModeType getFlushMode() {
+ return delegate.getFlushMode();
+ }
+
+ public LockModeType getLockMode(Object arg0) {
+ return delegate.getLockMode(arg0);
+ }
+
+ public Metamodel getMetamodel() {
+ return delegate.getMetamodel();
+ }
+
+ public Map<String, Object> getProperties() {
+ return delegate.getProperties();
+ }
+
+ public <T> T getReference(Class<T> arg0, Object arg1) {
+ return delegate.getReference(arg0, arg1);
+ }
+
+ public EntityTransaction getTransaction() {
+ return delegate.getTransaction();
+ }
+
+ public boolean isOpen() {
+ return delegate.isOpen();
+ }
+
+ public void joinTransaction() {
+ delegate.joinTransaction();
+ }
+
+ public void lock(Object arg0, LockModeType arg1, Map<String, Object> arg2) {
+ delegate.lock(arg0, arg1, arg2);
+ }
+
+ public void lock(Object arg0, LockModeType arg1) {
+ delegate.lock(arg0, arg1);
+ }
+
+ public <T> T merge(T arg0) {
+ return delegate.merge(arg0);
+ }
+
+ public void persist(Object arg0) {
+ delegate.persist(arg0);
+ }
+
+ public void refresh(Object arg0, LockModeType arg1, Map<String, Object> arg2) {
+ delegate.refresh(arg0, arg1, arg2);
+ }
+
+ public void refresh(Object arg0, LockModeType arg1) {
+ delegate.refresh(arg0, arg1);
+ }
+
+ public void refresh(Object arg0, Map<String, Object> arg1) {
+ delegate.refresh(arg0, arg1);
+ }
+
+ public void refresh(Object arg0) {
+ delegate.refresh(arg0);
+ }
+
+ public void remove(Object arg0) {
+ delegate.remove(arg0);
+ }
+
+ public void setFlushMode(FlushModeType arg0) {
+ delegate.setFlushMode(arg0);
+ }
+
+ public void setProperty(String arg0, Object arg1) {
+ delegate.setProperty(arg0, arg1);
+ }
+
+ public <T> T unwrap(Class<T> arg0) {
+ return delegate.unwrap(arg0);
+ }
+}
Modified: incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleManager.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleManager.java?rev=983007&r1=983006&r2=983007&view=diff
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleManager.java (original)
+++ incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleManager.java Fri Aug 6 14:59:49 2010
@@ -33,36 +33,48 @@ import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.Map.Entry;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.persistence.spi.PersistenceProvider;
-import org.apache.aries.util.VersionRange;
import org.apache.aries.jpa.container.ManagedPersistenceUnitInfo;
import org.apache.aries.jpa.container.ManagedPersistenceUnitInfoFactory;
import org.apache.aries.jpa.container.parsing.ParsedPersistenceUnit;
import org.apache.aries.jpa.container.parsing.PersistenceDescriptor;
import org.apache.aries.jpa.container.parsing.PersistenceDescriptorParser;
import org.apache.aries.jpa.container.parsing.PersistenceDescriptorParserException;
+import org.apache.aries.jpa.container.parsing.impl.PersistenceDescriptorParserImpl;
import org.apache.aries.jpa.container.unit.impl.ManagedPersistenceUnitInfoFactoryImpl;
+import org.apache.aries.util.VersionRange;
import org.apache.aries.util.tracker.RecursiveBundleTracker;
import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
import org.osgi.framework.Version;
import org.osgi.util.tracker.BundleTrackerCustomizer;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class locates, parses and manages persistence units defined in OSGi bundles.
*/
-public class PersistenceBundleManager implements BundleTrackerCustomizer
+public class PersistenceBundleManager implements BundleTrackerCustomizer, ServiceTrackerCustomizer, 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");
/** The bundle context for this bundle */
private BundleContext ctx = null;
+
/**
* A map of providers to persistence bundles this is used to guarantee that
* when a provider service is removed we can access all of the bundles that
@@ -85,33 +97,22 @@ public class PersistenceBundleManager im
private ManagedPersistenceUnitInfoFactory persistenceUnitFactory;
/** Parser for persistence descriptors */
private PersistenceDescriptorParser parser;
+ /** Registration for the Parser */
+ private ServiceRegistration parserReg;
/** Configuration for this extender */
private Properties config;
- private final RecursiveBundleTracker tracker;
-
- /**
- * Create the extender. Note that it will not start tracking
- * until the {@code open()} method is called
- * @param ctx The extender bundle's context
- */
- public PersistenceBundleManager(BundleContext ctx)
- {
- this.ctx = ctx;
- tracker = new RecursiveBundleTracker(ctx, Bundle.INSTALLED | Bundle.RESOLVED | Bundle.STARTING |
- Bundle.ACTIVE | Bundle.STOPPING, this);
- }
-
- /**
- * Provide a parser implementation
- * @param parser
- */
- public void setParser(PersistenceDescriptorParser descriptorParser) {
- parser = descriptorParser;
- }
+ private RecursiveBundleTracker tracker;
+ private ServiceTracker serviceTracker;
+ /** The quiesce participant service */
+ private ServiceRegistration quiesceReg;
+ /** A callback to shutdown the quiesce participant when it is done */
+ private DestroyCallback quiesceParticipant;
+ /** Are we quiescing */
+ private AtomicBoolean quiesce = new AtomicBoolean(false);
@SuppressWarnings("unchecked")
- public void open() {
+ private void open() {
//Create the pluggable ManagedPersistenceUnitInfoFactory
String className = config.getProperty(ManagedPersistenceUnitInfoFactory.DEFAULT_PU_INFO_FACTORY_KEY);
@@ -127,28 +128,38 @@ public class PersistenceBundleManager im
if(persistenceUnitFactory == null)
persistenceUnitFactory = new ManagedPersistenceUnitInfoFactoryImpl();
-
+ serviceTracker.open();
tracker.open();
}
- public void close()
+ private void close()
{
if (tracker != null) {
tracker.close();
}
+
+ if (serviceTracker != null) {
+ serviceTracker.close();
+ }
}
public Object addingBundle(Bundle bundle, BundleEvent event)
{
- EntityManagerFactoryManager mgr = setupManager(bundle, null, true);
- return mgr;
+ if(!!!quiesce.get()){
+ return setupManager(bundle, null, true);
+ }
+ return null;
}
/**
* A provider is being added, add it to our Set
* @param ref
*/
- public void addingProvider(ServiceReference ref)
+ public Object addingService(ServiceReference ref)
{
+ if(quiesce.get()){
+ return null;
+ }
+
Map<EntityManagerFactoryManager, ServiceReference> managersToManage = new HashMap<EntityManagerFactoryManager, ServiceReference>();
synchronized (this) {
if(_logger.isDebugEnabled())
@@ -193,6 +204,7 @@ public class PersistenceBundleManager im
setupManager(mgr.getBundle(), mgr, false);
}
}
+ return ref;
}
/**
@@ -200,12 +212,8 @@ public class PersistenceBundleManager im
* managers that it has been removed
* @param ref
*/
- public void removingProvider(ServiceReference ref)
- {
- //We may get a null reference if the ref-list is empty to start with
- if(ref == null)
- return;
-
+ public void removedService(ServiceReference ref, Object o)
+ {
if(_logger.isDebugEnabled())
_logger.debug("Removing a provider: {}", new Object[] {ref});
@@ -232,8 +240,8 @@ public class PersistenceBundleManager im
* and override the supplied properties
* @param props
*/
- public void setConfig(Properties props) {
- config = new Properties(props);
+ private void initConfig() {
+ config = new Properties();
URL u = ctx.getBundle().getResource(ManagedPersistenceUnitInfoFactory.ARIES_JPA_CONTAINER_PROPERTIES);
if(u != null) {
@@ -587,4 +595,111 @@ public class PersistenceBundleManager im
_logger.warn("The persistence units for bundle " + bundle.getSymbolicName() + "_" + bundle.getVersion()
+ " became invalid and will be destroyed.", e);
}
+
+
+ public void modifiedService(ServiceReference reference, Object service) {
+ //Just remove and re-add as the properties have changed
+ removedService(reference, service);
+ addingService(reference);
+ }
+
+
+ public void start(BundleContext context) throws Exception {
+
+ ctx = context;
+
+ initConfig();
+ initParser();
+
+ serviceTracker = new ServiceTracker(ctx, PersistenceProvider.class.getName(), this);
+
+ tracker = new RecursiveBundleTracker(ctx, Bundle.INSTALLED | Bundle.RESOLVED | Bundle.STARTING |
+ Bundle.ACTIVE | Bundle.STOPPING, this);
+
+ open();
+
+ try{
+ context.getBundle().loadClass(QUIESCE_PARTICIPANT_CLASS);
+ //Class was loaded, register
+ quiesceParticipant = new QuiesceParticipantImpl(this);
+ quiesceReg = context.registerService(QUIESCE_PARTICIPANT_CLASS,
+ quiesceParticipant, null);
+ } catch (ClassNotFoundException e) {
+ _logger.info("No quiesce support is available, so persistence contexts will not participate in quiesce operations", e);
+ }
+ }
+
+ private void initParser() {
+ parser = new PersistenceDescriptorParserImpl();
+ parserReg = ctx.registerService(PersistenceDescriptorParser.class.getName(), parser, null);
+ }
+
+ public void stop(BundleContext context) throws Exception {
+ close();
+ unregister(parserReg);
+ unregister(quiesceReg);
+ quiesceParticipant.callback();
+ }
+
+ /**
+ * Clean up a registration without throwing an exception
+ * @param reg
+ */
+ static void unregister(ServiceRegistration reg) {
+ if(reg != null)
+ try {
+ reg.unregister();
+ } catch (IllegalStateException ise) {
+ //we don't care
+ }
+ }
+
+ public BundleContext getCtx() {
+ return ctx;
+ }
+
+ public void quiesceBundle(Bundle bundleToQuiesce, final DestroyCallback callback) {
+
+ boolean thisBundle = bundleToQuiesce.equals(ctx.getBundle());
+
+ if(thisBundle) {
+ quiesce.compareAndSet(false, true);
+ unregister(quiesceReg);
+ }
+
+ Collection<EntityManagerFactoryManager> toDestroyNow = new ArrayList<EntityManagerFactoryManager>();
+ final Collection<EntityManagerFactoryManager> quiesceNow = new ArrayList<EntityManagerFactoryManager>();
+ synchronized (this) {
+ if(thisBundle) {
+ toDestroyNow.addAll(managersAwaitingProviders);
+ managersAwaitingProviders.clear();
+ quiesceNow.addAll(bundleToManagerMap.values());
+ bundleToManagerMap.clear();
+ quiesceNow.removeAll(toDestroyNow);
+ } else {
+ EntityManagerFactoryManager emfm = bundleToManagerMap.get(bundleToQuiesce);
+
+ if(emfm != null){
+ if(managersAwaitingProviders.remove(emfm))
+ toDestroyNow.add(emfm);
+ else
+ quiesceNow.add(emfm);
+ }
+ }
+ }
+
+ for(EntityManagerFactoryManager emfm : toDestroyNow)
+ emfm.destroy();
+
+ if(quiesceNow.isEmpty()) {
+ callback.callback();
+ } else {
+ DestroyCallback countdown = new CoundownCallback(quiesceNow.size(), callback);
+
+ for(EntityManagerFactoryManager emfm : quiesceNow)
+ emfm.quiesce(countdown);
+
+ }
+
+ }
}
Added: incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/QuiesceParticipantImpl.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/QuiesceParticipantImpl.java?rev=983007&view=auto
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/QuiesceParticipantImpl.java (added)
+++ incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/QuiesceParticipantImpl.java Fri Aug 6 14:59:49 2010
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIESOR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.jpa.container.impl;
+
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
+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.quiesce.manager.QuiesceCallback;
+import org.apache.aries.quiesce.participant.QuiesceParticipant;
+import org.osgi.framework.Bundle;
+
+/**
+ * This class provides Quiesce Participant support for JPA managed units. 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 {@link PersistenceBundleManager} instance */
+ private final PersistenceBundleManager mgr;
+
+ public QuiesceBundle(QuiesceCallback callback, Bundle bundleToQuiesce,
+ PersistenceBundleManager 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-Container-ThreadPool");
+ t.setDaemon(true);
+ return t;
+ }
+ });
+
+ /** The manager for persistence bundles */
+ private final PersistenceBundleManager mgr;
+
+ /** Some events that we need to tidy up */
+ private final BlockingQueue<DestroyCallback> unhandledQuiesces = new LinkedBlockingQueue<DestroyCallback>();
+
+ public QuiesceParticipantImpl(PersistenceBundleManager 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) {
+ unhandledQuiesces.add(new QuiesceDelegatingCallback(qc, b));
+ }
+ //If we are quiescing, then we need to quiesce this threadpool!
+ if(b.equals(mgr.getCtx().getBundle()))
+ executor.shutdown();
+ }
+ }
+
+ /**
+ * Close down this object
+ */
+ public void callback() {
+ executor.shutdown();
+ try {
+ for(DestroyCallback cbk : unhandledQuiesces) {
+ cbk.callback();
+ }
+ executor.awaitTermination(5, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ //We don't care
+ }
+ executor.shutdownNow();
+ }
+}