com.ephesoft.dcma.batch.status.StatusConveyor.java Source code

Java tutorial

Introduction

Here is the source code for com.ephesoft.dcma.batch.status.StatusConveyor.java

Source

/********************************************************************************* 
* Ephesoft is a Intelligent Document Capture and Mailroom Automation program 
* developed by Ephesoft, Inc. Copyright (C) 2015 Ephesoft Inc. 
* 
* This program is free software; you can redistribute it and/or modify it under 
* the terms of the GNU Affero General Public License version 3 as published by the 
* Free Software Foundation with the addition of the following permission added 
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK 
* IN WHICH THE COPYRIGHT IS OWNED BY EPHESOFT, EPHESOFT DISCLAIMS THE WARRANTY 
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. 
* 
* This program is distributed in the hope that it will be useful, but WITHOUT 
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
* FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more 
* details. 
* 
* You should have received a copy of the GNU Affero General Public License along with 
* this program; if not, see http://www.gnu.org/licenses or write to the Free 
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
* 02110-1301 USA. 
* 
* You can contact Ephesoft, Inc. headquarters at 111 Academy Way, 
* Irvine, CA 92617, USA. or at email address info@ephesoft.com. 
* 
* The interactive user interfaces in modified source and object code versions 
* of this program must display Appropriate Legal Notices, as required under 
* Section 5 of the GNU Affero General Public License version 3. 
* 
* In accordance with Section 7(b) of the GNU Affero General Public License version 3, 
* these Appropriate Legal Notices must retain the display of the "Ephesoft" logo. 
* If the display of the logo is not reasonably feasible for 
* technical reasons, the Appropriate Legal Notices must display the words 
* "Powered by Ephesoft". 
********************************************************************************/

package com.ephesoft.dcma.batch.status;

import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
import org.apache.commons.httpclient.methods.multipart.Part;
import org.apache.commons.httpclient.methods.multipart.StringPart;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.ephesoft.dcma.batch.service.EphesoftContext;
import com.ephesoft.dcma.core.common.ServiceType;
import com.ephesoft.dcma.core.component.ICommonConstants;
import com.ephesoft.dcma.da.domain.ServerRegistry;
import com.ephesoft.dcma.da.domain.ServiceStatus;
import com.ephesoft.dcma.da.service.ServiceStatusService;
import com.ephesoft.dcma.util.EphesoftStringUtil;

/**
 * Conveys and Notifies the status of services under failover mechanism. Provides utility to register services under host server.
 * 
 * <p>
 * The <code>StatusConveyor</code> class provides services for checking whether a given service type is allowed to be run on the server
 * or some other server is running the same services. It also registers the service under the server if it is not already registered
 * under some other servers.
 * </p>
 * 
 * @author Ephesoft
 * @version 1.0
 * @see ServiceType
 * 
 */

public final class StatusConveyor {

    /**
     * The instance {@link StatusConveyor} is used to maintain the instance of status conveyor.
     */
    private static StatusConveyor instance;

    /**
     * The serviceRegisteredMap {@link Map} is used for tracking service registered within any server.
     */
    private static Map<ServiceType, Boolean> serviceRegisteredMap;

    /**
     * The serviceStatusService {@link ServiceStatusService} is for using services given by the business layer.
     */
    @Autowired
    private ServiceStatusService serviceStatusService;

    /**
     * LOGGER for this class.
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(StatusConveyor.class);

    /**
     * Constant for web service URL which will handle service events.
     */
    private static final String NOTIFY_SERVER_FOR_SERVICE = "ws/notifyServerForService";

    /**
     * Constant for status code of successful handling of service event.
     */
    private static final int STATUS_OK = 200;

    /**
     * Private Constructor for restricting object creation outside this class.
     */
    private StatusConveyor() {
        super();
    }

    /**
     * Returns the instance of Status Conveyor and also initialises the map for service registration.
     * 
     * @return {@link StatusConveyor} instance of StatusConveyor.
     */
    public static StatusConveyor getStatusConveyor() {
        if (null == instance) {
            instance = new StatusConveyor();
            initializeMap();
        }
        return instance;
    }

    /**
     * Initialises the server register map for tracking whether a particular service is registered under some server or not.
     */
    private static void initializeMap() {
        LOGGER.debug("Initializing service register map");

        // Get all service types
        final ServiceType[] serviceTypeArray = ServiceType.values();
        serviceRegisteredMap = new HashMap<ServiceType, Boolean>(serviceTypeArray.length);

        // Initialise the map using default false
        for (ServiceType serviceType : serviceTypeArray) {
            serviceRegisteredMap.put(serviceType, Boolean.FALSE);
        }
        LOGGER.debug(EphesoftStringUtil.concatenate("Map initialized: ", serviceRegisteredMap.toString()));
    }

    /**
     * Checks the status of service passed by first checking whether service is registered under some server or not, if not it adds
     * that service under the current server otherwise check it checks if it is registered under current server. If it is registered
     * under current server it return true otherwise false.
     * 
     * 
     * @param serviceType {@link ServiceType} type of service for which status has to be checked.
     * @return true if registered under current server otherwise false.
     */
    public boolean checkForServiceStatus(final ServiceType serviceType) {
        LOGGER.debug(EphesoftStringUtil.concatenate("Checking status of service: ", serviceType.toString()));
        boolean isServiceAvailable = false;
        final ServerRegistry hostServerRegistry = EphesoftContext.getHostServerRegistry();
        if (null != hostServerRegistry) {

            // First we check whether given service type is registered or not.
            if (!serviceRegisteredMap.get(serviceType)) {
                registerService(hostServerRegistry, serviceType);
            }

            final List<ServiceStatus> serviceStatusList = serviceStatusService
                    .getServiceStatusListForServer(hostServerRegistry, serviceType);
            isServiceAvailable = (null != serviceStatusList && !serviceStatusList.isEmpty());
            LOGGER.debug(EphesoftStringUtil.concatenate("Status of service ", serviceType.toString(), " is:",
                    isServiceAvailable, " for server registry: ", hostServerRegistry.getAppContext()));
        } else {
            LOGGER.error("Server registry for the host server is null!");
        }
        return isServiceAvailable;
    }

    /**
     * Notifies any service event to fired on current server but needs to be handled by the server under which the service is
     * registered. It hits the particular server with the details required and registered server handles it respectively.
     * 
     * @param paramMap {@link Map<String, String>} details to be send to the server.
     * @param serviceType {@link ServiceType} type of service.
     */
    public void notifyServiceEvent(final Map<String, String> paramMap, final ServiceType serviceType) {
        if (null != serviceType) {
            LOGGER.debug(EphesoftStringUtil.concatenate("Notifying server for service: ", serviceType.toString()));
            final String notifyWebServiceUrl = getNotifyWebServiceUrl(serviceType);
            if (null != notifyWebServiceUrl && !notifyWebServiceUrl.isEmpty()) {
                final HttpClient httpClient = new HttpClient();
                final PostMethod postMethod = new PostMethod(notifyWebServiceUrl);
                Part[] partArray = null;
                int index = 0;

                // If the details are to be send to web service
                if (null == paramMap || paramMap.isEmpty()) {
                    partArray = new Part[1];
                } else {
                    LOGGER.debug(EphesoftStringUtil.concatenate("Parameter passed are: ", paramMap.toString()));
                    partArray = new Part[(paramMap.size() + 1)];
                    final Iterator<String> keyIterator = paramMap.keySet().iterator();
                    String key = null;
                    while (keyIterator.hasNext()) {
                        key = keyIterator.next();
                        partArray[index] = new StringPart(key, paramMap.get(key));
                        index++;
                    }
                }

                // Type of service which is a required parameter to be send
                partArray[index] = new StringPart(ICommonConstants.SERVICE_TYPE_PARAMETER,
                        String.valueOf(serviceType.getServiceType()));
                MultipartRequestEntity entity = new MultipartRequestEntity(partArray, postMethod.getParams());
                postMethod.setRequestEntity(entity);
                try {
                    int statusCode = httpClient.executeMethod(postMethod);

                    if (statusCode == STATUS_OK) {
                        LOGGER.debug(EphesoftStringUtil.concatenate(
                                "Server was notified successfully for service: ", serviceType.toString()));
                    } else {
                        LOGGER.error(
                                EphesoftStringUtil.concatenate("Server was not able to be notified for service: ",
                                        serviceType.toString(), " and status code: ", statusCode));
                    }
                } catch (HttpException httpException) {
                    LOGGER.error(
                            EphesoftStringUtil.concatenate("Could not connect to server for notifying service: ",
                                    serviceType.toString(), ICommonConstants.SPACE, httpException.getMessage()));
                } catch (IOException ioException) {
                    LOGGER.error(
                            EphesoftStringUtil.concatenate("Could not connect to server for notifying service: ",
                                    serviceType.toString(), ICommonConstants.SPACE, ioException.getMessage()));
                }
            }
        }
    }

    /**
     * Gets the URL for notify event web service for the service type passed. It fetches the server under which the service type is
     * currently registered and using the server registry it makes the URL of web service on that server.
     * 
     * @param serviceType {@link ServiceType} type of service.
     * @return {@link String} web service URL.
     */
    private String getNotifyWebServiceUrl(final ServiceType serviceType) {
        String notifyWebServiceUrl = null;
        if (null != serviceType) {
            LOGGER.debug(EphesoftStringUtil.concatenate("Getting web service URL for service: ",
                    serviceType.toString()));

            // Fetch the service status for the service type
            List<ServiceStatus> serviceStatusList = serviceStatusService.getServiceStatusList(serviceType);
            if (null != serviceStatusList && !serviceStatusList.isEmpty()) {

                // A service can be registered only under one server
                ServiceStatus serviceStatus = serviceStatusList.get(0);

                // Get the server information
                ServerRegistry serverRegistry = serviceStatus.getServerRegistry();
                LOGGER.debug(
                        EphesoftStringUtil.concatenate("Server to be notifed is: ", serverRegistry.getIpAddress()));
                if (null != serverRegistry) {

                    //Check for if request is from secure channel. 
                    if (EphesoftContext.getCurrent().isSecure()) {
                        notifyWebServiceUrl = EphesoftStringUtil.concatenate(ICommonConstants.HTTPS,
                                ICommonConstants.COLON, ICommonConstants.DOUBLE_FORWARD_SLASH,
                                serverRegistry.getIpAddress(), ICommonConstants.COLON, serverRegistry.getPort(),
                                serverRegistry.getAppContext(), ICommonConstants.FORWARD_SLASH,
                                NOTIFY_SERVER_FOR_SERVICE);
                    } else {
                        notifyWebServiceUrl = EphesoftStringUtil.concatenate(ICommonConstants.HTTP,
                                ICommonConstants.COLON, ICommonConstants.DOUBLE_FORWARD_SLASH,
                                serverRegistry.getIpAddress(), ICommonConstants.COLON, serverRegistry.getPort(),
                                serverRegistry.getAppContext(), ICommonConstants.FORWARD_SLASH,
                                NOTIFY_SERVER_FOR_SERVICE);
                    }
                    LOGGER.debug(EphesoftStringUtil.concatenate("URL generated is: ", notifyWebServiceUrl));
                }
            } else {
                LOGGER.debug(EphesoftStringUtil.concatenate("Service: ", serviceType.toString(),
                        " is not registered under any server."));
            }
        }
        return notifyWebServiceUrl;
    }

    /**
     * Registers service under current server if it is not registered under any other server. This creates an entry for the service
     * type passed.
     * 
     * @param hostServerRegistry {@link ServerRegistry} server registry of the host server.
     * @param serviceType {@link ServiceType} type of service passed.
     */
    private void registerService(final ServerRegistry hostServerRegistry, final ServiceType serviceType) {
        LOGGER.debug(EphesoftStringUtil.concatenate("Checking registration for service: ", serviceType.toString(),
                " under host server", hostServerRegistry.getIpAddress()));
        if (null != hostServerRegistry) {
            final List<ServiceStatus> serviceStatusList = serviceStatusService.getServiceStatusList(serviceType);
            if (null == serviceStatusList || serviceStatusList.isEmpty()) {
                LOGGER.debug(EphesoftStringUtil.concatenate("Registering service: ", serviceType.toString(),
                        "under host server", hostServerRegistry.getIpAddress()));
                final ServiceStatus serviceStatus = new ServiceStatus();
                serviceStatus.setServerRegistry(hostServerRegistry);
                serviceStatus.setServiceType(serviceType);
                serviceStatusService.createServiceStatus(serviceStatus);
            } else {
                LOGGER.debug(EphesoftStringUtil.concatenate(serviceType.toString(),
                        " Service is already registered under some server"));
            }
            serviceRegisteredMap.put(serviceType, Boolean.TRUE);
        }
    }
}