org.apache.servicemix.jbi.deployer.impl.Deployer.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.servicemix.jbi.deployer.impl.Deployer.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF 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.apache.servicemix.jbi.deployer.impl;

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.HashSet;
import java.util.concurrent.ConcurrentHashMap;

import javax.jbi.JBIException;
import javax.management.MBeanServer;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.servicemix.jbi.deployer.Component;
import org.apache.servicemix.jbi.deployer.DeployedAssembly;
import org.apache.servicemix.jbi.deployer.ServiceAssembly;
import org.apache.servicemix.jbi.deployer.SharedLibrary;
import org.apache.servicemix.jbi.deployer.ServiceUnit;
import org.apache.servicemix.jbi.deployer.events.LifeCycleListener;
import org.apache.servicemix.jbi.deployer.events.LifeCycleEvent;
import org.apache.servicemix.jbi.deployer.artifacts.AbstractLifecycleJbiArtifact;
import org.apache.servicemix.jbi.deployer.artifacts.ComponentImpl;
import org.apache.servicemix.jbi.deployer.artifacts.ServiceAssemblyImpl;
import org.apache.servicemix.jbi.deployer.artifacts.ServiceUnitImpl;
import org.apache.servicemix.jbi.deployer.artifacts.SharedLibraryImpl;
import org.apache.servicemix.jbi.deployer.artifacts.AssemblyReferencesListener;
import org.apache.servicemix.jbi.deployer.descriptor.ComponentDesc;
import org.apache.servicemix.jbi.deployer.descriptor.Descriptor;
import org.apache.servicemix.jbi.deployer.descriptor.DescriptorFactory;
import org.apache.servicemix.jbi.deployer.descriptor.Identification;
import org.apache.servicemix.jbi.deployer.descriptor.ServiceAssemblyDesc;
import org.apache.servicemix.jbi.deployer.descriptor.ServiceUnitDesc;
import org.apache.servicemix.jbi.deployer.descriptor.SharedLibraryDesc;
import org.apache.servicemix.jbi.deployer.descriptor.Target;
import org.apache.servicemix.jbi.runtime.ComponentWrapper;
import org.apache.servicemix.jbi.runtime.Environment;
import org.apache.servicemix.nmr.api.event.ListenerRegistry;
import org.apache.servicemix.nmr.core.ListenerRegistryImpl;
import org.fusesource.commons.management.ManagementStrategy;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.framework.SynchronousBundleListener;
import org.osgi.framework.BundleEvent;
import org.osgi.service.prefs.Preferences;
import org.osgi.service.prefs.PreferencesService;
import org.osgi.util.tracker.ServiceTracker;
import org.springframework.osgi.util.OsgiStringUtils;

/**
 * Deployer for JBI artifacts
 */
public class Deployer implements SynchronousBundleListener, LifeCycleListener {

    public static final String NAME = "NAME";
    public static final String TYPE = "TYPE";
    public static final String TYPE_SERVICE_ENGINE = "service-engine";
    public static final String TYPE_BINDING_COMPONENT = "binding-component";

    private static final Log LOGGER = LogFactory.getLog(Deployer.class);

    private BundleContext bundleContext;
    private final Set<Bundle> bundles = new HashSet<Bundle>();

    private final Map<String, SharedLibraryImpl> sharedLibraries = new ConcurrentHashMap<String, SharedLibraryImpl>();
    private final Map<String, ComponentImpl> components = new ConcurrentHashMap<String, ComponentImpl>();
    private final Map<String, ServiceAssemblyImpl> serviceAssemblies = new ConcurrentHashMap<String, ServiceAssemblyImpl>();

    private final Map<Bundle, AbstractInstaller> installers = new ConcurrentHashMap<Bundle, AbstractInstaller>();

    private final ThreadLocal<AbstractInstaller> jmxManaged = new ThreadLocal<AbstractInstaller>();

    private final Map<String, Boolean> wrappedComponents = new ConcurrentHashMap<String, Boolean>();

    private final Map<Bundle, List<ServiceRegistration>> services = new ConcurrentHashMap<Bundle, List<ServiceRegistration>>();

