All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.oracle.tools.junit.CoherenceClusterOrchestration Maven / Gradle / Ivy

/*
 * File: CoherenceClusterOrchestration.java
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * The contents of this file are subject to the terms and conditions of 
 * the Common Development and Distribution License 1.0 (the "License").
 *
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the License by consulting the LICENSE.txt file
 * distributed with this file, or by consulting https://oss.oracle.com/licenses/CDDL
 *
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file LICENSE.txt.
 *
 * MODIFICATIONS:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 */

package com.oracle.tools.junit;

import com.oracle.tools.Option;
import com.oracle.tools.Options;

import com.oracle.tools.deferred.Eventually;

import com.oracle.tools.predicate.Predicate;
import com.oracle.tools.runtime.ApplicationConsole;
import com.oracle.tools.runtime.ApplicationConsoleBuilder;
import com.oracle.tools.runtime.LocalPlatform;
import com.oracle.tools.runtime.Platform;

import com.oracle.tools.runtime.PropertiesBuilder;
import com.oracle.tools.runtime.actions.Block;
import com.oracle.tools.runtime.actions.InteractiveActionExecutor;
import com.oracle.tools.runtime.coherence.CoherenceCacheServer;
import com.oracle.tools.runtime.coherence.CoherenceCacheServerSchema;
import com.oracle.tools.runtime.coherence.CoherenceCluster;
import com.oracle.tools.runtime.coherence.CoherenceClusterBuilder;
import com.oracle.tools.runtime.coherence.CoherenceClusterMember;
import com.oracle.tools.runtime.coherence.FluentCoherenceClusterSchema;
import com.oracle.tools.runtime.coherence.ServiceStatus;
import com.oracle.tools.runtime.coherence.actions.RestartCoherenceClusterMemberAction;
import com.oracle.tools.runtime.coherence.callables.GetAutoStartServiceNames;

import com.oracle.tools.runtime.coherence.callables.GetServiceStatus;
import com.oracle.tools.runtime.console.SystemApplicationConsole;

import com.oracle.tools.runtime.java.options.HeapSize;
import com.oracle.tools.runtime.java.options.HotSpot;

import com.oracle.tools.runtime.options.ApplicationClosingBehavior;

import com.oracle.tools.util.Capture;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.CacheFactoryBuilder;
import com.tangosol.net.ConfigurableCacheFactory;
import com.tangosol.net.DefaultCacheFactoryBuilder;
import com.tangosol.net.DefaultConfigurableCacheFactory;

import org.junit.rules.ExternalResource;

import org.junit.runner.Description;

import org.junit.runners.model.Statement;

import static com.oracle.tools.deferred.DeferredHelper.invoking;

import static org.hamcrest.core.Is.is;

import java.net.InetAddress;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.Set;

import java.util.concurrent.ConcurrentHashMap;

/**
 * A JUnit {@link ExternalResource} to represent and orchestrate configuring,
 * establishing, accessing and tearing down a Oracle Coherence Cluster, with
 * support for requesting various ConfigurableCacheFactory implementations to
 * interact with the orchestrated Coherence Cluster.
 * 

* Copyright (c) 2015. All Rights Reserved. Oracle Corporation.
* Oracle is a registered trademark of Oracle Corporation and/or its affiliates. * * @author Jonathan Knight * @author Brian Oliver * @author Harvey Raja * @author Aleks Seovic */ public class CoherenceClusterOrchestration extends ExternalResource implements FluentCoherenceClusterSchema { // TODO: Introduce the ability to specify Coherence Closing/Shutdown Options (CacheFactory.shutdown + System.exit / System.halt) // TODO: Ensure the start up / shutdown sequence of Coherence Members matches Coherence Abstract Functional Test /** * The {@link LocalPlatform} on which the Coherence Cluster will be orchestrated. */ private LocalPlatform platform; /** * The {@link CoherenceCacheServerSchema} to use as a basis for * constructing a variety of {@link CoherenceClusterMember}s. */ private CoherenceCacheServerSchema commonServerSchema; /** * The {@link Options} to use when creating the {@link CoherenceCluster}. */ private Options clusterCreationOptions; /** * The {@link Options} to use when closing the {@link CoherenceCluster}. */ private Options clusterClosingOptions; /** * The {@link ApplicationConsoleBuilder} to use for constructing * {@link ApplicationConsole}s for each {@link CoherenceClusterMember}. */ private ApplicationConsoleBuilder consoleBuilder; /** * The {@link CoherenceCluster} established by the orchestrator. */ private CoherenceCluster cluster; /** * The {@link ConfigurableCacheFactory} sessions that have been * created against the orchestrated {@link CoherenceCluster}. */ private HashMap sessions; // the Coherence Cluster Port private Capture clusterPort; // the Coherence *Extend port private Capture extendPort; /** * The number of storage enable members that will be started in the cluster. */ private int storageMemberCount = 2; /** * Extra properties specific to the storage enabled cluster members. */ private PropertiesBuilder storageMemberProperties; /** * Extra properties specific to the proxy server cluster members. */ private PropertiesBuilder extendProxyServerProperties; /** * Constructs a {@link CoherenceClusterOrchestration}. */ public CoherenceClusterOrchestration() { // we're going to orchestrate the cluster using the LocalPlatform this.platform = LocalPlatform.getInstance(); // establish a Cluster port this.clusterPort = new Capture<>(platform.getAvailablePorts()); // establish the Extend port (is the same as the cluster port) this.extendPort = new Capture<>(platform.getAvailablePorts()); // establish a common server schema on which to base storage enabled and proxy members this.commonServerSchema = new CoherenceCacheServerSchema(); // establish the common server schema address and port details String hostAddress = platform.getLoopbackAddress().getHostAddress(); commonServerSchema.setLocalHostAddress(hostAddress); commonServerSchema.setClusterPort(clusterPort); commonServerSchema.setMulticastTTL(0); // we also define the proxy configuration (this will only be used if it's enabled) commonServerSchema.setSystemProperty("tangosol.coherence.extend.address", hostAddress); commonServerSchema.setSystemProperty("tangosol.coherence.extend.port", extendPort); // establish default java process configuration commonServerSchema.setHeadless(true); commonServerSchema.addOption(HotSpot.Mode.SERVER); commonServerSchema.addOption(HeapSize.of(256, HeapSize.Units.MB, 1024, HeapSize.Units.MB)); // by default we'll use the SystemApplicationConsole this.consoleBuilder = SystemApplicationConsole.builder(); // by default we don't have a cluster this.cluster = null; // by default the creation and closing options aren't set this.clusterCreationOptions = new Options(); this.clusterClosingOptions = new Options(); // by default we have no sessions this.sessions = new HashMap<>(); this.storageMemberProperties = new PropertiesBuilder(); this.extendProxyServerProperties = new PropertiesBuilder(); } @Override public Statement apply(Statement base, Description description) { // automatically set the cluster name to the test class name // if the cluster name isn't configured if (commonServerSchema.getClusterName() == null) { commonServerSchema.setClusterName(description.getClassName()); } return super.apply(base, description); } @Override protected void before() throws Throwable { // establish a CoherenceClusterBuilder with the required configuration CoherenceClusterBuilder clusterBuilder = new CoherenceClusterBuilder(); // define the schema for the storage enabled members of the cluster CoherenceCacheServerSchema storageServerSchema = createStorageEnabledMemberSchema(); clusterBuilder.addSchema("storage", storageServerSchema, storageMemberCount, consoleBuilder, platform, clusterCreationOptions.asArray()); // define the schema for the proxy enabled members of the cluster CoherenceCacheServerSchema proxyServerSchema = createProxyServerSchema(); int proxyMemberCount = 1; clusterBuilder.addSchema("proxy", proxyServerSchema, proxyMemberCount, consoleBuilder, platform, clusterCreationOptions.asArray()); int preferredClusterSize = storageMemberCount + proxyMemberCount; // establish the cluster cluster = clusterBuilder.realize(); // ensure that the cluster has been orchestrated correctly Eventually.assertThat(invoking(cluster).getClusterSize(), is(preferredClusterSize)); // ensure that all services marked as autostart on the proxy have started CoherenceClusterMember proxyServer = cluster.get("proxy-1"); Set setServiceNames = proxyServer.submit(new GetAutoStartServiceNames()); for (String sServiceName : setServiceNames) { Eventually.assertThat(invoking(proxyServer).isServiceRunning(sServiceName), is(true)); } // let the super-class perform it's initialization super.before(); } @Override protected void after() { // clean up the sessions synchronized (sessions) { for (ConfigurableCacheFactory session : sessions.values()) { CacheFactory.getCacheFactoryBuilder().release(session); } } CacheFactory.shutdown(); // close the cluster cluster.close(clusterClosingOptions.asArray()); // let the super-class perform it's cleanup as well super.after(); } protected CoherenceCacheServerSchema createStorageEnabledMemberSchema() { // define the schema for the storage enabled members of the cluster CoherenceCacheServerSchema storageServerSchema = new CoherenceCacheServerSchema(commonServerSchema); storageServerSchema.getSystemPropertiesBuilder().addProperties(storageMemberProperties); storageServerSchema.setRoleName("storage"); storageServerSchema.setStorageEnabled(true); return storageServerSchema; } protected CoherenceCacheServerSchema createProxyServerSchema() { CoherenceCacheServerSchema proxyServerSchema = new CoherenceCacheServerSchema(commonServerSchema); proxyServerSchema.getSystemPropertiesBuilder().addProperties(extendProxyServerProperties); proxyServerSchema.setRoleName("proxy"); proxyServerSchema.setStorageEnabled(false); proxyServerSchema.setSystemProperty("tangosol.coherence.extend.enabled", true); return proxyServerSchema; } /** * Sets the {@link ApplicationConsoleBuilder} to use for constructing * {@link ApplicationConsole}s for each {@link CoherenceClusterMember} * that is part of the orchestrated {@link CoherenceCluster}. * * @param consoleBuilder the {@link ApplicationConsoleBuilder} * * @return the {@link CoherenceClusterOrchestration} to permit fluent-style method-calls */ public CoherenceClusterOrchestration setConsoleBuilder(ApplicationConsoleBuilder consoleBuilder) { this.consoleBuilder = consoleBuilder; return this; } /** * Sets the {@link Option}s to be used when closing the {@link CoherenceCluster}. * * @param options the {@link Option}s * * @see ApplicationClosingBehavior * * @return the {@link CoherenceClusterOrchestration} to permit fluent-style method-calls */ public CoherenceClusterOrchestration setClusterClosingOptions(Option... options) { this.clusterClosingOptions = new Options(options); return this; } /** * Sets the {@link Option}s to be used when creating the {@link CoherenceCluster}. * * @param options the {@link Option}s * * @return the {@link CoherenceClusterOrchestration} to permit fluent-style method-calls */ public CoherenceClusterOrchestration setClusterCreationOptions(Option... options) { this.clusterCreationOptions = new Options(options); return this; } /** * Sets the specified system property. * * @param name the name of the system property * @param value the value for the system property * * @return the {@link CoherenceClusterOrchestration} to permit fluent-style method-calls */ public CoherenceClusterOrchestration setSystemProperty(String name, Object value) { this.commonServerSchema.setSystemProperty(name, value); return this; } /** * Obtains the {@link CoherenceCluster} that was established by the orchestration. * * @return the {@link CoherenceCluster} */ public CoherenceCluster getCluster() { return cluster; } @Override public CoherenceClusterOrchestration setClusterName(String name) { commonServerSchema.setClusterName(name); return this; } @Override public CoherenceClusterOrchestration setClusterPort(int port) { commonServerSchema.setClusterPort(port); return this; } @Override public CoherenceClusterOrchestration setClusterPort(Iterator ports) { commonServerSchema.setClusterPort(ports); return this; } @Override public CoherenceClusterOrchestration setMulticastTTL(int ttl) { commonServerSchema.setMulticastTTL(ttl); return this; } @Override public CoherenceClusterOrchestration setSiteName(String name) { commonServerSchema.setSiteName(name); return this; } @Override public CoherenceClusterOrchestration setWellKnownAddress(String address) { commonServerSchema.setWellKnownAddress(address); return this; } @Override public CoherenceClusterOrchestration setWellKnownAddressPort(int port) { commonServerSchema.setWellKnownAddressPort(port); return this; } @Override public CoherenceClusterOrchestration setWellKnownAddressPort(Iterator ports) { commonServerSchema.setWellKnownAddressPort(ports); return this; } @Override public String getClusterName() { return commonServerSchema.getClusterName(); } @Override public int getMulticastTTL() { return commonServerSchema.getMulticastTTL(); } @Override public String getSiteName() { return commonServerSchema.getSiteName(); } @Override public String getWellKnownAddress() { return commonServerSchema.getWellKnownAddress(); } @Override public CoherenceClusterOrchestration setCacheConfigURI(String cacheConfigURI) { commonServerSchema.setCacheConfigURI(cacheConfigURI); return this; } @Override public CoherenceClusterOrchestration setLog(String destination) { commonServerSchema.setLog(destination); return this; } @Override public CoherenceClusterOrchestration setLogLevel(int level) { commonServerSchema.setLogLevel(level); return this; } @Override public CoherenceClusterOrchestration setOperationalOverrideURI(String operationalOverrideURI) { commonServerSchema.setOperationalOverrideURI(operationalOverrideURI); return this; } @Override public CoherenceClusterOrchestration setPofConfigURI(String pofConfigURI) { commonServerSchema.setPofConfigURI(pofConfigURI); commonServerSchema.setPofEnabled(true); return this; } @Override public CoherenceClusterOrchestration setPofEnabled(boolean isEnabled) { commonServerSchema.setPofEnabled(isEnabled); return this; } @Override public String getCacheConfigURI() { return commonServerSchema.getCacheConfigURI(); } @Override public String getLog() { return commonServerSchema.getLog(); } @Override public int getLogLevel() { return commonServerSchema.getLogLevel(); } @Override public String getOperationalOverrideURI() { return commonServerSchema.getOperationalOverrideURI(); } @Override public String getPofConfigURI() { return commonServerSchema.getPofConfigURI(); } @Override public boolean isPofEnabled() { return commonServerSchema.isPofEnabled(); } /** * Obtains the {@link LocalPlatform} on which the {@link CoherenceClusterOrchestration} will * create sessions. *

* NOTE: The orchestrated {@link CoherenceCluster} may be orchestrated on one or more other * {@link Platform}s. * * @return the {@link LocalPlatform} */ public LocalPlatform getLocalPlatform() { return platform; } /** * Obtains a session (represented as a {@link ConfigurableCacheFactory)} against the * orchestrated Coherence Cluster for interacting with Coherence. *

* Attempts to request a session multiple times with the same {@link SessionBuilder} * will return the same session. * * @param builder the builder for the specific type of session * * @return a {@link ConfigurableCacheFactory} representing the Coherence Session. * * @throws IllegalStateException when an attempt to request sessions for * different {@link SessionBuilder}s is made */ public synchronized ConfigurableCacheFactory getSessionFor(SessionBuilder builder) { ConfigurableCacheFactory session = sessions.get(builder); if (session == null) { CoherenceCacheServerSchema sessionSchema = new CoherenceCacheServerSchema(commonServerSchema); sessionSchema.setRoleName("client"); sessionSchema.setStorageEnabled(false); session = builder.realize(platform, this, sessionSchema); sessions.put(builder, session); } return session; } /** * Sets the number of storage enabled members that will be started in the cluster. * * @param count the number of storage enabled members * * @return the {@link FluentCoherenceClusterSchema} */ public CoherenceClusterOrchestration setStorageMemberCount(int count) { storageMemberCount = count; return this; } /** * Sets the specified system property that will apply only to * storage enabled cluster members. * * @param name the name of the system property * @param value the value for the system property * * @return the {@link CoherenceClusterOrchestration} to permit fluent-style method-calls */ public CoherenceClusterOrchestration setStorageMemberSystemProperty(String name, Object value) { this.storageMemberProperties.setProperty(name, value); return this; } /** * Sets the specified system property that will apply only to * Extend proxy cluster members. * * @param name the name of the system property * @param value the value for the system property * * @return the {@link CoherenceClusterOrchestration} to permit fluent-style method-calls */ public CoherenceClusterOrchestration setProxyServerSystemProperty(String name, Object value) { this.extendProxyServerProperties.setProperty(name, value); return this; } /** * Perform a rolling restart of all of the storage members of the cluster. *

* This method performs a safe rolling restart, ensuring that the distributed * cache services are in a "safe" state before restarting the next member. *

* Rolling restart is not supported on a cluster with only a single storage * enabled member. * * @param options the {@link Option}s to use when realizing each new {@link CoherenceClusterMember} * * @throws IllegalStateException if the cluster has only a single storage member. */ public void restartStorageMembers(Option... options) { Predicate predicate = new Predicate() { @Override public boolean evaluate(CoherenceClusterMember member) { Set setServiceNames = member.submit(new GetAutoStartServiceNames()); for (String sServiceName : setServiceNames) { ServiceStatus status = member.submit(new GetServiceStatus(sServiceName)); if (status == ServiceStatus.ENDANGERED || status == ServiceStatus.ORPHANED || status == ServiceStatus.STOPPED || status == ServiceStatus.UNKNOWN) { return false; } } return true; } }; restartStorageMembers(predicate, options); } /** * Perform a rolling restart of all of the storage members of the cluster. *

* Rolling restart is not supported on a cluster with only a single storage * enabled member. * * @param predicate the {@link Predicate} that must evaluate to true before * each member of the cluster is restarted. * @param options the {@link Option}s to use when realizing each new {@link CoherenceClusterMember} * * @throws IllegalStateException if the cluster has only a single storage member. */ public void restartStorageMembers(Predicate predicate, Option... options) { if (storageMemberCount < 2) { throw new IllegalStateException("Cannot perform a rolling restart in a cluster with less than two " + "storage enabled members"); } CoherenceCacheServerSchema schema = createStorageEnabledMemberSchema(); Block block = new Block(); for (int i=1; i<=storageMemberCount; i++) { block.add(new RestartCoherenceClusterMemberAction("storage", schema, new SystemApplicationConsole(), predicate, platform, options)); } InteractiveActionExecutor executor = new InteractiveActionExecutor<>(cluster, block); executor.executeAll(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy