/*
* JBoss, Home of Professional Open Source
* Copyright 2009, Red Hat Middleware LLC, and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package com.arjuna.ats.jta.distributed.server.impl;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;
import javax.transaction.RollbackException;
import javax.transaction.Synchronization;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import javax.transaction.xa.XAException;
import javax.transaction.xa.Xid;
import org.jboss.tm.ExtendedJBossXATerminator;
import org.jboss.tm.TransactionImportResult;
import org.jboss.tm.JBossXATerminator;
import org.jboss.tm.TransactionTimeoutConfiguration;
import com.arjuna.ats.arjuna.common.CoordinatorEnvironmentBean;
import com.arjuna.ats.arjuna.common.CoreEnvironmentBean;
import com.arjuna.ats.arjuna.common.CoreEnvironmentBeanException;
import com.arjuna.ats.arjuna.common.ObjectStoreEnvironmentBean;
import com.arjuna.ats.arjuna.common.RecoveryEnvironmentBean;
import com.arjuna.ats.arjuna.coordinator.TransactionReaper;
import com.arjuna.ats.arjuna.coordinator.TxControl;
import com.arjuna.ats.arjuna.recovery.RecoveryManager;
import com.arjuna.ats.internal.arjuna.utils.ManualProcessId;
import com.arjuna.ats.internal.jbossatx.jta.XAResourceRecordWrappingPluginImpl;
import com.arjuna.ats.internal.jta.recovery.arjunacore.RecoveryXids;
import com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionImple;
import com.arjuna.ats.jbossatx.jta.RecoveryManagerService;
import com.arjuna.ats.jbossatx.jta.TransactionManagerService;
import com.arjuna.ats.jta.common.JTAEnvironmentBean;
import com.arjuna.ats.jta.distributed.TestResourceRecovery;
import com.arjuna.ats.jta.distributed.server.LocalServer;
import com.arjuna.ats.jta.distributed.server.LookupProvider;
import com.arjuna.ats.jta.distributed.server.RemoteServer;
public class ServerImpl implements LocalServer {
private String nodeName;
private RecoveryManagerService recoveryManagerService;
private TransactionManagerService transactionManagerService;
private RecoveryManager _recoveryManager;
private ClassLoader classLoaderForTransactionManager;
public void initialise(LookupProvider lookupProvider, String nodeName, int portOffset, String[] clusterBuddies, ClassLoader classLoaderForTransactionManager)
throws CoreEnvironmentBeanException, IOException, SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
this.nodeName = nodeName;
this.classLoaderForTransactionManager = classLoaderForTransactionManager;
RecoveryEnvironmentBean recoveryEnvironmentBean = com.arjuna.ats.arjuna.common.recoveryPropertyManager.getRecoveryEnvironmentBean();
recoveryEnvironmentBean.setRecoveryBackoffPeriod(1);
recoveryEnvironmentBean.setRecoveryInetAddress(InetAddress.getByName("localhost"));
recoveryEnvironmentBean.setRecoveryPort(4712 + portOffset);
recoveryEnvironmentBean.setTransactionStatusManagerInetAddress(InetAddress.getByName("localhost"));
recoveryEnvironmentBean.setTransactionStatusManagerPort(4713 + portOffset);
List<String> recoveryModuleClassNames = new ArrayList<String>();
recoveryModuleClassNames.add("com.arjuna.ats.internal.arjuna.recovery.AtomicActionRecoveryModule");
// recoveryModuleClassNames.add("com.arjuna.ats.internal.txoj.recovery.TORecoveryModule");
recoveryModuleClassNames.add("com.arjuna.ats.internal.jta.recovery.arjunacore.XARecoveryModule");
recoveryEnvironmentBean.setRecoveryModuleClassNames(recoveryModuleClassNames);
List<String> expiryScannerClassNames = new ArrayList<String>();
expiryScannerClassNames.add("com.arjuna.ats.internal.arjuna.recovery.ExpiredTransactionStatusManagerScanner");
recoveryEnvironmentBean.setExpiryScannerClassNames(expiryScannerClassNames);
recoveryEnvironmentBean.setRecoveryActivators(null);
CoreEnvironmentBean coreEnvironmentBean = com.arjuna.ats.arjuna.common.arjPropertyManager.getCoreEnvironmentBean();
// coreEnvironmentBean.setSocketProcessIdPort(4714 + nodeName);
coreEnvironmentBean.setNodeIdentifier(nodeName);
// coreEnvironmentBean.setSocketProcessIdMaxPorts(1);
coreEnvironmentBean.setProcessImplementationClassName(ManualProcessId.class.getName());
coreEnvironmentBean.setPid(portOffset);
CoordinatorEnvironmentBean coordinatorEnvironmentBean = com.arjuna.ats.arjuna.common.arjPropertyManager.getCoordinatorEnvironmentBean();
coordinatorEnvironmentBean.setEnableStatistics(false);
coordinatorEnvironmentBean.setDefaultTimeout(300);
coordinatorEnvironmentBean.setTransactionStatusManagerEnable(false);
coordinatorEnvironmentBean.setDefaultTimeout(0);
ObjectStoreEnvironmentBean actionStoreObjectStoreEnvironmentBean = com.arjuna.common.internal.util.propertyservice.BeanPopulator.getNamedInstance(
com.arjuna.ats.arjuna.common.ObjectStoreEnvironmentBean.class, null);
actionStoreObjectStoreEnvironmentBean.setObjectStoreDir(System.getProperty("user.dir") + "/distributedjta-tests/tx-object-store/" + nodeName);
ObjectStoreEnvironmentBean stateStoreObjectStoreEnvironmentBean = com.arjuna.common.internal.util.propertyservice.BeanPopulator.getNamedInstance(
com.arjuna.ats.arjuna.common.ObjectStoreEnvironmentBean.class, "stateStore");
stateStoreObjectStoreEnvironmentBean.setObjectStoreDir(System.getProperty("user.dir") + "/distributedjta-tests/tx-object-store/" + nodeName);
ObjectStoreEnvironmentBean communicationStoreObjectStoreEnvironmentBean = com.arjuna.common.internal.util.propertyservice.BeanPopulator
.getNamedInstance(com.arjuna.ats.arjuna.common.ObjectStoreEnvironmentBean.class, "communicationStore");
communicationStoreObjectStoreEnvironmentBean.setObjectStoreDir(System.getProperty("user.dir") + "/distributedjta-tests/tx-object-store/" + nodeName);
JTAEnvironmentBean jTAEnvironmentBean = com.arjuna.ats.jta.common.jtaPropertyManager.getJTAEnvironmentBean();
jTAEnvironmentBean.setLastResourceOptimisationInterface(org.jboss.tm.LastResource.class);
jTAEnvironmentBean.setTransactionManagerClassName("com.arjuna.ats.jbossatx.jta.TransactionManagerDelegate");
jTAEnvironmentBean.setUserTransactionClassName("com.arjuna.ats.internal.jta.transaction.arjunacore.UserTransactionImple");
jTAEnvironmentBean
.setTransactionSynchronizationRegistryClassName("com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionSynchronizationRegistryImple");
List<String> xaRecoveryNodes = new ArrayList<String>();
xaRecoveryNodes.add(nodeName);
jTAEnvironmentBean.setXaRecoveryNodes(xaRecoveryNodes);
List<String> xaResourceOrphanFilterClassNames = new ArrayList<String>();
xaResourceOrphanFilterClassNames.add("com.arjuna.ats.internal.jta.recovery.arjunacore.JTATransactionLogXAResourceOrphanFilter");
xaResourceOrphanFilterClassNames.add("com.arjuna.ats.internal.jta.recovery.arjunacore.JTANodeNameXAResourceOrphanFilter");
xaResourceOrphanFilterClassNames.add("com.arjuna.ats.internal.jta.recovery.arjunacore.SubordinateJTAXAResourceOrphanFilter");
jTAEnvironmentBean.setXaResourceOrphanFilterClassNames(xaResourceOrphanFilterClassNames);
jTAEnvironmentBean.setXAResourceRecordWrappingPlugin(new XAResourceRecordWrappingPluginImpl());
recoveryManagerService = new RecoveryManagerService();
recoveryManagerService.create();
recoveryManagerService.addXAResourceRecovery(new TestResourceRecovery(nodeName));
// This MUST be the last XAResourceRecovery class registered or you will
// get unexpected recovery results, could add a specific interface for
// this?
recoveryManagerService.addXAResourceRecovery(new ProxyXAResourceRecovery(nodeName, clusterBuddies));
recoveryManagerService.addSerializableXAResourceDeserializer(new ProxyXAResourceDeserializer());
// recoveryManagerService.start();
_recoveryManager = RecoveryManager.manager();
RecoveryManager.manager().initialize();
transactionManagerService = new TransactionManagerService();
TxControl txControl = new com.arjuna.ats.arjuna.coordinator.TxControl();
transactionManagerService.setJbossXATerminator(new com.arjuna.ats.internal.jbossatx.jta.jca.XATerminator());
transactionManagerService
.setTransactionSynchronizationRegistry(new com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionSynchronizationRegistryImple());
transactionManagerService.create();
}
@Override
public ClassLoader getClassLoader() {
return classLoaderForTransactionManager;
}
@Override
public void shutdown() throws Exception {
recoveryManagerService.stop();
TransactionReaper.transactionReaper().terminate(false);
}
@Override
public void doRecoveryManagerScan(boolean shortenSafetyInterval) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(getClassLoader());
int originalSafetyInterval = -1;
if (shortenSafetyInterval) {
try {
Field safetyIntervalMillis = RecoveryXids.class.getDeclaredField("safetyIntervalMillis");
safetyIntervalMillis.setAccessible(true);
originalSafetyInterval = (Integer) safetyIntervalMillis.get(null);
safetyIntervalMillis.set(null, 0);
} catch (Throwable t) {
t.printStackTrace();
}
} else {
try {
Field safetyIntervalMillis = RecoveryXids.class.getDeclaredField("safetyIntervalMillis");
safetyIntervalMillis.setAccessible(true);
originalSafetyInterval = (Integer) safetyIntervalMillis.get(null);
safetyIntervalMillis.set(null, 60000);
} catch (Throwable t) {
t.printStackTrace();
}
}
_recoveryManager.scan();
if (shortenSafetyInterval) {
try {
Field safetyIntervalMillis = RecoveryXids.class.getDeclaredField("safetyIntervalMillis");
safetyIntervalMillis.setAccessible(true);
safetyIntervalMillis.set(null, originalSafetyInterval);
} catch (Throwable t) {
t.printStackTrace();
}
} else {
try {
Field safetyIntervalMillis = RecoveryXids.class.getDeclaredField("safetyIntervalMillis");
safetyIntervalMillis.setAccessible(true);
safetyIntervalMillis.set(null, originalSafetyInterval);
} catch (Throwable t) {
t.printStackTrace();
}
}
Thread.currentThread().setContextClassLoader(classLoader);
}
@Override
public TransactionManager getTransactionManager() {
return transactionManagerService.getTransactionManager();
}
@Override
public Xid locateOrImportTransactionThenResumeIt(int remainingTimeout, Xid toResume) throws XAException, IllegalStateException, SystemException,
IOException {
JBossXATerminator xaTerminator = transactionManagerService.getJbossXATerminator();
if (!ExtendedJBossXATerminator.class.isInstance(xaTerminator)) {
System.out.printf("ExtendedJBossXATerminator: FAIL not an instance");
return null;
}
ExtendedJBossXATerminator extendedJBossXATerminator = (ExtendedJBossXATerminator) xaTerminator;
boolean subordinateCreated = false;
Transaction transaction = extendedJBossXATerminator.getTransaction(toResume);
if (transaction == null) {
TransactionImportResult transactionImportResult = extendedJBossXATerminator.importTransaction(toResume, remainingTimeout);
subordinateCreated = transactionImportResult.isNewImportedTransaction();
transaction = transactionImportResult.getTransaction();
}
transactionManagerService.getTransactionManager().resume(transaction);
return subordinateCreated ? ((com.arjuna.ats.jta.transaction.Transaction) transaction).getTxId() : null;
}
@Override
public String getNodeName() {
return nodeName;
}
@Override
public long getTimeLeftBeforeTransactionTimeout() throws RollbackException {
return ((TransactionTimeoutConfiguration) transactionManagerService.getTransactionManager()).getTimeLeftBeforeTransactionTimeout(true);
}
@Override
public Xid getCurrentXid() throws SystemException {
TransactionImple transaction = ((TransactionImple) transactionManagerService.getTransactionManager().getTransaction());
return transaction.getTxId();
}
@Override
public ProxyXAResource generateProxyXAResource(String remoteServerName, Xid migratedXid) throws SystemException, IOException {
return new ProxyXAResource(nodeName, remoteServerName, migratedXid, false);
}
@Override
public ProxyXAResource generateProxyXAResource(String remoteServerName, Xid migratedXid, boolean handleError) throws SystemException, IOException {
return new ProxyXAResource(nodeName, remoteServerName, migratedXid, handleError);
}
@Override
public Synchronization generateProxySynchronization(String remoteServerName, Xid toRegisterAgainst) {
return new ProxySynchronization(nodeName, remoteServerName, toRegisterAgainst);
}
@Override
public RemoteServer connectTo() {
return new RemoteServerImpl();
}
}