/** | |
* 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.ejb.openejb.extender; | |
import java.util.Map; | |
import java.util.concurrent.atomic.AtomicReference; | |
import javax.persistence.EntityManager; | |
import javax.persistence.EntityManagerFactory; | |
import org.apache.aries.jpa.container.context.JTAPersistenceContextManager; | |
import org.apache.aries.util.tracker.SingleServiceTracker; | |
import org.apache.aries.util.tracker.SingleServiceTracker.SingleServiceListener; | |
import org.apache.openejb.persistence.EntityManagerTxKey; | |
import org.apache.openejb.persistence.JtaEntityManagerRegistry; | |
import org.osgi.framework.BundleContext; | |
public class AriesPersistenceContextIntegration extends | |
JtaEntityManagerRegistry { | |
private static final AtomicReference<AriesPersistenceContextIntegration> INSTANCE = | |
new AtomicReference<AriesPersistenceContextIntegration>(); | |
private final SingleServiceTracker<JTAPersistenceContextManager> ariesJTARegistry; | |
private AriesPersistenceContextIntegration(BundleContext ctx) { | |
super(OSGiTransactionManager.get()); | |
ariesJTARegistry = new SingleServiceTracker<JTAPersistenceContextManager> | |
(ctx, JTAPersistenceContextManager.class, new DummySingleServiceListener()); | |
ariesJTARegistry.open(); | |
} | |
public static void init(BundleContext ctx) { | |
AriesPersistenceContextIntegration apci = new AriesPersistenceContextIntegration(ctx); | |
if(!!!INSTANCE.compareAndSet(null, apci)) | |
apci.destroy(); | |
} | |
public static AriesPersistenceContextIntegration get() { | |
return INSTANCE.get(); | |
} | |
public void destroy() { | |
INSTANCE.set(null); | |
ariesJTARegistry.close(); | |
} | |
@Override | |
public EntityManager getEntityManager(EntityManagerFactory emf, Map props, | |
boolean extended, String unitName) throws IllegalStateException { | |
if(!!!isTransactionActive()) | |
return super.getEntityManager(emf, props, extended, unitName); | |
JTAPersistenceContextManager mgr = ariesJTARegistry.getService(); | |
if(mgr == null) | |
throw new IllegalStateException("No JTAPersistenceContextManager service available"); | |
//Check if we, or OpenEJB, already have a context | |
EntityManager ariesEM = mgr.getExistingPersistenceContext(emf); | |
EntityManager openEjbEM = (EntityManager) OSGiTransactionManager.get(). | |
getResource(new EntityManagerTxKey(emf)); | |
if(ariesEM == null) { | |
if(openEjbEM == null) { | |
//If both are null then it's easier to let OpenEJB win and push the PC into Aries | |
openEjbEM = super.getEntityManager(emf, props, extended, unitName); | |
} | |
mgr.manageExistingPersistenceContext(emf, openEjbEM); | |
ariesEM = openEjbEM; | |
} else { | |
//We have an Aries EM, if OpenEJB doesn't then sort it out, if it does they should be the same | |
if(openEjbEM == null){ | |
if(extended) { | |
throw new IllegalStateException("We already have an active TX scope PersistenceContext, so we can't" + | |
"create an extended one"); | |
} else { | |
OSGiTransactionManager.get().putResource(new EntityManagerTxKey(emf), ariesEM); | |
openEjbEM = ariesEM; | |
} | |
} else { | |
//If both non null and not equal then something bad has happened | |
if(openEjbEM != ariesEM) { | |
throw new IllegalStateException("OpenEJB has been cheating. They have a different EntityManager to Aries"); | |
} | |
} | |
} | |
//We could return either ariesEM or openEjbEM at this point | |
return ariesEM; | |
} | |
private static final class DummySingleServiceListener implements SingleServiceListener { | |
public void serviceFound() {} | |
public void serviceLost() {} | |
public void serviceReplaced() {} | |
} | |
} |