/*
* JBoss, Home of Professional Open Source.
* Copyright 2013, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file 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 io.narayana.spi;
import com.arjuna.ats.arjuna.common.RecoveryEnvironmentBean;
import com.arjuna.ats.arjuna.common.recoveryPropertyManager;
import com.arjuna.ats.arjuna.logging.tsLogger;
import com.arjuna.ats.arjuna.recovery.RecoveryManager;
import com.arjuna.ats.jdbc.TransactionalDriver;
import com.arjuna.ats.jdbc.common.jdbcPropertyManager;
import com.arjuna.ats.jta.common.jtaPropertyManager;
import com.arjuna.ats.jta.utils.JNDIManager;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.*;
public class TransactionServiceFactory {
private static RecoveryManager recoveryManager;
private static boolean initialized = false;
private static InitialContext initialContext;
private static Set<String> jndiBindings = new HashSet<String>();
private static boolean replacedJndiProperties = false;
/**
* Makes the transaction service available by bind various transaction related object into the default
* JNDI tree.
* @param startRecoveryService set to true to start the recovery service.
* @throws InitializationException if no usable InitialContext is available
*/
public static synchronized void start(boolean startRecoveryService) throws InitializationException {
if (initialized)
return;
try {
initialContext = new InitialContext();
replacedJndiProperties = jdbcPropertyManager.getJDBCEnvironmentBean().getJndiProperties().size() == 0;
if (replacedJndiProperties)
jdbcPropertyManager.getJDBCEnvironmentBean().setJndiProperties(initialContext.getEnvironment());
DriverManager.registerDriver(new TransactionalDriver());
} catch (NamingException e) {
if (tsLogger.logger.isInfoEnabled())
tsLogger.logger.info("TransactionServiceFactory error:", e);
throw new InitializationException("No suitable JNDI provider available", e);
} catch (SQLException e) {
if (tsLogger.logger.isInfoEnabled())
tsLogger.logger.info("TransactionServiceFactory error:", e);
throw new InitializationException("Cannot initialize TransactionalDriver", e);
}
registerJndiBindings(initialContext);
initialized = true;
if (startRecoveryService)
startRecoveryService();
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
TransactionServiceFactory.stop();
}
});
}
/**
* Stop the transaction service. If the recovery manager was started previously then it to will be stopped.
*/
public static synchronized void stop() {
if (!initialized)
return;
if (recoveryManager != null) {
recoveryManager.terminate();
recoveryManager = null;
}
unregisterJndiBindings();
try {
DriverManager.deregisterDriver(new TransactionalDriver());
} catch (SQLException e) {
if (tsLogger.logger.isInfoEnabled())
tsLogger.logger.debug("Unable to deregister TransactionalDriver: " + e.getMessage(), e);
}
if (replacedJndiProperties)
jdbcPropertyManager.getJDBCEnvironmentBean().setJndiProperties(null);
initialized = false;
}
private static void startRecoveryService() {
if (recoveryManager == null) {
final RecoveryEnvironmentBean recoveryEnvironmentBean = recoveryPropertyManager.getRecoveryEnvironmentBean();
recoveryEnvironmentBean.setRecoveryModuleClassNames(Arrays.asList(
"com.arjuna.ats.internal.arjuna.recovery.AtomicActionRecoveryModule",
"com.arjuna.ats.internal.jta.recovery.arjunacore.XARecoveryModule"));
RecoveryManager.delayRecoveryManagerThread();
recoveryManager = RecoveryManager.manager();
recoveryManager.initialize();
}
}
private static Set<String> registerJndiBindings(InitialContext initialContext) throws InitializationException {
try {
JNDIManager.bindJTATransactionManagerImplementation(initialContext);
jndiBindings.add(jtaPropertyManager.getJTAEnvironmentBean().getTransactionManagerJNDIContext());
JNDIManager.bindJTAUserTransactionImplementation(initialContext);
jndiBindings.add(jtaPropertyManager.getJTAEnvironmentBean().getUserTransactionJNDIContext());
JNDIManager.bindJTATransactionSynchronizationRegistryImplementation(initialContext);
jndiBindings.add(jtaPropertyManager.getJTAEnvironmentBean().getTransactionSynchronizationRegistryJNDIContext());
} catch (NamingException e) {
if (tsLogger.logger.isInfoEnabled())
tsLogger.logger.infof("Unable to bind TM into JNDI: %s", e.getMessage());
throw new InitializationException("Unable to bind TM into JNDI", e);
}
return jndiBindings;
}
private static void unregisterJndiBindings() {
Iterator<String> bindingIterator = jndiBindings.iterator();
while (bindingIterator.hasNext()) {
try {
initialContext.unbind(bindingIterator.next());
} catch (NamingException e) {
if (tsLogger.logger.isDebugEnabled())
tsLogger.logger.debugf("Unable to unregister JNDI binding: %s" + e.getMessage());
}
bindingIterator.remove();
}
jndiBindings.clear();
}
}