org.mqnaas.core.impl.BindingManagement.java Source code

Java tutorial

Introduction

Here is the source code for org.mqnaas.core.impl.BindingManagement.java

Source

package org.mqnaas.core.impl;

/*
 * #%L
 * MQNaaS :: Core
 * %%
 * Copyright (C) 2007 - 2015 Fundaci Privada i2CAT, Internet i Innovaci a Catalunya
 * %%
 * This program 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 3 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/lgpl-3.0.html>.
 * #L%
 */

import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.mqnaas.bundletree.IBundleGuard;
import org.mqnaas.bundletree.IClassFilter;
import org.mqnaas.bundletree.IClassListener;
import org.mqnaas.core.api.IApplication;
import org.mqnaas.core.api.IBindingDecider;
import org.mqnaas.core.api.ICapability;
import org.mqnaas.core.api.ICoreModelCapability;
import org.mqnaas.core.api.ICoreProvider;
import org.mqnaas.core.api.IExecutionService;
import org.mqnaas.core.api.IObservationService;
import org.mqnaas.core.api.IResource;
import org.mqnaas.core.api.IResourceManagementListener;
import org.mqnaas.core.api.IRootResource;
import org.mqnaas.core.api.IRootResourceAdministration;
import org.mqnaas.core.api.IRootResourceProvider;
import org.mqnaas.core.api.IService;
import org.mqnaas.core.api.IServiceProvider;
import org.mqnaas.core.api.RootResourceDescriptor;
import org.mqnaas.core.api.Specification;
import org.mqnaas.core.api.Specification.Type;
import org.mqnaas.core.api.annotations.AddsResource;
import org.mqnaas.core.api.annotations.RemovesResource;
import org.mqnaas.core.api.exceptions.ApplicationActivationException;
import org.mqnaas.core.api.exceptions.ApplicationNotFoundException;
import org.mqnaas.core.api.exceptions.CapabilityNotFoundException;
import org.mqnaas.core.api.exceptions.ResourceNotFoundException;
import org.mqnaas.core.api.exceptions.ServiceNotFoundException;
import org.mqnaas.core.impl.dependencies.DependencyManagement;
import org.mqnaas.core.impl.notificationfilter.ResourceMonitoringFilter;
import org.mqnaas.core.impl.resourcetree.ApplicationNode;
import org.mqnaas.core.impl.resourcetree.CapabilityNode;
import org.mqnaas.core.impl.resourcetree.ResourceCapabilityTree;
import org.mqnaas.core.impl.resourcetree.ResourceCapabilityTreeController;
import org.mqnaas.core.impl.resourcetree.ResourceNode;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Predicate;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;

/**
 * <p>
 * <code>BindingManagement</code> is one of the core capabilities of MQNaaS and is the capability providing the most basic services, the management of
 * available services based on the available resources (managed by {@link IResourceManagement}) and the available capability implementations (managed
 * by the platform administrator by adding and removing bundles containing implementations).
 * </p>
 * 
 * <p>
 * It's main responsibilities are:
 * 
 * <ol>
 * <li><u>Manage the capabilities available in the platform.</u> This task has two aspects:
 * <ul>
 * <li>Manage the {@link ICapability}s available, e.g. which capability interfaces are defined</li>
 * <li>Manage the {@link ICapability} implementations available, e.g. which classes implement which {@link ICapability}s.
 * </ul>
 * </li>
 * <li><u>Manage the {@link IApplication}s available.</u> An <code>IApplication</code> is third party code requiring utilizing platform services to
 * provide its functionalities.</li>
 * <li><u>Listen to resource being added and removed (see {@link #resourceAdded(IResource, IApplication, Class)} and
 * {@link #resourceRemoved(IResource, IApplication, Class)}) for details and update the set of services available depending on available capability
 * implementations and resources.</li>
 * </ol>
 * 
 * <p>
 * Some of these services are not available to the majority of platform users, but are reserved for the sole use of the core, e.g.
 * {@link #resourceCreated(IResource, CapabilityInstance)} and {@link #resourceDestroyed(IResource, CapabilityInstance)}.
 * </p>
 */
public class BindingManagement implements IServiceProvider, IResourceManagementListener, IBindingManagement,
        IBindingManagementEventListener, ICoreModelCapability {

    private static final Logger log = LoggerFactory.getLogger(BindingManagement.class);

    // At the moment, this is the home of the MQNaaS resource
    // private MQNaaS mqNaaS;

    // Holds the capabilities bound to the given resource
    private List<CapabilityInstance> boundCapabilities;

    private List<ApplicationNode> applications;

    // Injected core services
    private IExecutionService executionService;
    private IObservationService observationService;
    private IRootResourceAdministration resourceAdministration;
    private IRootResourceProvider resourceProvider;
    private IBindingDecider bindingDecider;
    private IBundleGuard bundleGuard;
    private ICoreProvider coreProvider;

    // internal {@link IClassListener} instance
    private InternalClassListener internalClassListener;

    // Holds known capability implementations that will be checked for compatibility with resources in the system.
    Set<Class<? extends ICapability>> knownCapabilities;
    // Holds known application implementations
    private Set<Class<? extends IApplication>> knownApplications;

    private ResourceCapabilityTree tree;

    private DependencyManagement dependencyManagement;

    // Proxies. Required to execute methods as Services.
    private IBindingManagement bindingManagement;

    public BindingManagement() {

        boundCapabilities = Collections.synchronizedList(new ArrayList<CapabilityInstance>());
        applications = Collections.synchronizedList(new ArrayList<ApplicationNode>());

        knownCapabilities = new HashSet<Class<? extends ICapability>>();
        knownApplications = new HashSet<Class<? extends IApplication>>();

    }

    public void init() throws Exception {

        if (executionService == null || observationService == null || coreProvider == null
                || resourceProvider == null || resourceAdministration == null || bindingDecider == null
                || bundleGuard == null) {
            throw new Exception("Failed to initialize. Required services not set.");
        }

        dependencyManagement = new DependencyManagement();

        // Now activate the resource, the services get visible...
        // Initialize the MQNaaS resource to be able to bind upcoming
        // capability implementations to it...
        IRootResource mqNaaS = resourceAdministration
                .createRootResource(RootResourceDescriptor.create(new Specification(Type.CORE)));

        ResourceNode mqNaaSNode = ResourceCapabilityTreeController.createResourceNode(mqNaaS, null, null);

        // initialize the tree
        tree = new ResourceCapabilityTree();
        tree.setRootResourceNode(mqNaaSNode);

        CapabilityInstance resouceAdministrationCI = new CapabilityInstance(RootResourceManagement.class,
                resourceAdministration);
        CapabilityInstance executionServiceCI = new CapabilityInstance(ExecutionService.class, executionService);
        CapabilityInstance binderDeciderCI = new CapabilityInstance(BinderDecider.class, bindingDecider);
        CapabilityInstance bindingManagementCI = new CapabilityInstance(BindingManagement.class, this);
        CapabilityInstance coreProviderCI = new CapabilityInstance(CoreProvider.class, coreProvider);

        // Do the first binds manually
        bind(new CapabilityNode(resouceAdministrationCI), mqNaaSNode);
        bind(new CapabilityNode(executionServiceCI), mqNaaSNode);
        bind(new CapabilityNode(binderDeciderCI), mqNaaSNode);
        bind(new CapabilityNode(bindingManagementCI), mqNaaSNode);
        bind(new CapabilityNode(coreProviderCI), mqNaaSNode);

        // init proxies
        bindingManagement = (IBindingManagement) bindingManagementCI.getProxy();

        // Initialize the notifications necessary to track resources dynamically
        // Register the service {@link IResourceManagementListener#resourceAdded(IResource, IApplication, Class<? extends IApplication>);}
        // Register the service {@link IResourceManagementListener#resourceRemoved(IResource, IApplication, Class<? extends IApplication>);}
        try {
            // TODO Ensure these observations are treated BEFORE any other observation of resource creation/removal.
            // By now, applications willing to react to resource creation or removal should observe services in IResourceManagementListener.
            // They should not use ResourceMonitoringFilter, as the resource may not be ready to be used.
            observationService.registerObservation(new ResourceMonitoringFilter(AddsResource.class),
                    getService(mqNaaS, "resourceAdded", IResource.class, IApplication.class, Class.class));
            observationService.registerObservation(new ResourceMonitoringFilter(RemovesResource.class),
                    getService(mqNaaS, "resourceRemoved", IResource.class, IApplication.class, Class.class));
        } catch (ServiceNotFoundException e) {
            log.error("Error registering observation!", e);
            throw new ApplicationActivationException(e);
        }
        // register proxies as OSGI services
        BundleContext context = FrameworkUtil.getBundle(BindingManagement.class).getBundleContext();

        // only register with interfaces that extends ICapability (as the proxy)
        String[] bindingManagementIfaces = { IServiceProvider.class.getName(),
                ICoreModelCapability.class.getName() };
        context.registerService(bindingManagementIfaces, bindingManagementCI.getProxy(), null);

        String[] rootResourceManagementIfaces = { IRootResourceAdministration.class.getName(),
                IRootResourceProvider.class.getName() };
        context.registerService(rootResourceManagementIfaces, resouceAdministrationCI.getProxy(), null);

        context.registerService((Class<IExecutionService>) IExecutionService.class,
                (IExecutionService) executionServiceCI.getProxy(), null);
        context.registerService((Class<IBindingDecider>) IBindingDecider.class,
                (IBindingDecider) binderDeciderCI.getProxy(), null);
        context.registerService((Class<ICoreProvider>) ICoreProvider.class,
                (ICoreProvider) coreProviderCI.getProxy(), null);

        // register class listeners
        log.info("Registering as ClassListener with IApplicationClassFilter ICapabilityClassFilter");
        internalClassListener = new InternalClassListener();
        bundleGuard.registerClassListener(new IApplicationClassFilter(), internalClassListener);
        bundleGuard.registerClassListener(new ICapabilityClassFilter(), internalClassListener);
    }

    public void setExecutionService(IExecutionService executionService) {
        log.info("Setting IExecutionService");
        this.executionService = executionService;
    }

    public void setObservationService(IObservationService observationService) {
        log.info("Setting IObservationService");
        this.observationService = observationService;
    }

    public void setBindingDecider(IBindingDecider bindingDecider) {
        log.info("Setting IBindingDecider");
        this.bindingDecider = bindingDecider;
    }

    public void setBundleGuard(IBundleGuard bundleGuard) {
        log.info("Setting IBundleGuard");
        this.bundleGuard = bundleGuard;
    }

    public void setResourceAdministration(IRootResourceAdministration resourceAdministration) {
        log.info("Setting IRootResourceAdministration");
        this.resourceAdministration = resourceAdministration;
    }

    public void setResourceProvider(IRootResourceProvider resourceProvider) {
        log.info("Setting IRootResourceProvider");
        this.resourceProvider = resourceProvider;
    }

    public void setCoreProvider(ICoreProvider coreProvider) {
        log.info("Setting ICoreProvider");
        this.coreProvider = coreProvider;
    }

    ResourceCapabilityTree getResourceCapabilityTree() {
        return tree;
    }

    public static boolean isSupporting(IRootResource resource) {
        return resource.getDescriptor().getSpecification().getType() == Specification.Type.CORE;
    }

    // ///////////////////////////////////////
    // {@link IServiceProvider} implementation
    // ///////////////////////////////////////

    @Override
    public Multimap<Class<? extends IApplication>, IService> getServices(IResource resource) {

        if (resource == null)
            throw new NullPointerException("Can't get services of a null resource.");

        log.debug("Getting all services from resource " + resource.getId());

        Multimap<Class<? extends IApplication>, IService> services = ArrayListMultimap.create();

        for (CapabilityInstance representation : filterResolved(getCapabilityInstancesBoundToResource(resource))) {
            services.putAll(representation.getServices());
        }

        log.trace("Resource " + resource.getId() + " services: " + services.keySet());

        return services;
    }

    @Override
    public IService getService(IResource resource, String name, Class<?>... parameterClasses)
            throws ServiceNotFoundException {

        if ((resource == null || StringUtils.isEmpty(name)))
            throw new NullPointerException("Resource and service name are required to get a specific service.");

        log.debug("Getting service [resource=" + resource.getId() + ",service=" + name + ",params="
                + parameterClasses + "]");

        for (IService service : getServices(resource).values()) {
            if (service.getMetadata().getName().equals(name)) {
                if (Arrays.equals(service.getMetadata().getParameterTypes(), parameterClasses)) {
                    return service;
                }
            }
        }

        throw new ServiceNotFoundException("Service " + name + " of resource " + resource.getId() + " not found.");
    }

    @Override
    public IService getApplicationService(IApplication application, String serviceName,
            Class<?>... parameterClasses) throws ServiceNotFoundException {

        if ((application == null || StringUtils.isEmpty(serviceName)))
            throw new NullPointerException("Application and service name are required to get a specific service.");

        log.debug("Getting service [application=" + application.getClass().getName() + ",service=" + serviceName
                + ",params=" + parameterClasses + "]");

        for (ApplicationNode applicationNode : applications) {
            if (applicationNode.getContent().getInstance().equals(application)) {
                for (Class<? extends IApplication> interfaze : applicationNode.getContent().getServices()
                        .keySet()) {
                    for (IService service : applicationNode.getContent().getServices().get(interfaze)) {
                        if (service.getMetadata().getName().equals(serviceName)) {
                            if (Arrays.equals(service.getMetadata().getParameterTypes(), parameterClasses)) {
                                return service;
                            }
                        }

                    }
                }
            }

        }

        throw new ServiceNotFoundException(
                "Service " + serviceName + " of application " + application + " not found.");
    }

    // //////////////////////////////////////////////////
    // {@link IResourceManagementListener} implementation
    // //////////////////////////////////////////////////

    /**
     * <p>
     * This is the service called by the {@link IResourceManagement} whenever a new {@link IResource} was added to the platform.
     * </p>
     * <p>
     * The {@link BindingManagement} implementation than
     * <ol>
     * <li>checks whether the added {@link IResource} can be bound to any of the currently available capability implementations (using
     * {@link IBindingDecider#shouldBeBound(IResource, Class)}),</li>
     * <li>binds the {@link IResource} and the capability implementation,</li>
     * <li>resolves all capability dependencies, and</li>
     * <li>makes all services available which are defined in <b>all</b> newly resolved capability implementations.</li>
     * </ol>
     * 
     * @param resource
     *            The resource added to the platform
     * @param managedBy
     *            The IApplication managing given resource
     * @param parentInterface
     *            The interface managing given resource in managedBy instance
     * @throws ApplicationNotFoundException
     *             If the application <code>managedBy</code> does not exists in the platform.
     * @throws CapabilityNotFoundException
     *             If the capability <code>managedBy</code> does not exists in the platform.
     */
    @Override
    public void resourceAdded(IResource resource, IApplication managedBy,
            Class<? extends IApplication> parentInterface)
            throws CapabilityNotFoundException, ApplicationNotFoundException {

        if (resource == null || managedBy == null || parentInterface == null)
            throw new NullPointerException(
                    "Resource, application instance managing it, and the application interface are required to bind a resource.");

        log.info("Resource " + resource.getId() + " added.");
        log.debug("Added-resource information: [resource=" + resource.getId() + "managedBy="
                + managedBy.getClass().getName() + ",parentInterface=" + parentInterface.getName() + "]");

        ResourceNode resourceNode = ResourceCapabilityTreeController
                .getResourceNodeWithContent(tree.getRootResourceNode(), resource);

        if (resourceNode == null) {
            ApplicationNode parent = findApplicationNode(managedBy);

            bindingManagement.addResourceNode(new ResourceNode(resource, parent, parentInterface), parent,
                    parentInterface);
        } else
            log.warn("Resource " + resource.getId() + " already bound. Skipping it.");

    }

    /**
     * <p>
     * This is the service called by the {@link IResourceManagement} whenever a new {@link IResource} was removed from the platform.
     * </p>
     * <p>
     * The {@link BindingManagement} implementation than
     * 
     * <ol>
     * <li>unbinds the {@link IResource} from all its capability implementations,</li>
     * <li>unresolves all capability implementation dependencies, and</li>
     * <li>removes all services which were provided by the given resource.</li>
     * </ol>
     * 
     * @param resource
     *            The resource removed from the platform
     * @param managedBy
     *            The ICapability managing given resource
     * @param parentInterface
     *            The interface managing given resource in managedBy instance (UNUSED)
     */
    @Override
    public void resourceRemoved(IResource resource, IApplication managedBy,
            Class<? extends IApplication> parentInterface) {

        try {
            ApplicationNode parent = findApplicationNode(managedBy);

            ResourceNode toRemove = ResourceCapabilityTreeController.getChidrenWithContent(parent, resource);
            if (toRemove == null)
                throw new ResourceNotFoundException("Resource is not provided by given application");

            bindingManagement.removeResourceNode(toRemove, parent);

        } catch (ApplicationNotFoundException e) {
            log.error("No parent found!", e);
        } catch (CapabilityNotFoundException e) {
            log.error("No parent found!", e);
        } catch (ResourceNotFoundException e) {
            log.error("No resource to be removed found!", e);
        }
    }

    // /////////////////////////////////////////////////
    // {@link IBindingManagementEventListener} implementation
    // /////////////////////////////////////////////////

    @Override
    public void resourceAdded(ResourceNode added, ApplicationNode managedBy) {
        // Bind matching capabilities
        for (Class<? extends ICapability> capabilityClass : knownCapabilities) {
            if (bindingDecider.shouldBeBound(added.getContent(), capabilityClass)) {
                if (!ResourceCapabilityTreeController.isBound(capabilityClass, added)
                        && ResourceCapabilityTreeController.canBind(capabilityClass, added)) {
                    bindingManagement.bind(new CapabilityNode(new CapabilityInstance(capabilityClass)), added);
                } else {
                    if (ResourceCapabilityTreeController.isBound(capabilityClass, added))
                        log.info("Already bound " + capabilityClass + " to resource " + added.getContent());
                    else
                        log.info("Unable to bind " + capabilityClass + " to resource " + added.getContent());
                }
            }
        }
    }

    @Override
    public void resourceRemoved(ResourceNode removed, ApplicationNode wasManagedBy) {
        // Nothing to do, the resource is already removed
    }

    @Override
    public void capabilityInstanceBound(CapabilityNode bound, ResourceNode boundTo) {
        // add bound capability in dependencyManagement. It will resolve it and those depending on it, an activate them if applicable.
        if (bound == null)
            throw new NullPointerException(
                    "Error adding application to the system: Tried to bound a null capability!");
        log.debug("Adding capability to the system: " + bound.getContent());
        dependencyManagement.addApplicationInTheSystem(bound.getContent());
        log.debug("Added capability to the system: " + bound.getContent());
    }

    @Override
    public void capabilityInstanceUnbound(CapabilityNode unbound, ResourceNode wasBoundTo) {
        // remove unbound capability from dependencyManagement. It will unresolve it and those depending on it, an deactivate them if applicable.

        if (unbound == null)
            throw new NullPointerException(
                    "Error removing application from the system: Tried to unbound a null capability!");

        log.debug("Removing capability from the system: " + unbound.getContent());
        dependencyManagement.removeApplicationInTheSystem(unbound.getContent());
        log.debug("Removed capability from the system: " + unbound.getContent());

    }

    @Override
    public void applicationInstanceAdded(ApplicationInstance added) {
        // add added application in dependencyManagement. It will resolve it and those depending on it, an activate them if applicable.
        log.debug("Adding application to the system: " + added);
        dependencyManagement.addApplicationInTheSystem(added);
        log.debug("Added application to the system: " + added);
    }

    @Override
    public void applicationInstanceRemoved(ApplicationInstance removed) {
        // remove application from dependencyManagement. It will unresolve it and those depending on it, an deactivate them if applicable.
        log.debug("Removing application from the system: " + removed);
        dependencyManagement.removeApplicationInTheSystem(removed);
        log.debug("Removed application from the system: " + removed);

    }

    // ////////////////////////////////////////////////////////////////////////////////////
    // {@link ICapability} and {@link IApplication} {@link IClassFilter} implementations //
    // ////////////////////////////////////////////////////////////////////////////////////
    private class ICapabilityClassFilter implements IClassFilter {

        @Override
        public boolean filter(Class<?> clazz) {
            // retrieve only instantiable classes
            return ICapability.class.isAssignableFrom(clazz) && !clazz.isInterface()
                    && !Modifier.isAbstract(clazz.getModifiers());
        }

    }

    private class IApplicationClassFilter implements IClassFilter {

        @Override
        public boolean filter(Class<?> clazz) {
            // retrieve only instantiable classes
            return IApplication.class.isAssignableFrom(clazz) && !clazz.isInterface()
                    && !Modifier.isAbstract(clazz.getModifiers());
        }

    }

    // /////////////////////////////////////////
    // {@link IClassListener} implementation //
    // /////////////////////////////////////////
    private class InternalClassListener implements IClassListener {

        @Override
        // safe-casting of classes, checked previously
        @SuppressWarnings("unchecked")
        public void classEntered(Class<?> clazz) {
            log.debug("Received classEntered event for class: " + clazz.getCanonicalName());
            if (ICapability.class.isAssignableFrom(clazz)) {
                capabilitiesAdded(
                        Arrays.<Class<? extends ICapability>>asList((Class<? extends ICapability>) clazz));
            } else if (IApplication.class.isAssignableFrom(clazz)) {
                applicationsAdded(
                        Arrays.<Class<? extends IApplication>>asList((Class<? extends IApplication>) clazz));
            } else {
                log.error(
                        "Unknown ClassListener classEntered event received from class " + clazz.getCanonicalName());
            }
        }

        @Override
        // safe-casting of classes, checked previously
        @SuppressWarnings("unchecked")
        public void classLeft(Class<?> clazz) {
            log.debug("Received classLeft event for class: " + clazz.getCanonicalName());
            if (ICapability.class.isAssignableFrom(clazz)) {
                capabilitiesRemoved(
                        Arrays.<Class<? extends ICapability>>asList((Class<? extends ICapability>) clazz));
            } else if (IApplication.class.isAssignableFrom(clazz)) {
                applicationsRemoved(
                        Arrays.<Class<? extends IApplication>>asList((Class<? extends IApplication>) clazz));
            } else {
                log.error("Unknown ClassListener classLeft event received from class " + clazz.getCanonicalName());
            }
        }

    }

    // /////////////////////////////////////////
    // {@link IBindingManagement} implementation
    // /////////////////////////////////////////

    @Override
    public void addResourceNode(ResourceNode resource, ApplicationNode managedBy,
            Class<? extends IApplication> parentInterface) {

        if (resource == null || managedBy == null || parentInterface == null)
            throw new NullPointerException(
                    "Resource, application instance managing it, and the application interface are required to add a resource node.");

        log.trace("Adding resource node:[resourceNode=" + resource + ",managedBy=" + managedBy + ",parentInterface="
                + parentInterface.getClass().getName() + "]");

        // 1. Update the model
        ResourceCapabilityTreeController.addResourceNode(resource, managedBy, parentInterface);

        // 2. Notify this class about the addition
        // (it will attempt to bind available capabilities to the new resource)
        resourceAdded(resource, managedBy);
    }

    @Override
    public void removeResourceNode(ResourceNode toRemove, ApplicationNode managedBy) {

        log.trace("Removing resource node:[resourceNode=" + toRemove + ",managedBy=" + managedBy + "]");

        // 1. Remove on cascade (remove capabilities bound to this resource)
        // Notice recursivity between removeResource and unbind methods
        for (CapabilityNode bound : toRemove.getChildren()) {
            bindingManagement.unbind(bound, toRemove);
        }

        // 2. Update the model
        ResourceCapabilityTreeController.removeResourceNode(toRemove);

        // 3. Notify this class about the resource removal
        resourceRemoved(toRemove, managedBy);
    }

    @Override
    public void bind(CapabilityNode toBind, ResourceNode toBindTo) {

        if (toBind == null || toBindTo == null)
            throw new NullPointerException(
                    "Error binding capability and resource: Capability nor resource can't be null!");

        log.info("Binding " + toBind.getContent() + " to resource " + toBindTo.getContent());

        // ResourceNode resourceNode = ResourceCapabilityTreeController.getResourceNode(toBindTo);
        // if (resourceNode == null)
        // throw new ResourceNotFoundException("Unknown resource");

        // 1. Bind the representation to the resource
        toBind.getContent().bind(toBindTo.getContent());

        // 2. Update the model
        boundCapabilities.add(toBind.getContent());
        ResourceCapabilityTreeController.addCapabilityNode(toBind, toBindTo);

        // 3. Announce this class about the binding
        // (it will resolve the newly bound capabilityInstance)
        capabilityInstanceBound(toBind, toBindTo);
    }

    @Override
    public void unbind(CapabilityNode toUnbind, ResourceNode boundTo) {

        if (toUnbind == null || boundTo == null)
            throw new NullPointerException(
                    "Error unbinding capability and resource: Capability nor resource can't be null!");

        log.info("Unbinding " + toUnbind.getContent() + " bound to resource " + boundTo.getContent());

        // ResourceNode resourceNode = ResourceCapabilityTreeController.getResourceNode(boundTo);
        // if (resourceNode == null)
        // throw new ResourceNotFoundException("Unknown resource");
        //
        // if (!resourceNode.getChildren().contains(toUnbind))
        // throw new CapabilityInstanceNotFoundException(toUnbind.getContent());

        // 1. Remove on cascade (resources provided by toUnbind capability)
        // Notice recursivity between unbind and removeResource methods
        for (ResourceNode provided : toUnbind.getChildren()) {
            bindingManagement.removeResourceNode(provided, toUnbind);
        }

        // 2. Update the model
        ResourceCapabilityTreeController.removeCapabilityNode(toUnbind);
        boundCapabilities.remove(toUnbind.getContent());

        // 3. Announce this class about the unbinding
        // (it will unresolve the unbound capabilityInstance)
        capabilityInstanceUnbound(toUnbind, boundTo);

        // 4. Unbind the representation to the resource
        toUnbind.getContent().unbind();
    }

    @Override
    public void addApplicationInstance(ApplicationInstance applicationInstance) {

        log.info("Adding application " + applicationInstance);

        applications.add(new ApplicationNode(applicationInstance));

        applicationInstanceAdded(applicationInstance);
    }

    @Override
    public void removeApplicationInstance(ApplicationInstance applicationInstance) {

        log.info("Removing application " + applicationInstance);

        ApplicationNode found = null;
        for (ApplicationNode node : applications) {
            if (node.getContent().equals(applicationInstance)) {
                found = node;
                break;
            }
        }

        if (found != null) {
            applications.remove(found);
            applicationInstanceRemoved(found.getContent());
        }
    }

    // ///////////////////////////
    // Package-protected callbacks
    // ///////////////////////////

    /**
     * Package-protected callback: Called when application implementations (classes) are available.
     * 
     * @param capabilityClasses
     */
    void applicationsAdded(Collection<Class<? extends IApplication>> applicationClasses) {
        if (applicationClasses.isEmpty())
            return;

        knownApplications.addAll(applicationClasses);

        for (Class<? extends IApplication> applicationClass : applicationClasses) {
            ApplicationInstance application = new ApplicationInstance(applicationClass);

            if (bindingManagement != null) {
                bindingManagement.addApplicationInstance(application);
            } else {
                // calling the method directly without using a service
                // listeners will not be notified
                addApplicationInstance(application);
            }

        }

        printAvailableApplications();
    }

    /**
     * Package-protected callback: Called when application implementations (classes) are no longer available.
     * 
     * @param capabilityClasses
     */
    void applicationsRemoved(Collection<Class<? extends IApplication>> applicationClasses) {
        if (applicationClasses.isEmpty())
            return;

        knownApplications.removeAll(applicationClasses);

        Set<ApplicationInstance> appInstancesToBeRemoved = new HashSet<ApplicationInstance>();

        // collect ApplicationInstances to be removed using removed classes
        for (ApplicationNode applicationNode : applications) {
            ApplicationInstance application = applicationNode.getContent();
            if (applicationClasses.contains(application.getClazz()))
                appInstancesToBeRemoved.add(application);
        }

        // remove collected application instances
        for (ApplicationInstance applicationInstance : appInstancesToBeRemoved) {
            if (bindingManagement != null) {
                bindingManagement.removeApplicationInstance(applicationInstance);
            } else {
                // calling the method directly without using a service
                // listeners will not be notified
                removeApplicationInstance(applicationInstance);
            }
        }

        printAvailableApplications();
    }

    /**
     * Package-protected callback: Called when new capability implementations (classes) are available.
     * 
     * @param capabilityClasses
     */
    void capabilitiesAdded(Collection<Class<? extends ICapability>> capabilityClasses) {
        if (capabilityClasses.isEmpty())
            return;

        knownCapabilities.addAll(capabilityClasses);

        // Establish matches
        for (ResourceNode resourceNode : ResourceCapabilityTreeController
                .getAllResourceNodes(tree.getRootResourceNode())) {
            for (Class<? extends ICapability> capabilityClass : capabilityClasses) {
                if (bindingDecider.shouldBeBound(resourceNode.getContent(), capabilityClass)) {
                    if (!ResourceCapabilityTreeController.isBound(capabilityClass, resourceNode)
                            && ResourceCapabilityTreeController.canBind(capabilityClass, resourceNode))
                        if (bindingManagement != null) {
                            bindingManagement.bind(new CapabilityNode(new CapabilityInstance(capabilityClass)),
                                    resourceNode);
                        } else {
                            // calling the method directly without using a service
                            // listeners will not be notified
                            bind(new CapabilityNode(new CapabilityInstance(capabilityClass)), resourceNode);
                        }
                }
            }
        }
    }

    /**
     * Package-protected callback: Called when capability implementations (classes) are no longer available.
     * 
     * @param capabilityClasses
     */
    void capabilitiesRemoved(Collection<Class<? extends ICapability>> capabilityClasses) {
        if (capabilityClasses.isEmpty())
            return;

        knownCapabilities.removeAll(capabilityClasses);

        // unbind logic
        for (CapabilityNode capabilityNode : ResourceCapabilityTreeController
                .getAllCapabilityNodes(tree.getRootResourceNode())) {
            if (capabilityClasses.contains(capabilityNode.getContent().getClazz())) {

                if (bindingManagement != null) {
                    bindingManagement.unbind(capabilityNode, capabilityNode.getParent());
                } else {
                    // calling the method directly without using a service
                    // listeners will not be notified
                    unbind(capabilityNode, capabilityNode.getParent());
                }
            }
        }

    }

    // ///////////////
    // private methods
    // ///////////////

    List<CapabilityInstance> getAllCapabilityInstances() {
        return boundCapabilities;
    }

    List<ApplicationInstance> getAllApplicationInstances() {
        List<ApplicationInstance> applicationInstances = new ArrayList<ApplicationInstance>(applications.size());
        for (ApplicationNode node : applications) {
            applicationInstances.add(node.getContent());
        }
        return applicationInstances;
    }

    List<ApplicationInstance> getAllCapabilityAndApplicationInstances() {
        List<ApplicationInstance> capabsAndApps = getAllApplicationInstances();
        capabsAndApps.addAll(getAllCapabilityInstances());
        return capabsAndApps;
    }

    List<IResource> getAllResources() {
        List<ResourceNode> allResourceNodes = ResourceCapabilityTreeController
                .getAllResourceNodes(tree.getRootResourceNode());
        List<IResource> allResources = new ArrayList<IResource>(allResourceNodes.size());
        for (ResourceNode node : allResourceNodes) {
            allResources.add(node.getContent());
        }
        return allResources;
    }

    private Iterable<CapabilityInstance> filterResolved(Iterable<CapabilityInstance> toFilter) {
        Predicate<CapabilityInstance> isResolved = new Predicate<CapabilityInstance>() {
            @Override
            public boolean apply(CapabilityInstance ci) {
                return ci.isResolved();
            }
        };
        return Iterables.filter(toFilter, isResolved);
    }

    List<CapabilityInstance> getCapabilityInstancesBoundToResource(IResource resource) {

        ResourceNode resourceNode = ResourceCapabilityTreeController
                .getResourceNodeWithContent(tree.getRootResourceNode(), resource);
        if (resourceNode == null)
            return new ArrayList<CapabilityInstance>(0);

        List<CapabilityInstance> bound = new ArrayList<CapabilityInstance>();
        for (CapabilityNode capabNode : resourceNode.getChildren()) {
            bound.add(capabNode.getContent());
        }
        return bound;
    }

    List<IResource> getResourcesProvidedByCapabilityInstance(CapabilityInstance capabilityInstance) {

        CapabilityNode capab = ResourceCapabilityTreeController
                .getCapabilityNodeWithContent(tree.getRootResourceNode(), capabilityInstance);
        if (capab == null)
            return new ArrayList<IResource>(0);

        List<IResource> resources = new ArrayList<IResource>(capab.getChildren().size());
        for (ResourceNode resourceNode : capab.getChildren()) {
            resources.add(resourceNode.getContent());
        }
        return resources;
    }

    // ////////////////
    // Printing methods
    // ////////////////

    public void printAvailableApplications() {
        StringBuffer sb = new StringBuffer();

        sb.append("\nAVAILABLE APPLICATIONS -------------------------------------------\n");

        for (ApplicationInstance representation : getAllApplicationInstances()) {
            sb.append(representation + "\n");
        }

        sb.append("------------------------------------------------------------------\n");

        log.trace(sb.toString());
    }

    // @Override
    public void printAvailableServices() {
        StringBuffer sb = new StringBuffer();

        sb.append("\nAVAILABLE SERVICES -----------------------------------------------\n");

        for (IResource resource : resourceProvider.getRootResources()) {

            sb.append("Resource " + resource + "\n");

            for (CapabilityInstance representation : getCapabilityInstancesBoundToResource(resource)) {

                sb.append(representation + "\n");

                for (Class<? extends IApplication> capability : representation.getServices().keySet()) {
                    sb.append("  Services of " + capability + "\n");

                    sb.append("    ");
                    int index = 0;
                    for (IService service : representation.getServices().values()) {
                        if (index > 0)
                            sb.append(", ");
                        sb.append(service);
                        index++;
                    }
                    sb.append("\n");
                }
            }

            sb.append("\n");
        }

        sb.append("------------------------------------------------------------------\n");

        log.trace(sb.toString());
    }

    @Override
    public void activate() throws ApplicationActivationException {
        log.info("Initializing BindingMangement.");
        log.info("Initialized BindingMangement.");
    }

    @Override
    public void deactivate() {
        log.info("Removing BindingMangement.");
        log.info("Removed BindingMangement.");
    }

    /**
     * Returns the {@link ApplicationNode} of the given {@link IApplication} instance.
     * 
     * @param application
     *            Application which {@link ApplicationNode} is to be retrieved.
     * @return The {@link ApplicationNode} of the {@link IApplication} instance
     * @throws CapabilityNotFoundException
     *             If <code>application</code> is a {@link ICapability} instance but it's an unknown capability.
     * @throws ApplicationNotFoundException
     *             If <code>application</code> is a {@link IApplication} instance but it's an unknown application. *
     * 
     */
    private ApplicationNode findApplicationNode(IApplication application)
            throws CapabilityNotFoundException, ApplicationNotFoundException {
        ApplicationNode toReturn = null;
        if (application instanceof ICapability) {
            toReturn = ResourceCapabilityTreeController
                    .getCapabilityNodeWithContentCapability(tree.getRootResourceNode(), (ICapability) application);
            if (toReturn == null)
                throw new CapabilityNotFoundException((ICapability) application, "Unknown capability");
        } else {
            for (ApplicationNode applicationNode : applications) {
                if (applicationNode.getContent().getInstance().equals(application)) {
                    toReturn = applicationNode;
                    break;
                }
            }
            if (toReturn == null)
                throw new ApplicationNotFoundException(application, "Unknown application");

        }

        return toReturn;

    }

    @Override
    public IRootResource getRootResource(IResource resource) throws IllegalArgumentException {
        ResourceNode resourceNode = ResourceCapabilityTreeController.getRootResourceNodeFromResource(tree,
                resource);
        if (resourceNode == null) {
            log.error("No IRootResource found for resource: " + resource);
            throw new IllegalArgumentException("No IRootResource found!");
        }
        return (IRootResource) resourceNode.getContent();
    }

    @Override
    public Collection<Class<? extends ICapability>> getCapabilities(IResource resource) {

        Collection<Class<? extends ICapability>> resourceCapabilities = new ArrayList<Class<? extends ICapability>>();

        Iterable<CapabilityInstance> capabilities = filterResolved(getCapabilityInstancesBoundToResource(resource));
        for (CapabilityInstance capabilityInstance : capabilities)
            resourceCapabilities.addAll(capabilityInstance.getCapabilities());

        return resourceCapabilities;
    }

    @Override
    // safe-casting of classes, checked previously
    @SuppressWarnings("unchecked")
    public <C extends ICapability> C getCapability(IResource resource, Class<C> capabilityClass)
            throws CapabilityNotFoundException {
        return (C) getCapabilityInternalInstance(resource, capabilityClass).getProxy();
    }

    @Override
    // safe-casting of classes, checked previously
    @SuppressWarnings("unchecked")
    public <C extends ICapability> C getCapabilityInstance(IResource resource, Class<C> capabilityClass)
            throws CapabilityNotFoundException {
        return (C) getCapabilityInternalInstance(resource, capabilityClass).getInstance();
    }

    private CapabilityInstance getCapabilityInternalInstance(IResource resource,
            Class<? extends ICapability> capabilityClass) throws CapabilityNotFoundException {

        Iterable<CapabilityInstance> resourceCapabilities = filterResolved(
                getCapabilityInstancesBoundToResource(resource));
        for (CapabilityInstance capabilityInstance : resourceCapabilities)
            if (capabilityInstance.getCapabilities().contains(capabilityClass))
                return capabilityInstance;

        throw new CapabilityNotFoundException("Resource " + resource.getId()
                + " does not contain any resolved capability of type " + capabilityClass.getName());
    }

}