    private final Set<AbstractInstaller> pendingInstallers = new HashSet<AbstractInstaller>();

    private final Set<ServiceAssemblyImpl> pendingAssemblies = new HashSet<ServiceAssemblyImpl>();

    private File jbiRootDir;

    private PreferencesService preferencesService;

    private boolean autoStart = true;

    private ServiceTracker deployedComponentsTracker;

    private ServiceTracker deployedAssembliesTracker;

    private AssemblyReferencesListener endpointListener;

    private int shutdownTimeout;

    // Helper beans
    private ManagementStrategy managementStrategy;
    private Environment environment;

    private ListenerRegistry listenerRegistry;

    private MBeanServer mbeanServer;

    public Deployer() throws JBIException {
        // TODO: control that using properties
        jbiRootDir = new File(System.getProperty("servicemix.base"), "data/jbi");
        jbiRootDir.mkdirs();
        // Create listener registry
        listenerRegistry = new ListenerRegistryImpl();
        listenerRegistry.register(this, null);
    }

    public BundleContext getBundleContext() {
        return bundleContext;
    }

    public void setBundleContext(BundleContext bundleContext) {
        this.bundleContext = bundleContext;
    }

    public PreferencesService getPreferencesService() {
        return preferencesService;
    }

    public void setPreferencesService(PreferencesService preferencesService) {
        this.preferencesService = preferencesService;
    }

    public boolean isAutoStart() {
        return autoStart;
    }

    public void setAutoStart(boolean autoStart) {
        this.autoStart = autoStart;
    }

    public void setEndpointListener(AssemblyReferencesListener endpointListener) {
        this.endpointListener = endpointListener;
    }

    public AssemblyReferencesListener getEndpointListener() {
        return endpointListener;
    }

    public ManagementStrategy getManagementStrategy() {
        return managementStrategy;
    }

    public void setManagementStrategy(ManagementStrategy managementStrategy) {
        this.managementStrategy = managementStrategy;
    }

    public MBeanServer getMbeanServer() {
        return mbeanServer;
    }

    public void setMbeanServer(MBeanServer mbeanServer) {
        this.mbeanServer = mbeanServer;
    }

    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    public Environment getEnvironment() {
        return environment;
    }

    protected AbstractInstaller getJmxManaged() {
        return jmxManaged.get();
    }

    public void setJmxManaged(AbstractInstaller installer) {
        jmxManaged.set(installer);
    }

    public Map<String, SharedLibraryImpl> getSharedLibraries() {
        return sharedLibraries;
    }

    public Map<String, ComponentImpl> getComponents() {
        return components;
    }

    public Map<String, ServiceAssemblyImpl> getServiceAssemblies() {
        return serviceAssemblies;
    }

    public SharedLibraryImpl getSharedLibrary(String name) {
        return name != null ? sharedLibraries.get(name) : null;
    }

    public ComponentImpl getComponent(String name) {
        return name != null ? components.get(name) : null;
    }

    public ServiceAssemblyImpl getServiceAssembly(String name) {
        return name != null ? serviceAssemblies.get(name) : null;
    }

    public void setShutdownTimeout(int shutdownTimeout) {
        this.shutdownTimeout = shutdownTimeout;
    }

    public int getShutdownTimeout() {
        return shutdownTimeout;
    }

    public void init() throws Exception {
        // Track bundles
        bundleContext.addBundleListener(this);
        for (Bundle bundle : bundleContext.getBundles()) {
            if (bundle.getState() == Bundle.ACTIVE) {
                bundleChanged(new BundleEvent(BundleEvent.STARTED, bundle));
            }
        }
        // Track deployed components
        deployedComponentsTracker = new ServiceTracker(bundleContext, javax.jbi.component.Component.class.getName(),
                null) {
            public Object addingService(ServiceReference serviceReference) {
                Object o = super.addingService(serviceReference);
                registerDeployedComponent(serviceReference, (javax.jbi.component.Component) o);
                return o;
            }

            public void removedService(ServiceReference serviceReference, Object o) {
                unregisterDeployedComponent(serviceReference, (javax.jbi.component.Component) o);
                super.removedService(serviceReference, o);
            }
        };
        deployedComponentsTracker.open();
        // Track deployed service assemblies
        deployedAssembliesTracker = new ServiceTracker(bundleContext, DeployedAssembly.class.getName(), null) {
            public Object addingService(ServiceReference serviceReference) {
                Object o = super.addingService(serviceReference);
                registerDeployedServiceAssembly(serviceReference, (DeployedAssembly) o);
                return o;
            }

            public void removedService(ServiceReference serviceReference, Object o) {
                unregisterDeployedServiceAssembly(serviceReference, (DeployedAssembly) o);
                super.removedService(serviceReference, o);
            }
        };
        deployedAssembliesTracker.open();
    }

