org.infinispan.factories.GlobalComponentRegistry Maven / Gradle / Ivy
package org.infinispan.factories;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import org.infinispan.Version;
import org.infinispan.commands.module.ModuleCommandFactory;
import org.infinispan.commands.module.ModuleCommandInitializer;
import org.infinispan.commons.CacheException;
import org.infinispan.commons.util.uberjar.ManifestUberJarDuplicatedJarsWarner;
import org.infinispan.commons.util.uberjar.UberJarDuplicatedJarsWarner;
import org.infinispan.configuration.global.GlobalConfiguration;
import org.infinispan.configuration.global.ShutdownHookBehavior;
import org.infinispan.factories.annotations.SurvivesRestarts;
import org.infinispan.factories.components.ComponentMetadataRepo;
import org.infinispan.factories.scopes.Scope;
import org.infinispan.factories.scopes.Scopes;
import org.infinispan.jmx.CacheManagerJmxRegistration;
import org.infinispan.lifecycle.ComponentStatus;
import org.infinispan.lifecycle.ModuleLifecycle;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.manager.EmbeddedCacheManagerStartupException;
import org.infinispan.marshall.core.EncoderRegistry;
import org.infinispan.notifications.cachemanagerlistener.CacheManagerNotifier;
import org.infinispan.notifications.cachemanagerlistener.CacheManagerNotifierImpl;
import org.infinispan.persistence.factory.CacheStoreFactoryRegistry;
import org.infinispan.registry.InternalCacheRegistry;
import org.infinispan.registry.impl.InternalCacheRegistryImpl;
import org.infinispan.remoting.transport.Transport;
import org.infinispan.stats.ClusterContainerStats;
import org.infinispan.topology.ClusterTopologyManager;
import org.infinispan.topology.LocalTopologyManager;
import org.infinispan.util.ByteString;
import org.infinispan.util.ModuleProperties;
import org.infinispan.util.TimeService;
import org.infinispan.util.logging.Log;
import org.infinispan.util.logging.LogFactory;
import org.infinispan.util.logging.events.EventLogManager;
import org.infinispan.xsite.GlobalXSiteAdminOperations;
import net.jcip.annotations.ThreadSafe;
/**
* A global component registry where shared components are stored.
*
* @author Manik Surtani
* @since 4.0
*/
@Scope(Scopes.GLOBAL)
@SurvivesRestarts
@ThreadSafe
public class GlobalComponentRegistry extends AbstractComponentRegistry {
private static final Log log = LogFactory.getLog(GlobalComponentRegistry.class);
private static final AtomicBoolean versionLogged = new AtomicBoolean(false);
/**
* Hook to shut down the cache when the JVM exits.
*/
private Thread shutdownHook;
/**
* A flag that the shutdown hook sets before calling cache.stop(). Allows stop() to identify if it has been called
* from a shutdown hook.
*/
private boolean invokedFromShutdownHook;
private final GlobalConfiguration globalConfiguration;
/**
* Tracking set of created caches in order to make it easy to remove a cache on remote nodes.
*/
private final Set createdCaches;
private final ModuleProperties moduleProperties = new ModuleProperties();
private final ComponentMetadataRepo componentMetadataRepo;
final Collection moduleLifecycles;
final ConcurrentMap namedComponents = new ConcurrentHashMap<>(4);
protected final WeakReference defaultClassLoader;
/**
* Creates an instance of the component registry. The configuration passed in is automatically registered.
*
* @param configuration configuration with which this is created
*/
public GlobalComponentRegistry(GlobalConfiguration configuration,
EmbeddedCacheManager cacheManager,
Set createdCaches) {
ClassLoader configuredClassLoader = configuration.classLoader();
moduleLifecycles = ModuleProperties.resolveModuleLifecycles(configuredClassLoader);
componentMetadataRepo = new ComponentMetadataRepo();
// Load up the component metadata
componentMetadataRepo.initialize(ModuleProperties.getModuleMetadataFiles(configuredClassLoader), configuredClassLoader);
defaultClassLoader = new WeakReference<>(registerDefaultClassLoader(configuredClassLoader));
try {
// this order is important ...
globalConfiguration = configuration;
registerComponent(this, GlobalComponentRegistry.class);
registerComponent(configuration, GlobalConfiguration.class);
registerComponent(cacheManager, EmbeddedCacheManager.class);
registerComponent(new CacheManagerJmxRegistration(), CacheManagerJmxRegistration.class);
registerComponent(new CacheManagerNotifierImpl(), CacheManagerNotifier.class);
registerComponent(new InternalCacheRegistryImpl(), InternalCacheRegistry.class);
registerComponent(new CacheStoreFactoryRegistry(), CacheStoreFactoryRegistry.class);
registerComponent(new GlobalXSiteAdminOperations(), GlobalXSiteAdminOperations.class);
moduleProperties.loadModuleCommandHandlers(configuredClassLoader);
Map factories = moduleProperties.moduleCommandFactories();
if (factories != null && !factories.isEmpty())
registerNonVolatileComponent(factories, KnownComponentNames.MODULE_COMMAND_FACTORIES);
else
registerNonVolatileComponent(Collections.emptyMap(), KnownComponentNames.MODULE_COMMAND_FACTORIES);
this.createdCaches = createdCaches;
getOrCreateComponent(EventLogManager.class);
// This is necessary to make sure the transport has been started and is available to other components that
// may need it. This is a messy approach though - a proper fix will be in ISPN-1698
getOrCreateComponent(Transport.class);
// These two should not be necessary, but they are here as a workaround for ISPN-2371
getOrCreateComponent(LocalTopologyManager.class);
getOrCreateComponent(ClusterTopologyManager.class);
getOrCreateComponent(ClusterContainerStats.class);
getOrCreateComponent(EncoderRegistry.class);
getOrCreateComponent(ScheduledExecutorService.class, KnownComponentNames.TIMEOUT_SCHEDULE_EXECUTOR);
} catch (Exception e) {
throw new CacheException("Unable to construct a GlobalComponentRegistry!", e);
}
}
@Override
protected ClassLoader getClassLoader() {
return defaultClassLoader.get();
}
@Override
protected Log getLog() {
return log;
}
@Override
public ComponentMetadataRepo getComponentMetadataRepo() {
return componentMetadataRepo;
}
@Override
protected synchronized void removeShutdownHook() {
// if this is called from a source other than the shutdown hook, de-register the shutdown hook.
if (!invokedFromShutdownHook && shutdownHook != null) Runtime.getRuntime().removeShutdownHook(shutdownHook);
}
@Override
public TimeService getTimeService() {
return getOrCreateComponent(TimeService.class);
}
@Override
protected synchronized void addShutdownHook() {
ArrayList al = MBeanServerFactory.findMBeanServer(null);
ShutdownHookBehavior shutdownHookBehavior = globalConfiguration.shutdown().hookBehavior();
boolean registerShutdownHook = (shutdownHookBehavior == ShutdownHookBehavior.DEFAULT && al.isEmpty())
|| shutdownHookBehavior == ShutdownHookBehavior.REGISTER;
if (registerShutdownHook) {
log.tracef("Registering a shutdown hook. Configured behavior = %s", shutdownHookBehavior);
shutdownHook = new Thread(() -> {
try {
invokedFromShutdownHook = true;
GlobalComponentRegistry.this.stop();
} finally {
invokedFromShutdownHook = false;
}
});
Runtime.getRuntime().addShutdownHook(shutdownHook);
} else {
log.tracef("Not registering a shutdown hook. Configured behavior = %s", shutdownHookBehavior);
}
}
public final ComponentRegistry getNamedComponentRegistry(String name) {
//no need so sync this method as namedComponents is thread safe and correctly published (final)
return getNamedComponentRegistry(ByteString.fromString(name));
}
public final ComponentRegistry getNamedComponentRegistry(ByteString name) {
//no need so sync this method as namedComponents is thread safe and correctly published (final)
return namedComponents.get(name);
}
public synchronized final void registerNamedComponentRegistry(ComponentRegistry componentRegistry, String name) {
namedComponents.put(ByteString.fromString(name), componentRegistry);
}
public synchronized final void unregisterNamedComponentRegistry(String name) {
namedComponents.remove(ByteString.fromString(name));
}
public synchronized final void rewireNamedRegistries() {
for (ComponentRegistry cr : namedComponents.values())
cr.rewire();
}
public Map getModuleCommandInitializers() {
//moduleProperties is final so we don't need to synchronize this method for safe-publishing
return Collections.unmodifiableMap(moduleProperties.moduleCommandInitializers());
}
@Override
public synchronized void start() {
try {
// Do nothing if the global components are already running
if (!state.startAllowed())
return;
boolean needToNotify = state != ComponentStatus.RUNNING && state != ComponentStatus.INITIALIZING;
if (needToNotify) {
for (ModuleLifecycle l : moduleLifecycles) {
l.cacheManagerStarting(this, globalConfiguration);
}
}
super.start();
if (versionLogged.compareAndSet(false, true)) {
log.version(Version.printVersion());
}
if (needToNotify && state == ComponentStatus.RUNNING) {
for (ModuleLifecycle l : moduleLifecycles) {
l.cacheManagerStarted(this);
}
}
warnAboutUberJarDuplicates();
} catch (RuntimeException rte) {
EmbeddedCacheManagerStartupException exception = new EmbeddedCacheManagerStartupException(rte);
state = ComponentStatus.FAILED;
try {
super.stop();
} catch (Exception e) {
exception.addSuppressed(e);
}
throw exception;
}
}
private void warnAboutUberJarDuplicates() {
UberJarDuplicatedJarsWarner scanner = new ManifestUberJarDuplicatedJarsWarner();
scanner.isClasspathCorrectAsync()
.thenAcceptAsync(isClasspathCorrect -> {
if(!isClasspathCorrect)
log.warnAboutUberJarDuplicates();
});
}
@Override
public synchronized void stop() {
boolean needToNotify = state == ComponentStatus.RUNNING || state == ComponentStatus.INITIALIZING;
if (needToNotify) {
for (ModuleLifecycle l : moduleLifecycles) {
l.cacheManagerStopping(this);
}
}
super.stop();
if (state == ComponentStatus.TERMINATED && needToNotify) {
for (ModuleLifecycle l : moduleLifecycles) {
l.cacheManagerStopped(this);
}
}
}
public void notifyCacheStarted(String cacheName) {
ComponentRegistry cr = getNamedComponentRegistry(cacheName);
for (ModuleLifecycle l : moduleLifecycles) {
l.cacheStarted(cr, cacheName);
}
}
public final GlobalConfiguration getGlobalConfiguration() {
//this is final so no need to synchronise it
return globalConfiguration;
}
/**
* Removes a cache with the given name, returning true if the cache was removed.
*/
public synchronized boolean removeCache(String cacheName) {
return createdCaches.remove(cacheName);
}
public ModuleProperties getModuleProperties() {
return moduleProperties;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy