org.wso2.carbon.utils.deployment.GhostDeployerUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.wso2.carbon.utils.deployment.GhostDeployerUtils.java

Source

/*
 * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 * WSO2 Inc. licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.wso2.carbon.utils.deployment;

import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.axis2.AxisFault;
import org.apache.axis2.Constants;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.deployment.DeploymentException;
import org.apache.axis2.deployment.repository.util.DeploymentFileData;
import org.apache.axis2.description.AxisBinding;
import org.apache.axis2.description.AxisEndpoint;
import org.apache.axis2.description.AxisOperation;
import org.apache.axis2.description.AxisOperationFactory;
import org.apache.axis2.description.AxisService;
import org.apache.axis2.description.AxisServiceGroup;
import org.apache.axis2.description.Parameter;
import org.apache.axis2.engine.AxisConfiguration;
import org.apache.axis2.util.Utils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.CarbonConstants;
import org.wso2.carbon.base.ServerConfiguration;
import org.wso2.carbon.utils.CarbonUtils;
import org.wso2.carbon.utils.ServerConstants;

import javax.xml.namespace.QName;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * A collection of utility methods which are used by the Ghost Deployer
 */
public class GhostDeployerUtils {

    private static final String PARAMETER_VALUE_TRUE = "true";

    private static Log log = LogFactory.getLog(GhostDeployerUtils.class);

    public static final String GHOST_DEPLOYMENT = "GhostDeployment";
    public static final String ENABLED = GHOST_DEPLOYMENT + ".Enabled";
    public static final String PARTIAL_UPDATE_MODE = GHOST_DEPLOYMENT + ".PartialUpdate";

    // Map of ghost services which are currently being converted into actual services
    private static final String TRANSIT_GHOST_SERVICE_MAP = "TransitGhostServiceMap";

    private static final String SERVICE_ARCHIVE_FILE_NAME = "ServiceArchiveFileName";

    private GhostDeployerUtils() {
        //disable external instantiation
    }

    /**
     * Removes the given ghost service and deploys the actual service. Service file name is
     * extracted from the Ghost Service and then the actual service is deployed. Finally the
     * actual service is returned.
     *
     * @param axisConfig - AxisConfiguration instance
     * @param ghostService - Existing Ghost service
     * @return - newly deployed real service
     * @throws org.apache.axis2.AxisFault - On errors while removing existing service
     */
    public static AxisService deployActualService(AxisConfiguration axisConfig, AxisService ghostService)
            throws AxisFault {
        AxisService newService = null;
        /**
         * There can be multiple requests for the same ghost service depending on the level
         * of concurrency. Therefore we have to synchronize on the ghost service instance.
         */
        String serviceName = ghostService.getName();
        synchronized (serviceName.intern()) {
            // there can be situations in which the actual service is already deployed and
            // available in the axisConfig
            AxisService axisConfigService = axisConfig.getService(serviceName);
            if (axisConfigService == null) {
                return null;
            }

            Parameter actualGhostParam = axisConfigService.getParameter(CarbonConstants.GHOST_SERVICE_PARAM);
            if (actualGhostParam == null || "false".equals(actualGhostParam.getValue())) {
                // if the service from axisConfig is not a ghost, return it
                newService = axisConfigService;
            } else {
                GhostArtifactRepository ghostArtifactRepository = GhostDeployerUtils
                        .getGhostArtifactRepository(axisConfig);

                //TODO use a canonical path?
                DeploymentFileDataWrapper dfd = ghostArtifactRepository
                        .getDeploymentFileData(axisConfigService.getFileName().getPath());
                if (dfd != null) {
                    // remove the existing service
                    log.info("Removing Ghost Service and loading actual service : " + serviceName);
                    AxisServiceGroup existingSG = (AxisServiceGroup) axisConfigService.getParent();
                    existingSG.addParameter(CarbonConstants.KEEP_SERVICE_HISTORY_PARAM, PARAMETER_VALUE_TRUE);

                    // Add all services in the group to the ghost list
                    Map<String, AxisService> transitGhostList = getTransitGhostServicesMap(axisConfig);
                    for (Iterator<AxisService> servicesItr = existingSG.getServices(); servicesItr.hasNext();) {
                        AxisService service = servicesItr.next();
                        transitGhostList.put(service.getName(), service);
                    }

                    String serviceGroupName = existingSG.getServiceGroupName();
                    if (axisConfig.getServiceGroup(serviceGroupName) != null) {
                        axisConfig.removeServiceGroup(serviceGroupName);
                    }

                    if (axisConfig.getService(serviceName) != null) {
                        axisConfig.removeService(serviceName);
                    }
                    // deploy the new service
                    dfd.getDeploymentFileData().deploy();
                    newService = axisConfig.getService(serviceName);

                    // Remove all services in the new group from the ghost list
                    AxisServiceGroup newSG = (AxisServiceGroup) newService.getParent();
                    for (Iterator<AxisService> servicesItr = newSG.getServices(); servicesItr.hasNext();) {
                        AxisService service = servicesItr.next();
                        transitGhostList.remove(service.getName());
                    }
                }
            }
            updateLastUsedTime(newService);
        }
        return newService;
    }

    /**
     * Updates the last used timestamp of the given service. A new Paramter is created if it
     * doesn't already exists..
     *
     * @param service - AxisService instance
     */
    public static void updateLastUsedTime(AxisService service) {
        if (service == null) {
            return;
        }
        try {
            Parameter lastUsageParam = service.getParameter(CarbonConstants.SERVICE_LAST_USED_TIME);
            if (lastUsageParam == null) {
                lastUsageParam = new Parameter();
                lastUsageParam.setName(CarbonConstants.SERVICE_LAST_USED_TIME);
                service.addParameter(lastUsageParam);
            }
            lastUsageParam.setValue(System.currentTimeMillis());
        } catch (Exception e) {
            log.error("Error while updating " + CarbonConstants.SERVICE_LAST_USED_TIME + " parameter in service : "
                    + service.getName(), e);
        }
    }

    /**
     * Read the "Enabled" property under "GhostDeployment" config from the carbon.xml and return the boolean value
     *
     * @return - true if the property is set to true. otherwise false
     */
    public static boolean isGhostOn() {
        ServerConfiguration serverConfig = ServerConfiguration.getInstance();
        String ghostOn = serverConfig.getFirstProperty(ENABLED);
        return ghostOn != null && Boolean.parseBoolean(ghostOn);
    }

    /**
     * Read the "PartialUpdate" property under "GhostDeployment" config from the carbon.xml and return the boolean value
     *
     * @return - true if the property is set to true. otherwise false
     */
    @Deprecated
    public static boolean isPartialUpdateEnabled() {
        ServerConfiguration serverConfig = ServerConfiguration.getInstance();
        String partialUpdateOn = serverConfig.getFirstProperty(PARTIAL_UPDATE_MODE);
        return partialUpdateOn != null && Boolean.parseBoolean(partialUpdateOn);
    }

    /**
     * Get the map of services which are in transit. A particular service will be in this
     * map from the time the ghost service is removed from AxisConfig and the actual service is
     * deployed..
     *
     * @param axisConfig - AxisConfiguration instance
     * @return returns a map of strings which are the names of the services
     * @throws org.apache.axis2.AxisFault - on error while getting or setting map
     */
    public static synchronized Map<String, AxisService> getTransitGhostServicesMap(AxisConfiguration axisConfig)
            throws AxisFault {
        Parameter param = axisConfig.getParameter(TRANSIT_GHOST_SERVICE_MAP);
        Map<String, AxisService> transitMap = null;
        if (param != null) {
            transitMap = (Map<String, AxisService>) param.getValue();
        }
        if (transitMap == null) {
            transitMap = new HashMap<String, AxisService>();
            axisConfig.addParameter(TRANSIT_GHOST_SERVICE_MAP, transitMap);
        }
        return transitMap;
    }

    /**
     * When a ghost service is removed from the axisConfig and the corresponding actual service is
     * deployed, there's a time interval in which there's no AxisService in the AxisConfiguration
     * for the particular service name. Within this interval, if a request comes in to the service,
     * we have to somehow dispatch the service.
     * Within the above mentioned time interval, service is kept in a map. This method checks
     * whether the relevant service is available in that map and if it is found, returns the
     * name of the service.
     * IMPORTANT : This method assumes that the service name can be figured out using the To EPR of
     * the MessageContext. But it's only valid for HTTP/S transport. For other transports like
     * JMS, this won't work.
     *
     * @param msgCtx - MessageContext for the current request
     * @return - Service  if found, else null
     * @throws AxisFault - on errors while calling Axis2 APIs
     */
    public static AxisService dispatchServiceFromTransitGhosts(MessageContext msgCtx) throws AxisFault {
        AxisService actualService = null;
        // get the map of ghost services which are being redeployed..
        Map<String, AxisService> transitGhostMap = getTransitGhostServicesMap(
                msgCtx.getConfigurationContext().getAxisConfiguration());

        EndpointReference toEPR = msgCtx.getTo();
        if (toEPR != null) {
            String filePart = toEPR.getAddress();

            // Get the service/operation part from the request URL
            String serviceOpPart = Utils.getServiceAndOperationPart(filePart,
                    msgCtx.getConfigurationContext().getServiceContextPath());

            if (serviceOpPart != null) {
                // First remove anything after .
                int index = serviceOpPart.indexOf('.');
                if (index != -1) {
                    serviceOpPart = serviceOpPart.substring(0, index);
                }
                /**
                 * Split the serviceOpPart from '/' and add part by part and check whether we have
                 * a service. This is because we are supporting hierarchical services. We can't
                 * decide the service name just by looking at the request URL.
                 */
                String[] parts = serviceOpPart.split("/");
                String tmpServiceName = "";
                int count = 0;

                /**
                 * To avoid performance issues if an incorrect URL comes in with a long service name
                 * including lots of '/' separated strings, we limit the hierarchical depth to 10
                 */
                while (actualService == null && count < parts.length && count < Constants.MAX_HIERARCHICAL_DEPTH) {
                    tmpServiceName = count == 0 ? tmpServiceName + parts[count]
                            : tmpServiceName + "/" + parts[count];
                    if (transitGhostMap.containsKey(tmpServiceName)) {
                        actualService = transitGhostMap.get(tmpServiceName);
                    }
                    count++;
                }
            }
        }
        return actualService;
    }

    /**
     * When a ghost service is removed from the AxisConfiguration, name of that service is kept
     * temporary in a map. This method waits until the provided service name is removed from that
     * map. In other words, it waits until the actual service is deployed. After the actual
     * service is deployed, it is safe to forward the request further..
     *
     * @param serviceName - name of the service
     * @param axisConfig - current axisConfig instance
     * @throws AxisFault - on errors while reading ghost map
     */
    public static void waitForServiceToLeaveTransit(String serviceName, AxisConfiguration axisConfig)
            throws AxisFault {
        Map<String, AxisService> transitGhostMap = getTransitGhostServicesMap(axisConfig);
        while (transitGhostMap.containsKey(serviceName)) {
            // wait until the service is removed from ghost map
            try {
                Thread.sleep(2);
            } catch (InterruptedException e) {
                // ignored
            }
        }
    }

    /**
     * Checks if the given Axis service is a ghost service.
     *
     * @param axisService - The AxisService object to be checked if it's a ghost service
     * @return - true if the service is a ghost service
     */
    public static boolean isGhostService(AxisService axisService) {
        if (axisService == null) {
            return false;
        }
        Parameter ghostParam = axisService.getParameter(CarbonConstants.GHOST_SERVICE_PARAM);
        return ghostParam != null && PARAMETER_VALUE_TRUE.equals(ghostParam.getValue());
    }

    /**
     * Creates the Ghost ServiceGroup by reading the ghost metadata file. The created object will
     * contain the basic metadata of the service group which are enough to dispatch a request.
     *
     * @param axisConfig - AxisConfiguration instance
     * @param ghostFile - Ghost metadata file
     * @param originalFile - URL of the original service artifact
     * @return - AxisServiceGroup object which is created
     */
    public static AxisServiceGroup createGhostServiceGroup(AxisConfiguration axisConfig, File ghostFile,
            URL originalFile) {
        OMElement serviceGroupElm;
        AxisServiceGroup ghostGroup;
        synchronized (axisConfig) {
            try {
                InputStream xmlInputStream = new FileInputStream(ghostFile);
                serviceGroupElm = new StAXOMBuilder(xmlInputStream).getDocumentElement();
            } catch (Exception e) {
                log.error("Error while parsing ghost XML file : " + ghostFile.getAbsolutePath());
                return null;
            }
            // create service group
            ghostGroup = new AxisServiceGroup(axisConfig);
            ghostGroup.setServiceGroupName(
                    serviceGroupElm.getAttributeValue(new QName(CarbonConstants.GHOST_ATTR_NAME)));

            try {
                // create services
                for (Iterator itr = serviceGroupElm.getChildrenWithLocalName(CarbonConstants.GHOST_SERVICE); itr
                        .hasNext();) {
                    OMElement serviceElm = (OMElement) itr.next();
                    AxisService ghostService = new AxisService(
                            serviceElm.getAttributeValue(new QName(CarbonConstants.GHOST_ATTR_NAME)));
                    ghostService
                            .addParameter(new Parameter(CarbonConstants.GHOST_SERVICE_PARAM, PARAMETER_VALUE_TRUE));
                    // set the service type
                    String serviceType = serviceElm
                            .getAttributeValue(new QName(CarbonConstants.GHOST_ATTR_SERVICE_TYPE));
                    if (serviceType != null) {
                        ghostService.addParameter(new Parameter(ServerConstants.SERVICE_TYPE, serviceType));
                    }
                    // set security scenario
                    String secScenario = serviceElm
                            .getAttributeValue(new QName(CarbonConstants.GHOST_ATTR_SECURITY_SCENARIO));
                    if (secScenario != null) {
                        ghostService.addParameter(
                                new Parameter(CarbonConstants.GHOST_ATTR_SECURITY_SCENARIO, secScenario));
                    }
                    if (originalFile != null) {
                        ghostService.setFileName(originalFile);
                    } else {
                        ghostService.setFileName(new URL(
                                "file:" + serviceGroupElm.getAttributeValue(new QName(SERVICE_ARCHIVE_FILE_NAME))));
                    }

                    // Add operations to ghost service
                    OMElement operationsElm = serviceElm
                            .getFirstChildWithName(new QName(CarbonConstants.GHOST_SERVICE_OPERATIONS));
                    if (operationsElm != null) {
                        for (Iterator operationItr = operationsElm.getChildren(); operationItr.hasNext();) {
                            OMElement opElm = (OMElement) operationItr.next();
                            AxisOperation newOp = AxisOperationFactory.getOperationDescription(
                                    opElm.getAttributeValue(new QName(CarbonConstants.GHOST_ATTR_MEP)));
                            String ns = opElm.getNamespace() == null ? "" : opElm.getNamespace().getNamespaceURI();
                            newOp.setName(new QName(ns, opElm.getLocalName()));
                            ghostService.addOperation(newOp);
                        }
                    }

                    // Add endpoints to ghost service
                    OMElement endpointsElm = serviceElm
                            .getFirstChildWithName(new QName(CarbonConstants.GHOST_SERVICE_ENDPOINTS));
                    if (endpointsElm != null) {
                        for (Iterator endpointItr = endpointsElm.getChildren(); endpointItr.hasNext();) {
                            OMElement epElm = (OMElement) endpointItr.next();
                            AxisEndpoint axisEndpoint = new AxisEndpoint();
                            // set a dummy binding to the endpoint
                            axisEndpoint.setBinding(new AxisBinding());
                            axisEndpoint.setName(epElm.getLocalName());
                            ghostService.addEndpoint(epElm.getLocalName(), axisEndpoint);
                        }
                    }
                    if (axisConfig.getService(ghostService.getName()) == null) {
                        log.info("Deploying Ghost Axis2 Service: " + ghostService.getName());
                        ghostGroup.addService(ghostService);
                    }
                }
                ghostGroup.addParameter(new Parameter(CarbonConstants.GHOST_SERVICE_PARAM, PARAMETER_VALUE_TRUE));
            } catch (Exception e) {
                log.error("Error while creating Ghost Service from Ghost File : " + ghostFile.getAbsolutePath(), e);
            }
        }
        return ghostGroup;
    }

    /**
     * Creates the ghost file for the current service group. Basically this ghost file contains
     * basic metadata about the service group. Service name, operations, service type, MEP and
     * all endpoints are stored for each service found under the given service group.
     *
     * @param services - Services to be serialized
     * @param deploymentFileData - Absolute path to the service artifact
     * @param axisConfig - AxisConfiguration instance
     */
    public static void serializeServiceGroup(Set<AxisService> services, DeploymentFileData deploymentFileData,
            AxisConfiguration axisConfig) {

        for (AxisService service : services) { //iterate over the services deployed by this DFD.
            try {
                GhostDeployerUtils.updateLastUsedTime(service);
                // ghost metafile generation should only done in manager nodes.
                if (!CarbonUtils.isWorkerNode()) {
                    if (log.isDebugEnabled()) {
                        log.debug("Generating ghost file for service " + service.getName());
                    }
                    GhostDeployerUtils.serializeServiceGroup((AxisServiceGroup) service.getParent(), axisConfig,
                            deploymentFileData);
                }
            } catch (Exception ex) {
                log.error("Error while generating ghost meta file : " + service.getName(), ex);
            }

        }

    }

    private static void serializeServiceGroup(AxisServiceGroup serviceGroup, AxisConfiguration axisConfig,
            DeploymentFileData dfd) {
        String servicePath = dfd.getAbsolutePath();
        OMFactory omFactory = OMAbstractFactory.getOMFactory();
        // first create service group element
        OMElement serviceGroupEle = omFactory.createOMElement(new QName(CarbonConstants.GHOST_SERVICE_GROUP));
        serviceGroupEle.addAttribute(CarbonConstants.GHOST_ATTR_NAME, serviceGroup.getServiceGroupName(), null);

        serviceGroupEle.addAttribute(SERVICE_ARCHIVE_FILE_NAME, dfd.getFile().getName(), null);

        // we have to serialize all services
        for (Iterator<AxisService> services = serviceGroup.getServices(); services.hasNext();) {
            AxisService service = services.next();
            // service element
            OMElement serviceEle = omFactory.createOMElement(new QName(CarbonConstants.GHOST_SERVICE));
            serviceGroupEle.addChild(serviceEle);
            serviceEle.addAttribute(CarbonConstants.GHOST_ATTR_NAME, service.getName(), null);

            // get the service type
            String serviceType = null;
            Parameter serviceTypeParam = service.getParameter(ServerConstants.SERVICE_TYPE);
            if (serviceTypeParam != null) {
                serviceType = (String) serviceTypeParam.getValue();
            }
            if (serviceType != null) {
                serviceEle.addAttribute(CarbonConstants.GHOST_ATTR_SERVICE_TYPE, serviceType, null);
            }

            // operations
            OMElement operations = omFactory.createOMElement(new QName(CarbonConstants.GHOST_SERVICE_OPERATIONS));
            serviceEle.addChild(operations);
            for (Iterator<AxisOperation> ops = service.getOperations(); ops.hasNext();) {
                AxisOperation axisOperation = ops.next();
                OMElement opElement = omFactory.createOMElement(axisOperation.getName());
                opElement.addAttribute(CarbonConstants.GHOST_ATTR_MEP, axisOperation.getMessageExchangePattern(),
                        null);
                operations.addChild(opElement);
            }

            // endpoints
            OMElement endpoints = omFactory.createOMElement(new QName(CarbonConstants.GHOST_SERVICE_ENDPOINTS));
            serviceEle.addChild(endpoints);
            for (AxisEndpoint endpoint : service.getEndpoints().values()) {
                endpoints.addChild(omFactory.createOMElement(new QName(endpoint.getName())));
            }
        }

        // Now create a ghostFile and serialize the created OMElement
        String ghostMetafileDirPath = CarbonUtils.getGhostMetafileDir(axisConfig);
        if (ghostMetafileDirPath == null) {
            return;
        }
        String ghostPath = ghostMetafileDirPath + File.separator + CarbonConstants.GHOST_SERVICES_FOLDER;
        File ghostFolder = new File(ghostPath);
        if (!ghostFolder.exists() && !ghostFolder.mkdir()) {
            log.error("Error while creating ghostServices folder at : " + ghostPath);
            return;
        }

        FileOutputStream fos = null;
        try {
            File axisConfigRepoPathUrlToFile = new File(axisConfig.getRepository().getPath());
            //Add file seperator at the end of absolute path, to avoid getting an underscore in the beginning of
            // ghost file name.
            String axisConfigRepoPath = axisConfigRepoPathUrlToFile.getAbsolutePath().concat(File.separator);
            String axisConfigRepoPathToUnix = separatorsToUnix(axisConfigRepoPath);
            String ghostFileName = calculateGhostFileName(servicePath, axisConfigRepoPathToUnix);

            if (ghostFileName == null) {
                log.error("Could not derive ghost file name for the service: " + servicePath);
                return;
            }
            File serviceFile = new File(ghostPath + File.separator + ghostFileName);
            fos = new FileOutputStream(serviceFile);
            serviceGroupEle.serialize(fos);
            fos.flush();
        } catch (Exception e) {
            log.error("Error while serializing OMElement for Ghost Service Group: "
                    + serviceGroup.getServiceGroupName(), e);
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    log.error("Error while closing the file output stream", e);
                }
            }
        }
    }

    /**
     * Calculate the ghost file name using the original file name. This should be unique across
     * all service types and hierarchical services.
     *
     * @param fileName - original file name
     * @param repoPath - path of the axis2 repository
     * @return - derived ghost file name
     */
    public static String calculateGhostFileName(String fileName, String repoPath) {
        String ghostFileName = null;
        String javaTmpDir = System.getProperty("java.io.tmpdir");
        String cappUnzipPath = javaTmpDir.endsWith(File.separator) ? javaTmpDir + "carbonapps"
                : javaTmpDir + File.separator + "carbonapps";

        //since in Windows env, filename & repopath get two formats.
        fileName = separatorsToUnix(fileName);
        cappUnzipPath = separatorsToUnix(cappUnzipPath);
        if (fileName != null && fileName.startsWith(repoPath)) {
            // first drop the repo path
            ghostFileName = fileName.substring(repoPath.length());
        } else if (fileName != null && fileName.startsWith(cappUnzipPath)) {
            ghostFileName = fileName.substring(cappUnzipPath.length());

            // now the ghostFileName looks like following string. We need remove the temp car file name as well.
            //  /14144224998641144capp_1.0.0.car/datasource-test_1.0.0/datasource-test-1.0.0.aar
            ghostFileName = ghostFileName.substring(ghostFileName.indexOf(".car/") + 5);
        }

        if (ghostFileName != null) {
            // then remove the extension
            if (ghostFileName.lastIndexOf('.') != -1) {
                ghostFileName = ghostFileName.substring(0, ghostFileName.lastIndexOf('.'));
            }
            // adjust the path for windows..
            if (File.separatorChar == '\\') {
                ghostFileName = ghostFileName.replace('\\', '/');
            }
            // replace '/' with '_'
            ghostFileName = ghostFileName.replace('/', '_');
            // ghost file is always an XML
            ghostFileName += ".xml";
        }
        return ghostFileName;
    }

    /**
     * Creates a File instance for the ghost service according to the original file name..
     *
     * @param fileName - original service file name
     * @param axisConfig - AxisConfiguration instance
     * @return - File instance created
     */
    public static File getGhostFile(String fileName, AxisConfiguration axisConfig) {
        String ghostMetafilesDirPath = CarbonUtils.getGhostMetafileDir(axisConfig);
        File axisConfigRepoPathUrlToFile = new File(axisConfig.getRepository().getPath());
        //Add file seperator at the end of absolute path, to avoid getting an underscore in the beginning of
        // ghost file name.
        String axisConfigRepoPath = axisConfigRepoPathUrlToFile.getAbsolutePath().concat(File.separator);
        //since in Windows env, filename & repopath get two formats
        String axisConfigRepoPathToUnix = separatorsToUnix(axisConfigRepoPath);
        String ghostFileName = calculateGhostFileName(fileName, axisConfigRepoPathToUnix);

        if (ghostMetafilesDirPath != null && ghostFileName != null) {
            return new File(ghostMetafilesDirPath + File.separator + CarbonConstants.GHOST_SERVICES_FOLDER
                    + File.separator + ghostFileName);
        }
        return null;
    }

    /**
     * Adds the given service group to the transit map
     *
     * @param serviceGroup - to be added to transit map
     * @param axisConfig - current axis configuration
     * @throws AxisFault - on error
     */
    public static void addServiceGroupToTransitMap(AxisServiceGroup serviceGroup, AxisConfiguration axisConfig)
            throws AxisFault {
        Map<String, AxisService> transitGhostList = getTransitGhostServicesMap(axisConfig);
        for (Iterator<AxisService> servicesItr = serviceGroup.getServices(); servicesItr.hasNext();) {
            AxisService service = servicesItr.next();
            transitGhostList.put(service.getName(), service);
        }
    }

    /**
     * Removes given service group from transit map
     *
     * @param serviceGroup - to be removed from transit map
     * @param axisConfig - current axis configuration
     * @throws AxisFault - on error
     */
    public static void removeServiceGroupFromTransitMap(AxisServiceGroup serviceGroup, AxisConfiguration axisConfig)
            throws AxisFault {
        Map<String, AxisService> transitGhostList = getTransitGhostServicesMap(axisConfig);
        for (Iterator<AxisService> servicesItr = serviceGroup.getServices(); servicesItr.hasNext();) {
            AxisService service = servicesItr.next();
            transitGhostList.remove(service.getName());
        }
    }

    public static void deployGhostArtifacts(AxisConfiguration axisConfig) throws DeploymentException {
        // load the ghost service group
        File[] ghostMetaArtifacts;
        File ghostMetafilesDir = new File(CarbonUtils.getGhostMetafileDir(axisConfig) + File.separator
                + CarbonConstants.GHOST_SERVICES_FOLDER);
        boolean doDeploy = true;
        if (ghostMetafilesDir.exists()) {
            ghostMetaArtifacts = ghostMetafilesDir.listFiles();
            if (ghostMetaArtifacts == null) {
                return;
            }
        } else {
            return;
        }

        for (File ghostFile : ghostMetaArtifacts) {
            if (!ghostFile.getPath().endsWith(".svn")) {
                try {
                    AxisServiceGroup ghostServiceGroup = GhostDeployerUtils.createGhostServiceGroup(axisConfig,
                            ghostFile, null);
                    Map<String, AxisService> transitGhostList = getTransitGhostServicesMap(axisConfig);
                    if (axisConfig.getServiceGroup(ghostServiceGroup.getServiceGroupName()) == null) {

                        for (AxisService service : transitGhostList.values()) {
                            if (ghostServiceGroup.getService(service.getName()) != null) {
                                doDeploy = false;
                                break;
                            }
                        }
                        if (doDeploy) {
                            for (Iterator<AxisService> servicesItr = ghostServiceGroup.getServices(); servicesItr
                                    .hasNext();) {
                                AxisService axisService = servicesItr.next();
                                synchronized (axisService.getName().intern()) {
                                    if (axisConfig.getService(axisService.getName()) != null) {
                                        doDeploy = false;
                                        break;
                                    }
                                }
                            }
                            if (doDeploy && ghostServiceGroup.getServices().hasNext() && axisConfig
                                    .getServiceGroup(ghostServiceGroup.getServiceGroupName()) == null) {
                                log.info("Adding Ghost service group : " + ghostServiceGroup.getServiceGroupName());
                                axisConfig.addServiceGroup(ghostServiceGroup);
                            }
                        }
                    }
                } catch (Exception e) {
                    String msg = "Error while loading the Ghost Service : " + ghostFile.getAbsolutePath();
                    log.error(msg, e);
                    throw new DeploymentException(msg, e);
                }
            }
        }
    }

    public static void removeGhostFile(String filePath, AxisConfiguration axisConfig) {

        if (filePath == null) {
            return;
        }

        // Remove the corresponding ghost file
        File ghostFile = GhostDeployerUtils.getGhostFile(filePath, axisConfig);
        if (ghostFile != null && ghostFile.exists() && !ghostFile.delete()) {
            log.error("Error while deleting ghost file : " + ghostFile.getAbsolutePath());
        }
        if (log.isDebugEnabled()) {
            log.debug("deleted ghost file: " + filePath);
        }
        GhostArtifactRepository ghostArtifactRepository = GhostDeployerUtils.getGhostArtifactRepository(axisConfig);
        ghostArtifactRepository.removeDeploymentFileData(filePath);

    }

    /**
     * ghost registry stores @DeploymentFileData objects of services
     * that are in ghost state.
     *
     * @param ghostArtifactRepository Set the ghost artifact registry for this tenant
     * @param axisConfig The axis configuration of the tenant
     * @throws DeploymentException if error occurred while saving the ghost artifact registry
     */
    public static void setGhostArtifactRepository(GhostArtifactRepository ghostArtifactRepository,
            AxisConfiguration axisConfig) throws DeploymentException {

        try {
            axisConfig.addParameter(CarbonConstants.GHOST_ARTIFACT_REPOSITORY, ghostArtifactRepository);
        } catch (AxisFault axisFault) {
            log.error(axisFault.getMessage(), axisFault);
            throw new DeploymentException(axisFault);
        }

    }

    /**
     * get the ghost registry that store @DeploymentFileData objects of services
     * that are in ghost state.
     *
     * @param axisConfig The axis configuration of the tenant
     */
    public static GhostArtifactRepository getGhostArtifactRepository(AxisConfiguration axisConfig) {

        Parameter param = axisConfig.getParameter(CarbonConstants.GHOST_ARTIFACT_REPOSITORY);
        if (param != null) {
            return (GhostArtifactRepository) param.getValue();
        }
        return null;
    }

    public static String separatorsToUnix(String path) {
        if (path == null || !path.contains("\\")) {
            return path;
        }
        return path.replace("\\", "/");

    }

    /**
     * Load ghost services corresponding to a given axis2 service group
     *
     * @param ghostFile The ghost file that contains meta information to deploy a ghost service
     * @param deploymentFileData The deployment file data of the artifact we are about to deploy
     * @param axisConfig The axis configuration of the tenant
     * @throws DeploymentException
     */
    public static void deployGhostServiceGroup(File ghostFile, DeploymentFileData deploymentFileData,
            AxisConfiguration axisConfig) throws DeploymentException {

        try {
            AxisServiceGroup ghostServiceGroup = GhostDeployerUtils.createGhostServiceGroup(axisConfig, ghostFile,
                    deploymentFileData.getFile().toURI().toURL());
            axisConfig.addServiceGroup(ghostServiceGroup);

            //We need a reference to the @DeploymentFileData since it's currently in ghost state
            GhostDeployerUtils.getGhostArtifactRepository(axisConfig).addDeploymentFileData(deploymentFileData,
                    true);
        } catch (Exception e) {
            String msg = "Error while loading the Ghost Service : " + ghostFile.getAbsolutePath();
            log.error(msg, e);
            throw new DeploymentException(msg, e);
        }

    }

}