    public synchronized void destroy() throws Exception {
        for (Bundle bundle : bundles) {
            bundleChanged(new BundleEvent(BundleEvent.STOPPING, bundle));
        }
        deployedComponentsTracker.close();
        deployedAssembliesTracker.close();
        bundleContext.removeBundleListener(this);
    }

    public void bundleChanged(BundleEvent event) {
        switch (event.getType()) {
        case BundleEvent.STARTED:
            if (match(event.getBundle())) {
                bundles.add(event.getBundle());
                onBundleStarted(event.getBundle());
            }
            break;
        case BundleEvent.STOPPING:
            if (bundles.contains(event.getBundle())) {
                onBundleStopping(event.getBundle());
            }
            break;
        case BundleEvent.UNINSTALLED:
            if (bundles.remove(event.getBundle())) {
                onBundleUninstalled(event.getBundle());
            }
            break;
        }
    }

    protected boolean match(Bundle bundle) {
        LOGGER.debug("Checking bundle: '" + OsgiStringUtils.nullSafeNameAndSymName(bundle) + "'");
        URL url = bundle.getResource(DescriptorFactory.DESCRIPTOR_FILE);
        if (url == null) {
            LOGGER.debug("Bundle '" + OsgiStringUtils.nullSafeNameAndSymName(bundle)
                    + "' does not contain any JBI descriptor.");
            return false;
        }
        return true;
    }

    /**
     * Callback called when a new bundle has been started.
     * This method will check if the bundle is a JBI artifact and will process it accordingly.
     *
     * @param bundle
     */
    protected void onBundleStarted(Bundle bundle) {
        // If an installer has been registered, this means that we are using JMX or ant tasks to deploy the JBI artifact.
        // In such a case, let the installer do the work.
        // Else, the bundle has been deployed through the deploy folder or the command line or any other
        // non JBI way, which means we need to create an installer and install the artifact now.
        AbstractInstaller installer = getJmxManaged();
        if (installer != null) {
            installers.put(bundle, installer);
        } else {
            ClassLoader cl = Thread.currentThread().getContextClassLoader();
            try {
                Thread.currentThread().setContextClassLoader(getClass().getClassLoader());

                // Check if there is an already existing installer
                // This is certainly the case when a bundle has been stopped and is restarted.
                installer = installers.get(bundle);
                if (installer == null) {
                    URL url = bundle.getResource(DescriptorFactory.DESCRIPTOR_FILE);
                    Descriptor descriptor = DescriptorFactory.buildDescriptor(url);
                    DescriptorFactory.checkDescriptor(descriptor);
                    if (descriptor.getSharedLibrary() != null) {
                        LOGGER.info("Deploying bundle '" + OsgiStringUtils.nullSafeNameAndSymName(bundle)
                                + "' as a JBI shared library");
                        installer = new SharedLibraryInstaller(this, descriptor, null, true);
                    } else if (descriptor.getComponent() != null) {
                        LOGGER.info("Deploying bundle '" + OsgiStringUtils.nullSafeNameAndSymName(bundle)
                                + "' as a JBI component");
                        installer = new ComponentInstaller(this, descriptor, null, true);
                    } else if (descriptor.getServiceAssembly() != null) {
                        LOGGER.info("Deploying bundle '" + OsgiStringUtils.nullSafeNameAndSymName(bundle)
                                + "' as a JBI service assembly");
                        installer = new ServiceAssemblyInstaller(this, descriptor, (File) null, true);
                    } else {
                        throw new IllegalStateException("Unrecognized JBI descriptor: " + url);
                    }
                    installer.setBundle(bundle);
                }

                // TODO: handle the case where the bundle is restarted: i.e. the artifact is already installed
                try {
                    installer.init();
                    installer.install();
                    // only register installer if installation has been successfull
                    installers.put(bundle, installer);
                } catch (PendingException e) {
                    pendingInstallers.add(installer);
                    LOGGER.warn("Requirements not met for JBI artifact in bundle "
                            + OsgiStringUtils.nullSafeNameAndSymName(bundle) + ". Installation pending. " + e);
                }
            } catch (Exception e) {
                LOGGER.error("Error handling bundle start event", e);
            } finally {
                Thread.currentThread().setContextClassLoader(cl);
            }
        }
    }

    protected void onBundleStopping(Bundle bundle) {
        AbstractInstaller installer = getJmxManaged();
        if (installer == null) {
            installer = installers.get(bundle);
            if (installer != null) {
                try {
                    installer.stop(true);
                } catch (Exception e) {
                    LOGGER.warn("Error shutting down JBI artifact", e);
                }
            }
        }
        unregisterServices(bundle);
    }

    protected void onBundleUninstalled(Bundle bundle) {
        AbstractInstaller installer = getJmxManaged();
        if (installer == null) {
            installer = installers.remove(bundle);
            if (installer != null) {
                try {
                    pendingInstallers.remove(installer);
                    installer.setUninstallFromOsgi(true);
                    installer.uninstall(true);

                } catch (Exception e) {
                    LOGGER.warn("Error uninstalling JBI artifact", e);
                }
            }
        } else {
            installers.remove(bundle);
        }
    }

    public ServiceUnitImpl createServiceUnit(ServiceUnitDesc sud, File suRootDir, ComponentImpl component) {
        return new ServiceUnitImpl(sud, suRootDir, component);
    }

    public SharedLibraryImpl registerSharedLibrary(Bundle bundle, SharedLibraryDesc sharedLibraryDesc,
            ClassLoader classLoader) throws Exception {
        // Create shared library
        SharedLibraryImpl sl = new SharedLibraryImpl(bundle, sharedLibraryDesc, classLoader);
        sharedLibraries.put(sl.getName(), sl);
        Dictionary<String, String> props = new Hashtable<String, String>();
        // populate props from the library meta-data
        props.put(NAME, sharedLibraryDesc.getIdentification().getName());
        LOGGER.debug("Registering JBI Shared Library");
        registerService(bundle, SharedLibrary.class.getName(), sl, props);
        getManagementStrategy().manageObject(sl);
        // Check pending bundles
        checkPendingInstallers();
        return sl;
    }

    public ComponentImpl registerComponent(Bundle bundle, ComponentDesc componentDesc,
            javax.jbi.component.Component innerComponent, SharedLibrary[] sharedLibraries) throws Exception {
        String name = componentDesc.getIdentification().getName();
        Preferences prefs = preferencesService.getUserPreferences(name);
        ComponentImpl component = new ComponentImpl(bundle, componentDesc, innerComponent, prefs, autoStart,
                sharedLibraries);
        component.setListenerRegistry(listenerRegistry);
        // populate props from the component meta-data
        Dictionary<String, String> props = new Hashtable<String, String>();
        props.put(NAME, name);
        props.put(TYPE, componentDesc.getType());
        for (SharedLibrary lib : sharedLibraries) {
            ((SharedLibraryImpl) lib).addComponent(component);
        }
        components.put(name, component);
        // register the component in the OSGi registry
        LOGGER.debug("Registering JBI component");
        registerService(bundle, new String[] { Component.class.getName(), ComponentWrapper.class.getName() },
                component, props);
        // Now, register the inner component
        if (!wrappedComponents.containsKey(name)) {
            registerService(bundle, javax.jbi.component.Component.class.getName(), innerComponent, props);
        }
        getManagementStrategy().manageObject(component);
        return component;
    }

    public ServiceAssemblyImpl registerServiceAssembly(Bundle bundle, ServiceAssemblyDesc serviceAssemblyDesc,
            List<ServiceUnitImpl> sus) throws Exception {
        // Now create the SA and initialize it
        Preferences prefs = preferencesService
                .getUserPreferences(serviceAssemblyDesc.getIdentification().getName());
        ServiceAssemblyImpl sa = new ServiceAssemblyImpl(bundle, serviceAssemblyDesc, sus, prefs, endpointListener,
                autoStart);
        sa.setShutdownTimeout(shutdownTimeout);
        sa.setListenerRegistry(listenerRegistry);
        sa.init();
        serviceAssemblies.put(sa.getName(), sa);
        // populate props from the component meta-data
        Dictionary<String, String> props = new Hashtable<String, String>();
        props.put(NAME, serviceAssemblyDesc.getIdentification().getName());
        // register the service assembly in the OSGi registry
        LOGGER.debug("Registering JBI service assembly");
        registerService(bundle, ServiceAssembly.class.getName(), sa, props);
        getManagementStrategy().manageObject(sa);
        return sa;
    }

    protected void unregisterComponent(ComponentImpl component) {
        if (component != null) {
            try {
                component.stop(false);
                component.shutDown(false, true);
                // TODO: Undeploy SAs and put their bundles in the pending state
                // Undeploy SAs
                Set<ServiceAssemblyImpl> sas = new HashSet<ServiceAssemblyImpl>();
                for (ServiceUnit su : component.getServiceUnits()) {
                    sas.add((ServiceAssemblyImpl) su.getServiceAssembly());
                }
                for (ServiceAssemblyImpl sa : sas) {
                    Bundle bundle = sa.getBundle();
                    ServiceAssemblyInstaller installer = (ServiceAssemblyInstaller) installers.get(bundle);
                    if (installer != null) {
                        try {
                            installer.stop(true);
                            pendingAssemblies.remove(sa);
                            if (installer.getDeployedAssembly() == null) {
                                unregisterServiceAssembly(sa);
                                pendingInstallers.add(installer);
                            } else {
                                installers.remove(bundle);
                            }
                        } catch (Exception e) {
                            LOGGER.warn("Error uninstalling service assembly", e);
                        }
                    }
                }
                unregisterServices(component.getBundle());
            } catch (JBIException e) {
                LOGGER.warn("Error when shutting down component", e);
            }
            for (SharedLibrary lib : component.getSharedLibraries()) {
                ((SharedLibraryImpl) lib).removeComponent(component);
            }
            components.remove(component.getName());
        }
    }

    protected void unregisterServiceAssembly(ServiceAssemblyImpl assembly) {
        if (assembly != null) {
            serviceAssemblies.remove(assembly.getName());
            pendingAssemblies.remove(assembly);
            unregisterServices(assembly.getBundle());
            for (ServiceUnitImpl su : assembly.getServiceUnitsList()) {
                su.getComponentImpl().removeServiceUnit(su);
            }
        }
    }

    protected void unregisterSharedLibrary(SharedLibrary library) {
        if (library != null) {
            // TODO: shutdown all components
            sharedLibraries.remove(library.getName());
        }
    }

    public AbstractInstaller getInstaller(Object o) {
        if (o instanceof SharedLibraryImpl) {
            return installers.get(((SharedLibraryImpl) o).getBundle());
        }
        if (o instanceof ComponentImpl) {
            return installers.get(((ComponentImpl) o).getBundle());
        }
        if (o instanceof ServiceAssemblyImpl) {
            return installers.get(((ServiceAssemblyImpl) o).getBundle());
        }
        return null;
    }

    //===============================================================================
    //
    //   Pending artifacts support
    //
    //===============================================================================

    protected void checkPendingInstallers() {
        if (!pendingInstallers.isEmpty()) {
            final List<AbstractInstaller> pending = new ArrayList<AbstractInstaller>(pendingInstallers);
            pendingInstallers.clear();
            // Synchronous call because if using a separate thread
            // we run into deadlocks
            for (AbstractInstaller installer : pending) {
                try {
                    installer.init();
                    installer.install();
                    installers.put(installer.getBundle(), installer);
                } catch (PendingException e) {
                    pendingInstallers.add(installer);
                } catch (Exception e) {
                    LOGGER.warn("Error installing JBI artifact", e);
                }
            }
        }
    }

