com.tangosol.net.Coherence Maven / Gradle / Ivy
Show all versions of coherence Show documentation
/*
* Copyright (c) 2000, 2023, Oracle and/or its affiliates.
*
* Licensed under the Universal Permissive License v 1.0 as shown at
* https://oss.oracle.com/licenses/upl.
*/
package com.tangosol.net;
import com.oracle.coherence.common.base.Logger;
import com.oracle.coherence.common.base.Timeout;
import com.oracle.coherence.common.collections.ConcurrentHashMap;
import com.oracle.coherence.common.util.Duration;
import com.tangosol.application.ContainerContext;
import com.tangosol.application.Context;
import com.tangosol.coherence.config.Config;
import com.tangosol.coherence.config.scheme.ServiceScheme;
import com.tangosol.internal.health.HealthCheckWrapper;
import com.tangosol.internal.net.ConfigurableCacheFactorySession;
import com.tangosol.internal.net.SystemSessionConfiguration;
import com.tangosol.net.events.CoherenceDispatcher;
import com.tangosol.net.events.CoherenceLifecycleEvent;
import com.tangosol.net.events.EventDispatcher;
import com.tangosol.net.events.EventDispatcherAwareInterceptor;
import com.tangosol.net.events.EventDispatcherRegistry;
import com.tangosol.net.events.EventInterceptor;
import com.tangosol.net.events.InterceptorRegistry;
import com.tangosol.net.events.internal.CoherenceEventDispatcher;
import com.tangosol.net.events.internal.Registry;
import com.tangosol.util.Base;
import com.tangosol.util.CopyOnWriteMap;
import com.tangosol.util.HealthCheck;
import com.tangosol.util.RegistrationBehavior;
import com.tangosol.util.ResourceRegistry;
import com.tangosol.util.SimpleResourceRegistry;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
/**
* A {@link Coherence} instance encapsulates and controls one or more
* {@link Session} instances.
*
* A {@link Coherence} instance is typically created from a {@link CoherenceConfiguration}
* which contains one or more {@link SessionConfiguration} instances.
* The {@link Coherence} instance is then {@link #start() started} which in turn creates
* and starts the configured {@link Session Sessions}.
* When the {@link Coherence} instance is {@link #close() closed} all of the {@link Session}
* instances being managed are also {@link Session#close() closed}.
*
* An example of creating and starting a {@link Coherence} instance is shown below:
*
* SessionConfiguration session = SessionConfiguration.builder()
* .named("Prod")
* .withConfigUri("cache-config.xml")
* .build();
*
* CoherenceConfiguration cfg = CoherenceConfiguration.builder()
* .withSession(SessionConfiguration.defaultSession())
* .withSession(session)
* .build();
*
* Coherence coherence = Coherence.create(cfg);
*
* coherence.start();
*
*
* @author Jonathan Knight 2020.10.26
* @since 20.12
*
* @see CoherenceConfiguration
* @see SessionConfiguration
*/
public class Coherence
implements AutoCloseable
{
// ----- constructors ---------------------------------------------------
/**
* Create a {@link Coherence} instance using the state from the
* specified {@link CoherenceConfiguration}.
*
* This constructor is private, instances of {@link Coherence} should
* be created using the factory methods.
*
* @param config the {@link CoherenceConfiguration} to configure this instance
* @param mode the mode that this instance will run in
*
* @throws NullPointerException if the config parameter is {@code null}
*/
private Coherence(CoherenceConfiguration config, Mode mode)
{
f_config = Objects.requireNonNull(config);
f_mode = mode;
f_sName = config.getName();
f_registry = new SimpleResourceRegistry();
f_dispatcher = new CoherenceEventDispatcher(this);
f_health = new HealthCheckWrapper(new CoherenceHealth(), HealthCheckWrapper.SUBTYPE_COHERENCE);
Registry eventRegistry = new Registry();
f_registry.registerResource(InterceptorRegistry.class, eventRegistry);
f_registry.registerResource(EventDispatcherRegistry.class, eventRegistry);
eventRegistry.registerEventDispatcher(f_dispatcher);
for (EventInterceptor> interceptor : f_config.getInterceptors())
{
eventRegistry.registerEventInterceptor(interceptor);
}
for (LifecycleListener listener : ServiceLoader.load(LifecycleListener.class))
{
eventRegistry.registerEventInterceptor(listener);
}
}
// ----- factory methods ------------------------------------------------
/**
* Return the default {@link Coherence} instance, creating it if it does not already exist.
*
* @return a default {@link Coherence} instance
*/
public static Coherence create()
{
return builder(CoherenceConfiguration.create(), Mode.ClusterMember)
.build(true);
}
/**
* Create a default {@link Coherence} instance.
*
* @param config the configuration to use to create the
* {@link Coherence} instance
*
* @return a default {@link Coherence} instance
*/
public static Coherence create(CoherenceConfiguration config)
{
return create(config, Mode.ClusterMember);
}
/**
* Create a default {@link Coherence} instance.
*
* @param config the configuration to use to create the
* {@link Coherence} instance
* @param mode the {@link Mode} the {@link Coherence} instance will run in
*
* @return a default {@link Coherence} instance
*/
public static Coherence create(CoherenceConfiguration config, Mode mode)
{
return builder(config, mode).build();
}
/**
* Returns a {@link Builder} instance that can build a {@link Coherence}
* instance using the specified {@link CoherenceConfiguration}.
*
* The {@link Coherence} instance built by the {@code Builder} will be a
* cluster member. Coherence auto-start services will be managed by a
* {@link DefaultCacheServer} instance for each configured session.
*
* @param config the {@link CoherenceConfiguration} to use to build the {@link Coherence} instance
*
* @return a {@link Builder} instance that can build a {@link Coherence}
* instance using the specified {@link CoherenceConfiguration}
*/
public static Builder builder(CoherenceConfiguration config)
{
return clusterMemberBuilder(config);
}
/**
* Returns a {@link Builder} instance that can build a {@link Coherence}
* instance using the specified {@link CoherenceConfiguration}.
*
* The {@link Coherence} instance built by the {@code Builder} will be a
* cluster member. Coherence auto-start services will be managed by a
* {@link DefaultCacheServer} instance for each configured session.
*
* @param config the {@link CoherenceConfiguration} to use to build the {@link Coherence} instance
* @param mode the {@link Mode} the {@link Coherence} instance will run in
*
* @return a {@link Builder} instance that can build a {@link Coherence}
* instance using the specified {@link CoherenceConfiguration}
*/
public static Builder builder(CoherenceConfiguration config, Mode mode)
{
return new Builder(config, mode);
}
/**
* Return the default {@link Coherence} cluster member instance, creating it if it does not already exist.
*
* The {@link Coherence} instance built by the {@code Builder} will be a
* cluster member.
*
* @return a default {@link Coherence} instance
*/
public static Coherence clusterMember()
{
return clusterMemberBuilder(CoherenceConfiguration.create()).build(true);
}
/**
* Create a {@link Coherence} instance from the specified {@link CoherenceConfiguration}.
*
* The {@link Coherence} instance built by the {@code Builder} will be a
* cluster member.
*
* @param config the configuration to use to create the
* {@link Coherence} instance
*
* @return a {@link Coherence} instance from the specified {@link CoherenceConfiguration}
*/
public static Coherence clusterMember(CoherenceConfiguration config)
{
return clusterMemberBuilder(config).build();
}
/**
* Return the default {@link Coherence} client instance, creating it if it does not already exist.
*
* If using the default Coherence cache configuration file, this will configure Coherence
* to be an Extend client.
*
* If using the default Coherence Concurrent extensions, this will configure Coherence
* Concurrent to be an Extend client.
*
* @return a default {@link Coherence} instance
*/
public static Coherence client()
{
return clientBuilder(CoherenceConfiguration.create()).build(true);
}
/**
* Return the default {@link Coherence} client instance, creating it if it does not already exist.
*
* If using the default Coherence cache configuration file, this will configure Coherence
* to be an Extend client.
*
* If using the default Coherence Concurrent extensions, this will configure Coherence
* Concurrent to be an Extend client.
*
* @param mode the default mode to run the Coherence instance
*
* @return a default {@link Coherence} instance
*/
public static Coherence client(Mode mode)
{
return clientBuilder(CoherenceConfiguration.create(), mode).build(true);
}
/**
* Create a client {@link Coherence} instance from the specified {@link CoherenceConfiguration}.
*
* If using the default Coherence cache configuration file, this will configure Coherence
* to be an Extend client.
*
* If using the default Coherence Concurrent extensions, this will configure Coherence
* Concurrent to be an Extend client.
*
* @param config the configuration to use to create the
* {@link Coherence} instance
*
* @return a {@link Coherence} instance from the specified {@link CoherenceConfiguration}
*/
public static Coherence client(CoherenceConfiguration config)
{
return clientBuilder(config).build();
}
/**
* Create a default {@link Coherence} client instance, creating it if it does not already exist.
*
* If using the default Coherence cache configuration file, this will configure Coherence
* to be an Extend client.
*
* If using the default Coherence cache configuration file, this will configure Coherence
* to be an Extend client using a fixed address configured with the parameters
* {@code coherence.extend.address} and {@code coherence.extend.port}.
*
* @return a default {@link Coherence} instance
*/
public static Coherence fixedClient()
{
return fixedClientBuilder(CoherenceConfiguration.create()).build(true);
}
/**
* Create a client {@link Coherence} instance from the specified {@link CoherenceConfiguration}.
*
* If using the default Coherence cache configuration file, this will configure Coherence
* to be an Extend client.
*
* If using the default Coherence cache configuration file, this will configure Coherence
* to be an Extend client using a fixed address configured with the parameters
* {@code coherence.extend.address} and {@code coherence.extend.port}.
*
* @param config the configuration to use to create the
* {@link Coherence} instance
*
* @return a {@link Coherence} instance from the specified {@link CoherenceConfiguration}
*/
public static Coherence fixedClient(CoherenceConfiguration config)
{
return fixedClientBuilder(config).build();
}
/**
* Returns a {@link Builder} instance that can build a {@link Coherence}
* instance using the specified {@link CoherenceConfiguration}.
*
* The {@link Coherence} instance built by the {@code Builder} will be a
* cluster member. Coherence auto-start services will be managed by a
* {@link DefaultCacheServer} instance for each configured session.
*
* @return a {@link Builder} instance that can build a {@link Coherence}
* instance using the specified {@link CoherenceConfiguration}
*/
public static Builder clusterMemberBuilder(CoherenceConfiguration config)
{
return new Builder(config, Mode.ClusterMember);
}
/**
* Returns a {@link Builder} instance that can build a {@link Coherence}
* instance using the specified {@link CoherenceConfiguration}.
*
* The {@link Coherence} instance built by the {@code Builder} will be a
* client, it will not start or join a Coherence cluster.
*
* If using the default Coherence cache configuration file, this will configure Coherence
* to be an Extend client.
*
* If using the default Coherence Concurrent extensions, this will configure Coherence
* Concurrent to be an Extend client.
*
* @param config the {@link CoherenceConfiguration} to configure the {@link Coherence} instance
*
* @return a {@link Builder} instance that can build a {@link Coherence}
* instance using the specified {@link CoherenceConfiguration}
*/
public static Builder clientBuilder(CoherenceConfiguration config)
{
return clientBuilder(config, Mode.Client);
}
/**
* Returns a {@link Builder} instance that can build a {@link Coherence}
* instance using the specified {@link CoherenceConfiguration}.
*
* The {@link Coherence} instance built by the {@code Builder} will be a
* client, it will not start or join a Coherence cluster.
*
* If using the default Coherence cache configuration file, this will configure Coherence
* to be an Extend client.
*
* If using the default Coherence Concurrent extensions, this will configure Coherence
* Concurrent to be an Extend client.
*
* @param config the {@link CoherenceConfiguration} to configure the {@link Coherence} instance
* @param mode the default mode to run the Coherence instance
*
* @return a {@link Builder} instance that can build a {@link Coherence}
* instance using the specified {@link CoherenceConfiguration}
*/
public static Builder clientBuilder(CoherenceConfiguration config, Mode mode)
{
return new Builder(config, mode);
}
/**
* Returns a {@link Builder} instance that can build a {@link Coherence}
* instance using the specified {@link CoherenceConfiguration}.
*
* The {@link Coherence} instance built by the {@code Builder} will be a client
* using a fixed Extend address, it will not start or join a Coherence cluster.
*
* If using the default Coherence cache configuration file, this will configure Coherence
* to be an Extend client using a fixed address configured with the parameters
* {@code coherence.extend.address} and {@code coherence.extend.port}.
*
* If using the default Coherence Concurrent extensions, this will configure Coherence
* Concurrent to be an Extend client.
*
* @return a {@link Builder} instance that can build a {@link Coherence}
* instance using the specified {@link CoherenceConfiguration}
*/
public static Builder fixedClientBuilder(CoherenceConfiguration config)
{
return new Builder(config, Mode.ClientFixed);
}
/**
* Returns all of the {@link Coherence} instances.
*
* @return all of the {@link Coherence} instances
*/
public static Collection getInstances()
{
return Collections.unmodifiableCollection(s_mapInstance.values());
}
/**
* Returns the named {@link Coherence} instance or {@code null}
* if the name is {@code null} or no {@link Coherence} instance exists
* with the specified name.
*
* @param sName the name of the {@link Coherence} instance to return
*
* @return the named {@link Coherence} instance or {@code null} if no
* {@link Coherence} instance exists with the specified name
*/
public static Coherence getInstance(String sName)
{
return sName == null ? null : s_mapInstance.get(sName);
}
/**
* Returns a {@link Coherence} instance created or {@code null}
* if no {@link Coherence} instance exists.
*
* This method is useful if only a single {@link Coherence} instance
* exists in an application. If multiple instances exists the actual
* instance returned is undetermined.
*
* @return a {@link Coherence} instance created
*/
public static Coherence getInstance()
{
Coherence coherence = s_mapInstance.get(Coherence.DEFAULT_NAME);
if (coherence != null)
{
return coherence;
}
return s_mapInstance.entrySet()
.stream()
.findFirst()
.map(Map.Entry::getValue)
.orElse(null);
}
/**
* Find the {@link Session} instance with the given name across
* all {@link Coherence} instances.
*
* @param sName the {@link Session} name to find
*
* @return the an {@link Optional} containing the {@link Session} with
* the specified name, or an empty optional if the session does
* not exist
*/
public static Optional findSession(String sName)
{
for (Coherence coherence : s_mapInstance.values())
{
if (coherence.hasSession(sName))
{
Session session = coherence.getSession(sName);
if (session != null)
{
return Optional.of(session);
}
}
}
return Optional.empty();
}
/**
* Find the {@link Session} instances with the given scope name across
* all {@link Coherence} instances.
*
* @param sScope the scope name of the {@link Session Sessions} to find
*
* @return the an {@link Optional} containing the {@link Session} with
* the specified name, or an empty optional if the session does
* not exist
*/
public static Collection findSessionsByScope(String sScope)
{
Collection col = null;
if (Coherence.SYSTEM_SCOPE.equals(sScope))
{
col = s_systemSession.map(Session.class::cast)
.map(Collections::singleton).orElse(null);
}
if (col == null)
{
col = s_mapInstance.values()
.stream()
.flatMap(coh -> coh.getSessionsWithScope(sScope).stream())
.collect(Collectors.toList());
}
return col;
}
/**
* Close all {@link Coherence} instances.
*
* If starting {@link Coherence} instances ensured the Coherence {@link Cluster}
* instance then calling this method will also fully shutdown Coherence.
*/
@SuppressWarnings("OptionalAssignedToNull")
public static void closeAll()
{
Logger.info("Stopping all Coherence instances");
s_mapInstance.values().forEach(Coherence::close);
if (s_systemServiceMonitor != null)
{
s_systemServiceMonitor.close();
}
if (s_systemSession != null && s_systemSession.isPresent())
{
ConfigurableCacheFactorySession session = s_systemSession.get();
CacheFactoryBuilder builder = CacheFactory.getCacheFactoryBuilder();
ConfigurableCacheFactory ccf = session.getConfigurableCacheFactory();
try
{
session.close();
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
builder.release(ccf);
ccf.dispose();
}
}
Logger.info("All Coherence instances stopped");
s_systemServiceMonitor = null;
s_systemSession = null;
if (s_fEnsuredCluster != null && s_fEnsuredCluster)
{
CacheFactory.shutdown();
}
s_fEnsuredCluster = null;
}
// ----- Coherence API --------------------------------------------------
/**
* Returns the name of this {@link Coherence} instance.
*
* @return the name of this {@link Coherence} instance
*/
public String getName()
{
return f_sName;
}
/**
* Return the {@link Mode} that this instance is running as.
*
* @return the {@link Mode} that this instance is running as
*/
public Mode getMode()
{
return f_mode;
}
/**
* Returns the configuration used by this {@link Coherence} instance.
*
* @return the configuration used by this {@link Coherence} instance
*/
public CoherenceConfiguration getConfiguration()
{
return f_config;
}
/**
* Returns {@code true} if this {@link Coherence} instance can
* provide a {@link Session} with the specified name.
*
* @param sName the name of the {@link Session}
*
* @return {@code true} if this {@link Coherence} instance can
* provide a {@link Session} with the specified name
*/
public boolean hasSession(String sName)
{
if (SYSTEM_SESSION.equals(sName))
{
return m_localSystemSession != null && m_localSystemSession.isPresent();
}
SessionConfiguration configuration = getSessionConfiguration(sName);
return configuration != null && configuration.isEnabled();
}
/**
* Return a set of session names that this {@code Coherence}
* instance has.
*
* @return a set of session names that this {@code Coherence}
* instance has
*/
public Set getSessionNames()
{
return Collections.unmodifiableSet(f_mapSession.keySet());
}
/**
* Return a set of session scope names that this {@code Coherence}
* instance has.
*
* @return a set of session scope names that this {@code Coherence}
* instance has
*/
public Set getSessionScopeNames()
{
return f_mapSession.values()
.stream()
.map(Session::getScopeName)
.collect(Collectors.toSet());
}
/**
* Obtain the default {@link Session} from the {@link Coherence} instance.
*
* @return the default {@link Session}
*
* @throws IllegalStateException if this instance has been closed
*/
public Session getSession()
{
return getSession(DEFAULT_NAME);
}
/**
* Obtain the {@link Session} from the {@link Coherence} instance that was
* configured with the specified configuration name.
*
* @param sName the name of the {@link Session} to return
*
* @return an {@link Optional} containing the named {@link Session} or an
* empty {@link Optional} if this {@link Coherence} instance does
* not contain the named session
*
* @throws IllegalStateException if this instance has been closed
*/
public Optional getSessionIfPresent(String sName)
{
assertNotClosed();
return getSessionInternal(sName);
}
/**
* Obtain the {@link Session} from the {@link Coherence} instance that was
* configured with the specified configuration name.
*
* @param sName the name of the {@link Session} to return
*
* @return the named {@link Session}
*
* @throws IllegalArgumentException if no session exists for the specified name
* @throws IllegalStateException if this instance has been closed
*/
public Session getSession(String sName)
{
assertNotClosed();
String sSessionName = sName == null ? Coherence.DEFAULT_NAME : sName;
return getSessionInternal(sName)
.orElseThrow(() -> new IllegalArgumentException("No Session has been configured with the name " + sSessionName));
}
/**
* Add a {@link SessionConfiguration session} to this {@link Coherence} instance.
*
* The {@link SessionConfiguration#getName() session name} must be globally unique across
* all {@link Coherence} instances.
*
* If this {@link Coherence} instance is already running, then the session will be started
* immediately.
*
* @param config the {@link SessionConfiguration configuration} of the session to add
*
* @return this {@link Coherence} instance
*
* @throws IllegalArgumentException if the configuration does not have a name
* @throws IllegalStateException if this {@link Coherence} instance is closed
*/
public synchronized Coherence addSession(SessionConfiguration config)
{
assertNotClosed();
String sName = config.getName();
if (hasSession(sName))
{
throw new IllegalStateException("A Session with the name '" + sName
+ "' already exists in this Coherence instance '" + getName() + "'");
}
return addSessionInternal(config);
}
/**
* Add a {@link SessionConfiguration session} to this {@link Coherence} instance, iff a
* session configuration is not already present in this {@link Coherence} instance with
* the specified name.
*
* The {@link SessionConfiguration#getName() session name} must be globally unique across
* all {@link Coherence} instances.
*
* If this {@link Coherence} instance is already running, then the session will be started
* immediately.
*
* @param config the {@link SessionConfiguration configuration} of the session to add
*
* @return this {@link Coherence} instance
*
* @throws IllegalArgumentException if the configuration does not have a name
* @throws IllegalStateException if this {@link Coherence} instance is closed
*/
public Coherence addSessionIfAbsent(SessionConfiguration config)
{
return addSessionIfAbsent(config.getName(), () -> config);
}
/**
* Add a {@link SessionConfiguration session} to this {@link Coherence} instance, iff a
* session configuration is not already present in this {@link Coherence} instance with
* the specified name.
*
* The {@link SessionConfiguration#getName() session name} must be globally unique across
* all {@link Coherence} instances.
*
* If this {@link Coherence} instance is already running, then the session will be started
* immediately.
*
* @param sName the name of the session to add
* @param supplier a {@link Supplier} used to provide the {@link SessionConfiguration configuration}
* of the session to add, if the session is not present
*
* @return this {@link Coherence} instance
*
* @throws IllegalArgumentException if the configuration name does not match the name argument
* @throws IllegalArgumentException if the configuration does not have a name
* @throws IllegalStateException if this {@link Coherence} instance is closed
*/
public synchronized Coherence addSessionIfAbsent(String sName, Supplier supplier)
{
assertNotClosed();
if (hasSession(sName))
{
return this;
}
SessionConfiguration config = supplier.get();
if (!Objects.equals(sName, config.getName()))
{
throw new IllegalArgumentException("The configuration name '" + config.getName()
+ "' does not match the name argument '" + sName + "'");
}
return addSessionInternal(config);
}
private Coherence addSessionInternal(SessionConfiguration config)
{
validate(config);
String s;
f_mapAdditionalSessionConfig.put(config.getName(), config);
if (isStarted())
{
// This Coherence instance is already started so start the session
Iterable> globalInterceptors = f_config.getInterceptors();
startSession(config, globalInterceptors);
}
return this;
}
/**
* Obtain all the {@link Session Sessions} from the {@link Coherence} instance
* that are configured with the specified scope name.
*
* @param sScope the scope name of the {@link Session Sessions} to return
*
* @return the {@link Session} instances with the specified scope or
* an empty {@link Collection} if no {@link Session Sessions}
* have the required scope name
*
* @throws IllegalStateException if this instance has been closed
*/
public Collection getSessionsWithScope(String sScope)
{
assertNotClosed();
String sScopeName;
if (sScope == null || Coherence.DEFAULT_SCOPE.equals(sScope))
{
sScopeName = f_config.getApplicationContext()
.map(Context::getDefaultScope)
.orElse(Coherence.DEFAULT_SCOPE);
}
else
{
sScopeName = sScope;
}
if (m_localSystemSession.isPresent())
{
Session session = m_localSystemSession.get();
if (Coherence.SYSTEM_SCOPE.equals(sScope) || session.getScopeName().equals(sScope))
{
return Collections.singletonList(session);
}
}
return getSessionConfigurations()
.filter(cfg -> sScopeName.equals(cfg.getScopeName()))
.map(SessionConfiguration::getName)
.map(this::getSession)
.collect(Collectors.toList());
}
/**
* Obtain a {@link CompletableFuture} that will be completed when
* this {@link Coherence} instance has started.
*
* @return a {@link CompletableFuture} that will be completed when
* this {@link Coherence} instance has started
*/
public CompletableFuture whenStarted()
{
return f_futureStarted;
}
/**
* Obtain a {@link CompletableFuture} that will be completed when
* this {@link Coherence} instance has closed.
*
* @return a {@link CompletableFuture} that will be completed when
* this {@link Coherence} instance has closed
*/
public CompletableFuture whenClosed()
{
return f_futureClosed;
}
/**
* Return {@code true} if this {@link Coherence} instance has been started.
*
* @return {@code true} if this {@link Coherence} instance has been started
*/
public boolean isStarted()
{
return m_fStarted && !m_fClosed;
}
/**
* Return {@code true} if this {@link Coherence} instance has been closed.
*
* @return {@code true} if this {@link Coherence} instance has been closed
*/
public boolean isClosed()
{
return m_fClosed;
}
/**
* Start this {@link Coherence} instance and block until Coherence has started.
*
* This method will wait for the specified timeout.
*
* If this instance already been started and has not
* been closed this method call is a no-op.
*
* @return the running {@link Coherence} instance
*
* @throws InterruptedException if Coherence does not start within the timeout
*/
public Coherence startAndWait() throws InterruptedException
{
return startAndWait(DEFAULT_START_TIMEOUT);
}
/**
* Start this {@link Coherence} instance and block until Coherence has started.
*
* This method will wait for the specified timeout.
*
* If this instance already been started and has not
* been closed this method call is a no-op.
*
* @param timeout the timeout duration to wait for Coherence to start
*
* @return the running {@link Coherence} instance
*
* @throws InterruptedException if Coherence does not start within the timeout
*/
public Coherence startAndWait(Duration timeout) throws InterruptedException
{
long cMillis = timeout == null
? DEFAULT_START_TIMEOUT.as(Duration.Magnitude.MILLI)
: Math.max(1, timeout.as(Duration.Magnitude.MILLI));
try (Timeout ignored = Timeout.after(cMillis))
{
start(true);
}
return this;
}
/**
* Asynchronously start this {@link Coherence} instance.
*
* If this instance already been started and has not
* been closed this method call is a no-op.
*
* @return a {@link CompletableFuture} that will be completed when
* this {@link Coherence} instance has started
*/
public CompletableFuture start()
{
return start(false);
}
/**
* Start this {@link Coherence} instance.
*
* If this instance already been started and has not
* been closed this method call is a no-op.
*/
public void startOnCallingThread()
{
start(true);
}
/**
* Start this {@link Coherence} instance.
*
* If this instance already been started and has not
* been closed this method call is a no-op.
*
* @param fRunOnCallingThread {@code true} to start the Coherence instance synchronously
* on the calling thread, or {@code false} to start the
* Coherence instance asynchronously
*
* @return a {@link CompletableFuture} that will be completed when
* this {@link Coherence} instance has started
*/
private CompletableFuture start(boolean fRunOnCallingThread)
{
assertNotClosed();
if (m_fStarted)
{
return f_futureStarted;
}
synchronized (this)
{
assertNotClosed();
if (m_fStarted)
{
return f_futureStarted;
}
f_dispatcher.dispatchStarting();
m_fStarted = true;
try
{
Runnable runnable = () ->
{
ContainerContext context = f_config.getApplicationContext()
.map(Context::getContainerContext)
.orElse(null);
if (context != null)
{
ContainerContext contextCurrent = context.getCurrentThreadContext();
if (contextCurrent == null ||
!contextCurrent.getDomainPartition().equals(context.getDomainPartition()))
{
throw new IllegalStateException("start() called out of context");
}
if (!context.isGlobalDomainPartition())
{
context = context.getGlobalContext();
context.setCurrentThreadContext();
}
else
{
// null context indicates we don't need to reset the thread context
context = null;
}
}
try
{
if (f_mapServer.isEmpty())
{
startInternal();
}
f_mapServer.values().forEach(holder -> holder.getServer().waitForServiceStart());
f_futureStarted.complete(this);
f_dispatcher.dispatchStarted();
}
catch (Throwable thrown)
{
Logger.err(thrown);
f_futureStarted.completeExceptionally(thrown);
}
finally
{
if (context != null)
{
context.resetCurrentThreadContext();
}
}
};
if (fRunOnCallingThread)
{
runnable.run();
}
else
{
Thread t = Base.makeThread(null , runnable,
isDefaultInstance() ? "Coherence" : "Coherence:" + f_sName);
t.setDaemon(true);
t.start();
}
}
catch (Throwable thrown)
{
f_futureStarted.completeExceptionally(thrown);
}
}
return f_futureStarted;
}
/**
* Close this {@link Coherence} instance.
*/
@Override
public synchronized void close()
{
if (m_fClosed)
{
return;
}
f_dispatcher.dispatchStopping();
m_fClosed = true;
try
{
s_mapInstance.remove(f_sName);
if (m_fStarted)
{
m_fStarted = false;
// close sessions in reverse order
getSessionConfigurations()
.sorted(Comparator.reverseOrder())
.forEach(cfg ->
{
Session session = f_mapSession.get(cfg.getName());
try
{
session.close();
cfg.sessionProvider().ifPresent(p -> p.releaseSession(session));
}
catch(Throwable t)
{
Logger.err("Error closing session " + session.getName(), t);
}
});
// Stop servers in reverse order
f_mapServer.values()
.stream()
.sorted(Comparator.reverseOrder())
.map(PriorityHolder::getServer)
.forEach(this::stopServer);
f_mapServer.clear();
if (f_mode == Mode.Gar)
{
m_localSystemServiceMonitor.close();
if (m_localSystemSession.isPresent())
{
try
{
ConfigurableCacheFactorySession session = m_localSystemSession.get();
session.getConfigurableCacheFactory().dispose();
session.close();
SessionProvider provider = m_localSystemSessionConfig.sessionProvider()
.orElseGet(SessionProvider::get);
provider.releaseSession(session);
}
catch (Exception e)
{
Logger.err(e);
}
}
}
m_localSystemSession = null;
m_localSystemServiceMonitor = null;
}
getCluster().getManagement().unregister(f_health);
f_futureClosed.complete(null);
}
catch (Throwable thrown)
{
Logger.err(thrown);
f_futureClosed.completeExceptionally(thrown);
}
f_dispatcher.dispatchStopped();
f_registry.dispose();
}
/**
* Return the {@link ResourceRegistry} for this {@link Coherence} instance.
*
* @return the ResourceRegistry for this {@link Coherence} instance
*/
public ResourceRegistry getResourceRegistry()
{
return f_registry;
}
/**
* Return the {@link InterceptorRegistry} for this {@link Coherence} instance.
*
* @return the {@link InterceptorRegistry} for this {@link Coherence} instance
*/
public InterceptorRegistry getInterceptorRegistry()
{
return f_registry.getResource(InterceptorRegistry.class);
}
/**
* Return a {@link Cluster} object for Coherence services.
*
* @return a {@link Cluster} object, which may or may not be running
*/
public Cluster getCluster()
{
return CacheFactory.getCluster();
}
/**
* Returns the current management registry.
*
* @return the current management registry or {@code null}
* if the management is disabled on this node
*
* @since 22.06
*/
public com.tangosol.net.management.Registry getManagement()
{
return getCluster().getManagement();
}
/**
* Start a Coherence server.
*
* This method will start Coherence configured with a single session
* that uses the default cache configuration file. This is effectively
* the same as running {@link DefaultCacheServer#main(String[])} without
* any arguments but will additionally bootstrap a {@link Coherence}
* instance with the default name {@link Coherence#DEFAULT_NAME}
* and an unscoped {@link Session} with the same default name.
*
* @param args the program arguments.
*/
public static void main(String[] args)
{
if (args.length > 0 && args[0].equals("--version"))
{
System.out.println(CacheFactory.VERSION);
if (args.length == 1)
{
System.exit(0);
}
}
String sClient = Config.getProperty("coherence.client");
Mode mode = null;
try
{
mode = Mode.fromClientName(sClient);
}
catch (IllegalArgumentException e)
{
// ignored
}
Coherence coherence;
if (mode == null)
{
coherence = Coherence.clusterMember();
}
else
{
coherence = Coherence.builder(CoherenceConfiguration.create(), mode).build();
}
coherence.start();
// block forever (or until the Coherence instance is shutdown)
coherence.whenClosed().join();
}
// ----- Object methods -------------------------------------------------
@Override
public String toString()
{
return "Coherence{" +
"name='" + f_sName + '\'' +
", mode='" + f_mode + '\'' +
", started='" + m_fStarted + '\'' +
", closed='" + m_fClosed + '\'' +
", sessions=[" + getSessionConfigurations()
.map(s -> "{name='" + s.getName() + "', scope='" + s.getScopeName() + "'}")
.collect(Collectors.joining(",")) + "]" +
'}';
}
// ----- helper methods -------------------------------------------------
/**
* Return {@code true} if this is the default instance.
*
* @return {@code true} if this is the default instance
*/
private boolean isDefaultInstance()
{
return DEFAULT_NAME.equals(f_sName);
}
/**
* Assert that this {@link Coherence} instance is not closed.
*/
private void assertNotClosed()
{
if (m_fClosed)
{
throw new IllegalStateException("This " + getClass().getSimpleName() + " instance has been closed");
}
}
/**
* Obtain the {@link Session} from the {@link Coherence} instance that was
* configured with the specified configuration name.
*
* @param sName the name of the {@link Session} to return
*
* @return an {@link Optional} containing the named {@link Session} or an
* empty {@link Optional} if this {@link Coherence} instance does
* not contain the named session
*/
private Optional getSessionInternal(String sName)
{
if (Coherence.SYSTEM_SESSION.equals(sName))
{
return Optional.ofNullable(initializeSystemSession(Collections.emptyList()));
}
String sSessionName = sName == null ? Coherence.DEFAULT_NAME : sName;
SessionConfiguration configuration = getSessionConfiguration(sSessionName);
if (configuration == null || !configuration.isEnabled())
{
return Optional.empty();
}
return Optional.ofNullable(f_mapSession.get(sSessionName));
}
/**
* Start this {@link Coherence} instance.
*/
private synchronized void startInternal()
{
Iterable> globalInterceptors = f_config.getInterceptors();
Cluster cluster = CacheFactory.getCluster();
if (s_fEnsuredCluster == null)
{
s_fEnsuredCluster = !cluster.isRunning();
}
// ensure the System Session before doing anything else
// even though there might not actually be a System session
initializeSystemSession(globalInterceptors);
Logger.info(() -> isDefaultInstance()
? "Starting default Coherence instance" + " mode=" + f_mode
: "Starting Coherence instance " + f_sName + " mode=" + f_mode);
cluster.getManagement().register(f_health);
try
{
// Create the sessions in priority order of their configurations
getSessionConfigurations()
.sorted(Comparator.reverseOrder())
.forEach(configuration -> startSession(configuration, globalInterceptors));
}
catch (Throwable t)
{
Logger.err("Failed to start Coherence instance " + f_sName + " mode=" + f_mode, t);
close();
}
if (f_mode == Mode.ClusterMember || f_mode == Mode.Gar)
{
Logger.info(() -> "Started Coherence server " + f_sName + " mode=" + f_mode
+ CacheFactory.getCluster().getServiceBanner());
}
else
{
Logger.info(() -> "Started Coherence client " + f_sName + " mode=" + f_mode);
}
}
/**
* Start the specified {@link SessionConfiguration session}.
*
* @param configuration the {@link SessionConfiguration configuration} of the session to start
* @param globalInterceptors the {@link EventInterceptor interceptors} to add to the session
*/
private void startSession(SessionConfiguration configuration, Iterable> globalInterceptors)
{
if (m_fClosed)
{
// closed during start-up
return;
}
if (configuration.isEnabled())
{
String sName = configuration.getName();
Mode mode = configuration.getMode().orElse(f_mode);
if (Coherence.DEFAULT_NAME.equals(sName))
{
Logger.info("Starting default Session mode=" + mode);
}
else
{
Logger.info("Starting Session \"" + sName + "\" mode=" + mode);
}
Iterable extends EventInterceptor>> interceptors
= join(globalInterceptors, configuration.getInterceptors());
Optional optional = ensureSessionInternal(configuration, f_mode, getScopePrefix(), interceptors);
if (optional.isPresent())
{
Session session = optional.get();
// ensure that the session is activated
session.activate();
f_mapSession.put(sName, session);
if (session instanceof ConfigurableCacheFactorySession)
{
ConfigurableCacheFactorySession supplier = (ConfigurableCacheFactorySession) session;
ConfigurableCacheFactory ccf = supplier.getConfigurableCacheFactory();
if (mode == Mode.ClusterMember)
{
// This is a server and the session is not a client session so wrap in a DCS
// to manage the auto-start services.
DefaultCacheServer dcs = startCCF(sName, ccf);
f_mapServer.put(sName, new PriorityHolder(configuration.getPriority(), dcs));
}
}
}
else
{
Logger.warn("Skipping Session " + configuration.getName()
+ " Session provider returned null");
}
}
}
/**
* Returns the {@link SessionConfiguration} for the specified session.
*
* @param sName the name of the session
*
* @return the {@link SessionConfiguration} for the specified session,
* or {@code null} if this {@link Coherence} instance does not
* contain a {@link SessionConfiguration} with the specified
* name
*/
private SessionConfiguration getSessionConfiguration(String sName)
{
SessionConfiguration configuration = f_config.getSessionConfigurations().get(sName);
if (configuration == null)
{
configuration = f_mapAdditionalSessionConfig.get(sName);
}
return configuration;
}
/**
* Returns a {@link Stream} of all the {@link SessionConfiguration session configurations}
* this {@link Coherence} instance has.
*
* @return a {@link Stream} of all the {@link SessionConfiguration session configurations}
* this {@link Coherence} instance has
*/
private Stream getSessionConfigurations()
{
return Stream.concat(f_config.getSessionConfigurations().values().stream(),
f_mapAdditionalSessionConfig.values().stream());
}
/**
* Combine two Iterables of interceptors into a single iterable.
*
* @param one the first iterable of interceptors
* @param two the first iterable of interceptors
*
* @return the combined iterable of interceptors
*/
private static Iterable extends EventInterceptor>> join (Iterable extends EventInterceptor>> one,
Iterable extends EventInterceptor>> two)
{
if (one == null && two == null)
{
return Collections.emptyList();
}
if (one == null)
{
return two;
}
if (two == null)
{
return one;
}
Stream extends EventInterceptor>> s1 = StreamSupport.stream(one.spliterator(), false);
Stream extends EventInterceptor>> s2 = StreamSupport.stream(two.spliterator(), false);
return Stream.concat(s1, s2).collect(Collectors.toCollection(ArrayList::new));
}
/**
* Ensure the specified {@link Session} exists.
*
* @param configuration the {@link SessionConfiguration configuration} for the {@link Session}
* @param mode the {@link Mode} the requesting {@link Coherence} instance is running in
* @param sScopePrefix the prefix to prepend to the session scope
* @param interceptors optional {@link EventInterceptor interceptors} to add to
* the session in addition to any in the configuration
*
* @return the configured and started {@link Session}
*/
private static Optional ensureSessionInternal(SessionConfiguration configuration,
Mode mode, String sScopePrefix, Iterable extends EventInterceptor>> interceptors)
{
SessionProvider provider = configuration.sessionProvider().orElseGet(SessionProvider::get);
Optional optional = provider.createSession(configuration, mode, sScopePrefix, interceptors);
if (optional.isPresent())
{
String sName = configuration.getName();
if (sName == null || DEFAULT_NAME.equals(sName))
{
sName = "$Default$";
}
Logger.info("Created Session " + sName + " mode="
+ configuration.getMode().orElse(mode));
}
return optional;
}
/**
* Register the specified {@link EventInterceptor interceptors} with the {@link Session}.
*
* @param session the {@link Session} to register the interceptors with
* @param interceptors the {@link EventInterceptor interceptors} to register
*/
private static void registerInterceptors(Session session, Iterable extends EventInterceptor>> interceptors)
{
InterceptorRegistry registry = session.getInterceptorRegistry();
for (EventInterceptor> interceptor : interceptors)
{
registry.registerEventInterceptor(interceptor, RegistrationBehavior.FAIL);
}
}
/**
* Activate and start the autostart services in the specified {@link ConfigurableCacheFactory}.
*
* The {@link ConfigurableCacheFactory} will be wrapped in a {@link DefaultCacheServer} that
* will monitor and manage the {@link ConfigurableCacheFactory} services.
*
* @param sName the name of the {@link ConfigurableCacheFactory}
* @param ccf the {@link ConfigurableCacheFactory} to start
*
* @return the {@link DefaultCacheServer} that is managing and monitoring
* the {@link ConfigurableCacheFactory} services
*/
private DefaultCacheServer startCCF(String sName, ConfigurableCacheFactory ccf)
{
displayStartBanner(sName, ccf);
DefaultCacheServer dcs = new DefaultCacheServer(ccf);
dcs.startDaemon(DefaultCacheServer.DEFAULT_WAIT_MILLIS);
return dcs;
}
/**
* Activate and start the autostart services in the specified system {@link ConfigurableCacheFactory}.
*
* The {@link ConfigurableCacheFactory} will be wrapped in a {@link ServiceMonitor} that
* will monitor and manage the {@link ConfigurableCacheFactory} services.
*
* @param sName the name of the {@link ConfigurableCacheFactory}
* @param ccf the {@link ConfigurableCacheFactory} to start
*
* @return the {@link ServiceMonitor} that is managing and monitoring
* the {@link ConfigurableCacheFactory} services
*/
private ServiceMonitor startSystemCCF(String sName, ExtensibleConfigurableCacheFactory ccf)
{
displayStartBanner(sName, ccf);
ServiceMonitor monitor = new SimpleServiceMonitor(DefaultCacheServer.DEFAULT_WAIT_MILLIS);
monitor.setConfigurableCacheFactory(ccf);
ccf.activate();
monitor.registerServices(ccf.getServiceMap());
monitor.getThread().setName(sName + ':' + monitor.getThread().getName());
return monitor;
}
private void displayStartBanner(String sName, ConfigurableCacheFactory ccf)
{
String sScopeName = ccf.getScopeName();
boolean fHasScope = sScopeName != null && !sScopeName.isEmpty();
Logger.info(() -> (sName == null || sName.isEmpty()
? "Starting default session"
: "Starting session " + sName)
+ (fHasScope ? " with scope name " + sScopeName : ""));
}
/**
* Stop a {@link DefaultCacheServer} instance.
*
* @param dcs the {@link DefaultCacheServer} to stop
*/
private void stopServer(DefaultCacheServer dcs)
{
try
{
dcs.stop();
}
catch (Throwable thrown)
{
Logger.err(thrown);
}
}
/**
* Ensure that the singleton system {@link Session} exists and is started.
*
* The System session only applies to certain environments, so we may not
* actually start anything.
*
* @param interceptors any interceptors to add to the system session
*
* @return the singleton system {@link Session}
*/
@SuppressWarnings("OptionalAssignedToNull")
private Session initializeSystemSession(Iterable extends EventInterceptor>> interceptors)
{
boolean fCreated = false;
if (f_mode == Mode.Gar)
{
if (m_localSystemSession == null)
{
m_localSystemSessionLock.lock();
try
{
if (m_localSystemSession == null)
{
createSystemSession(interceptors);
fCreated = true;
}
}
finally
{
m_localSystemSessionLock.unlock();
}
}
if (!fCreated)
{
m_localSystemSession.ifPresent(session -> registerInterceptors(session, interceptors));
}
}
else
{
if (s_systemSession == null)
{
s_globalSystemSessionLock.lock();
try
{
if (s_systemSession == null)
{
s_systemSession = createSystemSession(interceptors);
fCreated = true;
}
}
finally
{
s_globalSystemSessionLock.unlock();
}
}
else
{
m_localSystemSession = s_systemSession;
}
s_systemServiceMonitor = m_localSystemServiceMonitor;
if (!fCreated)
{
s_systemSession.ifPresent(session -> registerInterceptors(session, interceptors));
}
}
return m_localSystemSession.orElse(null);
}
private Optional createSystemSession(Iterable extends EventInterceptor>> interceptors)
{
SessionConfiguration configuration = new SystemSessionConfiguration(f_mode);
String sScopePrefix = getScopePrefix();
Iterable extends EventInterceptor>> allInterceptors
= join(interceptors, configuration.getInterceptors());
Optional optional =
ensureSessionInternal(configuration, f_mode, sScopePrefix, allInterceptors)
.map(ConfigurableCacheFactorySession.class::cast);
if (optional.isPresent() && (Mode.ClusterMember == f_mode || Mode.Gar == f_mode))
{
ConfigurableCacheFactorySession session = optional.get();
ExtensibleConfigurableCacheFactory ccfSystem = (ExtensibleConfigurableCacheFactory)
session.getConfigurableCacheFactory();
m_localSystemServiceMonitor = startSystemCCF(configuration.getScopeName(), ccfSystem);
session.activate();
}
registerHealthChecks();
m_localSystemSessionConfig = configuration;
m_localSystemSession = optional;
return optional;
}
/**
* Visible for testing only, set the System {@link Session}.
*
* @param optional an optional containing the System {@link Session}
*/
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
static void setSystemSession(Optional optional)
{
s_systemSession = Objects.requireNonNull(optional);
}
/**
* Discover and register any {@link HealthCheck} instances using the {@link ServiceLoader}.
*/
private void registerHealthChecks()
{
ServiceLoader loader = ServiceLoader.load(HealthCheck.class);
com.tangosol.net.management.Registry registry = getCluster().getManagement();
for (HealthCheck healthCheck : loader)
{
Logger.info("Registering discovered HealthCheck: " + healthCheck.getName());
registry.register(healthCheck);
}
}
/**
* Validate the {@link CoherenceConfiguration}.
*
* @param configuration the {@link CoherenceConfiguration} to validate
*/
private static void validate(CoherenceConfiguration configuration)
{
Collection sessions = configuration.getSessionConfigurations().values();
Set setName = new HashSet<>();
for (SessionConfiguration sessionConfiguration : sessions)
{
validate(sessionConfiguration);
String sName = sessionConfiguration.getName();
if (!setName.add(sName))
{
throw new IllegalStateException("A Session with the name '" + sName
+ "' already exists in this Coherence configuration");
}
}
}
/**
* Validate the {@link SessionConfiguration}.
*
* @param configuration the {@link SessionConfiguration} to validate
*/
private static void validate(SessionConfiguration configuration)
{
String sName = configuration.getName();
if (sName == null)
{
throw new IllegalArgumentException("A session configuration must provide a non-null name");
}
}
/**
* Obtain the prefix to prepend to session scopes.
*
* @return the prefix to prepend to session scopes
*/
private String getScopePrefix()
{
if (f_mode == Mode.Gar)
{
return f_config.getApplicationContext()
.map(a ->
{
String sScope = a.getDefaultScope();
return ServiceScheme.getScopePrefix(sScope, a.getContainerContext());
})
.orElse(getName());
}
return Coherence.DEFAULT_SCOPE;
}
// ----- inner class: PriorityHolder ------------------------------------
/**
* A holder of a priority and a {@link DefaultCacheServer}.
*/
private static class PriorityHolder
implements Comparable
{
public PriorityHolder(int nPriority, DefaultCacheServer server)
{
f_nPriority = nPriority;
f_server = server;
}
public int getPriority()
{
return f_nPriority;
}
public DefaultCacheServer getServer()
{
return f_server;
}
@Override
public int compareTo(PriorityHolder o)
{
return Integer.compare(f_nPriority, o.f_nPriority);
}
// ----- data members -----------------------------------------------
/**
* The priority of this holder.
*/
private final int f_nPriority;
/**
* The {@link DefaultCacheServer} instance.
*/
private final DefaultCacheServer f_server;
}
// ----- inner class: Builder -------------------------------------------
/**
* A builder to build {@link Coherence} instances.
*/
public static class Builder
{
private Builder(CoherenceConfiguration config, Mode mode)
{
f_config = config;
f_mode = mode == null ? Mode.ClusterMember : mode;
}
/**
* Build a {@link Coherence} instance.
*
* @return a {@link Coherence} instance
*/
public Coherence build()
{
// validate the configuration
Coherence.validate(f_config);
return build(false);
}
// ----- helper methods ---------------------------------------------
protected Coherence build(boolean fAllowDuplicate)
{
Coherence coherence = new Coherence(f_config, f_mode);
Coherence prev = s_mapInstance.putIfAbsent(f_config.getName(), coherence);
if (prev != null && f_mode != Mode.Gar)
{
if (!fAllowDuplicate)
{
throw new IllegalStateException("A Coherence instance with the name "
+ f_config.getName() + " already exists");
}
return prev;
}
return coherence;
}
// ----- data members -----------------------------------------------
/**
* The configuration to use to build a {@link Coherence} instance.
*/
private final CoherenceConfiguration f_config;
/**
* The mode that the {@link Coherence} instance should run as.
*/
private final Mode f_mode;
}
// ----- inner enum Type ------------------------------------------------
/**
* An enum representing the different modes that a {@link Coherence}
* instance can run in.
*/
public enum Mode
{
/**
* The {@link Coherence} instance should run as a non-cluster member Extend client.
* The proxy will be discovered using the name service.
*/
Client("remote"),
/**
* The {@link Coherence} instance should run as a non-cluster member Extend client,
* configured with a fixed address and port.
*/
ClientFixed("remote-fixed"),
/**
* The {@link Coherence} instance should run as a cluster member client.
*/
ClusterMember("direct"),
/**
* The {@link Coherence} instance should run as a non-cluster member gRPC client.
* The proxy will be discovered using the name service.
*/
Grpc("grpc"),
/**
* The {@link Coherence} instance should run as a non-cluster member gRPC client,
* configured with a fixed address and port.
*/
GrpcFixed("grpc-fixed"),
/**
* The {@link Coherence} instance has been created from a gar.
*/
Gar("direct");
Mode(String sClient)
{
f_sClient = sClient;
}
/**
* Returns the default {@code coherence.client} property.
*
* @return the default {@code coherence.client} property
*/
public String getClient()
{
return f_sClient;
}
/**
* Return the {@link Mode} for the given client name.
*
* @param sClient the client name
*
* @return the {@link Mode} for the given client name
*
* @throws IllegalArgumentException – if specified client name does not match any {@link Mode}
*/
public static Mode fromClientName(String sClient)
{
for (Mode mode : Mode.values())
{
if (mode.getClient().equals(sClient))
{
return mode;
}
}
throw new IllegalArgumentException("No Mode exists with a client name \"" + sClient + "\"");
}
// ----- data members -----------------------------------------------
/**
* The default {@code coherence.client} property for this mode.
*/
private final String f_sClient;
}
// ----- inner interface LifecycleListener ------------------------------
/**
* An interface implemented by listeners of {@link CoherenceLifecycleEvent CoherenceLifecycleEvents}.
*
* Implementations of this interface properly registered as services will be discovered
* using the {@link ServiceLoader} and automatically registered as interceptors with
* each {@link Coherence} instance.
*/
public interface LifecycleListener
extends EventDispatcherAwareInterceptor
{
@Override
void onEvent(CoherenceLifecycleEvent event);
@Override
default void introduceEventDispatcher(String sIdentifier, EventDispatcher dispatcher)
{
if (dispatcher instanceof CoherenceDispatcher)
{
dispatcher.addEventInterceptor(sIdentifier, this);
}
}
}
// ----- Health ---------------------------------------------------------
/**
* The Coherence instance's health check.
*/
private class CoherenceHealth
implements HealthCheck
{
@Override
public String getName()
{
if (Coherence.this.isDefaultInstance())
{
return "Default";
}
return Coherence.this.getName();
}
@Override
public boolean isMemberHealthCheck()
{
return true;
}
@Override
public boolean isReady()
{
return Coherence.this.isStarted();
}
@Override
public boolean isLive()
{
return Coherence.this.isStarted();
}
@Override
public boolean isStarted()
{
return Coherence.this.isStarted();
}
@Override
public boolean isSafe()
{
return Coherence.this.isStarted();
}
}
// ----- constants ------------------------------------------------------
/**
* The name of the System configuration uri.
*/
public static final String SYS_CCF_URI = "coherence-system-config.xml";
/**
* The System scope name.
*/
public static final String SYSTEM_SCOPE = "$SYS";
/**
* The System session name.
*/
public static final String SYSTEM_SESSION = SYSTEM_SCOPE;
/**
* The default scope name.
*/
public static final String DEFAULT_SCOPE = "";
/**
* The default session name.
*/
public static final String DEFAULT_NAME = "";
/**
* The system property to use to set the default timeout to wait for Coherence instances to start.
*/
public static final String PROP_START_TIMEOUT = "coherence.startup.timeout";
/**
* The default start up timeout.
*/
public static final Duration DEFAULT_START_TIMEOUT = new Duration(5, Duration.Magnitude.MINUTE);
// ----- data members ---------------------------------------------------
/**
* The map of all named {@link Coherence} instances.
*/
private static final CopyOnWriteMap s_mapInstance = new CopyOnWriteMap<>(LinkedHashMap.class);
/**
* The lock to manage the global system session state.
*/
private static final Lock s_globalSystemSessionLock = new ReentrantLock();
/**
* The global System session.
*/
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
private static Optional s_systemSession;
/**
* The {@link DefaultCacheServer} wrapping the System session.
*/
private static ServiceMonitor s_systemServiceMonitor;
/**
* The lock to manage this instance's system session state.
*/
private final Lock m_localSystemSessionLock = new ReentrantLock();
/**
* This instance's System session configuration.
*/
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
private SessionConfiguration m_localSystemSessionConfig;
/**
* This instance's System session.
*/
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
private Optional m_localSystemSession;
/**
* The {@link DefaultCacheServer} wrapping the local System session.
*/
private ServiceMonitor m_localSystemServiceMonitor;
/**
* A flag indicating whether the bootstrap API ensured the Coherence cluster service.
*/
private static Boolean s_fEnsuredCluster = null;
/**
* The name of this {@link Coherence} instance.
*/
private final String f_sName;
/**
* This session's {@link ResourceRegistry}.
*/
private final ResourceRegistry f_registry;
/**
* The event dispatcher.
*/
private final CoherenceEventDispatcher f_dispatcher;
/**
* The configuration for this {@link Coherence} instance.
*/
private final CoherenceConfiguration f_config;
/**
* A {@link Map} of additional {@link SessionConfiguration session configurations}.
*/
private final Map f_mapAdditionalSessionConfig = new ConcurrentHashMap<>();
/**
* The map of named {@link PriorityHolder} instances containing a {@link DefaultCacheServer}
* instance wrapping a session.
*/
private final Map f_mapServer = new HashMap<>();
/**
* The map of named {@link Session} instances.
*/
private final Map f_mapSession = new CopyOnWriteMap<>(new HashMap<>());
/**
* This {@link Coherence} instance {@link CoherenceHealth health check MBean}.
*/
private final HealthCheckWrapper f_health;
/**
* A flag indicating whether this {@link Coherence} instance is started.
*/
private volatile boolean m_fStarted = false;
/**
* A flag indicating whether this {@link Coherence} instance is stopped.
*/
private volatile boolean m_fClosed = false;
/**
* A {@link CompletableFuture} that will be completed when this {@link Coherence}
* instance has started.
*/
private final CompletableFuture f_futureStarted = new CompletableFuture<>();
/**
* A {@link CompletableFuture} that will be completed when this {@link Coherence}
* instance has stopped.
*/
private final CompletableFuture f_futureClosed = new CompletableFuture<>();
/**
* The {@link Mode} that the {@link Coherence} instance will run in.
*/
private final Mode f_mode;
}