EmbeddedCacheManager manager = new DefaultCacheManager("my-config-file.xml"); Cache defaultCache = manager.getCache();
Programmatic Infinispan configuration is centered around CacheManager API. Although every single aspect of Infinispan configuration could be set programmatically, the most usual approach is to create a starting point in a form of XML configuration file and then in runtime, if needed, programmatically tune a specific configuration to suit the use case best.
EmbeddedCacheManager manager = new DefaultCacheManager("my-config-file.xml"); Cache defaultCache = manager.getCache();
Let assume that a new synchronously replicated cache is to be configured programmatically. First, a fresh instance of Configuration object is created, and the cache mode is set to synchronous replication. Finally, the configuration is defined/registered with a manager. If specified cache name "repl" hasn't been defined before, default cache's configuration is cloned and overriden with a clone of our newly created configuration.
Configuration c = new Configuration(); c.setCacheMode(CacheMode.REPL_SYNC); String newCacheName = "repl"; manager.defineConfiguration(newCacheName, c); Cache<String, String> cache = manager.getCache(newCacheName);
The default cache configuration (or any other cache configuration) can be used as a starting point for creation of a new cache. For example, lets say that infinispan-config-file.xml specifies a replicated cache as a default and that a distributed cache is desired with a specific L1 lifespan while at the same time retaining all other aspects of a default cache in my-config-file.xml. Therefore, the starting point would be a clone instance of default Configuration object and then the cache mode and L1 lifespan would be set accordingly. As a final step the configuration is defined/registered with a manager.
EmbeddedCacheManager manager = new DefaultCacheManager("infinispan-config-file.xml"); Configuration c = manager.getDefaultConfiguration().clone(); c.setCacheMode(CacheMode.DIST_SYNC); c.setL1Lifespan(60000L); String newCacheName = "distributedWithL1"; manager.defineConfiguration(newCacheName, c); Cache<String, String> cache = manager.getCache(newCacheName);
As long as the based configuration is the default named cache, the previous code works perfectly fine. However, other times the base configuration might be another named cache. So, how can new configurations be defined based on other defined caches? Take the previous example and imagine that instead of taking the default cache as base, a named cache called "replicatedCache" is used as base. The code would look something like this:
EmbeddedCacheManager manager = new DefaultCacheManager("infinispan-config-file.xml"); Configuration c = new Configuration(); // Only those values explicitly set are ported over to the new configuration c.setCacheMode(CacheMode.DIST_SYNC); c.setL1Lifespan(60000L); String newCacheName = "distributedWithL1"; // Here, the base 'replicatedCache' configuration is taken, // the values explicitly configured in the overriding configuration are applied, // and a brand new configuration with name 'distributedWithL1' is created. manager.defineConfiguration(newCacheName, "replicatedCache", c); Cache<String, String> cache = manager.getCache(newCacheName);
Refer to CacheManager, Configuration, and GlobalConfiguration javadocs for more details.
Starting with Infinispan 5.0, a new, fluent, way of programmatically configuring Infinispan is available to users. The aim of this API is to make it easier to chain coding of configuration options in order to speed up the coding itself and make the configuration more readable. This new configuration can be used for both the global and the cache level configuration. In order to maintain backwards compatibility, this new API is available via separate classes which are FluentGlobalConfiguration and FluentConfiguration respectively and the existing options in GlobalConfiguration and Configuration have been deprecated. In future major releases, this new API will replace the existing APIs in GlobalConfiguration/Configuration, so it's recommended that you adjust any programmatic configuration. In order to access the fluent API, simply navigate via the fluent() method available in the old configuration classes. Once in the fluent configuration classes, you can call build() in order to produce an old configuration object. Let's look at some examples on configuring both global and cache level options with this new API:
One of the most commonly configured global option is the transport layer, where you indicate how an Infinispan node will discover the others:
GlobalConfiguration globalConfig = new GlobalConfiguration().fluent() .transport() .clusterName("qa-cluster") .addProperty("configurationFile", "jgroups-tcp.xml") .machineId("qa-machine").rackId("qa-rack") .build();
Sometimes you might also want to get global JMX statistics and information about the transport, or the cache manager in general. To enable global JMX statistics simply do:
GlobalConfiguration globalConfig = new GlobalConfiguration().fluent() .globalJmxStatistics() .build();
Further options at the global JMX statistics level allows you for example to configure the cache manager name which comes handy when you have multiple cache managers running on the same system, or how to locate the JMX MBean Server:
GlobalConfiguration globalConfig = new GlobalConfiguration().fluent() .globalJmxStatistics() .cacheManagerName("SalesCacheManager") .mBeanServerLookupClass(JBossMBeanServerLookup.class) .build();
Some of the Infinispan features are powered by a group of the thread pool executors which can also be tweaked at this global level. For example:
GlobalConfiguration globalConfig = new GlobalConfiguration().fluent() .replicationQueueScheduledExecutor() .factory(DefaultScheduledExecutorFactory.class) .addProperty("threadNamePrefix", "RQThread") .build();
You can not only configure global, cache manager level, options, but you can also configure cache level options such as the cluster mode:
Configuration config = new Configuration().fluent() .clustering() .mode(Configuration.CacheMode.DIST_SYNC) .sync() .l1().lifespan(25000L) .hash().numOwners(3) .build();
Or you can configure eviction/expiration settings too:
Configuration config = new Configuration().fluent() .eviction() .maxEntries(20000).strategy(EvictionStrategy.LIRS) .wakeUpInterval(5000L) .expiration() .maxIdle(120000L) .build();
An application might also want to interact with an Infinispan cache within the boundaries of JTA and to do that you need to configure the transaction layer and optionally tweak the locking settings. When interacting with transactional caches, you might want to enable recovery to deal with transactions that finished with an heuristic outcome and if you do that, you will often want to enable JMX management and statistics gathering too:
Configuration config = new Configuration().fluent() .locking() .concurrencyLevel(10000).isolationLevel(IsolationLevel.REPEATABLE_READ) .lockAcquisitionTimeout(12000L).useLockStriping(false).writeSkewCheck(true) .transaction() .recovery() .transactionManagerLookup(new GenericTransactionManagerLookup()) .jmxStatistics() .build();
Configuring Infinispan with one or several chained persistent stores is simple too:
Configuration config = new Configuration().fluent() .loaders() .shared(false).passivation(false).preload(false) .addCacheLoader( new FileCacheStoreConfig() .location("/tmp").streamBufferSize(1800) .asyncStore() .threadPoolSize(20) .ignoreModifications(false) .purgeSynchronously(false)) .addCacheLoader( new ClusterCacheLoaderConfig().remoteCallTimeout(35000L)) .build();
Finally, the new configuration API has brought other noticeable changes such as the removal of explicit enabling configuration calls. For example, in the past if you wanted to configure global jmx statistics, you had to explicitly call setEnabled(true) or similar. This is no longer necessary since simply calling globalJmxStatistics() directly enables global jmx statistics which makes a lot of sense since when you start calling configuration methods for the global jmx statistics is because you want it to behave it in a particular way. However, sometimes you might explicitly disable a configuration option and so in those cases where configurations can be enabled, a disable() call is available too. For example:
Configuration config = new Configuration().fluent() .transaction() .recovery().disable() .build();
The fluent configuration can also be used to configure more advanced or exotic options, such as advanced externalizers:
GlobalConfiguration globalConfig = new GlobalConfiguration().fluent() .serialization() .addAdvancedExternalizer(PersonExternalizer.class) .addAdvancedExternalizer(999, AddressExternalizer.class) .build();
Or, add custom interceptors:
Configuration config = new Configuration().fluent() .customInterceptors() .add(new FirstInterceptor()).first() .add(new LastInterceptor()).last() .add(new FixPositionInterceptor()).atIndex(8) .add(new AfterInterceptor()).after(LockingInterceptor.class) .add(new BeforeInterceptor()).before(CallInterceptor.class) .build();
For information on the individual configuration options, please check the configuration guide.