/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
* Copyright (c) Ericsson AB, 2004-2008. All rights reserved.
*
* 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 https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/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 glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [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.
*/
package org.jvnet.glassfish.comms.gms;
//import org.jvnet.glassfish.comms.clb.core.*;
import com.sun.enterprise.admin.server.core.AdminService;
import com.sun.enterprise.config.ConfigContext;
import com.sun.enterprise.config.ConfigException;
import com.sun.enterprise.config.serverbeans.Cluster;
import com.sun.enterprise.config.serverbeans.ClusterHelper;
import com.sun.enterprise.config.serverbeans.Config;
import com.sun.enterprise.config.serverbeans.ConfigAPIHelper;
import com.sun.enterprise.ee.cms.core.CallBack;
import com.sun.enterprise.ee.cms.core.FailureNotificationActionFactory;
import com.sun.enterprise.ee.cms.core.FailureNotificationSignal;
import com.sun.enterprise.ee.cms.core.GMSConstants;
import com.sun.enterprise.ee.cms.core.GMSException;
import com.sun.enterprise.ee.cms.core.GMSFactory;
import com.sun.enterprise.ee.cms.core.GMSNotEnabledException;
import com.sun.enterprise.ee.cms.core.GroupManagementService;
import com.sun.enterprise.ee.cms.core.JoinNotificationActionFactory;
import com.sun.enterprise.ee.cms.core.JoinNotificationSignal;
import com.sun.enterprise.ee.cms.core.JoinedAndReadyNotificationActionFactory;
import com.sun.enterprise.ee.cms.core.JoinedAndReadyNotificationSignal;
import com.sun.enterprise.ee.cms.core.PlannedShutdownActionFactory;
import com.sun.enterprise.ee.cms.core.PlannedShutdownSignal;
import com.sun.enterprise.ee.cms.core.ServiceProviderConfigurationKeys;
import com.sun.enterprise.ee.cms.core.Signal;
import com.sun.enterprise.ee.cms.impl.client.FailureNotificationActionFactoryImpl;
import com.sun.enterprise.ee.cms.impl.client.JoinNotificationActionFactoryImpl;
import com.sun.enterprise.ee.cms.impl.client.JoinedAndReadyNotificationActionFactoryImpl;
import com.sun.enterprise.ee.cms.impl.client.PlannedShutdownActionFactoryImpl;
import com.sun.enterprise.ee.cms.spi.MemberStates;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jvnet.glassfish.comms.util.LogUtil;
/**
*
* @author kshitiz
*/
public abstract class GMSEventListener implements EventListener, CallBack{
private static final Logger _logger = LogUtil.CLB_LOGGER.getLogger();
private String clusterName;
private GroupManagementService gms;
private boolean startedGMSModule;
private FailureNotificationActionFactory failureNotificationActionFactory;
private PlannedShutdownActionFactory plannedShutdownActionFactory;
private JoinedAndReadyNotificationActionFactory joinedAndReadyNotificationActionFactory;
private JoinNotificationActionFactory joinNotificationActionFactory;
private boolean spectatorMode;
public GMSEventListener(String clusterName)
throws GMSEventListenerException {
this.clusterName = clusterName;
gms = null;
spectatorMode = false;
registerCallBackHandler();
}
public GMSEventListener(String clusterName, boolean spectatorMode)
throws GMSEventListenerException {
this.clusterName = clusterName;
gms = null;
this.spectatorMode = spectatorMode;
registerCallBackHandler();
}
public void processNotification(Signal signal) {
if (signal instanceof JoinedAndReadyNotificationSignal){
boolean isClusterStartup =
(((JoinedAndReadyNotificationSignal)signal).getEventSubType().equals(
GMSConstants.startupType.GROUP_STARTUP));
onRecovery(signal.getGroupName(), signal.getMemberToken(),
isClusterStartup);
} else if (signal instanceof FailureNotificationSignal) {
onFailure(signal.getGroupName(), signal.getMemberToken(),
false);
} else if (signal instanceof PlannedShutdownSignal) {
boolean isClusterShutdown =
(((PlannedShutdownSignal)signal).getEventSubType().equals(
GMSConstants.shutdownType.GROUP_SHUTDOWN));
onFailure(signal.getGroupName(), signal.getMemberToken(),
isClusterShutdown);
} else if (signal instanceof JoinNotificationSignal){
MemberStates memberState =
((JoinNotificationSignal) signal).getMemberState();
if (_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE,
"clb.recieved_join_notification_for_instance",
new Object[]{signal.getMemberToken(), clusterName, memberState.name()});
}
//if member state is ALIVEANDREADY, then mark this instance as
//recovered, this has to be case of network outage
//if member state is READY then JOINANDREADY event will come,
//and instance will be marked healthy then
if (memberState == MemberStates.ALIVEANDREADY)
onRecovery(signal.getGroupName(), signal.getMemberToken(),
false);
//Else if member state is not ALIVE or READY mark it as failed,
//If member is not in above state, then it can be a case of
//transient failure. Mark this instance as failed. It will marked
//healthy again when JoinedAndReadyNotification is received
/* Still not sure whether this case need to be handled
else if(memberState != MemberStates.ALIVE
&& memberState != MemberStates.READY)
onFailure(signal.getGroupName(), signal.getMemberToken());
*/
}
}
private void registerCallBackHandler()
throws GMSEventListenerException {
startedGMSModule = false;
while(gms == null){
try {
gms = GMSFactory.getGMSModule(clusterName);
} catch (GMSNotEnabledException ex) {
// It means gms module is not started for this cluster
//For core members, this should already be started as part of GMS lifecycle.
//If it is not started then it can be either a configuration issue,
//or gms startup/initialization issue. Cannot handle this case, hence
//throw an exception in this case
if (!spectatorMode) {
String message = _logger.getResourceBundle().
getString("clb.gms_module_not_started_for_self_lb_cluster") + clusterName;
throw new GMSEventListenerException(message);
}
//Already one attempt was made to start this GMS module
//Will not retry, throwing an exception
if(startedGMSModule){
String message = _logger.getResourceBundle().
getString("clb.unable_to_get_gms_module") + clusterName;
throw new GMSEventListenerException(message);
}
// Start a GMS module in this case
if(_logger.isLoggable(Level.FINE))
_logger.log(Level.FINE,
"clb.starting_gms_module",
new Object[]{clusterName});
startGMSModule();
startedGMSModule = true;
if(_logger.isLoggable(Level.FINE))
_logger.log(Level.FINE,
"clb.starting_gms_module",
new Object[]{clusterName, gms});
} catch (GMSException ex) {
throw new GMSEventListenerException(ex);
}
}
failureNotificationActionFactory = new FailureNotificationActionFactoryImpl(this);
gms.addActionFactory(failureNotificationActionFactory);
plannedShutdownActionFactory = new PlannedShutdownActionFactoryImpl(this);
gms.addActionFactory(plannedShutdownActionFactory);
joinedAndReadyNotificationActionFactory = new JoinedAndReadyNotificationActionFactoryImpl(this);
gms.addActionFactory(joinedAndReadyNotificationActionFactory);
joinNotificationActionFactory = new JoinNotificationActionFactoryImpl(this);
gms.addActionFactory(joinNotificationActionFactory);
}
private GroupManagementService startGMSModule() throws GMSEventListenerException {
String instanceName = com.sun.enterprise.server.ondemand.OnDemandServer.getServerContext()
.getInstanceName();
Runnable gmsModule = GMSFactory.startGMSModule(instanceName,
clusterName, //Adding itself as spectator
GroupManagementService.MemberType.SPECTATOR, getGMSConfigProps());
ClusterGMSModuleThread gmsModuleThread = new ClusterGMSModuleThread(gmsModule);
gmsModuleThread.start();
return gms;
}
private Properties getGMSConfigProps() throws GMSEventListenerException {
Properties props = new Properties();
Config config;
Cluster cluster;
ConfigContext configContext;
try {
configContext = AdminService.getAdminService().getAdminContext()
.getAdminConfigContext();
cluster = ClusterHelper.getClusterByName(configContext, clusterName);
String configRef = cluster.getConfigRef();
config = ConfigAPIHelper.getConfigByName(configContext, configRef);
com.sun.enterprise.config.serverbeans.GroupManagementService gmsConfig =
config.getGroupManagementService();
if(!gmsConfig.isEnabled()){
String message = _logger.getResourceBundle().
getString("clb.gms_not_enabled") + clusterName;
throw new GMSEventListenerException(message);
}
props.put(ServiceProviderConfigurationKeys.FAILURE_DETECTION_RETRIES.toString(),
gmsConfig.getFdProtocolMaxTries());
props.put(ServiceProviderConfigurationKeys.FAILURE_DETECTION_TIMEOUT.toString(),
gmsConfig.getFdProtocolTimeoutInMillis());
props.put(ServiceProviderConfigurationKeys.DISCOVERY_TIMEOUT.toString(),
gmsConfig.getPingProtocolTimeoutInMillis());
props.put(ServiceProviderConfigurationKeys.FAILURE_VERIFICATION_TIMEOUT.toString(),
gmsConfig.getVsProtocolTimeoutInMillis());
String timeout = gmsConfig.getFailureDetectionTCPRetransmitTimeout();
if (timeout != null)
props.put(ServiceProviderConfigurationKeys.FAILURE_DETECTION_TCP_RETRANSMIT_TIMEOUT.toString(),
timeout);
props.put(ServiceProviderConfigurationKeys.MULTICASTADDRESS.toString(),
cluster.getHeartbeatAddress());
props.put(ServiceProviderConfigurationKeys.MULTICASTPORT.toString(),
cluster.getHeartbeatPort());
} catch (ConfigException e) {
_logger.log(Level.SEVERE,
"clb.exception_getting_properties_for_gms_module",
new Object[]{clusterName, e.getMessage()});
if(_logger.isLoggable(Level.FINE))
_logger.log(Level.FINE, "clb.caught_an_exception", e);
}
return props;
}
public GroupManagementService getGroupManagementService(){
return gms;
}
public void cleanup() {
gms.removeActionFactory(failureNotificationActionFactory);
gms.removeActionFactory(plannedShutdownActionFactory);
gms.removeActionFactory(joinedAndReadyNotificationActionFactory);
gms.removeActionFactory(joinNotificationActionFactory);
//To be confirmed how to shut down a GMS module
if(startedGMSModule)
gms.shutdown(GMSConstants.shutdownType.INSTANCE_SHUTDOWN);
}
public abstract void onRecovery(String clusterName, String instanceName,
boolean isClusterStartup);
public abstract void onFailure(String clusterName, String instanceName,
boolean isClusterShutdown);
public final void onDisable(String clusterName, String instanceName){
//GMS will never propogate a disable event, so making this method
//as unsupported
throw new UnsupportedOperationException();
}
public final void onEnable(String clusterName, String instanceName){
//GMS will never propogate a enable event, so making this method
//as unsupported
throw new UnsupportedOperationException();
};
public final void onAdd(String clusterName, String instanceName, boolean
lbEnabled){
//GMS will never propogate instance add event, so making this method
//as unsupported
throw new UnsupportedOperationException();
}
public final void onDelete(String clusterName, String instanceName){
//GMS will never propogate instance delete event, so making this method
//as unsupported
throw new UnsupportedOperationException();
};
class ClusterGMSModuleThread extends Thread{
ClusterGMSModuleThread(Runnable gmsModule){
super(gmsModule);
}
}
}