Skip to content
Permalink
Browse files
ARIES-1783 EM joins transaction when needed
EMSupplier makes a cached EM join a transaction if there is currently
an active one.
  • Loading branch information
Daniel Estermann committed Nov 26, 2018
1 parent 96b2573 commit 12292696477fd0b982fb8e8a82a11a87e9c15764
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 17 deletions.
@@ -17,6 +17,7 @@

import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import javax.transaction.Transactional;
import javax.transaction.Transactional.TxType;
@@ -53,7 +54,9 @@ public Collection<Car> getCars() {
ref = getService();
CarService carService = bundleContext.getService(ref);
carService.addCar(c);
return Arrays.asList(this.getCar("TR123"));
final List<Car> returnVal = Arrays.asList(this.getCar("TR123"));
carService.deleteCar("TR123");
return returnVal;
} finally {
if (ref != null) {
bundleContext.ungetService(ref);
@@ -75,7 +78,9 @@ public void updateCar(Car car) {
}

@Override
@Transactional
public void deleteCar(String id) {
em.remove(this.getCar(id));
}

public void setBundleContext(BundleContext bundleContext) {
@@ -43,10 +43,10 @@
public class BlueprintTest extends AbstractCarJPAITest {
@Inject
Coordinator coordinator;

@Inject
UserTransaction ut;

@Test
public void testCoordination() {
assertNoCoordination();
@@ -66,7 +66,7 @@ public void testCoordination() {
Assert.assertEquals(0, carService.getCars().size());
}
}

@Test
public void testInjectToMethod() throws Exception {
carLifecycle(getCarService("method"));
@@ -86,7 +86,7 @@ public void testEmf() throws Exception {
public void testEm() throws Exception {
carLifecycle(getCarService("em"));
}

@Test
public void testEmJtaAnn() throws Exception {
carLifecycle(getCarService("emJtaAnn"));
@@ -96,17 +96,17 @@ public void testEmJtaAnn() throws Exception {
public void testSupplier() throws Exception {
carLifecycle(getCarService("supplier"));
}

@Test
public void testRealTransactional() throws Exception {
carRealTransactionalLifecycle(getCarService("emJtaAnn"));
}

@Test
public void testInlined() throws Exception {
carRealTransactionalLifecycle(getCarService("emJtaAnnInlined"));
}

@Test
public void testCoordinationLifecycle() throws InterruptedException, ExecutionException {
CarService carService = getCarService("em");
@@ -127,7 +127,6 @@ public void testCoordinationLifecycle() throws InterruptedException, ExecutionEx
}

@Test
@Ignore
public void testCarWithRequiresNewAnnotation() throws Exception {
CarService cs = getCarService("rn");
cs.getCars();
@@ -146,7 +145,7 @@ private void carLifecycle(CarService carService) {
assertBlueCar(carService.getCar(BLUE_PLATE));
carService.deleteCar(BLUE_PLATE);
}

private void carRealTransactionalLifecycle(CarService carService) throws IllegalStateException, SystemException, NotSupportedException {
assertNoCoordination();
if (carService.getCar(BLACK_CAR_PLATE) != null) {
@@ -162,7 +161,7 @@ private void assertNoCoordination() {
Coordination coord = coordinator.peek();
Assert.assertNull("There should not be a coordination on this thread", coord);
}

private void assertNoCars(CarService carService) {
Assert.assertEquals("Invalid number of cars", 0, carService.getCars().size());
}
@@ -29,8 +29,16 @@

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.transaction.Status;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;

import org.apache.aries.jpa.supplier.EmSupplier;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceReference;
import org.osgi.service.coordinator.Coordination;
import org.osgi.service.coordinator.Coordinator;
import org.osgi.service.coordinator.Participant;
@@ -39,7 +47,7 @@

/**
* Thread safe way to use an EntityManager.
*
*
* Before the EMF is closed the close() method has to be called to make
* sure all EMs are closed.
*/
@@ -88,17 +96,34 @@ public EntityManager get() {
setEm(coordination, em);
coordination.addParticipant(new EmShutDownParticipant());
}
else {
final Bundle bundle = FrameworkUtil.getBundle(this.getClass());
if (bundle != null) {
final BundleContext bundleContext = bundle.getBundleContext();
ServiceReference<TransactionManager> tmRef = bundleContext.getServiceReference(TransactionManager.class);
TransactionManager tm = bundleContext.getService(tmRef);
try {
final Transaction transaction = tm.getTransaction();
if (transaction != null && transaction.getStatus() == Status.STATUS_ACTIVE) {
em.joinTransaction();
}
}
catch( SystemException se ) {
throw new IllegalStateException("Unable to check transaction status and join the transaction", se);
}
}
}
return em;
}

Coordination getTopCoordination() {
Coordination coordination = coordinator.peek();
while (coordination != null && coordination.getEnclosingCoordination() != null) {
coordination = coordination.getEnclosingCoordination();
}
return coordination;
}

private void setEm(Coordination coordination, EntityManager em) {
Map<Class<?>, Object> vars = coordination.getVariables();
synchronized (vars) {
@@ -126,7 +151,7 @@ private EntityManager removeEm(Coordination coordination) {
}
}


@SuppressWarnings("unchecked")
private Map<String, EntityManager> getEmMap(Coordination coordination) {
Map<String, EntityManager> emMap = (Map<String, EntityManager>)coordination.getVariables().get(EntityManager.class);
@@ -167,7 +192,7 @@ public boolean close() {
}

private synchronized boolean shutdownRemaining() {
boolean clean = emSet.isEmpty();
boolean clean = emSet.isEmpty();
if (!clean) {
LOG.warn("{} EntityManagers still open after timeout. Shutting them down now", emSet.size());
}
@@ -206,7 +231,7 @@ public void ended(Coordination coordination) throws Exception {
EntityManager em = removeEm(coordination);
emSet.remove(em);
em.close();

if (shutdown.get()) {
emsToShutDown.countDown();
}

0 comments on commit 1229269

Please sign in to comment.