/*
* JBoss, Home of Professional Open Source
* Copyright 2009 Red Hat Inc. and/or its affiliates and other
* contributors as indicated by the @author tags. All rights reserved.
* 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 org.infinispan.config;
import org.infinispan.config.Configuration.EvictionType;
import org.infinispan.config.GlobalConfiguration.TransportType;
import org.infinispan.configuration.cache.VersioningScheme;
import org.infinispan.loaders.CacheLoaderConfig;
import org.infinispan.loaders.CacheStoreConfig;
import org.infinispan.loaders.decorators.SingletonStoreConfig;
import org.infinispan.transaction.TransactionMode;
import org.infinispan.transaction.TransactionProtocol;
import org.infinispan.util.concurrent.IsolationLevel;
import org.infinispan.util.logging.Log;
import org.infinispan.util.logging.LogFactory;
import java.util.Set;
/**
* ConfigurationValidatingVisitor checks semantic validity of InfinispanConfiguration instance.
*
*
* @author Vladimir Blagojevic
* @author Pedro Ruivo
* @since 4.0
* @deprecated Belongs to old configuration and so will dissapear in future releases
*/
@SuppressWarnings("boxing")
@Deprecated
public class ConfigurationValidatingVisitor extends AbstractConfigurationBeanVisitor {
private static final Log log = LogFactory.getLog(ConfigurationValidatingVisitor.class);
private TransportType tt = null;
private boolean evictionEnabled = false;
private Configuration cfg;
@Override
public void visitSingletonStoreConfig(SingletonStoreConfig ssc) {
if (tt == null && ssc.isSingletonStoreEnabled()) throw new ConfigurationException("Singleton store configured without transport being configured");
}
@Override
public void visitTransportType(TransportType tt) {
this.tt = tt;
}
@Override
public void visitConfiguration(Configuration cfg) {
this.cfg= cfg;
}
@Override
public void visitClusteringType(Configuration.ClusteringType clusteringType) {
Configuration.CacheMode mode = clusteringType.mode;
Configuration.AsyncType async = clusteringType.async;
Configuration.StateRetrievalType state = clusteringType.stateRetrieval;
// certain combinations are illegal, such as state transfer + invalidation
if (mode.isInvalidation() && state.fetchInMemoryState)
throw new ConfigurationException("Cache cannot use INVALIDATION mode and have fetchInMemoryState set to true.");
if (mode.isDistributed() && async.useReplQueue)
throw new ConfigurationException("Use of the replication queue is invalid when using DISTRIBUTED mode.");
if (mode.isSynchronous() && async.useReplQueue)
throw new ConfigurationException("Use of the replication queue is only allowed with an ASYNCHRONOUS cluster mode.");
// If replicated and fetch state transfer was not explicitly
// disabled, then force enabling of state transfer
Set<String> overriden = clusteringType.stateRetrieval.overriddenConfigurationElements;
if (mode.isReplicated() && !state.isFetchInMemoryState()
&& !overriden.contains("fetchInMemoryState")) {
log.debug("Cache is replicated but state transfer was not defined, so force enabling it");
state.fetchInMemoryState(true);
}
}
@Override
public void visitL1Type(Configuration.L1Type l1Type) {
boolean l1Enabled = l1Type.enabled;
boolean l1OnRehash = l1Type.onRehash;
// If L1 is disabled, L1ForRehash should also be disabled
if (!l1Enabled && l1OnRehash) {
Set<String> overridden = l1Type.overriddenConfigurationElements;
if (overridden.contains("onRehash")) {
throw new ConfigurationException("Can only move entries to L1 on rehash when L1 is enabled");
} else {
log.debug("L1 is disabled and L1OnRehash was not defined, disabling it");
l1Type.onRehash(false);
}
}
}
@Override
public void visitCacheLoaderManagerConfig(CacheLoaderManagerConfig cacheLoaderManagerConfig) {
if (!evictionEnabled && cacheLoaderManagerConfig.isPassivation())
log.passivationWithoutEviction();
boolean shared = cacheLoaderManagerConfig.isShared();
if (!shared) {
for (CacheLoaderConfig loaderConfig : cacheLoaderManagerConfig.getCacheLoaderConfigs()) {
if (loaderConfig instanceof CacheStoreConfig) {
CacheStoreConfig storeConfig = (CacheStoreConfig)loaderConfig;
Boolean fetchPersistentState = storeConfig.isFetchPersistentState();
Boolean purgeOnStartup = storeConfig.isPurgeOnStartup();
if (!fetchPersistentState && !purgeOnStartup && cfg.getCacheMode().isClustered()) {
log.staleEntriesWithoutFetchPersistentStateOrPurgeOnStartup();
}
}
}
}
}
@Override
public void visitVersioningConfigurationBean(Configuration.VersioningConfigurationBean config) {
if (cfg.getIsolationLevel() == IsolationLevel.SERIALIZABLE &&
(!cfg.isEnableVersioning() || cfg.getVersioningScheme() != VersioningScheme.GMU)) {
throw new ConfigurationException("Expected GMU versioning scheme when SERIALIZABLE is enabled");
}
}
@Override
public void visitEvictionType(EvictionType et) {
evictionEnabled = et.strategy.isEnabled();
if (et.strategy.isEnabled() && et.maxEntries <= 0)
throw new ConfigurationException("Eviction maxEntries value cannot be less than or equal to zero if eviction is enabled");
}
@Override
public void visitQueryConfigurationBean(Configuration.QueryConfigurationBean qcb) {
if ( ! qcb.enabled ) {
return;
}
// Check that the query module is on the classpath.
try {
String clazz = "org.infinispan.query.Search";
ClassLoader classLoader;
if ((classLoader = cfg.getClassLoader()) == null)
Class.forName(clazz);
else
classLoader.loadClass(clazz);
} catch (ClassNotFoundException e) {
log.warnf("Indexing can only be enabled if infinispan-query.jar is available on your classpath, and this jar has not been detected. Intended behavior may not be exhibited.");
}
}
@Override
public void visitTransactionType(Configuration.TransactionType bean) {
if (bean.transactionManagerLookup == null && bean.transactionManagerLookupClass == null) {
if (bean.build().isInvocationBatchingEnabled()) {
bean.transactionManagerLookupClass = null;
if (!bean.useSynchronization) log.debug("Switching to Synchronization-based enlistment.");
bean.useSynchronization = true;
}
}
if (bean.transactionProtocol.isTotalOrder()) {
//in the future we can allow this in total order??
if (bean.transactionMode == TransactionMode.NON_TRANSACTIONAL) {
log.tracef("Non transactional cache is not supported in Total Order protocol. Total Order protocol will" +
" be ignored.");
return;
}
//total order only supports replicated and distributed mode
if (!cfg.getCacheMode().isReplicated() && !cfg.getCacheMode().isDistributed()) {
log.cacheModeNotSupportedByTOProtocol(cfg.getCacheModeString());
bean.transactionProtocol(TransactionProtocol.TWO_PHASE_COMMIT);
return;
}
if (cfg.isRequireVersioning() && cfg.getVersioningScheme() == null) {
log.trace("No versioning scheme specified but versioning is required, defaulting to simple versioning.");
cfg.setVersioningScheme(VersioningScheme.SIMPLE);
}
//eager locking is no longer needed
if(bean.isUseEagerLocking()) {
log.tracef("Eager locking will be ignore with Total Order protocol");
}
}
if (bean.transactionProtocol.isPassiveReplication()) {
if (bean.transactionMode == TransactionMode.NON_TRANSACTIONAL) {
log.tracef("Non transactional cache is not supported in Passive Replication protocol. Passive Replication " +
"protocol will be ignored.");
return;
}
//for now, only supports full replication
if (!cfg.getCacheMode().isReplicated()) {
log.cacheModeNotSupportedByPRProtocol(cfg.getCacheModeString());
bean.transactionProtocol(TransactionProtocol.TWO_PHASE_COMMIT);
return;
}
if (cfg.isRequireVersioning() && cfg.getVersioningScheme() == null) {
log.trace("No versioning scheme specified but versioning is required, defaulting to simple versioning.");
cfg.setVersioningScheme(VersioningScheme.SIMPLE);
}
}
}
@Override
public void visitDataPlacementType(Configuration.DataPlacementType dataPlacementType) {
if (dataPlacementType.enabled) {
if (!cfg.getCacheMode().isDistributed()) {
throw new ConfigurationException("Data Placement Optimizer only works in distributed mode");
}
if (dataPlacementType.objectLookupFactory == null) {
throw new ConfigurationException("Expected an Object Lookup Factory instance");
}
if (dataPlacementType.coolDowntime < 1000) {
throw new ConfigurationException("Expected a cool down time higher or equal than 1000");
}
if (dataPlacementType.maxNumberOfKeysToRequest < 1) {
throw new ConfigurationException("The max number of keys to request should be higher than 0");
}
}
}
}