blob: bd42c39f3670c789a9e66c41e7431469a1c2c9ba [file] [log] [blame]
/*
* 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.openjpa.ee;
import java.util.LinkedList;
import java.util.List;
import javax.transaction.NotSupportedException;
import javax.transaction.SystemException;
import javax.transaction.TransactionManager;
import org.apache.openjpa.lib.conf.Configurable;
import org.apache.openjpa.lib.conf.Configuration;
import org.apache.openjpa.lib.util.J2DoPrivHelper;
import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.util.InvalidStateException;
/**
* Implementation of the {@link ManagedRuntime} interface that searches
* through a set of known JNDI locations and method invocations to locate the
* appropriate mechanism for obtaining a TransactionManager.
* Built in support is provided for the following Application Servers:
* <ul>
* <li>Bluestone</li>
* <li>GlassFish</li>
* <li>HP Application Server</li>
* <li>JBoss</li>
* <li>JRun</li>
* <li>OpenEJB</li>
* <li>Oracle Application Server</li>
* <li>Orion</li>
* <li>SunONE</li>
* <li>Weblogic</li>
* <li>Websphere</li>
* </ul>
*
* @author Marc Prud'hommeaux
*/
public class AutomaticManagedRuntime extends AbstractManagedRuntime
implements ManagedRuntime, Configurable {
private static final String [] JNDI_LOCS = new String []{
"javax.transaction.TransactionManager", // weblogic
"java:/TransactionManager", // jboss, jrun, Geronimo
"java:/DefaultDomain/TransactionManager", // jrun too
"java:comp/pm/TransactionManager", // orion & oracle
"java:comp/TransactionManager", // generic
"java:appserver/TransactionManager", // GlassFish
"java:pm/TransactionManager", // borland
"aries:services/javax.transaction.TransactionManager", // Apache Aries
};
private static final String [] METHODS = new String[]{
"com.arjuna.jta.JTA_TransactionManager.transactionManager", // hp
"com.bluestone.jta.SaTransactionManagerFactory.SaGetTransactionManager",
"org.openejb.OpenEJB.getTransactionManager",
"com.sun.jts.jta.TransactionManagerImpl.getTransactionManagerImpl",
"com.inprise.visitransact.jta.TransactionManagerImpl."
+ "getTransactionManagerImpl", // borland
};
private final ManagedRuntime REGISTRY;
private final WLSManagedRuntime WLS;
private final SunOneManagedRuntime SUNONE;
private final WASManagedRuntime WAS;
private final WASRegistryManagedRuntime WAS_REG;
private static Localizer _loc = Localizer.forPackage
(AutomaticManagedRuntime.class);
public AutomaticManagedRuntime() {
ManagedRuntime mr = null;
mr = null;
try {
mr = (ManagedRuntime) Class.
forName("org.apache.openjpa.ee.RegistryManagedRuntime").
newInstance();
} catch (Throwable t) {
// might be JTA version lower than 1.1, which doesn't have
// TransactionSynchronizationRegistry
}
REGISTRY = mr;
mr = null;
try {
mr = new WLSManagedRuntime();
} catch (Throwable t) {
}
WLS = (WLSManagedRuntime) mr;
mr = null;
try {
mr = new SunOneManagedRuntime();
} catch (Throwable t) {
}
SUNONE = (SunOneManagedRuntime) mr;
mr = null;
try {
mr = new WASManagedRuntime();
} catch (Throwable t) {
}
WAS = (WASManagedRuntime) mr;
mr = null;
try {
// In a WebSphere environment the thread's current classloader might
// not have access to the WebSphere APIs. However the "runtime"
// classloader will have access to them.
// Should not need a doPriv getting this class' classloader
ClassLoader cl = AutomaticManagedRuntime.class.getClassLoader();
Class<WASRegistryManagedRuntime> mrClass =
(Class<WASRegistryManagedRuntime>) J2DoPrivHelper
.getForNameAction(
WASRegistryManagedRuntime.class.getName(),
true, cl).run();
mr = J2DoPrivHelper.newInstanceAction(mrClass).run();
} catch (Throwable t) {
// safe to ignore
}
WAS_REG = (WASRegistryManagedRuntime) mr;
}
private Configuration _conf = null;
private ManagedRuntime _runtime = null;
@Override
public TransactionManager getTransactionManager()
throws Exception {
if (_runtime != null)
return _runtime.getTransactionManager();
List<Throwable> errors = new LinkedList<>();
TransactionManager tm = null;
// Try the registry extensions first so that any applicable vendor
// specific extensions are used.
if (WAS_REG != null) {
try {
tm = WAS_REG.getTransactionManager();
} catch (Throwable t) {
errors.add(t);
}
if (tm != null) {
_runtime = WAS_REG;
return tm;
}
}
// Then try the registry, which is the official way to obtain
// transaction synchronication in JTA 1.1
if (REGISTRY != null) {
try {
tm = REGISTRY.getTransactionManager();
} catch (Throwable t) {
errors.add(t);
}
if (tm != null) {
_runtime = REGISTRY;
return tm;
}
}
if (WLS != null) {
try {
tm = WLS.getTransactionManager();
} catch (Throwable t) {
errors.add(t);
}
if (tm != null) {
_runtime = WLS;
return tm;
}
}
if (WAS != null) {
try {
WAS.setConfiguration(_conf);
WAS.startConfiguration();
WAS.endConfiguration();
tm = WAS.getTransactionManager();
} catch (Throwable t) {
errors.add(t);
}
if (tm != null) {
_runtime = WAS;
return tm;
}
}
// try to find a jndi runtime
JNDIManagedRuntime jmr = new JNDIManagedRuntime();
for (String jndiLoc : JNDI_LOCS) {
jmr.setTransactionManagerName(jndiLoc);
try {
tm = jmr.getTransactionManager();
}
catch (Throwable t) {
errors.add(t);
}
if (tm != null) {
_runtime = jmr;
return tm;
}
}
// look for a method runtime
InvocationManagedRuntime imr = new InvocationManagedRuntime();
for (String method : METHODS) {
imr.setConfiguration(_conf);
imr.setTransactionManagerMethod(method);
try {
tm = imr.getTransactionManager();
}
catch (Throwable t) {
errors.add(t);
}
if (tm != null) {
_runtime = imr;
return tm;
}
}
if (SUNONE != null) {
try {
tm = SUNONE.getTransactionManager();
} catch (Throwable t) {
errors.add(t);
}
if (tm != null) {
_runtime = SUNONE;
return tm;
}
}
Throwable[] t = (Throwable []) errors.toArray(
new Throwable [errors.size()]);
throw new InvalidStateException(_loc.get("tm-not-found")).
setFatal(true).setNestedThrowables(t);
}
@Override
public void setConfiguration(Configuration conf) {
_conf = conf;
}
@Override
public void startConfiguration() {
}
@Override
public void endConfiguration() {
}
@Override
public void setRollbackOnly(Throwable cause)
throws Exception {
// check to see if the runtime is cached
if (_runtime == null)
getTransactionManager();
if (_runtime != null)
_runtime.setRollbackOnly(cause);
}
@Override
public Throwable getRollbackCause()
throws Exception {
// check to see if the runtime is cached
if (_runtime == null)
getTransactionManager();
if (_runtime != null)
return _runtime.getRollbackCause();
return null;
}
@Override
public Object getTransactionKey() throws Exception, SystemException {
if(_runtime == null)
getTransactionManager();
if(_runtime != null )
return _runtime.getTransactionKey();
return null;
}
/**
* Delegate nonTransactional work to the appropriate managed runtime. If no
* managed runtime is found then delegate {@link AbstractManagedRuntime}.
*/
@Override
public void doNonTransactionalWork(Runnable runnable)
throws NotSupportedException {
// Obtain a transaction manager to initialize the runtime.
try {
getTransactionManager();
} catch (Exception e) {
NotSupportedException nse =
new NotSupportedException(_loc
.get("tm-unavailable", _runtime).getMessage());
nse.initCause(e);
throw nse;
}
_runtime.doNonTransactionalWork(runnable);
}
}