Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pluggable BTM context #39

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions btm/src/main/java/bitronix/tm/ServicesFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package bitronix.tm;

import bitronix.tm.BitronixTransactionManager;
import bitronix.tm.BitronixTransactionSynchronizationRegistry;
import bitronix.tm.Configuration;
import bitronix.tm.TransactionManagerServices;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import bitronix.tm.journal.DiskJournal;
import bitronix.tm.journal.Journal;
import bitronix.tm.journal.NullJournal;
import bitronix.tm.recovery.Recoverer;
import bitronix.tm.resource.ResourceLoader;
import bitronix.tm.timer.TaskScheduler;
import bitronix.tm.twopc.executor.AsyncExecutor;
import bitronix.tm.twopc.executor.Executor;
import bitronix.tm.twopc.executor.SyncExecutor;
import bitronix.tm.utils.ClassLoaderUtils;
import bitronix.tm.utils.DefaultExceptionAnalyzer;
import bitronix.tm.utils.ExceptionAnalyzer;
import bitronix.tm.utils.InitializationException;

/**
* Factory of services.
*/
public class ServicesFactory {
private final static Logger log = LoggerFactory.getLogger(TransactionManagerServices.class);

public static BitronixTransactionManager crateTransactionManager() {
return new BitronixTransactionManager();
}

public static BitronixTransactionSynchronizationRegistry createTransactionSynchronizationRegistry() {
return new BitronixTransactionSynchronizationRegistry();
}

public static Configuration createConfiguration() {
return new Configuration();
}

public static Journal createJournal(Journal journal, String configuredJournal) throws InitializationException {
if ("null".equals(configuredJournal) || null == configuredJournal) {
journal = new NullJournal();
} else if ("disk".equals(configuredJournal)) {
journal = new DiskJournal();
} else {
try {
Class<?> clazz = ClassLoaderUtils.loadClass(configuredJournal);
journal = (Journal) clazz.newInstance();
} catch (Exception ex) {
throw new InitializationException("invalid journal implementation '" + configuredJournal + "'", ex);
}
}
if (log.isDebugEnabled()) {
log.debug("using journal " + configuredJournal);
}
return journal;
}

public static TaskScheduler createTaskScheduler() {
return new TaskScheduler();
}

public static ResourceLoader createResourceLoader() {
return new ResourceLoader();
}

public static Recoverer createRecoverer() {
return new Recoverer();
}

public static Executor createExecutor(boolean isAsynchronouse2Pc) {
Executor executor;
if (isAsynchronouse2Pc) {
if (log.isDebugEnabled()) {
log.debug("using AsyncExecutor");
}
executor = new AsyncExecutor();
} else {
if (log.isDebugEnabled()) {
log.debug("using SyncExecutor");
}
executor = new SyncExecutor();
}
return executor;
}

public static ExceptionAnalyzer createExceptionAnalyser(String exceptionAnalyzerName) {
ExceptionAnalyzer analyzer;
analyzer = new DefaultExceptionAnalyzer();
if (exceptionAnalyzerName != null) {
try {
analyzer = (ExceptionAnalyzer) ClassLoaderUtils.loadClass(exceptionAnalyzerName).newInstance();
} catch (Exception ex) {
log.warn("failed to initialize custom exception analyzer, using default one instead", ex);
}
}
return analyzer;
}


}
169 changes: 27 additions & 142 deletions btm/src/main/java/bitronix/tm/TransactionManagerServices.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,18 @@
*/
package bitronix.tm;

import bitronix.tm.journal.DiskJournal;
import java.util.Iterator;
import java.util.ServiceLoader;

import bitronix.tm.journal.Journal;
import bitronix.tm.journal.NullJournal;
import bitronix.tm.recovery.Recoverer;
import bitronix.tm.resource.ResourceLoader;
import bitronix.tm.spi.BitronixContext;
import bitronix.tm.spi.DefaultBitronixContext;
import bitronix.tm.timer.TaskScheduler;
import bitronix.tm.twopc.executor.AsyncExecutor;
import bitronix.tm.twopc.executor.Executor;
import bitronix.tm.twopc.executor.SyncExecutor;
import bitronix.tm.utils.ClassLoaderUtils;
import bitronix.tm.utils.DefaultExceptionAnalyzer;
import bitronix.tm.utils.ExceptionAnalyzer;
import bitronix.tm.utils.InitializationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
* Container for all BTM services.
Expand All @@ -45,218 +38,110 @@
*/
public class TransactionManagerServices {

private final static Logger log = LoggerFactory.getLogger(TransactionManagerServices.class);

private static final Lock transactionManagerLock = new ReentrantLock();
private static volatile BitronixTransactionManager transactionManager;
private final static BitronixContext context;

private static final AtomicReference<BitronixTransactionSynchronizationRegistry> transactionSynchronizationRegistryRef = new AtomicReference<BitronixTransactionSynchronizationRegistry>();
private static final AtomicReference<Configuration> configurationRef = new AtomicReference<Configuration>();
private static final AtomicReference<Journal> journalRef = new AtomicReference<Journal>();
private static final AtomicReference<TaskScheduler> taskSchedulerRef = new AtomicReference<TaskScheduler>();
private static final AtomicReference<ResourceLoader> resourceLoaderRef = new AtomicReference<ResourceLoader>();
private static final AtomicReference<Recoverer> recovererRef = new AtomicReference<Recoverer>();
private static final AtomicReference<Executor> executorRef = new AtomicReference<Executor>();
private static final AtomicReference<ExceptionAnalyzer> exceptionAnalyzerRef = new AtomicReference<ExceptionAnalyzer>();
static {
Iterator<BitronixContext> iterator = ServiceLoader.load(BitronixContext.class).iterator();
if (iterator.hasNext()) {
context = iterator.next();
} else {
context = new DefaultBitronixContext();
}
}

/**
* Create an initialized transaction manager.
* @return the transaction manager.
*/
public static BitronixTransactionManager getTransactionManager() {
transactionManagerLock.lock();
try {
if (transactionManager == null) {
transactionManager = new BitronixTransactionManager();
}
return transactionManager;
} finally {
transactionManagerLock.unlock();
}
return context.getTransactionManager();
}

/**
* Create the JTA 1.1 TransactionSynchronizationRegistry.
* @return the TransactionSynchronizationRegistry.
*/
public static BitronixTransactionSynchronizationRegistry getTransactionSynchronizationRegistry() {
BitronixTransactionSynchronizationRegistry transactionSynchronizationRegistry = transactionSynchronizationRegistryRef.get();
if (transactionSynchronizationRegistry == null) {
transactionSynchronizationRegistry = new BitronixTransactionSynchronizationRegistry();
if (!transactionSynchronizationRegistryRef.compareAndSet(null, transactionSynchronizationRegistry)) {
transactionSynchronizationRegistry = transactionSynchronizationRegistryRef.get();
}
}
return transactionSynchronizationRegistry;
return context.getTransactionSynchronizationRegistry();
}

/**
* Create the configuration of all the components of the transaction manager.
* @return the global configuration.
*/
public static Configuration getConfiguration() {
Configuration configuration = configurationRef.get();
if (configuration == null) {
configuration = new Configuration();
if (!configurationRef.compareAndSet(null, configuration)) {
configuration = configurationRef.get();
}
}
return configuration;
return context.getConfiguration();
}

/**
* Create the transactions journal.
* @return the transactions journal.
*/
public static Journal getJournal() {
Journal journal = journalRef.get();
if (journal == null) {
String configuredJournal = getConfiguration().getJournal();
if ("null".equals(configuredJournal) || null == configuredJournal) {
journal = new NullJournal();
} else if ("disk".equals(configuredJournal)) {
journal = new DiskJournal();
} else {
try {
Class<?> clazz = ClassLoaderUtils.loadClass(configuredJournal);
journal = (Journal) clazz.newInstance();
} catch (Exception ex) {
throw new InitializationException("invalid journal implementation '" + configuredJournal + "'", ex);
}
}
if (log.isDebugEnabled()) { log.debug("using journal " + configuredJournal); }

if (!journalRef.compareAndSet(null, journal)) {
journal = journalRef.get();
}
}
return journal;
return context.getJournal();
}

/**
* Create the task scheduler.
* @return the task scheduler.
*/
public static TaskScheduler getTaskScheduler() {
TaskScheduler taskScheduler = taskSchedulerRef.get();
if (taskScheduler == null) {
taskScheduler = new TaskScheduler();
if (!taskSchedulerRef.compareAndSet(null, taskScheduler)) {
taskScheduler = taskSchedulerRef.get();
} else {
taskScheduler.start();
}
}
return taskScheduler;
return context.getTaskScheduler();
}

/**
* Create the resource loader.
* @return the resource loader.
*/
public static ResourceLoader getResourceLoader() {
ResourceLoader resourceLoader = resourceLoaderRef.get();
if (resourceLoader == null) {
resourceLoader = new ResourceLoader();
if (!resourceLoaderRef.compareAndSet(null, resourceLoader)) {
resourceLoader = resourceLoaderRef.get();
}
}
return resourceLoader;
return context.getResourceLoader();
}

/**
* Create the transaction recoverer.
* @return the transaction recoverer.
*/
public static Recoverer getRecoverer() {
Recoverer recoverer = recovererRef.get();
if (recoverer == null) {
recoverer = new Recoverer();
if (!recovererRef.compareAndSet(null, recoverer)) {
recoverer = recovererRef.get();
}
}
return recoverer;
return context.getRecoverer();
}

/**
* Create the 2PC executor.
* @return the 2PC executor.
*/
public static Executor getExecutor() {
Executor executor = executorRef.get();
if (executor == null) {
if (getConfiguration().isAsynchronous2Pc()) {
if (log.isDebugEnabled()) { log.debug("using AsyncExecutor"); }
executor = new AsyncExecutor();
} else {
if (log.isDebugEnabled()) { log.debug("using SyncExecutor"); }
executor = new SyncExecutor();
}
if (!executorRef.compareAndSet(null, executor)) {
executor.shutdown();
executor = executorRef.get();
}
}
return executor;
return context.getExecutor();
}

/**
* Create the exception analyzer.
* @return the exception analyzer.
*/
public static ExceptionAnalyzer getExceptionAnalyzer() {
ExceptionAnalyzer analyzer = exceptionAnalyzerRef.get();
if (analyzer == null) {
String exceptionAnalyzerName = getConfiguration().getExceptionAnalyzer();
analyzer = new DefaultExceptionAnalyzer();
if (exceptionAnalyzerName != null) {
try {
analyzer = (ExceptionAnalyzer) ClassLoaderUtils.loadClass(exceptionAnalyzerName).newInstance();
} catch (Exception ex) {
log.warn("failed to initialize custom exception analyzer, using default one instead", ex);
}
}
if (!exceptionAnalyzerRef.compareAndSet(null, analyzer)) {
analyzer.shutdown();
analyzer = exceptionAnalyzerRef.get();
}
}
return analyzer;
public static ExceptionAnalyzer getExceptionAnalyzer() {
return context.getExceptionAnalyzer();
}

/**
* Check if the transaction manager has started.
* @return true if the transaction manager has started.
*/
public static boolean isTransactionManagerRunning() {
return transactionManager != null;
return context.isTransactionManagerRunning();
}

/**
* Check if the task scheduler has started.
* @return true if the task scheduler has started.
*/
public static boolean isTaskSchedulerRunning() {
return taskSchedulerRef.get() != null;
return context.isTaskSchedulerRunning();
}

/**
* Clear services references. Called at the end of the shutdown procedure.
*/
protected static synchronized void clear() {
transactionManager = null;

transactionSynchronizationRegistryRef.set(null);
configurationRef.set(null);
journalRef.set(null);
taskSchedulerRef.set(null);
resourceLoaderRef.set(null);
recovererRef.set(null);
executorRef.set(null);
exceptionAnalyzerRef.set(null);
context.clear();
}

}
Loading