Package org.apache.felix.ipojo.composite.service.provides

Source Code of org.apache.felix.ipojo.composite.service.provides.ProvidedServiceHandler

/*
* 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.felix.ipojo.composite.service.provides;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Dictionary;
import java.util.List;
import java.util.Properties;

import org.apache.felix.ipojo.ComponentInstance;
import org.apache.felix.ipojo.ConfigurationException;
import org.apache.felix.ipojo.Factory;
import org.apache.felix.ipojo.HandlerFactory;
import org.apache.felix.ipojo.HandlerManager;
import org.apache.felix.ipojo.MissingHandlerException;
import org.apache.felix.ipojo.PolicyServiceContext;
import org.apache.felix.ipojo.UnacceptableConfiguration;
import org.apache.felix.ipojo.architecture.ComponentTypeDescription;
import org.apache.felix.ipojo.architecture.HandlerDescription;
import org.apache.felix.ipojo.composite.CompositeHandler;
import org.apache.felix.ipojo.composite.instance.InstanceHandler;
import org.apache.felix.ipojo.composite.service.instantiator.ServiceDependencyHandler;
import org.apache.felix.ipojo.composite.service.instantiator.ServiceImporter;
import org.apache.felix.ipojo.composite.service.instantiator.SvcInstance;
import org.apache.felix.ipojo.metadata.Element;
import org.apache.felix.ipojo.parser.ManifestMetadataParser;
import org.apache.felix.ipojo.parser.ParseException;
import org.apache.felix.ipojo.util.DependencyModel;
import org.apache.felix.ipojo.util.DependencyStateListener;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Filter;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;

/**
* Composite Provided Service Handler.
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
public class ProvidedServiceHandler extends CompositeHandler implements DependencyStateListener {

    /**
     * External context.
     */
    private BundleContext m_context;
   
    /**
     * List of "available" services in the internal context.
     */
    private List m_services = new ArrayList();

    /**
     * List of exporters.
     */
    private List m_exporters = new ArrayList();

    /**
     * List of managed services.
     */
    private List m_managedServices = new ArrayList();

    /**
     * List of component type.
     */
    private List m_types;
   
    /**
     * Handler description.
     */
    private ProvidedServiceHandlerDescription m_description;

    /**
     * Initialize the component type.
     * @param desc : component type description to populate.
     * @param metadata : component type metadata.
     * @throws ConfigurationException : metadata are incorrect.
     * @see org.apache.felix.ipojo.Handler#initializeComponentFactory(org.apache.felix.ipojo.architecture.ComponentTypeDescription, org.apache.felix.ipojo.metadata.Element)
     */
    public void initializeComponentFactory(ComponentTypeDescription desc, Element metadata) throws ConfigurationException {
        Element[] provides = metadata.getElements("provides");
        for (int i = 0; i < provides.length; i++) {
            String action = provides[i].getAttribute("action");
            if (action == null) {
                throw new ConfigurationException("Invalid composition service providing : no specified action");
            } else if (action.equalsIgnoreCase("implement")) {
                String spec = provides[i].getAttribute("specification");
                if (spec == null) {
                    throw new ConfigurationException("Malformed provides : the specification attribute is mandatory");
                } else {
                    desc.addProvidedServiceSpecification(spec);
                }
            } else if (action.equalsIgnoreCase("export")) {
                String spec = provides[i].getAttribute("specification");
                if (spec == null) {
                    throw new ConfigurationException("Malformed exports - Missing the specification attribute");
                } else {
                    desc.addProvidedServiceSpecification(spec);
                }
            } else {
                throw new ConfigurationException("Invalid composition service providing : unknown action " + action);
            }
        }
    }

    /**
     * Configure the handler.
     * @param metadata : the metadata of the component
     * @param configuration : the instance configuration
     * @throws ConfigurationException  : the exporter cannot be created
     * @see org.apache.felix.ipojo.CompositeHandler#configure(org.apache.felix.ipojo.CompositeManager, org.apache.felix.ipojo.metadata.Element, java.util.Dictionary)
     */
    public void configure(Element metadata, Dictionary configuration) throws ConfigurationException {
        m_context = getCompositeManager().getContext();

        Element[] provides = metadata.getElements("provides", "");
        for (int i = 0; i < provides.length; i++) {
            String action = provides[i].getAttribute("action");
            if (action.equalsIgnoreCase("implement")) {
                ProvidedService svc = new ProvidedService(this, provides[i], Integer.toString(i));
                m_managedServices.add(svc);
            } else if (action.equalsIgnoreCase("export")) {
                boolean optional = false;
                boolean aggregate = false;
                String specification = provides[i].getAttribute("specification");

                String filter = "(objectClass=" + specification + ")";

                String opt = provides[i].getAttribute("optional");
                optional = opt != null && opt.equalsIgnoreCase("true");

                String agg = provides[i].getAttribute("aggregate");
                aggregate = agg != null && agg.equalsIgnoreCase("true");

                String givenFilter = provides[i].getAttribute("filter");
                if (givenFilter != null) {
                    filter = "(&" + filter + givenFilter + ")"; //NOPMD
                }

                Filter fil = null;
                try {
                    fil = m_context.createFilter(filter);
                } catch (InvalidSyntaxException e) {
                    throw new ConfigurationException("An exporter filter is invalid " + filter + " : " + e.getMessage());
                }

                Comparator cmp = DependencyModel.getComparator(provides[i], m_context);
                int policy = DependencyModel.getPolicy(provides[i]);
                Class spec = DependencyModel.loadSpecification(specification, m_context);

                ServiceExporter imp = new ServiceExporter(spec, fil, aggregate, optional, cmp, policy, getCompositeManager().getServiceContext(), m_context, this, getCompositeManager());
                m_exporters.add(imp);
            } // Others case cannot happen. The test was already made during the factory initialization.
        }
       
        m_description = new ProvidedServiceHandlerDescription(this, m_managedServices, m_exporters);

    }

    /**
     * Start method.
     * Start all managed provided service.
     * @see org.apache.felix.ipojo.CompositeHandler#start()
     */
    public void start() {
        // Compute imports and instances
        computeAvailableServices();
        computeAvailableTypes();

        for (int i = 0; i < m_managedServices.size(); i++) {
            ProvidedService svc = (ProvidedService) m_managedServices.get(i);
            try {
                checkServiceSpecification(svc);
                svc.start();
            } catch (CompositionException e) {
                error("Cannot start the provided service handler", e);
                setValidity(false);
                return;
            }
        }

        for (int i = 0; i < m_exporters.size(); i++) {
            ServiceExporter exp = (ServiceExporter) m_exporters.get(i);
            exp.start();
        }

        isHandlerValid();
    }

    /**
     * Stop method.
     * Stop all managed provided service.
     * @see org.apache.felix.ipojo.CompositeHandler#stop()
     */
    public void stop() {
        for (int i = 0; i < m_managedServices.size(); i++) {
            ProvidedService svc = (ProvidedService) m_managedServices.get(i);
            svc.stop();
        }

        for (int i = 0; i < m_exporters.size(); i++) {
            ServiceExporter exp = (ServiceExporter) m_exporters.get(i);
            exp.stop();
        }
    }

    /**
     * Check the handler validity.
     * @see org.apache.felix.ipojo.CompositeHandler#isValid()
     */
    private void isHandlerValid() {
        for (int i = 0; i < m_exporters.size(); i++) {
            ServiceExporter exp = (ServiceExporter) m_exporters.get(i);
            if (exp.getState() != DependencyModel.RESOLVED) {
                setValidity(false);
                return;
            }
        }

        setValidity(true);
    }

    /**
     * Handler state changed.
     * @param state : the new instance state.
     * @see org.apache.felix.ipojo.CompositeHandler#stateChanged(int)
     */
    public void stateChanged(int state) {
        if (state == ComponentInstance.INVALID) {
            for (int i = 0; i < m_managedServices.size(); i++) {
                ProvidedService svc = (ProvidedService) m_managedServices.get(i);
                svc.unregister();
            }
            return;
        }

        // If the new state is VALID => register all the services
        if (state == ComponentInstance.VALID) {
            for (int i = 0; i < m_managedServices.size(); i++) {
                ProvidedService svc = (ProvidedService) m_managedServices.get(i);
                svc.register();
            }
            return;
        }
    }

    /**
     * Notify the handler that an exporter becomes invalid.
     *
     * @param exporter : the implicated exporter.
     */
    public void invalidate(DependencyModel exporter) {
        // An export is no more valid
        if (getValidity()) {
            setValidity(false);
        }

    }

    /**
     * Notify the handler that an exporter becomes valid.
     *
     * @param exporter : the implicated exporter.
     */
    public void validate(DependencyModel exporter) {
        // An import becomes valid
        if (!getValidity()) {
            isHandlerValid();
        }
    }

    /**
     * Build the list of available specification.
     * @return the list of available specification.
     */
    protected List getSpecifications() {
        return m_services;
    }

    /**
     * Build the list of available specifications.
     */
    private void computeAvailableServices() {
        // Get instantiated services :
        ServiceDependencyHandler handler = (ServiceDependencyHandler) getHandler(HandlerFactory.IPOJO_NAMESPACE + ":subservice");

        for (int i = 0; handler != null && i < handler.getInstances().size(); i++) {
            SvcInstance svc = (SvcInstance) handler.getInstances().get(i);
            String itf = svc.getServiceSpecification();
            boolean agg = svc.isAggregate();
            boolean opt = svc.isOptional();

            SpecificationMetadata specMeta = new SpecificationMetadata(itf, m_context, agg, opt, this);
            m_services.add(specMeta);
        }

        for (int i = 0; handler != null && i < handler.getRequirements().size(); i++) {
            ServiceImporter imp = (ServiceImporter) handler.getRequirements().get(i);
            String itf = imp.getSpecification().getName();
            boolean agg = imp.isAggregate();
            boolean opt = imp.isOptional();

            SpecificationMetadata specMeta = new SpecificationMetadata(itf, m_context, agg, opt, this);
            m_services.add(specMeta);
        }
    }

    /**
     * Check composite requirement against service specification requirement is available.
     * @param svc : the provided service to check
     * @throws CompositionException : occurs if the specification field of the service specification cannot be analyzed correctly.
     */
    private void checkServiceSpecification(ProvidedService svc) throws CompositionException {
        try {
            Class spec = m_context.getBundle().loadClass(svc.getSpecification());
            Field specField = spec.getField("specification");
            Object object = specField.get(null);
            if (object instanceof String) {
                Element specification = ManifestMetadataParser.parse((String) object);
                Element[] reqs = specification.getElements("requires");
                for (int j = 0; reqs != null && j < reqs.length; j++) {
                    ServiceImporter imp = getAttachedRequirement(reqs[j]);
                    if (imp != null) {
                        // Fix service-level dependency flag
                        imp.setServiceLevelDependency();
                    }
                    checkRequirement(imp, reqs[j]);
                }
            } else {
                error("[" + getCompositeManager().getInstanceName() + "] The specification field of the service specification " + svc.getSpecification() + " needs to be a String");
                throw new CompositionException("Service Specification checking failed : The specification field of the service specification " + svc.getSpecification() + " needs to be a String");
            }
        } catch (NoSuchFieldException e) {
            return; // No specification field
        } catch (ClassNotFoundException e) {
            error("[" + getCompositeManager().getInstanceName() + "] The service specification " + svc.getSpecification() + " cannot be load");
            throw new CompositionException("The service specification " + svc.getSpecification() + " cannot be load : " + e.getMessage());
        } catch (IllegalArgumentException e) {
            error("[" + getCompositeManager().getInstanceName() + "] The field 'specification' of the service specification " + svc.getSpecification() + " is not accessible : " + e.getMessage());
            throw new CompositionException("The field 'specification' of the service specification " + svc.getSpecification() + " is not accessible : " + e.getMessage());
        } catch (IllegalAccessException e) {
            error("[" + getCompositeManager().getInstanceName() + "] The field 'specification' of the service specification " + svc.getSpecification() + " is not accessible : " + e.getMessage());
            throw new CompositionException("The field 'specification' of the service specification " + svc.getSpecification() + " is not accessible : " + e.getMessage());
        } catch (ParseException e) {
            error("[" + getCompositeManager().getInstanceName() + "] The field 'specification' of the service specification " + svc.getSpecification() + " does not contain a valid String : " + e.getMessage());
            throw new CompositionException("The field 'specification' of the service specification " + svc.getSpecification() + " does not contain a valid String : " + e.getMessage());
        }
    }

    /**
     * Look for the implementation (i.e. composite) requirement for the given service-level requirement metadata.
     * @param element : the service-level requirement metadata
     * @return the ServiceImporter object, null if not found or if the DependencyHandler is not plugged to the instance
     */
    private ServiceImporter getAttachedRequirement(Element element) {
        ServiceDependencyHandler handler = (ServiceDependencyHandler) getHandler(HandlerFactory.IPOJO_NAMESPACE + ":subservice");
        if (handler == null) { return null; }

        String identity = element.getAttribute("id");
        if (identity != null) {
            // Look for dependency Id
            for (int i = 0; i < handler.getRequirements().size(); i++) {
                ServiceImporter imp = (ServiceImporter) handler.getRequirements().get(i);
                if (imp.getId().equals(identity)) { return imp; }
            }
        }

        // If not found or no id, look for a dependency with the same specification
        String requirement = element.getAttribute("specification");
        for (int i = 0; i < handler.getRequirements().size(); i++) {
            ServiceImporter imp = (ServiceImporter) handler.getRequirements().get(i);
            if (imp.getId().equals(requirement) || imp.getSpecification().getName().equals(requirement)) { return imp; }
        }
        return null;
    }

    /**
     * Check the correctness of the composite requirement against the service level dependency.
     * @param imp : requirement to check
     * @param elem : service-level dependency metadata
     * @throws CompositionException : occurs if the requirement does not match with service-level specification requirement
     */
    private void checkRequirement(ServiceImporter imp, Element elem) throws CompositionException {
        String optional = elem.getAttribute("optional");
        boolean opt = optional != null && optional.equalsIgnoreCase("true");

        String aggregate = elem.getAttribute("aggregate");
        boolean agg = aggregate != null && aggregate.equalsIgnoreCase("true");

        if (imp == null) {
            // Add the missing requirement
            ServiceDependencyHandler handler = (ServiceDependencyHandler) getHandler(HandlerFactory.IPOJO_NAMESPACE + ":subservice");
            if (handler == null) {
                // Look for the ServiceDependencyHandler factory
                HandlerManager handlerManager = null;
                try {
                    ServiceReference[] refs = m_context.getServiceReferences(Factory.class.getName(), "(&(handler.name=subservice)(handler.namespace=" + HandlerFactory.IPOJO_NAMESPACE + ")(handler.type=composite))");
                    Factory factory = (Factory) m_context.getService(refs[0]);
                    handlerManager = (HandlerManager) factory.createComponentInstance(null, getCompositeManager().getServiceContext());
                } catch (InvalidSyntaxException e) {
                    // Should not happen
                } catch (UnacceptableConfiguration e) {
                    // Should not happen
                } catch (MissingHandlerException e) {
                    // Should not happen
                } catch (ConfigurationException e) {
                    // Should not happen
                }
               
                // Add the required handler
                try {
                    handlerManager.init(getCompositeManager(), new Element("composite", ""), new Properties());
                } catch (ConfigurationException e) {
                    error("Internal error : cannot configure the Import Handler : " + e.getMessage());
                    throw new CompositionException("Internal error : cannot configure the Import Handler : " + e.getMessage());
                }
                handler = (ServiceDependencyHandler) handlerManager.getHandler();
                getCompositeManager().addCompositeHandler(handlerManager);
            }

            String spec = elem.getAttribute("specification");
            String filter = "(&(objectClass=" + spec + ")(!(instance.name=" + getCompositeManager().getInstanceName() + ")))"; // Cannot import yourself
            String givenFilter = elem.getAttribute("filter");
            if (givenFilter != null) {
                filter = "(&" + filter + givenFilter + ")"; //NOPMD
            }

            BundleContext context = new PolicyServiceContext(getCompositeManager().getGlobalContext(), getCompositeManager().getParentServiceContext(), PolicyServiceContext.GLOBAL);

            Filter fil = null;
            try {
                fil = getCompositeManager().getGlobalContext().createFilter(filter);
            } catch (InvalidSyntaxException e) {
                throw new CompositionException("A required filter " + filter + " is malformed : " + e.getMessage());
            }

            Class specToImport = null;
            try {
                specToImport = getCompositeManager().getGlobalContext().getBundle().loadClass(spec);
            } catch (ClassNotFoundException e) {
                throw new CompositionException("A required specification cannot be loaded : " + spec);
            }

            ServiceImporter importer = new ServiceImporter(specToImport, fil, agg, opt, null, DependencyModel.DYNAMIC_BINDING_POLICY, context, null, handler);

            handler.getRequirements().add(importer);
            SpecificationMetadata specMeta = new SpecificationMetadata(spec, m_context, agg, opt, this);
            m_services.add(specMeta); // Update the available types
            return;
        }

        if (imp.isAggregate() && !agg) {
            error("[" + getCompositeManager().getInstanceName() + "] The requirement " + elem.getAttribute("specification") + " is aggregate in the implementation and is declared as a simple service-level requirement");
            throw new CompositionException("The requirement " + elem.getAttribute("specification") + " is aggregate in the implementation and is declared as a simple service-level requirement");
        }

        String filter = elem.getAttribute("filter");
        if (filter != null) {
            String filter2 = imp.getFilter();
            if (filter2 == null || !filter2.equalsIgnoreCase(filter)) {
                error("[" + getCompositeManager().getInstanceName() + "] The specification requirement " + elem.getAttribute("specification") + " as not the same filter as declared in the service-level requirement");
                throw new CompositionException("The specification requirement " + elem.getAttribute("specification") + " as not the same filter as declared in the service-level requirement");
            }
        }
    }

    public HandlerDescription getDescription() {
        return m_description;
    }

    /**
     * Build available instance types.
     */
    private void computeAvailableTypes() {
        InstanceHandler handler = (InstanceHandler) getHandler(HandlerFactory.IPOJO_NAMESPACE + ":instance");
        if (handler == null) {
            m_types = new ArrayList();
        } else {
            m_types = handler.getUsedType();
        }
    }

    public List getInstanceType() {
        return m_types;
    }

}
TOP

Related Classes of org.apache.felix.ipojo.composite.service.provides.ProvidedServiceHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.