/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* or packager/legal/LICENSE.txt. 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 at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* 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]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
/**
* @author Sheetal.Vartak@Sun.COM
*/
@Service()
/*
* Used only for user-managed clusters. This ties each cluster
* instance to port 9090 for GMS communication, so only
* one instance can be run per machine. For more information, including
* how we could let the user set this, see the usage in
* readGMSConfigProps().
*/
/*
* Used only for user-managed clusters. This prop can be set
* on the group management service object to override the default
* history table.
*/
"KEEP_FORMER_MEMBER_HISTORY";
// all set in postConstruct
private ConcurrentHashMap<CallBack, JoinNotificationActionFactory> callbackJoinActionFactoryMapping =
private ConcurrentHashMap<CallBack, JoinedAndReadyNotificationActionFactory> callbackJoinedAndReadyActionFactoryMapping =
private ConcurrentHashMap<CallBack, FailureNotificationActionFactory> callbackFailureActionFactoryMapping =
private ConcurrentHashMap<CallBack, FailureSuspectedActionFactory> callbackFailureSuspectedActionFactoryMapping =
private ConcurrentHashMap<CallBack, GroupLeadershipNotificationActionFactory> callbackGroupLeadershipActionFactoryMapping =
private ConcurrentHashMap<CallBack, PlannedShutdownActionFactory> callbackPlannedShutdownActionFactoryMapping =
private boolean aliveAndReadyLoggingEnabled = false;
private boolean testFailureRecoveryHandler = false;
public void postConstruct() {
}
return clusterName;
}
if (initialized.compareAndSet(false, true)) {
this.clusterName = clusterName;
if (clusterName == null) {
return false;
}
try {
} catch (GMSException ge) {
// ignore
}
return false;
}
if (server.isClusteredDas()) {
// this is for the user-managed cluster case
} else {
// must be the DAS since it not direclty considered a member of cluster by domain.xml.
// iterate over all clusters to find the cluster that has name passed in.
break;
}
}
}
return false; //don't enable GMS
// only want to do this in the case of the DAS
}
}
"clusterName=" + clusterName +
" clusterConfig=" + clusterConfig);
}
try {
} catch (GMSException e) {
// prevent access to a malformed gms object.
return false;
// also ensure for any unchecked exceptions (such as NPE during initialization) during initialization
// that the malformed gms object is not allowed to be accesssed through the gms adapter.
} catch (Throwable t) {
// prevent access to a malformed gms object.
return false;
}
initializationComplete.set(true);
}
return initialized.get();
}
public void complete() {
initialized.compareAndSet(true, false);
initializationComplete.compareAndSet(true, false);
}
return hHistory;
}
try {
/*
* Should not fail, but we need to make sure it doesn't
* affect GMS just in case.
*/
} catch (Throwable t) {
t.getLocalizedMessage());
}
}
/*
* This is used in the user-managed cluster case where there
* is no cluster config bean and instances can come and
* go dynamically.
*
* can grow without bound, so we check a property to
* pass this to the health history object. The default
* is to drop former members.
*/
boolean keepFormerMembers = false;
if (keepFormerMemberProp != null) {
}
try {
/*
* Should not fail, but we need to make sure it doesn't
* affect GMS just in case.
*/
} catch (Throwable t) {
t.getLocalizedMessage());
}
}
} else {
}
// Next line should correspond with GlassFish default for grizzly.
// For GlassFish 3.1.2, that is grizzly 1.9.
// For GlassFish with Grizzly 2.0, just let this default to it.
try {
switch (key) {
case MULTICASTADDRESS:
// not supported in UMC case yet
}
}
break;
case MULTICASTPORT:
// not supported in UMC case yet
}
}
break;
if (clusterConfig != null) {
String value = clusterConfig.getGroupManagementService().getFailureDetection().getHeartbeatFrequencyInMillis();
}
}
break;
if (clusterConfig != null) {
String value = clusterConfig.getGroupManagementService().getFailureDetection().getMaxMissedHeartbeats();
}
}
break;
if (clusterConfig != null) {
String value = clusterConfig.getGroupManagementService().getFailureDetection().getVerifyFailureWaittimeInMillis();
}
}
break;
case DISCOVERY_TIMEOUT:
if (clusterConfig != null) {
}
}
break;
case IS_BOOTSTRAPPING_NODE:
// TODO: check this isDas call. Need to check clustered DAS?
break;
// todo
break;
case BIND_INTERFACE_ADDRESS:
if (server.isClusteredDas()) {
"GMS_BIND_INTERFACE_ADDRESS");
}
}
// todo: remove check for value length greater than 1.
// this value could be anything from IPv4 address, IPv6 address, hostname, network interface name.
// Only supported IPv4 address in gf v2.
} else {
"gmsservice.bind.int.address.invalid",
addr);
}
}
break;
if (clusterConfig != null) {
String value = clusterConfig.getGroupManagementService().getFailureDetection().getVerifyFailureConnectTimeoutInMillis();
}
}
break;
case MULTICAST_POOLSIZE:
case INCOMING_MESSAGE_QUEUE_SIZE :
// case MAX_MESSAGE_LENGTH: todo uncomment with shoal-gms.jar with this defined is promoted.
if (clusterConfig != null) {
"No config property found for %s",
keyName));
}
break;
}
}
/*
int positiveint = 0;
try {
positiveint = Integer.getInteger(value);
} catch (Throwable t) {}
// todo
if (positiveint > 0) {
configProps.put(keyName, positiveint);
} // todo else log event that invalid value was provided.
*/
}
break;
// These Shoal GMS configuration parameters are not supported to be set.
// Must place here or they will get flagged as not handled.
case LOOPBACK:
break;
// end unsupported Shoal GMS configuration parameters.
default:
"service provider key %s ignored", keyName));
}
break;
} /* end switch over ServiceProviderConfigurationKeys enum */
} catch (Throwable t) {
t.getLocalizedMessage());
}
} /* end for loop over ServiceProviderConfigurationKeys */
/*
* Special case for user-managed clusters. This is the equivalent
* of setting GMS_LISTENER_PORT on a cluster object (if there
* were one). This ties GMS to the same port on all instances.
* If we want to allow users to specify different ports for
* each instance, then we can look for this property in the
* server config instead (but that is more work for the user
* discovery uri list).
*/
if (server.isClusteredDas()) {
}
// check for Grizzly transport specific properties in GroupManagementService property list and then cluster property list.
// cluster property is more specific than group-mangement-service, so allow cluster property to override group-management-service proeprty
// if a GrizzlyConfigConstant property is in both list.
if (clusterConfig != null) {
continue;
}
"processing group-management-service property name=" +
}
"skipping group-management-service property name=" +
name +
" since value is unresolved symbolic token=" +
value);
}
} else {
"processing group-management-service property name=" +
}
}
if (!validateGMSProperty(name)) {
}
}
}
}
continue;
}
"processing cluster property name=" + name +
" value= " + value);
}
"skipping cluster property name=" + name +
" since value is unresolved symbolic token=" +
value);
}
} else {
}
// undocumented property for testing purposes.
// impossible to register handlers in a regular app before gms starts up.
// special case mapping. Glassfish Cluster property GMS_LISTENER_PORT maps to Grizzly Config Constants TCPSTARTPORT and TCPENDPORT.
} else if (ServiceProviderConfigurationKeys
} else {
// handle normal case. one to one mapping.
"processing cluster property name=" + name +
" value= " + value);
if (!validateGMSProperty(name)) {
}
}
}
}
}
}
/*
* Get existing nodes based on cluster element in domain.
* Then check for DAS address in das.properties. When the
* list is set to 'generate' then the gms listener port
* must also be specified. So the same port is used for
* each cluster member.
*/
if (gmsPortProp == null ||
clusterPort = "9090";
} else {
}
}
// get cluster member server refs
"checking cluster.getServerRef() for '%s'",
}
/*
* When an instance (not DAS) starts up, it will add
* its own address to the discovery list. This is ok
* now. If we want to skip it, here's the place to
* check.
*/
"adding server ref %s to set of instance names",
}
}
// use server refs to find matching nodes
"found server for name %s",
name));
}
"Adding host '%s' to discovery list", host));
}
}
}
}
// add das location from das.properties if needed
if (server.isInstance()) {
try {
"found das.props file at %s",
}
":" +
}
} catch (IOException ioe) {
}
}
// trim list if needed and return
if (lastCommaIndex != -1) {
}
"returning discovery list '%s'",
}
}
try {
} finally {
try {
} catch (IOException ignored) {}
}
}
return props;
}
boolean result = false;
try {
result = true;
try {
result = true;
}
}
int HA_MAX_GMS_MESSAGE_LENGTH = 4 * (1024 * 1024) + (2 * 1024); // Default to 4 MB limit in glassfish.
configProps.put(ServiceProviderConfigurationKeys.MAX_MESSAGE_LENGTH.toString(), Integer.toString(HA_MAX_GMS_MESSAGE_LENGTH));
// read GMS configuration from domain.xml
//remove GMSLogDomain.getLogger(GMSLogDomain.GMS_LOGGER).setLevel(gmsLogLevel);
try {
//fix gf it 12905
if (testFailureRecoveryHandler &&
// this must be here or appointed recovery server notification is not printed out for automated testing.
registerFailureRecoveryListener("GlassfishFailureRecoveryHandlerTest", this);
}
// handle cases where gms is not set and for some reason this handler did not get unregistered.
return;
}
// todo: remove these when removing the test register ones above.
// consider putting following, includding call to joinedAndReady into a timertask.
// this time would give instance time to get its heartbeat cache updated by all running
// READY cluster memebrs
// final long MAX_WAIT_DURATION = 4000;
//
// long elapsedDuration = (joinTime == 0L) ? 0 : System.currentTimeMillis() - joinTime;
// long waittime = MAX_WAIT_DURATION - elapsedDuration;
// if (waittime > 0L && waittime <= MAX_WAIT_DURATION) {
// try {
// logger.info("wait " + waittime + " ms before signaling joined and ready");
// Thread.sleep(waittime);
// } catch(Throwable t) {}
// }
// validateCoreMembers();
}
}
};
} catch (GMSException e) {
// failed to start so unregister event listener that calls GMS.
throw e;
}
} else {
throw new GMSException("gms object is null.");
}
}
return;
}
}
}
}
private void checkInitialized() {
throw new IllegalStateException("GMSAdapter not properly initialized.");
}
}
return gms;
}
//return the gms instance for that group
try {
} catch (GMSException e) {
return null;
}
}
}
try {
/*
* Should not fail, but we need to make sure it doesn't
* affect GMS just in case. In the non-DAS case, hHistory
* will always be null so we skip it. In the DAS case,
* it shouldn't be null unless we've already seen an
* error logged during construction.
*/
}
} catch (Throwable t) {
t.getLocalizedMessage());
}
// testing only. one must set cluster property GMS_TEST_FAILURE_RECOVERY to true for the following to execute. */
logger.log(Level.INFO, "gmsservice.failurerecovery.start.notification", new Object[]{frsSignal.getComponentName(), frsSignal.getMemberToken()});
try {
Thread.sleep(20 * 1000); // sleep 20 seconds. simulate wait time to allow instance to restart and do self recovery before another instance does it.
} catch (InterruptedException ignored) {
}
logger.log(Level.INFO, "gmsservice.failurerecovery.completed.notification", new Object[]{frsSignal.getComponentName(), frsSignal.getMemberToken()});
}
if (this.aliveAndReadyLoggingEnabled) {
if (signal instanceof JoinedAndReadyNotificationSignal ||
signal instanceof FailureNotificationSignal ||
signal instanceof PlannedShutdownSignal) {
if (signal instanceof JoinedAndReadyNotificationSignal) {
}
}
if (signal instanceof PlannedShutdownSignal) {
}
}
new Object [] {
});
}
}
}
// each of the getModule(s) methods are temporary. see class-level comment.
/**
* Registers a JoinNotification Listener.
*
* @param callback processes GMS notification JoinNotificationSignal
*/
}
}
/**
* Registers a JoinAndReadyNotification Listener.
*
* @param callback processes GMS notification JoinAndReadyNotificationSignal
*/
JoinedAndReadyNotificationActionFactory jnaf = new JoinedAndReadyNotificationActionFactoryImpl(callback);
}
}
/**
* Register a listener for all events that represent a member has left the group.
*
* @param callback Signal can be either PlannedShutdownSignal, FailureNotificationSignal or JoinNotificationSignal(subevent Rejoin).
*/
}
}
/**
* Registers a PlannedShutdown Listener.
*
* @param callback processes GMS notification PlannedShutdownSignal
*/
}
}
/**
* Registers a FailureSuspected Listener.
*
* @param callback processes GMS notification FailureSuspectedSignal
*/
}
}
/**
* Registers a FailureNotification Listener.
*
* @param callback processes GMS notification FailureNotificationSignal
*/
}
}
/**
* Registers a FailureRecovery Listener.
*
* @param callback processes GMS notification FailureRecoverySignal
* @param componentName The name of the parent application's component that should be notified of selected for
* performing recovery operations. One or more components in the parent application may
* want to be notified of such selection for their respective recovery operations.
*/
}
}
/**
* Registers a Message Listener.
*
* @param componentName Name of the component that would like to consume
* Messages. One or more components in the parent application would want to
* be notified when messages arrive addressed to them. This registration
* allows GMS to deliver messages to specific components.
* @param messageListener processes GMS MessageSignal
*/
}
}
/**
* Registers a GroupLeadershipNotification Listener.
*
* @param callback processes GMS notification GroupLeadershipNotificationSignal. This event occurs when the GMS masters leaves the Group
* and another member of the group takes over leadership. The signal indicates the new leader.
*/
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
JoinedAndReadyNotificationActionFactory jaf = callbackJoinedAndReadyActionFactoryMapping.get(callback);
}
}
}
}
}
}
GroupLeadershipNotificationActionFactory glnf = callbackGroupLeadershipActionFactoryMapping.get(callback);
}
}
}
}
}