org.infinispan.factories.InterceptorChainFactory Maven / Gradle / Ivy
package org.infinispan.factories;
import java.util.List;
import org.infinispan.commons.CacheConfigurationException;
import org.infinispan.commons.CacheException;
import org.infinispan.configuration.cache.CacheMode;
import org.infinispan.configuration.cache.CompatibilityModeConfiguration;
import org.infinispan.configuration.cache.Configuration;
import org.infinispan.configuration.cache.Configurations;
import org.infinispan.configuration.cache.CustomInterceptorsConfiguration;
import org.infinispan.configuration.cache.InterceptorConfiguration;
import org.infinispan.configuration.cache.StoreConfiguration;
import org.infinispan.factories.annotations.DefaultFactoryFor;
import org.infinispan.interceptors.AsyncInterceptor;
import org.infinispan.interceptors.AsyncInterceptorChain;
import org.infinispan.interceptors.InterceptorChain;
import org.infinispan.interceptors.distribution.DistributionBulkInterceptor;
import org.infinispan.interceptors.distribution.L1LastChanceInterceptor;
import org.infinispan.interceptors.distribution.L1NonTxInterceptor;
import org.infinispan.interceptors.distribution.L1TxInterceptor;
import org.infinispan.interceptors.distribution.NonTxDistributionInterceptor;
import org.infinispan.interceptors.distribution.ScatteredDistributionInterceptor;
import org.infinispan.interceptors.distribution.TriangleDistributionInterceptor;
import org.infinispan.interceptors.distribution.TxDistributionInterceptor;
import org.infinispan.interceptors.distribution.VersionedDistributionInterceptor;
import org.infinispan.interceptors.impl.AsyncInterceptorChainImpl;
import org.infinispan.interceptors.impl.BatchingInterceptor;
import org.infinispan.interceptors.impl.CacheLoaderInterceptor;
import org.infinispan.interceptors.impl.CacheMgmtInterceptor;
import org.infinispan.interceptors.impl.CacheWriterInterceptor;
import org.infinispan.interceptors.impl.CallInterceptor;
import org.infinispan.interceptors.impl.ClusteredCacheLoaderInterceptor;
import org.infinispan.interceptors.impl.CompatibilityInterceptor;
import org.infinispan.interceptors.impl.DistCacheWriterInterceptor;
import org.infinispan.interceptors.impl.EntryWrappingInterceptor;
import org.infinispan.interceptors.impl.GroupingInterceptor;
import org.infinispan.interceptors.impl.InvalidationInterceptor;
import org.infinispan.interceptors.impl.InvocationContextInterceptor;
import org.infinispan.interceptors.impl.IsMarshallableInterceptor;
import org.infinispan.interceptors.impl.NotificationInterceptor;
import org.infinispan.interceptors.impl.PassivationWriterInterceptor;
import org.infinispan.interceptors.impl.PrefetchInterceptor;
import org.infinispan.interceptors.impl.RetryingEntryWrappingInterceptor;
import org.infinispan.interceptors.impl.ScatteredCacheWriterInterceptor;
import org.infinispan.interceptors.impl.TransactionalStoreInterceptor;
import org.infinispan.interceptors.impl.TxInterceptor;
import org.infinispan.interceptors.impl.VersionedEntryWrappingInterceptor;
import org.infinispan.interceptors.locking.NonTransactionalLockingInterceptor;
import org.infinispan.interceptors.locking.OptimisticLockingInterceptor;
import org.infinispan.interceptors.locking.PessimisticLockingInterceptor;
import org.infinispan.interceptors.totalorder.TotalOrderDistributionInterceptor;
import org.infinispan.interceptors.totalorder.TotalOrderInterceptor;
import org.infinispan.interceptors.totalorder.TotalOrderStateTransferInterceptor;
import org.infinispan.interceptors.totalorder.TotalOrderVersionedDistributionInterceptor;
import org.infinispan.interceptors.totalorder.TotalOrderVersionedEntryWrappingInterceptor;
import org.infinispan.interceptors.xsite.NonTransactionalBackupInterceptor;
import org.infinispan.interceptors.xsite.OptimisticBackupInterceptor;
import org.infinispan.interceptors.xsite.PessimisticBackupInterceptor;
import org.infinispan.partitionhandling.PartitionHandling;
import org.infinispan.partitionhandling.impl.PartitionHandlingInterceptor;
import org.infinispan.statetransfer.StateTransferInterceptor;
import org.infinispan.statetransfer.TransactionSynchronizerInterceptor;
import org.infinispan.transaction.LockingMode;
import org.infinispan.transaction.TransactionMode;
import org.infinispan.util.logging.Log;
import org.infinispan.util.logging.LogFactory;
/**
* Factory class that builds an interceptor chain based on cache configuration.
*
* For backwards compatibility, the factory will register both a {@link AsyncInterceptorChain} and
* a {@link InterceptorChain} before initializing the interceptors.
*
* @author Manik Surtani ([email protected])
* @author [email protected]
* @author Marko Luksa
* @author Pedro Ruivo
* @since 4.0
*/
@DefaultFactoryFor(classes = {AsyncInterceptorChain.class, InterceptorChain.class})
public class InterceptorChainFactory extends AbstractNamedCacheComponentFactory implements AutoInstantiableFactory {
private static final Log log = LogFactory.getLog(InterceptorChainFactory.class);
private AsyncInterceptor createInterceptor(AsyncInterceptor interceptor,
Class extends AsyncInterceptor> interceptorType) {
AsyncInterceptor chainedInterceptor = componentRegistry.getComponent(interceptorType);
if (chainedInterceptor == null) {
register(interceptorType, interceptor);
chainedInterceptor = interceptor;
}
return chainedInterceptor;
}
private void register(Class extends AsyncInterceptor> clazz, AsyncInterceptor chainedInterceptor) {
try {
componentRegistry.registerComponent(chainedInterceptor, clazz);
} catch (RuntimeException e) {
log.unableToCreateInterceptor(clazz, e);
throw e;
}
}
public AsyncInterceptorChain buildInterceptorChain() {
TransactionMode transactionMode = configuration.transaction().transactionMode();
boolean needsVersionAwareComponents = transactionMode.isTransactional() &&
Configurations.isTxVersioned(configuration);
AsyncInterceptorChain interceptorChain =
new AsyncInterceptorChainImpl(componentRegistry.getComponentMetadataRepo());
// add the interceptor chain to the registry first, since some interceptors may ask for it.
// Add both the old class and the new interface
componentRegistry.registerComponent(interceptorChain, AsyncInterceptorChain.class);
componentRegistry.registerComponent(new InterceptorChain(interceptorChain), InterceptorChain.class);
boolean invocationBatching = configuration.invocationBatching().enabled();
boolean isTotalOrder = configuration.transaction().transactionProtocol().isTotalOrder();
CacheMode cacheMode = configuration.clustering().cacheMode();
if (cacheMode.needsStateTransfer()) {
interceptorChain.appendInterceptor(createInterceptor(new DistributionBulkInterceptor<>(),
DistributionBulkInterceptor.class), false);
}
// load the icInterceptor first
if (invocationBatching) {
interceptorChain.appendInterceptor(createInterceptor(new BatchingInterceptor(), BatchingInterceptor.class), false);
}
interceptorChain.appendInterceptor(createInterceptor(new InvocationContextInterceptor(), InvocationContextInterceptor.class), false);
CompatibilityModeConfiguration compatibility = configuration.compatibility();
if (compatibility.enabled()) {
interceptorChain.appendInterceptor(createInterceptor(
new CompatibilityInterceptor(), CompatibilityInterceptor.class), false);
}
// add marshallable check interceptor for situations where we want to figure out before marshalling
if (hasAsyncStore())
interceptorChain.appendInterceptor(createInterceptor(new IsMarshallableInterceptor(), IsMarshallableInterceptor.class), false);
// load the cache management interceptor next
if (configuration.jmxStatistics().available()) {
interceptorChain.appendInterceptor(createInterceptor(new CacheMgmtInterceptor(), CacheMgmtInterceptor.class), false);
}
// load the state transfer lock interceptor
// the state transfer lock ensures that the cache member list is up-to-date
// so it's necessary even if state transfer is disabled
if (cacheMode.needsStateTransfer()) {
if (isTotalOrder) {
interceptorChain.appendInterceptor(createInterceptor(new TotalOrderStateTransferInterceptor(),
TotalOrderStateTransferInterceptor.class), false);
} else {
interceptorChain.appendInterceptor(createInterceptor(new StateTransferInterceptor(), StateTransferInterceptor.class), false);
}
if (transactionMode.isTransactional()) {
interceptorChain.appendInterceptor(createInterceptor(new TransactionSynchronizerInterceptor(), TransactionSynchronizerInterceptor.class), false);
}
if (configuration.clustering().partitionHandling().whenSplit() != PartitionHandling.ALLOW_READ_WRITES) {
interceptorChain.appendInterceptor(createInterceptor(new PartitionHandlingInterceptor(), PartitionHandlingInterceptor.class), false);
}
}
//load total order interceptor
if (isTotalOrder) {
interceptorChain.appendInterceptor(createInterceptor(new TotalOrderInterceptor(), TotalOrderInterceptor.class), false);
}
// load the tx interceptor
if (transactionMode.isTransactional())
interceptorChain.appendInterceptor(createInterceptor(new TxInterceptor(), TxInterceptor.class), false);
//the total order protocol doesn't need locks
if (!isTotalOrder && !cacheMode.isScattered()) {
if (transactionMode.isTransactional()) {
if (configuration.transaction().lockingMode() == LockingMode.PESSIMISTIC) {
interceptorChain.appendInterceptor(createInterceptor(new PessimisticLockingInterceptor(), PessimisticLockingInterceptor.class), false);
} else {
interceptorChain.appendInterceptor(createInterceptor(new OptimisticLockingInterceptor(), OptimisticLockingInterceptor.class), false);
}
} else {
interceptorChain.appendInterceptor(createInterceptor(new NonTransactionalLockingInterceptor(), NonTransactionalLockingInterceptor.class), false);
}
}
// NotificationInterceptor is used only for Prepare/Commit/Rollback notifications
// This needs to be after locking interceptor to guarantee that locks are still held when raising notifications
if (transactionMode.isTransactional() && configuration.transaction().notifications()) {
interceptorChain.appendInterceptor(createInterceptor(new NotificationInterceptor(), NotificationInterceptor.class), false);
}
if (configuration.sites().hasEnabledBackups() && !configuration.sites().disableBackups()) {
if (transactionMode == TransactionMode.TRANSACTIONAL) {
if (configuration.transaction().lockingMode() == LockingMode.OPTIMISTIC) {
interceptorChain.appendInterceptor(createInterceptor(new OptimisticBackupInterceptor(), OptimisticBackupInterceptor.class), false);
} else {
interceptorChain.appendInterceptor(createInterceptor(new PessimisticBackupInterceptor(), PessimisticBackupInterceptor.class), false);
}
} else {
interceptorChain.appendInterceptor(createInterceptor(new NonTransactionalBackupInterceptor(), NonTransactionalBackupInterceptor.class), false);
}
}
// This needs to be added after the locking interceptor (for tx caches) but before the wrapping interceptor.
if (configuration.clustering().l1().enabled()) {
interceptorChain.appendInterceptor(createInterceptor(new L1LastChanceInterceptor(), L1LastChanceInterceptor.class), false);
}
if (configuration.clustering().hash().groups().enabled()) {
interceptorChain.appendInterceptor(createInterceptor(new GroupingInterceptor(), GroupingInterceptor.class), false);
}
if (cacheMode.isScattered()) {
interceptorChain.appendInterceptor(createInterceptor(new PrefetchInterceptor(), PrefetchInterceptor.class), false);
}
if (needsVersionAwareComponents) {
if (isTotalOrder) {
interceptorChain.appendInterceptor(createInterceptor(new TotalOrderVersionedEntryWrappingInterceptor(),
TotalOrderVersionedEntryWrappingInterceptor.class), false);
} else {
interceptorChain.appendInterceptor(createInterceptor(new VersionedEntryWrappingInterceptor(), VersionedEntryWrappingInterceptor.class), false);
}
} else if (cacheMode.isScattered()) {
interceptorChain.appendInterceptor(createInterceptor(new RetryingEntryWrappingInterceptor(), RetryingEntryWrappingInterceptor.class), false);
} else {
interceptorChain.appendInterceptor(createInterceptor(new EntryWrappingInterceptor(), EntryWrappingInterceptor.class), false);
}
if (configuration.persistence().usingStores()) {
if (cacheMode.isClustered()) {
interceptorChain.appendInterceptor(createInterceptor(new ClusteredCacheLoaderInterceptor(), ClusteredCacheLoaderInterceptor.class), false);
} else {
interceptorChain.appendInterceptor(createInterceptor(new CacheLoaderInterceptor(), CacheLoaderInterceptor.class), false);
}
if (configuration.persistence().passivation()) {
interceptorChain.appendInterceptor(createInterceptor(new PassivationWriterInterceptor(), PassivationWriterInterceptor.class), false);
} else {
boolean transactionalStore = configuration.persistence().stores().stream().anyMatch(StoreConfiguration::transactional);
if (transactionalStore && transactionMode.isTransactional())
interceptorChain.appendInterceptor(createInterceptor(new TransactionalStoreInterceptor(), TransactionalStoreInterceptor.class), false);
switch (cacheMode) {
case DIST_SYNC:
case DIST_ASYNC:
case REPL_SYNC:
case REPL_ASYNC:
interceptorChain.appendInterceptor(createInterceptor(new DistCacheWriterInterceptor(), DistCacheWriterInterceptor.class), false);
break;
case SCATTERED_SYNC:
interceptorChain.appendInterceptor(createInterceptor(new ScatteredCacheWriterInterceptor(), ScatteredCacheWriterInterceptor.class), false);
break;
default:
interceptorChain.appendInterceptor(createInterceptor(new CacheWriterInterceptor(), CacheWriterInterceptor.class), false);
break;
}
}
}
if (configuration.clustering().l1().enabled()) {
if (transactionMode.isTransactional()) {
interceptorChain.appendInterceptor(createInterceptor(new L1TxInterceptor(), L1TxInterceptor.class), false);
}
else {
interceptorChain.appendInterceptor(createInterceptor(new L1NonTxInterceptor(), L1NonTxInterceptor.class), false);
}
}
switch (cacheMode) {
case INVALIDATION_SYNC:
case INVALIDATION_ASYNC:
interceptorChain.appendInterceptor(createInterceptor(new InvalidationInterceptor(), InvalidationInterceptor.class), false);
break;
case DIST_SYNC:
case REPL_SYNC:
if (needsVersionAwareComponents) {
if (isTotalOrder) {
interceptorChain.appendInterceptor(createInterceptor(new TotalOrderVersionedDistributionInterceptor(),
TotalOrderVersionedDistributionInterceptor.class), false);
} else {
interceptorChain.appendInterceptor(createInterceptor(new VersionedDistributionInterceptor(), VersionedDistributionInterceptor.class), false);
}
break;
}
case DIST_ASYNC:
case REPL_ASYNC:
if (transactionMode.isTransactional()) {
if (isTotalOrder) {
interceptorChain.appendInterceptor(createInterceptor(new TotalOrderDistributionInterceptor(), TotalOrderDistributionInterceptor.class), false);
} else {
interceptorChain.appendInterceptor(createInterceptor(new TxDistributionInterceptor(), TxDistributionInterceptor.class), false);
}
} else {
if (cacheMode.isDistributed() && Configurations.isEmbeddedMode(globalConfiguration)) {
interceptorChain.appendInterceptor(createInterceptor(new TriangleDistributionInterceptor(), TriangleDistributionInterceptor.class), false);
} else {
interceptorChain.appendInterceptor(createInterceptor(new NonTxDistributionInterceptor(), NonTxDistributionInterceptor.class), false);
}
}
break;
case SCATTERED_SYNC:
interceptorChain.appendInterceptor(createInterceptor(new ScatteredDistributionInterceptor(), ScatteredDistributionInterceptor.class), false);
break;
case LOCAL:
//Nothing...
}
AsyncInterceptor callInterceptor = createInterceptor(new CallInterceptor(), CallInterceptor.class);
interceptorChain.appendInterceptor(callInterceptor, false);
log.trace("Finished building default interceptor chain.");
buildCustomInterceptors(interceptorChain, configuration.customInterceptors());
return interceptorChain;
}
private void buildCustomInterceptors(AsyncInterceptorChain interceptorChain, CustomInterceptorsConfiguration customInterceptors) {
for (InterceptorConfiguration config : customInterceptors.interceptors()) {
if (interceptorChain.containsInterceptorType(config.asyncInterceptor().getClass())) continue;
AsyncInterceptor customInterceptor = config.asyncInterceptor();
SecurityActions.applyProperties(customInterceptor, config.properties());
register(customInterceptor.getClass(), customInterceptor);
if (config.first())
interceptorChain.addInterceptor(customInterceptor, 0);
else if (config.last())
interceptorChain.addInterceptorBefore(customInterceptor, CallInterceptor.class);
else if (config.index() >= 0)
interceptorChain.addInterceptor(customInterceptor, config.index());
else if (config.after() != null) {
boolean added = interceptorChain.addInterceptorAfter(customInterceptor, config.after());
if (!added) {
throw new CacheConfigurationException("Cannot add after class: " + config.after()
+ " as no such interceptor exists in the default chain");
}
} else if (config.before() != null) {
boolean added = interceptorChain.addInterceptorBefore(customInterceptor, config.before());
if (!added) {
throw new CacheConfigurationException("Cannot add before class: " + config.before()
+ " as no such interceptor exists in the default chain");
}
} else if (config.position() == InterceptorConfiguration.Position.OTHER_THAN_FIRST_OR_LAST) {
interceptorChain.addInterceptor(customInterceptor, 1);
}
}
}
private boolean hasAsyncStore() {
List loaderConfigs = configuration.persistence().stores();
for (StoreConfiguration loaderConfig : loaderConfigs) {
if (loaderConfig.async().enabled())
return true;
}
return false;
}
@Override
public T construct(Class componentType) {
try {
AsyncInterceptorChain asyncInterceptorChain = buildInterceptorChain();
if (componentType == InterceptorChain.class) {
return componentType.cast(componentRegistry.getComponent(InterceptorChain.class));
} else {
return componentType.cast(asyncInterceptorChain);
}
} catch (CacheException ce) {
throw ce;
} catch (Exception e) {
throw new CacheConfigurationException("Unable to build interceptor chain", e);
}
}
public static InterceptorChainFactory getInstance(ComponentRegistry componentRegistry, Configuration configuration) {
InterceptorChainFactory icf = new InterceptorChainFactory();
icf.componentRegistry = componentRegistry;
icf.configuration = configuration;
return icf;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy