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

org.glassfish.gms.GMSAdapterImpl Maven / Gradle / Ivy

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2010 Sun Microsystems, Inc. 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.glassfish.gms;

import com.sun.enterprise.config.serverbeans.*;
import com.sun.enterprise.ee.cms.core.*;
import com.sun.enterprise.ee.cms.core.GroupManagementService;
import com.sun.enterprise.ee.cms.impl.client.*;
import com.sun.logging.LogDomains;

import java.util.List;
import java.util.Properties;

import static com.sun.enterprise.ee.cms.core.ServiceProviderConfigurationKeys.*;

import com.sun.enterprise.mgmt.transport.grizzly.GrizzlyConfigConstants;
import com.sun.enterprise.util.SystemPropertyConstants;
import java.util.Properties;
import java.util.Enumeration;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.FileNotFoundException;
import org.glassfish.api.Startup;
import org.glassfish.api.admin.ServerEnvironment;
import org.glassfish.api.event.EventTypes;
import org.glassfish.api.event.Events;
import org.glassfish.gms.bootstrap.GMSAdapter;
import org.jvnet.hk2.annotations.Inject;
import org.jvnet.hk2.annotations.Service;
import org.jvnet.hk2.component.Habitat;
import org.jvnet.hk2.component.PostConstruct;
import org.jvnet.hk2.config.types.Property;

/**
 * @author [email protected]
 */
@Service()
public class GMSAdapterImpl implements GMSAdapter, PostConstruct, CallBack {

    private static final Logger logger =
        LogDomains.getLogger(GMSAdapterImpl.class, LogDomains.GMS_LOGGER);
    private static final String BEGINS_WITH = "^";
    private static final String GMS_PROPERTY_PREFIX = "GMS_";
    private static final String GMS_PROPERTY_PREFIX_REGEXP = BEGINS_WITH + GMS_PROPERTY_PREFIX;

    private GroupManagementService gms;

    private final static String INSTANCE_NAME = "INSTANCE_NAME";
    private final static String CLUSTER_NAME = "CLUSTER_NAME";

    private final static String CORE = "CORE";
    private final static String SPECTATOR = "SPECTATOR";
    private final static String MEMBERTYPE_STRING = "MEMBER_TYPE";

    // all set in postConstruct
    private String instanceName = null;
    private boolean isDas = false;
    private Cluster cluster = null;
    private String clusterName = null;
    private Config clusterConfig = null;

    @Inject
    Events events;

    @Inject
    ServerEnvironment env;

    @Inject(name=ServerEnvironment.DEFAULT_INSTANCE_NAME)
    Server server;

    @Inject
    Habitat habitat;

    @Override
    public void postConstruct() {
        logger.setLevel(Level.CONFIG);
        logger.log(Level.CONFIG, "gmsservice.postconstruct");

        Domain domain = habitat.getComponent(Domain.class);
        instanceName = env.getInstanceName();

        isDas = env.isDas();
        if (isDas) {
            // hack: only supporting one cluster for M2
            cluster = domain.getClusters().getCluster().get(0);
        } else {
            cluster = server.getCluster();
        }

        if (cluster == null) {
            logger.log(Level.WARNING, "gmsservice.nocluster.warning");
            return;       //don't enable GMS
        }

        clusterName = cluster.getName();
        clusterConfig = domain.getConfigNamed(clusterName + "-config");
        if (logger.isLoggable(Level.CONFIG)) {
            logger.config("clusterName=" + clusterName);
            logger.config("clusterConfig=" + clusterConfig);
            logger.config("domaing.getConfigs()=" + domain.getConfigs());
        }
        try {
            initializeGMS();
        } catch (GMSException e) {
            logger.log(Level.WARNING, "gmsexception.occurred", e.getLocalizedMessage());
        }
    }

    private void initStopGapGMSConfiguration(Properties configProps) {
        getSystemProps(configProps);   //setting up Shoal defaults
        readFromPropsFile(configProps);

        // trim white space from keys and values.  Was needed for java property files, unsure whether needed when getting from domain.xml
        for (Enumeration property = configProps.propertyNames(); property.hasMoreElements();) {
            String key = (String) property.nextElement();
            String value = configProps.getProperty(key);
            if (value != null) {
                configProps.setProperty(key.trim(), value.trim());
            }
        }
    }
    

    private void readGMSConfigProps(Properties configProps) {
        configProps.put(MEMBERTYPE_STRING, isDas ? SPECTATOR : CORE);
        for (ServiceProviderConfigurationKeys key : ServiceProviderConfigurationKeys.values()) {
            String keyName = key.toString();
            try {
            switch (key) {
                case MULTICASTADDRESS:
                    if (cluster != null) {
                        configProps.put(keyName, cluster.getGmsMulticastAddress());
                    }
                    break;

                case MULTICASTPORT:
                    if (cluster != null) {
                        configProps.put(keyName, cluster.getGmsMulticastPort());
                    }
                    break;

                case FAILURE_DETECTION_TIMEOUT:
                    if (clusterConfig != null) {
                        String  value = clusterConfig.getGroupManagementService().getFailureDetection().getHeartbeatFrequencyInMillis();
                        configProps.put(keyName, value);
                    }
                    break;

                case FAILURE_DETECTION_RETRIES:
                    if (clusterConfig != null) {
                        String  value = clusterConfig.getGroupManagementService().getFailureDetection().getMaxMissedHeartbeats();
                        configProps.put(keyName, value);
                    }
                    break;

                case FAILURE_VERIFICATION_TIMEOUT:
                    if (clusterConfig != null) {
                        String  value = clusterConfig.getGroupManagementService().getFailureDetection().getVerifyFailureWaittimeInMillis();
                        configProps.put(keyName, value);
                    }
                    break;

                case DISCOVERY_TIMEOUT:
                    if (clusterConfig != null) {
                        String  value = clusterConfig.getGroupManagementService().getGroupDiscoveryTimeoutInMillis();
                        configProps.put(keyName, value);
                    }
                    break;

                case IS_BOOTSTRAPPING_NODE:
                    configProps.put(keyName, isDas ? Boolean.TRUE.toString() : Boolean.FALSE.toString());
                    break;

                case VIRTUAL_MULTICAST_URI_LIST:
                    // todo
                    break;

                case BIND_INTERFACE_ADDRESS:
                    if (cluster != null) {
                        String value = cluster.getGmsBindInterfaceAddress().trim();
                        if (value != null && value.length() > 1 && value.charAt(0) != '$') {

                            // 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.

                            // todo: handle invalid inputs.  for this case, validate that value can be associated with a network interface on machine.
                            // need to provide admin feedback when this value is not set correctly.
                            configProps.put(keyName, value);
                        }
                    }
                    break;

                case FAILURE_DETECTION_TCP_RETRANSMIT_TIMEOUT:
                    if (clusterConfig != null) {
                        String  value = clusterConfig.getGroupManagementService().getFailureDetection().getVerifyFailureConnectTimeoutInMillis();
                        configProps.put(keyName, value);
                    }
                    break;

                case MULTICAST_POOLSIZE:
                case INCOMING_MESSAGE_QUEUE_SIZE :
                // case MAX_MESSAGE_LENGTH:    todo uncomment with shoal-gms.jar with this defined is promoted.
                case FAILURE_DETECTION_TCP_RETRANSMIT_PORT:

                    if (clusterConfig != null) {
                        Property prop = clusterConfig.getGroupManagementService().getProperty(keyName);
                        if (prop == null) {
                            if (logger.isLoggable(Level.FINE)) {
                                logger.fine(String.format(
                                    "No config property found for %s",
                                    keyName));
                            }
                            break;
                        }
                        String value = prop.getValue().trim();
                        configProps.put(keyName, value);
                        /*
                        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:
//                    logger.log();
                    break;
            }  /* end switch over ServiceProviderConfigurationKeys enum */
            } catch (Throwable t) {
                logger.log(Level.WARNING,
                    "gmsexception.processing.config.props", t);
            }
        } /* end for loop over ServiceProviderConfigurationKeys */

        // 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.
        List props = null;
        if (clusterConfig != null) {
            props = clusterConfig.getGroupManagementService().getProperty();
            for (Property prop : props) {
                String name = prop.getName().trim();
                String value = prop.getValue().trim();
                logger.config("processing group-management-service property name=" + name + " value= " + value);
                  if (value.startsWith("${")) {
                    logger.config("skipping group-management-service property name=" + name + " since value is unresolved symbolic token="+ value);
                } else if (name != null ) {
                    try {
                        logger.config("processing group-management-service property name=" + name + " value= " + value);
                        if (name.startsWith(GMS_PROPERTY_PREFIX)) {
                            name = name.replaceFirst(GMS_PROPERTY_PREFIX_REGEXP, "");
                        }
                        GrizzlyConfigConstants key = GrizzlyConfigConstants.valueOf(name);
                        configProps.put(name, value);
                    } catch (IllegalArgumentException iae) {
                    }
                }
            }

            
        }
        if (cluster != null) {
            props = cluster.getProperty();
            for (Property prop : props) {
                String name = prop.getName().trim();
                String value = prop.getValue().trim();
                logger.config("processing cluster property name=" + name + " value= " + value);
                if (value.startsWith("${")) {
                    logger.config("skipping cluster property name=" + name + " since value is unresolved symbolic token="+ value);
                } else if (name != null ) {
                    try {
                        if (name.startsWith(GMS_PROPERTY_PREFIX)) {
                            name = name.replaceFirst(GMS_PROPERTY_PREFIX_REGEXP, "");
                        }
                        if (name.compareTo("LISTENER_PORT") == 0 ) {

                            // special case mapping.  Glassfish Cluster property GMS_LISTENER_PORT maps to Grizzly Config Constants TCPSTARTPORT and TCPENDPORT.
                            configProps.put(GrizzlyConfigConstants.TCPSTARTPORT.toString(), value);
                            configProps.put(GrizzlyConfigConstants.TCPENDPORT.toString(), value);
                         } else {
                            // handle normal case.  one to one mapping.
                            GrizzlyConfigConstants key = GrizzlyConfigConstants.valueOf(name);
                            configProps.put(name, value);
                        }
                    } catch (IllegalArgumentException iae) {

                    }
                }
            }
        }
    }

    private void initializeGMS() throws GMSException{
        Properties configProps = new Properties();

        // todo  delete once readGMSConfigProps() confirmed to replace this functionality for certain.
        // pre-M2 stop-gap gms configuration read GMS configuration from java property files, one per instance and cluster.
        //initStopGapGMSConfiguration(configProps);

        // read GMS configuration from domain.xml
        readGMSConfigProps(configProps);
        
        printProps(configProps);

        String memberType = (String) configProps.get(MEMBERTYPE_STRING);   

        gms = (GroupManagementService) GMSFactory.startGMSModule(instanceName, clusterName,
                GroupManagementService.MemberType.valueOf(memberType), configProps);

        if (gms != null) {
            try {

                gms.addActionFactory(new JoinedAndReadyNotificationActionFactoryImpl(this));
                gms.addActionFactory(new JoinNotificationActionFactoryImpl(this));
                gms.addActionFactory(new FailureNotificationActionFactoryImpl(this));
                gms.addActionFactory(new PlannedShutdownActionFactoryImpl(this));
                gms.addActionFactory(new FailureSuspectedActionFactoryImpl(this));

                events.register(new org.glassfish.api.event.EventListener() {
                    @Override
                    public void event(Event event) {
                        if (event.is(EventTypes.SERVER_SHUTDOWN)) {
                            logger.fine("Calling gms.shutdown()...");
                            gms.shutdown(GMSConstants.shutdownType.INSTANCE_SHUTDOWN);
                        } else if (event.is(EventTypes.SERVER_READY)) {
                            logger.fine("Ready");
                            gms.reportJoinedAndReadyState(clusterName);
                        }
                    }
                });

                gms.join();
            } catch (GMSException e) {
                logger.log(Level.WARNING, "gmsexception.occurred", e.getLocalizedMessage());
            }

            logger.log(Level.CONFIG, "gmsservice.started ", new Object[]{instanceName, clusterName});

        } else throw new GMSException("gms object is null.");

        logger.info(instanceName + " joined group " + clusterName);

    }

    private Properties readFromPropsFile(Properties configProps) {
        final String INSTANCE_PROPS_FILE_LOCATION = "/clusters/" + clusterName + "/" + instanceName + ".properties";
        final String CLUSTER_PROPS_FILE_LOCATION = "/clusters/" + clusterName + "/cluster.properties";

        //load default properties

        String install_location= System.getProperty(SystemPropertyConstants.INSTALL_ROOT_PROPERTY);
        String fileName = install_location + INSTANCE_PROPS_FILE_LOCATION;
        logger.config("configProps file location ..." + install_location + INSTANCE_PROPS_FILE_LOCATION + "and " +
                install_location + CLUSTER_PROPS_FILE_LOCATION);
        FileInputStream in;
        try {

            in = new FileInputStream(fileName);
            configProps.load(in);
            in.close();

        } catch (FileNotFoundException fe) {
            logger.log(Level.WARNING, "Cannot find the properties file : " + fileName, fe.getLocalizedMessage() + "Using Shoal Defaults..." );
            return configProps;

        } catch (IOException ioe) {
            logger.log(Level.WARNING, "Exception while trying to load the properties file.Using GMS default properties", ioe.getLocalizedMessage());
            return configProps;
        }

        try {
            fileName = install_location + CLUSTER_PROPS_FILE_LOCATION;

            in = new FileInputStream(fileName);
            configProps.load(in);
            in.close();
            return configProps;
        } catch (FileNotFoundException fe) {
            logger.log(Level.WARNING, "Cannot find the properties file : " + fileName + "Using GMS default properties", fe.getLocalizedMessage());
            return configProps;

        } catch (IOException ioe) {
            logger.log(Level.WARNING, "Exception while trying to load the properties file.Using GMS default properties", ioe.getLocalizedMessage());
            return configProps;
        }
    }

    private Properties getSystemProps(Properties configProps) {

        if (logger.isLoggable(Level.FINE)) {
            logger.log(Level.FINE, "Is initial host=" + System.getProperty("IS_INITIAL_HOST"));
        }
        configProps.put(INSTANCE_NAME, instanceName);
        configProps.put(CLUSTER_NAME, clusterName);

        // bobby: get the other names into here
        if (instanceName.equals("server")) {   //instance is DAS
            configProps.put(MEMBERTYPE_STRING, SPECTATOR);

            configProps.put(ServiceProviderConfigurationKeys.IS_BOOTSTRAPPING_NODE.toString(), true);
        } else {
            configProps.put(MEMBERTYPE_STRING, System.getProperty(MEMBERTYPE_STRING, CORE).toUpperCase());
            configProps.put(ServiceProviderConfigurationKeys.IS_BOOTSTRAPPING_NODE.toString(),
                    System.getProperty("IS_INITIAL_HOST", "false"));
        }

        configProps.put(ServiceProviderConfigurationKeys.MULTICASTADDRESS.toString(),
                System.getProperty("MULTICASTADDRESS", "229.9.1.1"));

        configProps.put(ServiceProviderConfigurationKeys.MULTICASTPORT.toString(), 2299);

        if (System.getProperty("INITIAL_HOST_LIST") != null) {
            configProps.put(ServiceProviderConfigurationKeys.VIRTUAL_MULTICAST_URI_LIST.toString(),
                    System.getProperty("INITIAL_HOST_LIST"));
        }

        configProps.put(ServiceProviderConfigurationKeys.FAILURE_DETECTION_RETRIES.toString(),
                System.getProperty(ServiceProviderConfigurationKeys.FAILURE_DETECTION_RETRIES.toString(), "3"));

        configProps.put(ServiceProviderConfigurationKeys.FAILURE_DETECTION_TIMEOUT.toString(),
                System.getProperty(ServiceProviderConfigurationKeys.FAILURE_DETECTION_TIMEOUT.toString(), "2000"));

        configProps.put(ServiceProviderConfigurationKeys.DISCOVERY_TIMEOUT.toString(),
                System.getProperty(ServiceProviderConfigurationKeys.DISCOVERY_TIMEOUT.toString(), "5000"));

        configProps.put(ServiceProviderConfigurationKeys.FAILURE_VERIFICATION_TIMEOUT.toString(),
                System.getProperty(ServiceProviderConfigurationKeys.FAILURE_VERIFICATION_TIMEOUT.toString(), "1500"));

        String timeout = System.getProperty(ServiceProviderConfigurationKeys.FAILURE_DETECTION_TCP_RETRANSMIT_TIMEOUT.toString());
        if (timeout != null)
            configProps.put(ServiceProviderConfigurationKeys.FAILURE_DETECTION_TCP_RETRANSMIT_TIMEOUT.toString(),
                    timeout);


        //Uncomment this to receive loop back messages
        //configProps.put(ServiceProviderConfigurationKeys.LOOPBACK.toString(), "true");
        final String bindInterfaceAddress = System.getProperty("BIND_INTERFACE_ADDRESS");
        if (bindInterfaceAddress != null) {
            configProps.put(ServiceProviderConfigurationKeys.BIND_INTERFACE_ADDRESS.toString(), bindInterfaceAddress);
        }
        configProps.put(GrizzlyConfigConstants.TCPSTARTPORT.toString(), System.getProperty("TCPSTARTPORT", "9090"));
        configProps.put(GrizzlyConfigConstants.TCPENDPORT.toString(), System.getProperty("TCPENDPORT", "9120"));

        return configProps;
    }

    private void printProps(Properties prop) {
        if (!logger.isLoggable(Level.CONFIG)) {
            return;
        }

        StringBuilder sb = new StringBuilder();
        for (String key : prop.stringPropertyNames()) {
            sb.append(key).append(" = ").append(prop.get(key)).append("  ");
        }
        logger.log(Level.CONFIG, "gmsservice.print.properties", sb.toString());
    }

    public Startup.Lifecycle getLifecycle() {
        return Startup.Lifecycle.SERVER;
    }

    public GroupManagementService getGMS(String groupName) {
        //return the gms instance for that group
        try {
            return GMSFactory.getGMSModule(groupName);
        } catch (GMSException e) {
            logger.log(Level.SEVERE, "Exception in getting GMS module for group " + groupName , e.getLocalizedMessage());
            return null;
        }
    }

    @Override
    public void processNotification(Signal signal) {
        logger.log(Level.INFO, "gmsservice.processNotification", signal.getClass().getName());
    }

    // each of the getModule(s) methods are temporary. see class-level comment.
    @Override
    public GroupManagementService getModule() {
        return gms;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy