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

org.ow2.util.plan.deployer.impl.DeploymentPlanDeployer Maven / Gradle / Ivy

The newest version!
/**
 * OW2 Util
 * Copyright (C) 2009-2012 Bull S.A.S.
 * Copyright (C) 2008 SERLI
 * Contact: [email protected]
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * --------------------------------------------------------------------------
 * $Id: DeploymentPlanDeployer.java 6240 2012-04-18 11:03:10Z sauthieg $
 * --------------------------------------------------------------------------
 */

package org.ow2.util.plan.deployer.impl;

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.ow2.util.archive.api.ArchiveException;
import org.ow2.util.archive.api.IArchive;
import org.ow2.util.archive.impl.ArchiveManager;
import org.ow2.util.ee.deploy.api.deployable.IDeployable;
import org.ow2.util.ee.deploy.api.deployable.OSGiDeployable;
import org.ow2.util.ee.deploy.api.deployer.DeployerException;
import org.ow2.util.ee.deploy.api.deployer.IDeployerManager;
import org.ow2.util.ee.deploy.api.deployer.UnsupportedDeployerException;
import org.ow2.util.ee.deploy.api.helper.DeployableHelperException;
import org.ow2.util.ee.deploy.impl.deployer.AbsDeployerList;
import org.ow2.util.ee.deploy.impl.helper.DeployableHelper;
import org.ow2.util.log.Log;
import org.ow2.util.log.LogFactory;
import org.ow2.util.plan.bindings.deploymentplan.Deployment;
import org.ow2.util.plan.bindings.deploymentplan.DeploymentHelper;
import org.ow2.util.plan.bindings.deploymentplan.DeploymentPlan;
import org.ow2.util.plan.bindings.deploymentplan.DeploymentPlanFragment;
import org.ow2.util.plan.bindings.exceptions.InvalidDeploymentException;
import org.ow2.util.plan.deploy.deployable.api.DeploymentPlanDeployable;
import org.ow2.util.plan.deploy.deployable.impl.DeploymentPlanDeployableImpl;
import org.ow2.util.plan.deployer.api.DeploymentPlanDeploymentException;
import org.ow2.util.plan.deployer.api.DeploymentPlanUndeploymentException;
import org.ow2.util.plan.deployer.api.FragmentDeploymentException;
import org.ow2.util.plan.deployer.api.FragmentUndeploymentException;
import org.ow2.util.plan.deployer.api.IDeploymentPlanDeployer;
import org.ow2.util.plan.deployer.api.condition.EvaluationException;
import org.ow2.util.plan.deployer.api.condition.IConditionEvaluator;
import org.ow2.util.plan.fetcher.api.IResourceFetcher;
import org.ow2.util.plan.fetcher.api.IResourceFetcherFactoryManager;
import org.ow2.util.plan.monitor.api.IResourceMonitor;
import org.ow2.util.plan.reader.plan.IPlanReader;
import org.ow2.util.url.URLUtils;

/**
 * Deployer for the deployment plan deployables.
 * @author Mickaël LEDUQUE
 */
//public class DeploymentPlanDeployer>
//        extends AbsDeployerList implements IDeploymentPlanDeployer {
public class DeploymentPlanDeployer
        extends AbsDeployerList implements IDeploymentPlanDeployer {

    /**
     * The DeployerManager that will be used to deploy parts of the deployment
     * plans.
     */
    private IDeployerManager deployerManager = null;

    /**
     * The Deployment -> Deployable mappings.
     */
    private Map> deploymentToDeployableMap = new HashMap>();

    /**
     * The Deployment -> Fetcher mappings.
     */
    private Map deploymentToFetcherMap = new HashMap();

    /**
     * The resource monitor.
     */
    private IResourceMonitor resourceMonitor = null;

    /**
     * Logger.
     */
    private static Log logger = LogFactory.getLog(DeploymentPlanDeployer.class);

    /**
     * The deployed deployment plans.
     */
    private Collection deploymentPlans = new ArrayList();

    /**
     * The PlanReader that will be used to parse the deployment plan.
     */
    private IPlanReader planReader;

    /**
     * The resource fetchers manager.
     */
    private IResourceFetcherFactoryManager fetcherFactoryManager = null;

    /**
     * Evaluates conditional plans.
     */
    private IConditionEvaluator conditionEvaluator;

    /**
     * {@inheritDoc}
     * @throws UnsupportedDeployerException any.
     */
    @Override
    public void deploy(final IDeployable deployable) throws DeployerException, UnsupportedDeployerException {
        if (deployable == null) {
            throw new DeployerException("Null deployable");
        }
        if (!DeploymentPlanDeployable.class.isInstance(deployable)) {
            throw new DeployerException("Bad deployable type " + deployable.getClass());
        }
        DeploymentPlanDeployable deploymentPlanDeployable = DeploymentPlanDeployable.class.cast(deployable);

        DeploymentPlan deploymentPlan = null;
        if (planReader == null) {
            throw new DeployerException("Deployment aborted - The PlanReader is null");
        }
        URL archiveUrl = null;
        try {
            archiveUrl = deploymentPlanDeployable.getArchive().getURL();
        } catch (ArchiveException e) {
            throw new DeployerException("Error while getting URL for archive " + deploymentPlanDeployable.getArchive() + " - Deployment aborted", e);
        }
        try {
            File archiveFile = URLUtils.urlToFile(archiveUrl);
            deploymentPlan = planReader.readPlan(archiveFile);
        } catch (Exception e) {
            throw new DeployerException("Error while parsing archive " + archiveUrl + " - Deployment aborted", e);
        }

        if (deploymentPlan == null) {
            // Some strange error occured
            throw new DeployerException("The deployable " + deployable + " resolved in null deployment plan - Deployment aborted");
        }
        deploymentPlanDeployable.setAttachedData(deploymentPlan);

        // Quickly exit the deployment if the plan level condition is not met
        try {
            if (!isActivated(deploymentPlan.getCondition())) {
                return;
            }
        } catch (EvaluationException e) {
            throw new DeployerException("Cannot evaluate condition '"
                    + deploymentPlan.getCondition() + "'", e);
        }

        try {
            deployDeploymentPlan(deploymentPlan);
        } catch (DeploymentPlanDeploymentException e) {
            throw new DeployerException("Deployment plan deployment failed", e);
        }

        logger.debug("Deployable {0} deployed", deployable);
        this.deploymentPlans.add(deploymentPlanDeployable);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isDeployed(final IDeployable deployable) throws DeployerException {
        return this.deploymentPlans.contains(deployable);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean supports(final IDeployable deployable) {
        return DeploymentPlanDeployableImpl.class.isInstance(deployable);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void undeploy(final IDeployable deployable) throws DeployerException {
        if (deployable == null) {
            throw new DeployerException("Null deployable");
        }
        if (!DeploymentPlanDeployable.class.isInstance(deployable)) {
            throw new DeployerException("Bad deployable type " + deployable.getClass());
        }
        if (isDeployed(deployable)) {
            /**
             *  the deployable provided by the caller in order to be undeployed
             */
            DeploymentPlanDeployable deploymentPlanDeployableToUndeploy = DeploymentPlanDeployable.class.cast(deployable);
            /**
             *  the deployable that will be undeployed is in the deploymentPlans list.
             *  Find it, and remove it from the deploymentPlans list.
             */
            DeploymentPlanDeployable deploymentPlanDeployableToUndeployReally = null;
            Iterator it = this.deploymentPlans.iterator();
            while (it.hasNext()) {
                DeploymentPlanDeployable deploymentPlanDeployable = it.next();
                // As two Deployables with same URL are equal, we also have to compare hashCode values
                if (deploymentPlanDeployable.equals(deploymentPlanDeployableToUndeploy)) {
                    deploymentPlanDeployableToUndeployReally = deploymentPlanDeployable;
                    break;
                }
            }
            /**
             * Undeploy the deployable we found.
             */
            if (deploymentPlanDeployableToUndeployReally == null) {
                throw new DeployerException("Didn't found deployable to undeploy" + deployable);
            }

            undeployRealDeployable(deploymentPlanDeployableToUndeployReally);
        } else {
            throw new DeployerException("Cannot undeploy deployable " + deployable + " that is not deployed");
        }
    }

    /**
     * Undeploy the same deployable which has been deployed previously.
     * @param deploymentPlanDeployableToUndeployReally The given deployable
     * @throws DeployerException If the undeploy operation fails.
     */
    private void undeployRealDeployable(final DeploymentPlanDeployable deploymentPlanDeployableToUndeployReally) throws DeployerException {
        this.deploymentPlans.remove(deploymentPlanDeployableToUndeployReally);

        DeploymentPlan deploymentPlan = deploymentPlanDeployableToUndeployReally.getAttachedData();
        try {
            undeployDeploymentPlan(deploymentPlan);
        } catch (DeploymentPlanUndeploymentException e) {
            throw new DeployerException("Deployment plan undeployment failed" , e);
        }

        logger.debug("deployable {0} undeployed", deploymentPlanDeployableToUndeployReally);
    }

    /**
     * {@inheritDoc}
     */
    public void setPlanReader(final IPlanReader planReader) {
        this.planReader = planReader;
    }

    /**
     * {@inheritDoc}
     */
    public IPlanReader getPlanReader() {
        return this.planReader;
    }

    /**
     * Deploys a deployment plan object.
     * @param deploymentPlan the deployment plan.
     * @throws DeploymentPlanDeploymentException
     * @throws UnsupportedDeployerException
     */
    private void deployDeploymentPlan(final DeploymentPlan deploymentPlan)
                                            throws DeploymentPlanDeploymentException, UnsupportedDeployerException {

        for (Deployment deployment : deploymentPlan.getDeployments()) {
            DeploymentPlanFragment fragment = (DeploymentPlanFragment) deployment;
            try {
                deployDeployment(fragment);
                fragment.setDeployed(true);
            } catch (Exception deployException) {
                // One deployment has failed. Is the deployment plan atomic?
                if (deploymentPlan.isAtomic()) {
                    logger.error(
                            "The deployment plan {0} failed and is atomic; it must be undeployed",
                            deploymentPlan);
                    // try to undeploy everything
                    try {
                        undeployDeploymentPlan(deploymentPlan);
                    } catch (DeploymentPlanUndeploymentException undeployException) {
                        logger.error("The deployment plan was not correctly undeployed.");
                    }
                    throw new DeploymentPlanDeploymentException("Error while deploying part " + fragment + " of deployment plan " + deploymentPlan, deployException);
                }

                logger.error("Error while trying to deployed fragment ''{0}'' of deployment plan ''{1}''. Not atomic, so continue...", fragment, deploymentPlan, deployException);

            }
        }
    }

    private boolean isActivated(String condition) throws EvaluationException {
        if (condition == null) {
            // no condition => always activated
            return true;
        }

        // Evaluate the real condition
        return (conditionEvaluator.evaluate(condition));
    }

    private void undeployDeploymentPlan(final DeploymentPlan deploymentPlan) throws DeploymentPlanUndeploymentException {
        for (Deployment deployment : deploymentPlan.getDeployments()) {
            DeploymentPlanFragment fragment = (DeploymentPlanFragment) deployment;
            boolean partialFail = false;
            if (fragment.isDeployed()) {
                try {
                    undeployDeployment(fragment);
                    fragment.setDeployed(false);
                } catch (FragmentUndeploymentException e) {
                    logger.error("Error undeploying deployment {0} of deployment plan {1}",
                           fragment, deploymentPlan);
                    // Will continue to try undeploying other resources
                    partialFail = true;
                }
            }
            // We've done as much as we could, now we can fail
            // Note : we've lost the exception stack
            if (partialFail == true) {
                throw new DeploymentPlanUndeploymentException();
            }
        }
    }

    /**
     * {@inheritDoc}
     * @throws UnsupportedDeployerException
     */
    public void deployDeployment(final Deployment deployment) throws FragmentDeploymentException, UnsupportedDeployerException {
        if (deployment == null) {
            throw new FragmentDeploymentException("Null deployment fragment.");
        }
        if (!(deployment instanceof DeploymentPlanFragment)) {
            throw new FragmentDeploymentException("Bad deployment instance : " + deployment);
        }
        DeploymentPlanFragment fragment = (DeploymentPlanFragment)deployment;

        // Quickly exit the deployment if the fragment level condition is not met
        try {
            if (!isActivated(fragment.getCondition())) {
                return;
            }
        } catch (EvaluationException e) {
            throw new FragmentDeploymentException("Cannot evaluate condition '"
                    + fragment.getCondition() + "'", e);

        }

        Boolean reloadable = null;
        try {
            reloadable = DeploymentHelper.isReloadable(fragment);
        } catch (InvalidDeploymentException e) {
            throw new FragmentDeploymentException("Invalid deployment found : " + fragment, e);
        }

        File file = null;
        IResourceFetcher fetcher = null;
        try {
            fetcher = this.fetcherFactoryManager.getResourceFetcher(fragment);
            fetcher.resolve();
            file = fetcher.getResource();
        } catch (Exception e) {
            throw new FragmentDeploymentException(e);
        }

        // File is a 'local' file containing the resource. We just need to deploy it the usual way.
        if (file == null) {
            throw new FragmentDeploymentException("Null file");
        }
        // Create an archive
        IArchive archive = ArchiveManager.getInstance().getArchive(file);
        if (archive == null) {
            throw new FragmentDeploymentException("Null archive for file " + file);
        }
        // Create a deployable
        IDeployable deployable = null;
        try {
            deployable = DeployableHelper.getDeployable(archive);
        } catch (DeployableHelperException e) {
            throw new FragmentDeploymentException(e);
        }
        if (deployable == null) {
            throw new FragmentDeploymentException("Null deployable for archive" + archive);
        }

        // Check the start property to define if the bundle must be started or not
        if (OSGiDeployable.class.isInstance(deployable)) {
            try {
                Boolean start = DeploymentHelper.isStart(fragment);
                OSGiDeployable.class.cast(deployable).setStart(start);
                Boolean reference = DeploymentHelper.isReference(fragment);
                OSGiDeployable.class.cast(deployable).setReference(reference);
                Integer startLevel = DeploymentHelper.getStartLevel(fragment);
                OSGiDeployable.class.cast(deployable).setStartLevel(startLevel);
                Boolean startTransient = DeploymentHelper.isStartTransient(fragment);
                OSGiDeployable.class.cast(deployable).setStartTransient(startTransient);
            } catch (InvalidDeploymentException e) {
                throw new FragmentDeploymentException("Invalid deployment found : " + fragment, e);
            }
        }

        boolean isDeployed;
        try {
            isDeployed = this.deployerManager.isDeployed(deployable);
        } catch (DeployerException e) {
            throw new FragmentDeploymentException("Cannot check if deployable " + deployable + " is already deployed", e);
        }

        // Deploy the deployable only if it's not yet deployed
        if (!isDeployed) {
            try {
                this.deployerManager.deploy(deployable);
            } catch (DeployerException e) {
                throw new FragmentDeploymentException("Exception while deploying deployable " + deployable, e);
            } catch (UnsupportedDeployerException e) {
                throw new UnsupportedDeployerException("No deployer found for deployable " +  deployable, e);
            }catch (Exception e) {
                throw new FragmentDeploymentException("No deployer found for deployable " +  deployable, e);
            }
        }

        // Store the deployment->deployable
        deploymentToDeployableMap.put(fragment, deployable);
        if (reloadable) {
            if (!deploymentToFetcherMap.containsValue(fetcher)) {
                // Add this resource to the managed ones.
                this.resourceMonitor.addMonitoredResource(fetcher);
            }

            // Store the deployment->fetcher
            deploymentToFetcherMap.put(fragment, fetcher);
        }
    }

    /**
     * {@inheritDoc}
     */
    /* The only cases this will be used are : 1. when undeploying a deployment plan and 2. when
    redeploying a modified resource (by the monitor) */
    public void undeployDeployment(final Deployment deployment) throws FragmentUndeploymentException {
        if (deployment == null) {
            throw new FragmentUndeploymentException("Null deployment fragment.");
        }

        // find the deployable and undeploy it
        IDeployable deployable = deploymentToDeployableMap.get(deployment);
        if (deployable == null) {
            throw new FragmentUndeploymentException("Cannot undeploy resource " + deployment.toString() + " - Trying to finish undeployment");
        }

        // find the fetcher and stop monitoring it
        IResourceFetcher fetcher = deploymentToFetcherMap.get(deployment);

        // Remove stored deployment entries from Maps
        cleanDeploymentMaps(deployment, null);

        if (fetcher != null) {
            // Remove this resource from the monitored ones
            if (!deploymentToFetcherMap.containsValue(fetcher)) {
                try {
                    this.resourceMonitor.removeMonitoredResource(fetcher);
                } catch (Exception e) {
                    logger.error("Cannot stop monitoring the resource ''{0}'':", deployment.toString());
                }
            } else {
                logger.debug("Do not stop monitoring resource ''{0}'': another deployment plan makes reference to it.", deployment.toString());
            }
        }

        // Undeploy only if no deployment plans make reference to this deployable
        if (!deploymentToDeployableMap.containsValue(deployable)) {
            try {
                if(DeploymentPlanDeployable.class.isInstance(deployable)) {
                    undeployRealDeployable(DeploymentPlanDeployable.class.cast(deployable));
                } else {
                    this.deployerManager.undeploy(deployable);
                }
            } catch (Exception e) {
                throw new FragmentUndeploymentException("Could not undeploy resource " + deployable.getArchive() + " - Trying to finish undeployment");
            }
        } else {
            // Remove stored sub deployments entries from Maps as the deployable has not been undeployed
            cleanDeploymentMaps(deployment, deployable);
            logger.debug("Do not undeploy archive ''{0}'': another deployment plan makes reference to it.", deployable.getArchive());
        }
    }

    /**
     * Remove Maps entries for a given deployment.
     * In case the deployable is not null, also remove sub deployments.
     * @param deployment The deployment to remove from Maps
     * @param deployable The deployable to analyse (may be null)
     */
    private void cleanDeploymentMaps(final Deployment deployment, final IDeployable deployable) {
        deploymentToDeployableMap.remove(deployment);
        deploymentToFetcherMap.remove(deployment);

        if (deployable != null && DeploymentPlanDeployable.class.isInstance(deployable)) {
            DeploymentPlanDeployable deploymentPlanDeployable = DeploymentPlanDeployable.class.cast(deployable);
            DeploymentPlan deploymentPlan = deploymentPlanDeployable.getAttachedData();

            for (Deployment subDeployment : deploymentPlan.getDeployments()) {
                cleanDeploymentMaps(subDeployment, deploymentToDeployableMap.get(subDeployment));
            }
        }
    }
    
    public void setFetcherFactoryManager(final IResourceFetcherFactoryManager factoryManager) {
        this.fetcherFactoryManager = factoryManager;
    }

    /**
     * {@inheritDoc}
     */
    public IResourceFetcherFactoryManager getFetcherFactoryManager() {
        return this.fetcherFactoryManager;
    }

    /**
     * {@inheritDoc}
     */
    public void setDeployerManager(final IDeployerManager deployerManager) {
        this.deployerManager = deployerManager;
    }

    /**
     * {@inheritDoc}
     */
    public IDeployerManager getDeployerManager() {
        return this.deployerManager;
    }

    /**
     * {@inheritDoc}
     */
    public Integer getDeploymentPlansCount() {
        return this.deploymentPlans.size();
    }

    /**
     * {@inheritDoc}
     */
    public List getDeploymentPlansIds() {
        List result = new ArrayList();
        for (DeploymentPlanDeployable deploymentPlanDeployable : this.deploymentPlans) {
            DeploymentPlan deploymentPlan = deploymentPlanDeployable.getAttachedData();
            if (deploymentPlan.getId() == null) {
                result.add("");
            } else {
                result.add(deploymentPlan.getId());
            }

        }
        return result;
    }


    /**
     * {@inheritDoc}
     */
    public List getDeploymentPlansUrls() {
        List result = new ArrayList();
        for (DeploymentPlanDeployable deploymentPlanDeployable : this.deploymentPlans) {
            URL url;
            try {
                url = deploymentPlanDeployable.getArchive().getURL();
                result.add(URLUtils.urlToFile(url).getPath());
            } catch (ArchiveException e) {
                logger.error("Error in deployable archive.", e);
            }
        }
        return result;
    }
    /**
     * {@inheritDoc}
     */
    public IResourceMonitor getResourceMonitor() {
        return this.resourceMonitor;
    }

    /**
     * {@inheritDoc}
     */
    public void setResourceMonitor(final IResourceMonitor resourceMonitor) {
        this.resourceMonitor = resourceMonitor;
    }

    /**
     * {@inheritDoc}
     */
    public DeploymentPlanDeployable getOwnerDeploymentPlanDeployable(final Deployment deployment) {
        for (DeploymentPlanDeployable deploymentPlanDeployable : this.deploymentPlans) {
            DeploymentPlan deploymentPlan = deploymentPlanDeployable.getAttachedData();
            if (deploymentPlan.getDeployments().contains(deployment)) {
                return deploymentPlanDeployable;
            }
        }
        return null;
    }

    public void setConditionEvaluator(IConditionEvaluator conditionEvaluator) {
        this.conditionEvaluator = conditionEvaluator;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy