OW2 Consortium jonas

Rev

Rev 17362 | Rev 17381 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2008 Bull S.A.S.
 * Contact: jonas-team@ow2.org
 *
 * Application Versioning System
 * Copyright (C) 2008 France Telecom R&D
 *
 * 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: UpdateCenterDeploymentPlanDeployer.java 17370 2009-05-14 11:37:53Z loverad $
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.updatecenter.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.List;
import java.util.Map;

import org.ow2.jonas.lib.bootstrap.JProp;
import org.ow2.jonas.updatecenter.IUpdateCenterDeploymentPlanDeployer;
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.impl.helper.DeployableHelper;
import org.ow2.util.ee.deploy.impl.helper.DeployableHelperException;
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.deploymentplan.maven2.Maven2Deployment;
import org.ow2.util.plan.bindings.deploymentplan.obr.ObrDeployment;
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.impl.DeploymentPlanDeployer;
import org.ow2.util.plan.deployer.api.IDeploymentPlanDeployer;
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 Update deployment plan deployables.
 * @author Daniel Lovera
 */
public class UpdateCenterDeploymentPlanDeployer implements IUpdateCenterDeploymentPlanDeployer {

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

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

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

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

    /**
     * The name of the JONAS_BASE directory.
     */
    protected static final String JONAS_BASE = JProp.getJonasBase();

    /**
     * The deployed update deployment plans.
     */
    private Collection<DeploymentPlanDeployable> updateCenterDeploymentPlans = new ArrayList<DeploymentPlanDeployable>();

    /**
     * The PlanReader that used to parse the update deployment plans.
     */
    private IPlanReader planReader;

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

    /**
     * The deployment plan deployer.
     */
    private DeploymentPlanDeployer deploymentPlanDeployer = null;

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

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

    /**
     * {@inheritDoc}
     */
    public IResourceMonitor getResourceMonitor() {
        return this.resourceMonitor;
    }

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

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

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

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

    /**
     * {@inheritDoc}
     */
    public void setFetcherFactoryManager(final IResourceFetcherFactoryManager factoryManager) {
        this.fetcherFactoryManager = factoryManager;
    }

    /**
     * {@inheritDoc}
     */
    public DeploymentPlanDeployer getDeploymentPlanDeployer() {
        return deploymentPlanDeployer;
    }

    /**
     * {@inheritDoc}
     */
    public void setDeploymentPlanDeployer(final DeploymentPlanDeployer deploymentPlanDeployer) {
        this.deploymentPlanDeployer = deploymentPlanDeployer;
    }

    /**
     * {@inheritDoc}
     */
    public void deploy(final IDeployable<?> deployable) throws DeployerException {

        if (deployable == null) {
            logger.error("Null deployable");
            throw new DeployerException("Null deployable");
        }

        if (!(deployable instanceof DeploymentPlanDeployable)) {
            logger.error("Bad deployable type {0}", deployable.getClass());
            throw new DeployerException("Bad deployable type");
        }
        DeploymentPlanDeployable deploymentPlanDeployable = (DeploymentPlanDeployable) deployable;

        DeploymentPlan updateDeploymentPlan = null;
        if (planReader == null) {
            logger.error("Update deployment aborted - the Update Center PlanReader is null");
            throw new DeployerException("the Update Center PlanReader is null");
        }
        URL archiveUrl = null;
        try {
            archiveUrl = deploymentPlanDeployable.getArchive().getURL();
        } catch (ArchiveException e) {
            logger.error("Error while getting URL for archive {0} - Update deployment aborted", deploymentPlanDeployable
                    .getArchive());
            throw new DeployerException(e);
        }
        try {
            File archiveFile = URLUtils.urlToFile(archiveUrl);
            updateDeploymentPlan = planReader.readPlan(archiveFile);
        } catch (Exception e) {
            logger.error("Error while parsing archive {0} - Update deployment aborted", archiveUrl);
            throw new DeployerException(e);
        }

        if (updateDeploymentPlan == null) {
            /* Some strange error occured */
            logger.error("The deployable {0} resolved in null deployment plan - Update Deployment aborted", deployable);
            throw new DeployerException("null deployment plan structure");
        }
        deploymentPlanDeployable.setAttachedData(updateDeploymentPlan);

        try {
            updateDeploymentPlans(updateDeploymentPlan);
            // deployUpdateDeploymentPlans(updateDeploymentPlan);
        } catch (DeploymentPlanDeploymentException e) {
            logger.error("Deployment plan deployment failed; exception: {0}", e);
            throw new DeployerException(e);
        } catch (DeploymentPlanUndeploymentException e) {
            logger.error("Deployment plan undeployment failed; exception: {0}", e);
            throw new DeployerException(e);
        }

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

        this.updateCenterDeploymentPlans.add(deploymentPlanDeployable);
    }

    /**
     * {@inheritDoc}
     */
    public boolean isDeployed(final IDeployable<?> deployable) throws DeployerException {
        return this.updateCenterDeploymentPlans.contains(deployable);
    }

    /**
     * {@inheritDoc}
     */
    public boolean supports(final IDeployable<?> deployable) {
        if (deployable instanceof DeploymentPlanDeployableImpl) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * {@inheritDoc}
     */
    public void undeploy(final IDeployable<?> deployable) throws DeployerException {
        if (deployable == null) {
            logger.error("Null deployable");
            throw new DeployerException("Null deployable");
        }
        if (!(deployable instanceof DeploymentPlanDeployable)) {
            logger.error("Bad deployable type {0}", deployable.getClass());
            throw new DeployerException("Bad deployable type");
        }
        if (isDeployed(deployable)) {
            this.updateCenterDeploymentPlans.remove(deployable);
            DeploymentPlanDeployable deploymentPlanDeployable = (DeploymentPlanDeployable) deployable;
            DeploymentPlan deploymentPlan = deploymentPlanDeployable.getAttachedData();
            try {
                undeployDeploymentPlans(deploymentPlan);
                // undeployUpdateDeploymentPlans(deploymentPlan);
                // redeployUpdateDeploymentPlans(deploymentPlan);
            } catch (DeploymentPlanUndeploymentException e) {
                logger.error("Deployment plan undeployment failed; exception: {0}", e);
                throw new DeployerException(e);
            }

            logger.debug("deployable {0} undeployed", deployable);
        } else {
            logger.error("Cannot undeploy deployable {0} - it is not deployed", deployable);
            throw new DeployerException("Cannot undeploy deployable that is not deployed");
        }
    }

    /**
     * Returns the deployment plan object related to a deployed service.
     * @param serviceId the service id.
     * @return the deployment plan object related to the service given.
     */
    private DeploymentPlan findDeployedServicePlan(final String serviceId) {
        // serviceId only, we don't check version for now
        Collection<DeploymentPlanDeployable> deployedplans = this.deploymentPlanDeployer.getDeploymentPlans();
        for (DeploymentPlanDeployable deploymentplandeployable : deployedplans) {
            if (serviceId.equals(deploymentplandeployable.getModuleName())) {
                return deploymentplandeployable.getAttachedData();
            }
        }
        return null;
    }

    /**
     * Returns the deployment plan object related to a non deployed service.
     * @param serviceId the service id.
     * @return the deployment plan object related to the service given.
     * @throws DeploymentPlanDeploymentException if the service is not found.
     */
    private DeploymentPlan findNonDeployedServicePlan(final String serviceId) throws DeploymentPlanDeploymentException {

        File deployDirectory = new File(JONAS_BASE + File.separator + "conf" + File.separator + "deployment");

        // Directory exists ?
        if (!deployDirectory.exists()) {
            logger.warn("The given directory ''{0}'' is neither present on the filesystem or in JONAS_BASE ''{1}''",
                    deployDirectory, JONAS_BASE);
            throw new DeploymentPlanDeploymentException("service '" + serviceId + "' not found");
        }

        File[] files = deployDirectory.listFiles();
        List<DeploymentPlanDeployable> deploymentplanDeployables = new ArrayList<DeploymentPlanDeployable>();

        if (files != null) {
            for (File f : files) {
                // Get deployable
                IArchive archive = ArchiveManager.getInstance().getArchive(f);
                if (archive == null) {
                    logger.warn("Ignoring invalid file ''{0}''", f);
                    continue;
                }

                IDeployable<?> deployable;
                try {
                    deployable = DeployableHelper.getDeployable(archive);
                } catch (DeployableHelperException e) {
                    logger.warn("Cannot get a deployable for the archive '" + archive + "'", e);
                    continue;
                }

                if (deployable instanceof DeploymentPlanDeployable) {
                    DeploymentPlanDeployable deployableplan = (DeploymentPlanDeployable) deployable;

                    if (serviceId.equals(deployableplan.getModuleName())) {
                        try {
                            return this.deploymentPlanDeployer.getPlanReader().readPlan(f);
                        } catch (Exception e) {
                            logger.error("Error while parsing file ''{0}'' - Service ''{1}'' update aborted", f, serviceId);
                            throw new DeploymentPlanDeploymentException(e);
                        }

                    }

                }

            }
        }
        // service not found
        return null;
    }

    /**
     * Updates a deployment plan object.
     * @param deploymentplan the deployment plan object.
     * @throws DeploymentPlanDeploymentException if an update deployment fails.
     * @throws DeploymentPlanUndeploymentException if a requested deployment
     *         revert fails.
     */
    private void updateDeploymentPlans(final DeploymentPlan deploymentplan) throws DeploymentPlanDeploymentException,
            DeploymentPlanUndeploymentException {

        boolean serviceStarted = true;

        logger.debug("Deploymentplan ''{0}''",deploymentplan.getId());
        for (DeploymentPlan plans : deploymentplan.getDeploymentPlans()) {
            updateDeploymentPlans(plans);
        }

        if (deploymentplan.getId() == null) {
            throw new DeploymentPlanDeploymentException("Service Id is null");
        }

        // look for service deployment plan in deployed services
        DeploymentPlan currentdeploymentplan = findDeployedServicePlan(deploymentplan.getId());

        // if service is not started
        if (currentdeploymentplan == null) {
            serviceStarted = false;
            // we look in the deployment plans directory
            currentdeploymentplan = findNonDeployedServicePlan(deploymentplan.getId());
        }

        if (currentdeploymentplan == null) {
            logger.debug("Service ''{0}'' not found", deploymentplan.getId());
        } else {

            // service is found
            updateDeploymentPlan(currentdeploymentplan, deploymentplan, serviceStarted);
        }

    }

    /**
     * Compares the deployment fragments from two deployment plans objects and
     * deploys/undeploys fragments to perform the update.
     * @param currentdeploymentplan a given deployment plan to compare.
     * @param deploymentplan a given deployment plan to compare.
     * @throws DeploymentPlanDeploymentException if a deployment fails.
     * @throws DeploymentPlanUnDeploymentException if an undeployemnt fails.
     */
    private void updateDeploymentPlan(final DeploymentPlan currentdeploymentplan, final DeploymentPlan deploymentplan,
            final boolean serviceStarted) throws DeploymentPlanDeploymentException, DeploymentPlanUndeploymentException {

        List<Deployment> deploymentsToUndeploy = new ArrayList<Deployment>();
        List<Deployment> alreadyDeployedDeployments = new ArrayList<Deployment>();

        boolean found = false;

        for (Deployment currentdeployment : currentdeploymentplan.getDeployments()) {
            for (Deployment newdeployment : deploymentplan.getDeployments()) {
                if (newdeployment.getIdAttr().equals(currentdeployment.getIdAttr())) {
                    DeploymentPlanFragment newfragment = (DeploymentPlanFragment) newdeployment;
                    DeploymentPlanFragment currentfragment = (DeploymentPlanFragment) currentdeployment;
                    if (compareFragments(currentfragment, newfragment)) {
                        alreadyDeployedDeployments.add(newdeployment);
                        found = true;
                    }
                }
            }
            if (!found) {
                deploymentsToUndeploy.add(currentdeployment);
            }
            found = false;
        }
        for (Deployment deployment : alreadyDeployedDeployments) {
            deploymentplan.getDeployments().remove(deployment);
        }

        // if service must be started we deploy/undeploy the deployments objects
        if (serviceStarted) {
            undeployDeployments(deploymentsToUndeploy);
            deployDeploymentPlan(deploymentplan);
        }
        // we save service config to reach the updated state at startup
        // to do....
    }

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

        for (Deployment deployment : deploymentplan.getDeployments()) {
            //logger.debug("Deployment id: {0}", deployment.getIdAttr());

            DeploymentPlanFragment fragment = (DeploymentPlanFragment) deployment;

            try {
                deployDeployment(fragment);
                fragment.setDeployed(true);
            } catch (FragmentDeploymentException deployException) {
                logger.error("Error while deploying part {0} of deployment plan {1} : {2}", fragment, deploymentplan,
                        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 {
                        undeployDeploymentPlans(deploymentplan);
                    } catch (DeploymentPlanUndeploymentException undeployException) {
                        logger.error("The deployment plan was not correctly undeployed.");
                    }
                }
                throw new DeploymentPlanDeploymentException(deployException);
            }
        }
    }

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

        Boolean reloadable = null;
        try {
            reloadable = DeploymentHelper.isReloadable(fragment);
        } catch (InvalidDeploymentException e) {
            logger.error("Invalid deployment found : {0} with id {1}", fragment);
            throw new FragmentDeploymentException(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 alocal 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 (deployable instanceof OSGiDeployable) {
            try {
                Boolean start = DeploymentHelper.isStart(fragment);
                ((OSGiDeployable) deployable).setStart(start);
                Boolean reference = DeploymentHelper.isReference(fragment);
                ((OSGiDeployable) deployable).setReference(reference);
            } catch (InvalidDeploymentException e) {
                logger.error("Invalid deployment found : {0} with id {1}", fragment);
                throw new FragmentDeploymentException(e);
            }
        }

        /* Deploy the deployable */
        try {
            this.deployerManager.deploy(deployable);
            logger.debug("deploying {0}", deployable.getShortName());
        } catch (DeployerException e) {
            logger.error("Exception while deploying deployable {0}: {1}", deployable, e.getMessage());
            throw new FragmentDeploymentException(e);
        } catch (UnsupportedDeployerException e) {
            logger.error("No deployer found for deployable {0}", deployable);
            throw new FragmentDeploymentException(e);
        }

        // Store the deployment->deployable
        this.deploymentPlanDeployer.getDeploymentToDeployableMap().put(fragment, deployable);
        if (reloadable) {
            // add this resource to the managed ones.
            this.resourceMonitor.addMonitoredResource(fetcher);
        }
    }

    /**
     * Undeploys all deployment plans object.
     * @param deploymentPlan the deployment plan.
     * @throws DeploymentPlanDeploymentException
     * @throws DeploymentPlanUndeploymentException
     */
    private void undeployDeploymentPlans(final DeploymentPlan deploymentPlan) throws DeploymentPlanUndeploymentException {

        for (DeploymentPlan plans : deploymentPlan.getDeploymentPlans()) {
            undeployDeploymentPlans(plans);
        }
        undeployDeploymentPlan(deploymentPlan);

    }

    /**
     * Undeploys a deployment plan object.
     * @param deploymentPlan the deployment plan.
     * @throws DeploymentPlanUndeploymentException
     */
    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();
            }
        }
    }

    /**
     * Undeploys all deployments from a given list.
     * @param deployments the deployments list.
     * @throws DeploymentPlanUndeploymentException if an undeployment fails.
     */
    private void undeployDeployments(final List<Deployment> deployments) throws DeploymentPlanUndeploymentException {

        for (Deployment deployment : deployments) {
            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}", fragment);
                    // 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}
     */
    /*
     * 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 = this.deploymentPlanDeployer.getDeploymentToDeployableMap().get(deployment);
        if (deployable == null) {
            throw new FragmentUndeploymentException("Cannot undeploy Deployment " + deployment.toString());
        }
        this.deploymentPlanDeployer.getDeploymentToDeployableMap().remove(deployment);

        try {
            this.deployerManager.undeploy(deployable);
            logger.debug("undeploying {0}", deployable.getShortName());
        } catch (Exception e) {
            logger.error("Could not undeploy resource {0} - trying to finish undeployment", deployable.getArchive());
            throw new FragmentUndeploymentException(e);
        }

    }

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

        }
        return result;
    }

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

    /**
     * {@inheritDoc}
     */
    public DeploymentPlanDeployable getOwnerDeploymentPlanDeployable(final Deployment deployment) {

        for (DeploymentPlanDeployable deploymentPlanDeployable : this.updateCenterDeploymentPlans) {
            DeploymentPlan deploymentPlan = deploymentPlanDeployable.getAttachedData();

            /*
             * List<ServiceDescription> services = deploymentPlan.getServices();
             * for (ServiceDescription service : services) { for
             * (ServiceDeploymentPlan deploymentplan :
             * service.getServiceDeploymentPlans()) {
             * if(searchDeployment(deploymentplan, deployment)); { return
             * deploymentPlanDeployable; } } } }
             */

            if (searchDeployment(deploymentPlan, deployment))
                ;
            {
                return deploymentPlanDeployable;
            }
        }
        return null;
    }

    /**
     * Search for a deployment object recursively in a deployment plan object.
     * Returns true if the deployment is found and false otherwise.
     * @param deploymentPlan
     * @return
     */
    private boolean searchDeployment(DeploymentPlan deploymentPlan, final Deployment deployment) {
        boolean found = false;
        if (deploymentPlan.getDeployments().contains(deployment)) {
            return true;
        } else {
            for (DeploymentPlan plans : deploymentPlan.getDeploymentPlans()) {
                found = searchDeployment(plans, deployment);
            }
            return found;
        }
    }

    /**
     * Compares two lists containing deployments objects, returns all the
     * deployments objects from the first list which are not in the second one.
     * @param currentDeployments a given deployments list to compare.
     * @param incomingDeployments a given deployments list to compare.
     * @return a list of deployments object from the first list which are not in
     *         the second one.
     */
    public List<Deployment> getDeploymentsToUndeploy(final List<Deployment> currentDeployments,
            final List<Deployment> incomingDeployments) {

        List<Deployment> deploymentsToUnDeploy = new ArrayList<Deployment>();
        boolean found = false;

        for (Deployment currentdeployment : currentDeployments) {
            for (Deployment newdeployment : incomingDeployments) {
                if (newdeployment.getIdAttr().equals(currentdeployment.getIdAttr())) {
                    DeploymentPlanFragment newfragment = (DeploymentPlanFragment) newdeployment;
                    DeploymentPlanFragment currentfragment = (DeploymentPlanFragment) currentdeployment;
                    if (compareFragments(currentfragment, newfragment)) {
                        logger.debug(" fragment {0} already deployed in this version", newfragment.getIdAttr());
                        found = true;
                    }
                }
            }
            if (!found) {
                deploymentsToUnDeploy.add(currentdeployment);
            }
            found = false;
        }
        return deploymentsToUnDeploy;
    }

    /**
     * Compares two deployment plan fragments
     * @param currentfragment a given fragment to compare.
     * @param newfragment a given fragment to compare.
     * @return true if both fragments type and version are identical, false
     *         otherwise.
     */
    public boolean compareFragments(DeploymentPlanFragment currentfragment, DeploymentPlanFragment newfragment) {

        // we want fragments to belong to the same class,
        // and to be either Obr or Maven types in order to compare versions
        // otherwise we uninstall the current and install the new one

        if (currentfragment.getClass().equals(newfragment.getClass())
                && (currentfragment instanceof ObrDeployment || currentfragment instanceof Maven2Deployment)) {
            if (currentfragment instanceof ObrDeployment) {
                return ((((ObrDeployment) currentfragment).getBundleVersion()).equals(((ObrDeployment) newfragment)
                        .getBundleVersion()));
            }

            if (currentfragment instanceof Maven2Deployment) {
                return ((((Maven2Deployment) currentfragment).getVersion()).equals(((Maven2Deployment) newfragment)
                        .getVersion()));
            }
        }
        return false;
    }
}