/**
* Copyright (c) 2013-2016, The SeedStack authors <http://seedstack.org>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.seedstack.seed.core.internal.transaction;
import io.nuun.kernel.api.plugin.InitState;
import io.nuun.kernel.api.plugin.PluginException;
import io.nuun.kernel.api.plugin.context.InitContext;
import io.nuun.kernel.api.plugin.request.ClasspathScanRequest;
import org.seedstack.seed.core.internal.AbstractSeedPlugin;
import org.seedstack.seed.transaction.TransactionConfig;
import org.seedstack.seed.transaction.spi.TransactionHandler;
import org.seedstack.seed.transaction.spi.TransactionManager;
import org.seedstack.seed.transaction.spi.TransactionMetadataResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
/**
* This plugin manages transactional matters in SEED code:
* <ul>
* <li>detects transaction-enabled methods and add the corresponding interceptor around them,</li>
* <li>holds a registry of all transaction handlers,</li>
* <li>provides various utilities for implementing transactional behavior.</li>
* </ul>
*/
public class TransactionPlugin extends AbstractSeedPlugin {
private static final Logger LOGGER = LoggerFactory.getLogger(TransactionPlugin.class);
private final Set<Class<? extends TransactionMetadataResolver>> transactionMetadataResolvers = new HashSet<>();
private TransactionManager transactionManager;
private Class<? extends TransactionHandler> defaultTransactionHandlerClass;
@Override
public String name() {
return "transaction";
}
@Override
public Collection<ClasspathScanRequest> classpathScanRequests() {
return classpathScanRequestBuilder().subtypeOf(TransactionMetadataResolver.class).build();
}
@Override
public InitState initialize(InitContext initContext) {
TransactionConfig transactionConfig = getConfiguration(TransactionConfig.class);
Class<? extends TransactionManager> txManager = transactionConfig.getManager();
if (txManager == null) {
txManager = LocalTransactionManager.class;
}
try {
this.transactionManager = txManager.newInstance();
} catch (Exception e) {
throw new PluginException("Unable to instantiate transaction manager from class " + txManager, e);
}
this.defaultTransactionHandlerClass = transactionConfig.getDefaultHandler();
initContext.scannedSubTypesByParentClass().get(TransactionMetadataResolver.class).stream()
.filter(TransactionMetadataResolver.class::isAssignableFrom)
.forEach(candidate -> {
transactionMetadataResolvers.add(candidate.asSubclass(TransactionMetadataResolver.class));
LOGGER.trace("Detected transaction metadata resolver {}", candidate.getCanonicalName());
});
LOGGER.debug("Detected {} transaction metadata resolver(s)", transactionMetadataResolvers.size());
return InitState.INITIALIZED;
}
@Override
public Object nativeUnitModule() {
return new TransactionModule(
this.transactionManager,
this.defaultTransactionHandlerClass,
this.transactionMetadataResolvers
);
}
/**
* Checks if a method is detected as transactional by this plugin.
*
* @param method the method to check.
* @return true if the method is candidate to be transactional, false otherwise.
*/
public boolean isTransactional(Method method) {
return TransactionalResolver.INSTANCE.test(method);
}
}