    protected void checkPendingAssemblies() {
        List<ServiceAssemblyImpl> sas = new ArrayList<ServiceAssemblyImpl>(pendingAssemblies);
        pendingAssemblies.clear();
        for (ServiceAssemblyImpl sa : sas) {
            try {
                sa.init();
            } catch (JBIException e) {
                pendingAssemblies.add(sa);
            }
        }
    }

    public void lifeCycleChanged(LifeCycleEvent event) throws JBIException {
        if (event.getLifeCycleMBean() instanceof ComponentImpl) {
            ComponentImpl comp = (ComponentImpl) event.getLifeCycleMBean();
            switch (event.getType()) {
            case Stopping:
                if (comp.getState() == AbstractLifecycleJbiArtifact.State.Started) {
                    // Stop deployed SAs
                    for (ServiceAssemblyImpl sa : comp.getServiceAssemblies()) {
                        if (sa.getState() == ServiceAssemblyImpl.State.Started) {
                            sa.stop(false);
                            pendingAssemblies.add(sa);
                        }
                    }
                }
                break;
            case ShuttingDown:
                if (comp.getState() == AbstractLifecycleJbiArtifact.State.Stopped) {
                    // Shutdown deployed SAs
                    for (ServiceAssemblyImpl sa : comp.getServiceAssemblies()) {
                        if (sa.getState() == ServiceAssemblyImpl.State.Stopped) {
                            sa.shutDown(false, event.isForced());
                            pendingAssemblies.add(sa);
                        }
                    }
                }
                break;
            case Started:
                checkPendingInstallers();
                checkPendingAssemblies();
                break;
            }
        }

        // propagate lifecycle event to management strategy
        // 
        try {
            getManagementStrategy().notify(event);
        } catch (Exception e) {
            // ignore
        }
    }

    //===============================================================================
    //
    //   OSGi packaging support
    //
    //===============================================================================

    /**
     * Register an already deployed JBI component.
     * If the component has been deployed using a JBI packaging, the deployer should already have
     * registered it, so it will do nothing.  If the component has been deployed directly through
     * an OSGi packaging (by simply registering the component in the OSGi registry), the deployer
     * will perform the needed tasks.
     *
     * @param reference
     * @param component
     */
    protected void registerDeployedComponent(ServiceReference reference, javax.jbi.component.Component component) {
        String name = (String) reference.getProperty(NAME);
        if (name != null && !components.containsKey(name)) {
            String type = (String) reference.getProperty(TYPE);
            Descriptor descriptor = new Descriptor();
            ComponentDesc componentDesc = new ComponentDesc();
            componentDesc.setIdentification(new Identification());
            componentDesc.getIdentification().setName(name);
            componentDesc.setType(type);
            descriptor.setComponent(componentDesc);

            try {
                wrappedComponents.put(name, true);
                ComponentInstaller installer = new ComponentInstaller(this, descriptor, null, autoStart);
                installer.setBundle(reference.getBundle());
                installer.setInnerComponent(component);
                installer.init();
                installer.install();
                bundles.add(reference.getBundle());
            } catch (Exception e) {
                LOGGER.warn("Error registering deployed component", e);
            }

            //            Preferences prefs = preferencesService.getUserPreferences(name);
            //            ComponentImpl wrapper = new ComponentImpl(reference.getBundle(), componentDesc, component, prefs, autoStart, new SharedLibrary[0]);
            //            wrapper.setListenerRegistry(listenerRegistry);
            //            wrappedComponents.put(name, true);
            //            components.put(name, wrapper);
            //            Dictionary<String, String> props = new Hashtable<String, String>();
            //            props.put(NAME, name);
            //            props.put(TYPE, componentDesc.getType());
            //            registerService(reference.getBundle(), new String[] { Component.class.getName(), ComponentWrapper.class.getName() },
            //                            wrapper, props);
        }
    }

    protected void unregisterDeployedComponent(ServiceReference reference,
            javax.jbi.component.Component component) {
        String name = (String) reference.getProperty(NAME);
        if (name != null) {
            wrappedComponents.remove(name);
            unregisterComponent(getComponent(name));
        }
    }

    public void registerDeployedServiceAssembly(ServiceReference reference, DeployedAssembly assembly) {
        try {
            ServiceAssemblyDesc desc = new ServiceAssemblyDesc();
            desc.setIdentification(new Identification());
            desc.getIdentification().setName(assembly.getName());
            List<ServiceUnitDesc> sus = new ArrayList<ServiceUnitDesc>();
            for (Map.Entry<String, String> unit : assembly.getServiceUnits().entrySet()) {
                ServiceUnitDesc suDesc = new ServiceUnitDesc();
                suDesc.setIdentification(new Identification());
                suDesc.getIdentification().setName(unit.getKey());
                suDesc.setTarget(new Target());
                suDesc.getTarget().setComponentName(unit.getValue());
                sus.add(suDesc);
            }
            desc.setServiceUnits(sus.toArray(new ServiceUnitDesc[sus.size()]));
            Descriptor descriptor = new Descriptor();
            descriptor.setServiceAssembly(desc);

            ServiceAssemblyInstaller installer = new ServiceAssemblyInstaller(this, descriptor, assembly,
                    autoStart);
            installer.setBundle(reference.getBundle());
            try {
                installer.init();
                installer.install();
                installers.put(installer.getBundle(), installer);
            } catch (PendingException e) {
                pendingInstallers.add(installer);
                LOGGER.warn("Requirements not met for JBI artifact in bundle "
                        + OsgiStringUtils.nullSafeNameAndSymName(reference.getBundle()) + ". Installation pending. "
                        + e);
            }
            bundles.add(reference.getBundle());
        } catch (Exception e) {
            LOGGER.error("Error registering deployed service assembly", e);
        }
    }

    public void unregisterDeployedServiceAssembly(ServiceReference reference, DeployedAssembly assembly) {
        // TODO: what to do here ? we should not uninstall the bundle as it's managed externally
        // TODO: but we should maybe stop / shut it down
        ServiceAssemblyImpl sa = getServiceAssembly(assembly.getName());
        if (sa != null) {
            try {
                if (sa.getState() == AbstractLifecycleJbiArtifact.State.Started) {
                    sa.stop(false);
                }
                if (sa.getState() == AbstractLifecycleJbiArtifact.State.Stopped) {
                    sa.shutDown(false, true);
                }
                for (ServiceUnitImpl su : sa.getServiceUnitsList()) {
                    su.undeploy();
                }
            } catch (Exception e) {
                LOGGER.error("Error unregistering deployed service assembly", e);
            } finally {
                unregisterServiceAssembly(sa);
            }
        }
    }

    //===============================================================================
    //
    //   OSGi Services registrations
    //
    //===============================================================================

    /**
     * Register and keep track of an OSGi service
     *
     * @param bundle
     * @param clazz
     * @param service
     * @param props
     */
    protected void registerService(Bundle bundle, String clazz, Object service, Dictionary props) {
        registerService(bundle, new String[] { clazz }, service, props);
    }

    protected void registerService(Bundle bundle, String[] clazz, Object service, Dictionary props) {
        BundleContext context = bundle.getBundleContext() != null ? bundle.getBundleContext() : getBundleContext();
        ServiceRegistration reg = context.registerService(clazz, service, props);
        List<ServiceRegistration> registrations = services.get(bundle);
        if (registrations == null) {
            registrations = new ArrayList<ServiceRegistration>();
            services.put(bundle, registrations);
        }
        registrations.add(reg);
    }

    protected void unregisterServices(Bundle bundle) {
        List<ServiceRegistration> registrations = services.remove(bundle);
        // If unregisterServices is called when the bundle is stopped (RESOLVED),
        // all services have already been unregistered, so no need to iterate
        if (registrations != null && bundle.getState() != Bundle.RESOLVED) {
            for (ServiceRegistration reg : registrations) {
                try {
                    reg.unregister();
                } catch (IllegalStateException e) {
                    // Ignore
                }
            }
        }
    }

}