org.cacheonix.Cacheonix Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cacheonix-core Show documentation
Show all versions of cacheonix-core Show documentation
Cacheonix is an open source distributed cache for Java that allows its users to scale Java applications in a cluster while preserving the simplicity of design and coding in a single Java VM.
The newest version!
/*
* Cacheonix Systems licenses this file to You under the LGPL 2.1
* (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.cacheonix.org/products/cacheonix/license-lgpl-2.1.htm
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.cacheonix;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.net.InetAddress;
import java.net.URL;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.cacheonix.cache.Cache;
import org.cacheonix.cache.CacheExistsException;
import org.cacheonix.cache.ConfigurationException;
import org.cacheonix.cluster.Cluster;
import org.cacheonix.cluster.ClusterEventSubscriber;
import org.cacheonix.impl.AbstractCacheonix;
import org.cacheonix.impl.DistributedCacheonix;
import org.cacheonix.impl.cache.local.LocalCacheonix;
import org.cacheonix.impl.config.BroadcastConfiguration;
import org.cacheonix.impl.config.CacheonixConfiguration;
import org.cacheonix.impl.config.ConfigurationReader;
import org.cacheonix.impl.config.MulticastBroadcastConfiguration;
import org.cacheonix.impl.util.StringUtils;
import org.cacheonix.impl.util.array.HashMap;
import org.cacheonix.impl.util.logging.Logger;
import static org.cacheonix.impl.config.ConfigurationConstants.FALLBACK_CACHEONIX_XML_RESOURCE;
import static org.cacheonix.impl.config.SystemProperty.NAME_CACHEONIX_CONFIGURATION;
import static org.cacheonix.impl.config.SystemProperty.NAME_CACHEONIX_FALLBACK_CONFIGURATION;
/**
* A singleton that creates and provides access to various Cacheonix features such as caching, parallel computing and
* distrbuted locks. Accessing a Cache
Each cache in Cacheonix is uniquely identified by its name within
* Cacheonix configuration. To get a cache from Cacheonix instance use method getCache()
.
* Example:
*
* Cache cache = Cacheonix.getInstance().getCache("my.cache");
*
* Configuring Cacheonix
Visit online
* Cacheonix documentation for information on configuring Cacheonix.
Code Examples
Visit online code examples for examples on
* working with the cache API.
*
* @see #getCache(String)
* @see #createCache(String)
* @see #createCache(String, String)
* @see #cacheExists(String)
* @see Cache
*/
public abstract class Cacheonix {
/**
* Logger.
*
* @noinspection UNUSED_SYMBOL, UnusedDeclaration
*/
private static final Logger LOG = Logger.getLogger(Cacheonix.class); // NOPMD
/**
* Object to synchronize on when accessing class-wide state.
*/
private static final Object CLASS_STATE_LOCK = new Object();
/**
* Holds cache MANAGERS accessed by a configuration name.
*
* @see #getInstance(String)
*/
private static final Map INSTANCES = new HashMap(1);
/**
* Default configuration file.
*/
public static final String CACHEONIX_XML = "cacheonix-config.xml";
/**
* Returns a cache with the given name. If a cache configuration is not defined in the configuration file, this
* method will create a cache using a default cache configuration template if system property
* cacheonix.auto.create.cache
is set to true
(default is true
).
*
* Named caches are defined in the Cacheonix configuration file cacheonix-config.xml
.
*
* @param cacheName case-sensitive name of the cache
* @return named cache or null if a cache with this name cannot be found.
* @noinspection PublicMethodNotExposedInInterface
*/
public abstract Cache getCache(String cacheName);
/**
* Shuts down Cacheonix by shutting down its caches and running all necessary cleanups. Calling this shortcut method
* produces the same results as calling shutdown(ShutdownMode.GRACEFUL_SHUTDOWN, false)
. This method
* should be called once in Cacheonix instance's lifetime, ideally right before the application exits.
*
* @throws ShutdownException if this Cacheonix instance has already been shutdown.
* @see #isShutdown()
*/
public final void shutdown() {
shutdown(ShutdownMode.GRACEFUL_SHUTDOWN, false);
}
/**
* Shuts down Cacheonix by shutting down its caches and running all necessary cleanups.
*
* @param shutdownMode a shutdown mode.
* @param unregisterSingleton if true
, the singleton will be unregistered and the next call to
* Cacheonix.getInstance()
will perform a lazy init thus returning a new,
* operational instance of Cacheonix. Setting this parameter to true
is
* useful when writing unit tests that use Cacheonix where tearDown
must
* perform a complete cleanup and setUp
must provide a fresh, clean instance
* of Cacheonix. If unregisterSingleton
is false
, the singleton
* won't be unregistered and subsequent calls to Cacheonix.getInstance()
will
* return an instance that has been shutdown. Most of the times
* unregisterSingleton should be set to false
to ensure that
* once shutdown Cacheonix stays shutdown.
* @throws ShutdownException if this Cacheonix instance has already been shutdown.
* @see ShutdownMode#FORCED_SHUTDOWN
* @see ShutdownMode#GRACEFUL_SHUTDOWN
* @see Cacheonix#getInstance()
*/
public abstract void shutdown(final ShutdownMode shutdownMode, final boolean unregisterSingleton);
/**
* Returns an unmodifiable collection of {@link Cache} instances belonging to this Cacheonix instance.
*
* @return unmodifiable collection of {@link Cache} instances belonging to this Cacheonix instance.
* @see Cache
*/
public abstract Collection getCaches();
/**
* Shutdowns and deletes the cache.
*
* @param cacheName name of the cache to delete.
* @noinspection NestedTryStatement
* @see #getCache(String)
* @see #createCache(String)
*/
public abstract void deleteCache(String cacheName);
/**
* Creates a cache using a template cache configuration. If a cache configuration cannot be not fond, this method
* uses the cache configuration template that name is provides as a second argument.
*
* The cache configuration template is a cache configuration that has attribute "template" set to "yes" or "true". A
* configuration with name "default" is always a template configuration.
*
* The template cache configuration cannot be started.
*
* Example of cacheonix-config.xml:
*
*
* <?xml version ="1.0"?>
* <cacheonix xmlns="http://www.cacheonix.org/schema/configuration"
* xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
* xsi:schemaLocation="http://www.cacheonix.org/schema/configuration http://www.cacheonix.org/schema/cacheonix-config-2.0.xsd">
*
* <server>
*
* <listener>
* <tcp port="8879" buffer="128k"/>
* </listener>
*
* <broadcast>
* <multicast multicastAddress="225.0.1.2" multicastPort="9998" multicastTTL="0"/>
* </broadcast>
*
* <partitionedCache name="customer.cache">
* <store>
* <lru maxElements="10000" maxBytes="10mb"/>
* <expiration idleTime="120s"/>
* </store>
* </partitionedCache>
*
* </server>
* </cacheonix>
*
*
*
* @param cacheName name of the cache to create.
* @param templateName name of the template to use when creating the cache.
* @return a new cache
* @throws IllegalArgumentException if the cache already exists or if the cacheName
is a name of a
* template configuration.
* @see #createCache(String)
* @see #getCache(String)
* @see #deleteCache(String)
*/
public abstract Cache createCache(String cacheName, String templateName) throws IllegalArgumentException;
/**
* Returns true
if a cache with the given name exists. Returns false
if a cache with the
* given name does not exist.
*
* @param cacheName name of the cache to check.
* @return true
if a cache with the given name exists or false
if does not.
*/
public abstract boolean cacheExists(String cacheName);
/**
* Creates a cache with a given name.
*
* If a cache configuration with this name is not found, a default cache configuration is used. A default
* configuration is a configuration with a name "default".
*
* Example:
*
* // Create a cache using the default template
* Cache cache = Cacheonix.getInstance().createCache("my.cache");
*
*
* Example of cacheonix-config.xml with default template:
*
*
* <?xml version ="1.0"?>
* <cacheonix xmlns="http://www.cacheonix.org/schema/configuration"
* xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
* xsi:schemaLocation="http://www.cacheonix.org/schema/configuration http://www.cacheonix.org/schema/cacheonix-config-2.0.xsd">
*
* <server>
*
* <listener>
* <tcp port="8879" buffer="128k"/>
* </listener>
*
* <broadcast>
* <multicast multicastAddress="225.0.1.2" multicastPort="9998" multicastTTL="0"/>
* </broadcast>
*
* <partitionedCache name="default" template="true">
* <store>
* <lru maxElements="10000" maxBytes="10mb"/>
* <expiration idleTime="120s"/>
* </store>
* </partitionedCache>
*
* </server>
* </cacheonix>
*
*
*
* @param cacheName name of the cache to create.
* @return created cache
* @see #getCache(String)
* @see #deleteCache(String)
*/
public abstract Cache createCache(String cacheName);
/**
* Returns or creates a Cacheonix instance for the given configuration path. The path can be a fully qualified URL, a
* file or a resource in the classpath.
*
* @param configurationPath defines path to a resource containing Cacheonix configuration file.
* @return Cacheonix instance.
* @throws CacheExistsException DuplicateClusterConfigurationException IOException StorageException
* @noinspection MethodReturnOfConcreteClass
*/
public static Cacheonix getInstance(final String configurationPath) throws ConfigurationException {
try {
if (StringUtils.isBlank(configurationPath)) {
throw new ConfigurationException("Configuration path cannot be null or empty but it is");
}
// Get from class path
final String normalizedPath = configurationPath.charAt(0) == '/' ? configurationPath : '/' + configurationPath;
final URL cacheonixXmlResource = Cacheonix.class.getResource(normalizedPath);
if (cacheonixXmlResource != null) {
return getInstanceFromExternalPath(cacheonixXmlResource.toExternalForm());
}
// Get from current directory
final File currentDirCacheonixXml = new File(configurationPath);
if (currentDirCacheonixXml.exists()) {
return getInstanceFromExternalPath(
currentDirCacheonixXml.getCanonicalFile().toURI().toURL().toExternalForm());
}
return getInstanceFromExternalPath(configurationPath);
} catch (final IOException e) {
throw new ConfigurationException("Unexpected error while getting Cacheonix instance: " + e, e);
}
}
/**
* Returns or creates a Cacheonix instance for the given configuration resource name. The resource name defines path
* to Cacheonix configuration file. The configuration file should be found in the classpath.
*
* @param configurationPath defines path to a file containing Cacheonix configuration file.
* @return Cacheonix instance.
* @throws ConfigurationException if configuration error occurs
* @noinspection MethodReturnOfConcreteClass, deprecation
*/
public static Cacheonix getInstance(final File configurationPath) throws ConfigurationException {
try {
return getInstanceFromExternalPath(configurationPath.getCanonicalFile().toURL().toExternalForm());
} catch (final IOException e) {
throw new ConfigurationException("Unexpected error while getting Cacheonix instance: " + e, e);
}
}
private static Cacheonix getInstanceFromExternalPath(final String externalFormPath) throws IOException {
synchronized (CLASS_STATE_LOCK) {
final AbstractCacheonix existingInstance = INSTANCES.get(externalFormPath);
if (existingInstance != null) {
return existingInstance;
}
// Not found, create
final AbstractCacheonix newInstance = createInstance(externalFormPath);
// Startup
newInstance.startup();
// Register
INSTANCES.put(externalFormPath, newInstance);
// Return result
return newInstance;
}
}
/**
* Returns a singleton instance of Cacheonix using a default Cacheonix configuration. Cacheonix finds the default
* configuration by looking for cacheonix-config.xml
* in the following order. Each step is executed only if the previous step has not defined the configuration:
* - Use the configuration defined by the URL in the system property
cacheonix.configuration
. The
* property is passed to JVM by using command line parameter -Dcacheonix.configuration=<path to
* configuration>
- Use
cacheonix-config.xml
from the classpath - Use
*
cacheonix-config.xml
from the local directory - Use the fall-back
*
META-INF/cacheonix-config.xml
in the cacheonix.jar
*
* To disable the fall-back configuration, use JVM's command line parameter -Dcacheonix.fallback.configuration=false
.
*
* We recommend disabling the fall-back configuration when using Cacheonix in a production environment. The fall-back
* configuration may hide the fact that the production configuration is missing. Disabling it helps Cacheonix to fail
* fast thus allowing to discover the fact that the production configuration is missing.
*
* @return a singleton instance of Cacheonix.
* @throws IllegalStateException if a cache with a duplicate name is found in the Cacheonix configuration; if the
* cache configuration cannot be found.
* @noinspection MethodReturnOfConcreteClass, JavaDoc, deprecation
*/
public static Cacheonix getInstance() throws ConfigurationException {
try {
// Find configuration at the system property cacheonix.configuration
final String systemProperty = System.getProperty(NAME_CACHEONIX_CONFIGURATION);
if (!StringUtils.isBlank(systemProperty)) {
return getInstance(systemProperty);
}
// Find configuration in the classpath
final URL cacheonixXmlResource = Cacheonix.class.getResource('/' + CACHEONIX_XML);
if (cacheonixXmlResource != null) {
return getInstanceFromExternalPath(cacheonixXmlResource.toExternalForm());
}
// Get from current directory
final File currentDirCacheonixXml = new File(CACHEONIX_XML);
if (currentDirCacheonixXml.exists()) {
return getInstanceFromExternalPath(currentDirCacheonixXml.toURL().toExternalForm());
}
final String fallbackProperty = System.getProperty(NAME_CACHEONIX_FALLBACK_CONFIGURATION, "true");
if ("false".equalsIgnoreCase(fallbackProperty)) {
throw new IllegalStateException("Cacheonix configuration cannot be found");
}
// Fallback to the packaged configuration
final URL fallbackCacheonixXmlResource = Cacheonix.class.getResource(FALLBACK_CACHEONIX_XML_RESOURCE);
if (fallbackCacheonixXmlResource == null) {
throw new IllegalStateException("Cacheonix configuration cannot be found");
}
return getInstanceFromExternalPath(fallbackCacheonixXmlResource.toExternalForm());
} catch (final IOException e) {
throw new ConfigurationException("Unexpected error while getting Cacheonix instance: " + e, e);
}
}
/**
* Returns a cluster this Cacheonix instance is a member of.
*
* @return the cluster this Cacheonix instance is a member of.
*/
public abstract Cluster getCluster();
/**
* Check if this Cacheonix instance has been shutdown.
*
* @return true
if this Cacheonix instance has been shutdown. Otherwise returns false.
* @see #shutdown()
*/
public abstract boolean isShutdown();
/**
* Creates a concrete Cacheonix instance based on the configuration.
*
* @param externalFormPath configuration path.
* @return a concrete Cacheonix instance based on the configuration.
* @throws IOException if a Cacheonix instance cannot be created.
*/
private static AbstractCacheonix createInstance(final String externalFormPath) throws IOException {
// Read configuration
final ConfigurationReader configurationReader = new ConfigurationReader();
final CacheonixConfiguration configuration = configurationReader.readConfiguration(externalFormPath);
if (configuration.getServer() != null) {
// Limit broadcast to the local host if mcast TTL is 0
final BroadcastConfiguration broadcastConfiguration = configuration.getServer().getBroadcastConfiguration();
final MulticastBroadcastConfiguration multicastConfiguration = broadcastConfiguration.getMulticast();
if (multicastConfiguration != null && multicastConfiguration.getMulticastTTL() == 0) {
configuration.getServer().getListener().getTcp().setAddress(InetAddress.getByName("127.0.0.1"));
}
return new DistributedCacheonix(configuration.getServer());
} else if (configuration.getLocal() != null) {
return new LocalCacheonix(configuration);
} else {
throw new IllegalArgumentException("Unknown configuration type: " + externalFormPath);
}
}
/**
* Removes a given Cacheonix instance from the cache managers registry.
*
* @param instance the Cacheonix instance to unregister.
*/
@SuppressWarnings("MethodMayBeStatic")
protected final void unregister(final Cacheonix instance) {
synchronized (CLASS_STATE_LOCK) {
final Set> entrySet = INSTANCES.entrySet();
for (final Iterator> iter = entrySet.iterator(); iter.hasNext(); ) {
final Entry entry = iter.next();
//noinspection ObjectEquality
if (entry.getValue() == instance) { // Intended comparison by reference
//noinspection ControlFlowStatementWithoutBraces
if (LOG.isDebugEnabled()) LOG.debug("Unregistering: " + instance.getDescription()); // NOPMD
iter.remove();
return;
}
}
}
}
/**
* Returns a brief, single-line, free-from description of this instance.
*
* @return the description of this instance.
*/
protected abstract String getDescription();
/**
* {@inheritDoc}
*/
public String toString() {
return "Cacheonix{" +
"INSTANCES.size()=" + INSTANCES.size() +
'}';
}
public static Cacheonix getInstance(final String configurationPath,
final ClusterEventSubscriber clusterEventSubscriber) {
return null;
}
}