Package fr.imag.adele.apam.apform.impl

Source Code of fr.imag.adele.apam.apform.impl.ApamComponentFactory$ApamTracker

/**
* Copyright 2011-2012 Universite Joseph Fourier, LIG, ADELE team
*   Licensed 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 fr.imag.adele.apam.apform.impl;

import java.util.Dictionary;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;

import org.apache.felix.ipojo.ComponentFactory;
import org.apache.felix.ipojo.ConfigurationException;
import org.apache.felix.ipojo.HandlerManager;
import org.apache.felix.ipojo.IPojoContext;
import org.apache.felix.ipojo.architecture.ComponentTypeDescription;
import org.apache.felix.ipojo.metadata.Attribute;
import org.apache.felix.ipojo.metadata.Element;
import org.apache.felix.ipojo.util.Logger;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;

import fr.imag.adele.apam.Apam;
import fr.imag.adele.apam.CST;
import fr.imag.adele.apam.Component;
import fr.imag.adele.apam.apform.ApformComponent;
import fr.imag.adele.apam.apform.impl.handlers.MessageProviderHandler;
import fr.imag.adele.apam.apform.impl.handlers.PropertyInjectionHandler;
import fr.imag.adele.apam.apform.impl.handlers.RelationInjectionHandler;
import fr.imag.adele.apam.declarations.AtomicImplementationDeclaration;
import fr.imag.adele.apam.declarations.ComponentDeclaration;
import fr.imag.adele.apam.declarations.CompositeDeclaration;
import fr.imag.adele.apam.declarations.ImplementationDeclaration;
import fr.imag.adele.apam.declarations.InstanceDeclaration;
import fr.imag.adele.apam.declarations.PropertyDefinition;
import fr.imag.adele.apam.declarations.RelationDeclaration;
import fr.imag.adele.apam.declarations.Reporter;
import fr.imag.adele.apam.declarations.RequirerInstrumentation;
import fr.imag.adele.apam.declarations.encoding.Decoder;
import fr.imag.adele.apam.declarations.encoding.ipojo.MetadataParser;
import fr.imag.adele.apam.declarations.encoding.ipojo.MetadataParser.IntrospectionService;
import fr.imag.adele.apam.declarations.references.resources.InterfaceReference;
import fr.imag.adele.apam.declarations.references.resources.ResourceReference;
import fr.imag.adele.apam.impl.BaseApformComponent;
import fr.imag.adele.apam.impl.ComponentBrokerImpl;

/**
* This is the base class for all component factories that are used to represent APAM components at the iPojo
* level.
*
* @author vega
*
*/
public abstract class ApamComponentFactory extends ComponentFactory implements IntrospectionService, Reporter {

    /**
     * The name space of this factory
     */
    public static final String APAM_NAMESPACE = "fr.imag.adele.apam";
    /**
     * Configuration property to specify the component declaration
     */
    public static final String COMPONENT_DECLARATION_PROPERTY = "declaration";

  /**
     * A dynamic reference to the APAM platform
     */
    protected final ServiceTracker apamTracker;
   
    /**
     * The corresponding component declaration
     */
    protected ComponentDeclaration  declaration;

    /**
     * If the declaration can not be loaded this is the cause
     */
    protected ConfigurationException  declarationError;
   
  /**
   * The associated Apform component
   */
  protected final ApformComponent   apform;
   
    /**
     * Initializes an APAM component factory
     */
    public ApamComponentFactory(BundleContext context, Element element) throws ConfigurationException {
        super(context,element);
        this.apamTracker  = new ApamTracker(context);
        this.apform      = createApform();

    }

  /**
     * Once the factory is started register it in APAM
     */
    @Override
    public synchronized void start() {
        super.start();
        apamTracker.open();
    }

    /**
     * Once the factory is stopped unregister it from APAM
     */
    @Override
    public synchronized void stop() {
        super.stop();
        apamTracker.close();
    }

    /**
     * Creates the Apform object used to mediate between APAM and this factory
     */
    protected abstract ApformComponent createApform();
   
  /**
   * This class represents the base functionality of Apform mediation object between APAM and a component factory
   */
  protected abstract class Apform<C extends Component, D extends ComponentDeclaration> extends BaseApformComponent<C,D>  {

    @SuppressWarnings("unchecked")
    public Apform() {
      super( (D) ApamComponentFactory.this.declaration);
    }
   
    @Override
    public Bundle getBundle() {
      return ApamComponentFactory.this.getBundleContext().getBundle();
    }
  }
 
    /**
     * Get the associated Apform component
     */
    public ApformComponent getApform() {
      return apform;
    }
   
    /**
     * Get the associated declaration
     */
    public ComponentDeclaration getDeclaration() {
    return declaration;
  }
   
    /**
     * Register this component with APAM
     */
  protected abstract void bindToApam(Apam apam);

    /**
     * Unregister this component from APAM
     *
     * @param apam
     */
  protected void unbindFromApam(Apam apam) {
    ((ComponentBrokerImpl)CST.componentBroker).disappearedComponent(getName());
    }

    /**
     * Whether this component factory has an associated instrumented class
     */
    protected abstract boolean hasInstrumentedCode();

    /**
     * Computes required handlers.
     */
  @Override
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public List getRequiredHandlerList() {

      List<RequiredHandler> requiredHandlers = (List<RequiredHandler>) super.getRequiredHandlerList();

        /*
         * APAM do not use a handler for each element in the metadata, so we need to override the default
         * behavior
         */
        for (Iterator<RequiredHandler> handlers = requiredHandlers.iterator(); handlers.hasNext();) {
            RequiredHandler handlerDescription = handlers.next();
            String namespace = handlerDescription.getNamespace();
            if ( namespace != null && APAM_NAMESPACE.equals(namespace))
                handlers.remove();
        }
     
        /*
         *  Parse metadata to get APAM core declaration
         */
    try {
      Decoder parser = new MetadataParser(this);
      this.declaration = parser.decode(m_componentMetadata,this);

    } catch (Exception e) {
      e.printStackTrace();
      this.declaration    = null;
      this.declarationError   = new ConfigurationException(e.getLocalizedMessage());
      return requiredHandlers;
    }

    /*
     * Calculate the minimal set of handlers based on the component declaration
     */
    if (this.declaration instanceof AtomicImplementationDeclaration) {
      AtomicImplementationDeclaration componentDeclaration = (AtomicImplementationDeclaration) this.declaration;

      if (MessageProviderHandler.isRequired(componentDeclaration))
        requiredHandlers.add(new RequiredHandler(MessageProviderHandler.NAME, APAM_NAMESPACE));

      if (RelationInjectionHandler.isRequired(componentDeclaration))
        requiredHandlers.add(new RequiredHandler(RelationInjectionHandler.NAME, APAM_NAMESPACE));
     
      if (PropertyInjectionHandler.isRequired(componentDeclaration))
        requiredHandlers.add(new RequiredHandler(PropertyInjectionHandler.NAME, APAM_NAMESPACE));
    }

        return requiredHandlers;
    }

    /**
     * Verify implementation declaration
     */
    @Override
    public void check(Element element) throws ConfigurationException {
        if (hasInstrumentedCode())
            super.check(element);
       
        if (this.declaration == null)
          throw this.declarationError;
    }

    /**
     * Handle errors in parsing APAM declaration
     */
    @Override
    public void report(Severity severity, String message) {
        switch (severity) {
          case INFO:
            getLogger().log(Logger.INFO,message);
            break;
          case SUSPECT:
            case WARNING:
                getLogger().log(Logger.INFO,"Error parsing APAM declaration " + m_componentMetadata + " : " + message);
                break;

            case ERROR:
                throw new IllegalArgumentException("Error parsing APAM declaration "+getFactoryName()+":  "+message);
        }
    }


    /**
     * Whether this component factory can be instantiated directly via the iPojo API.
     */
    protected abstract boolean isInstantiable();
  

    /**
     * Creates a primitive instance.
     * This method is called when holding the lock.
     *
     * NOTE In APAM component factories we override definitively this method to be sure that the created instance
     * is an implementation of ApamInstanceManager.
     *
     * Subclasses should instead override {@link #createApamInstance(IPojoContext, HandlerManager[])} in order to
     * specialize instance creation.
     */
    @Override
    @SuppressWarnings({ "rawtypes" })
    public final ApamInstanceManager createInstance(Dictionary configuration, IPojoContext context, HandlerManager[] handlers)
            throws ConfigurationException {

        if (! isInstantiable())
            throw new ConfigurationException(
                    "Only APAM instantiable components can be directly instantiated by Ipojo, use instead the APAM API");

        /*
           * Create a native APAM instance and configure it.
           */
        ApamInstanceManager instance = createApamInstance(context,handlers);

        try {
            instance.configure(m_componentMetadata, configuration);
            instance.start();
            return instance;
        } catch (ConfigurationException e) {
            // An exception occurs while executing the configure or start
            // methods.
            if (instance != null) {
                instance.dispose();
                instance = null;
            }
            throw e;
        } catch (Exception e) { // All others exception are handled here.
            if (instance != null) {
                instance.dispose();
                instance = null;
            }
            m_logger.log(Logger.ERROR, e.getMessage(), e);
            throw new ConfigurationException(e.getMessage());
        }
    }

    /**
     * Creates a new native APAM instance, if this component represents an instantiable entity.
     */
    protected abstract ApamInstanceManager createApamInstance(IPojoContext context, HandlerManager[] handlers);
   
    /**
     * Gets the component type description.
     *
     * @return the component type description
     * @see org.apache.felix.ipojo.ComponentFactory#getComponentTypeDescription()
     */
    @Override
    public ComponentTypeDescription getComponentTypeDescription() {
        return new Description(this);
    }

    /**
     * Get reflection information for the loaded implementation class
     */
    public Class<?> getInstrumentedClass(String classname) throws ClassNotFoundException {
        return getBundleContext().getBundle().loadClass(classname);
    }
  
    /**
     * Defines the implementation description.
     *
     * @see ComponentTypeDescription
     */
    protected static class Description extends ComponentTypeDescription {

        /**
         * Creates the Apam Implementation Description.
         */
        protected Description(ApamComponentFactory factory) {
            super(factory);

            /*
             * add all provided interfaces of the component to the description
             */
            for (InterfaceReference providedInterface : factory.declaration.getProvidedResources(InterfaceReference.class)) {
                addProvidedServiceSpecification(providedInterface.getJavaType());
            }

        }

        /**
         * Gets the attached factory.
         *
         * Redefines with covariant result type.
         **/
        @Override
        public ApamComponentFactory getFactory() {
            return (ApamComponentFactory) super.getFactory();
        }

        /**
         * Gets the component type description.
         */
        @Override
        public Element getDescription() {

            Element description = super.getDescription();

            if (getFactory().declaration != null) {

                ComponentDeclaration declaration = getFactory().declaration;

                Element componentDescription = new Element(COMPONENT_DECLARATION_PROPERTY, APAM_NAMESPACE);
                componentDescription.addAttribute(new Attribute("name",declaration.getName()));
                componentDescription.addAttribute(new Attribute("type",declaration.getClass().getSimpleName()));

                if (declaration instanceof ImplementationDeclaration) {
                    ImplementationDeclaration implementation = (ImplementationDeclaration) declaration;
                    if (implementation.getSpecification() != null ) {
                        componentDescription.addAttribute(new Attribute("specification",implementation.getSpecification().getName()));
                    }
                }

                if (declaration instanceof CompositeDeclaration) {
                    CompositeDeclaration composite = (CompositeDeclaration) declaration;
                    if (composite.getSpecification() != null && composite.getMainComponent() != null) {
                        componentDescription.addAttribute(new Attribute("main",composite.getMainComponent().getName()));
                    }
                }

                if (declaration instanceof InstanceDeclaration) {
                    InstanceDeclaration instance = (InstanceDeclaration) declaration;
                    if (instance.getImplementation() != null ) {
                        componentDescription.addAttribute(new Attribute("implementation",instance.getImplementation().getName()));
                    }
                }

                Element providesDescription = new Element("provides", APAM_NAMESPACE);;
                for (ResourceReference resource : declaration.getProvidedResources()) {
                    Element provideDescription = new Element("provides", APAM_NAMESPACE);
                    provideDescription.addAttribute(new Attribute("resource", resource.toString()));
                    providesDescription.addElement(provideDescription);
                }
                componentDescription.addElement(providesDescription);

                Element relationsDescription = new Element("dependencies", APAM_NAMESPACE);;
                for (RelationDeclaration relationDeclaration : declaration.getRelations()) {
                    Element relationDescription = new Element("relation", APAM_NAMESPACE);
                    relationDescription.addAttribute(new Attribute("id", relationDeclaration.getIdentifier()));
                    relationDescription.addAttribute(new Attribute("resource", relationDeclaration.getTarget().toString()));
                    relationDescription.addAttribute(new Attribute("multiple", Boolean.toString(relationDeclaration.isMultiple())));


                    Element injectionsDescription = new Element("instrumentations", APAM_NAMESPACE);
                    for (RequirerInstrumentation injectionDeclaration : relationDeclaration.getInstrumentations()) {
                        Element injectionDescription = new Element("instrumentation", APAM_NAMESPACE);
                        injectionDescription.addAttribute(new Attribute("name", injectionDeclaration.getName()));
                        injectionDescription.addAttribute(new Attribute("resource", injectionDeclaration.getRequiredResource().toString()));
                        injectionDescription.addAttribute(new Attribute("multiple", Boolean.toString(injectionDeclaration.acceptMultipleProviders())));
                        injectionsDescription.addElement(injectionDescription);
                    }
                    relationDescription.addElement(injectionsDescription);

                    Element constraintsDescription = new Element("constraints", APAM_NAMESPACE);
                    for (String constraint : relationDeclaration.getImplementationConstraints()) {
                        Element constraintDescription = new Element("implementation", APAM_NAMESPACE);
                        constraintDescription.addAttribute(new Attribute("filter", constraint));
                        constraintsDescription.addElement(constraintDescription);
                    }
                    for (String constraint : relationDeclaration.getInstanceConstraints()) {
                        Element constraintDescription = new Element("instance", APAM_NAMESPACE);
                        constraintDescription.addAttribute(new Attribute("filter", constraint));
                        constraintsDescription.addElement(constraintDescription);
                    }
                    relationDescription.addElement(constraintsDescription);

                    Element preferencesDescription = new Element("preferences", APAM_NAMESPACE);
                    int priority=0;
                    for ( String preference : relationDeclaration.getImplementationPreferences()) {
                        Element preferenceDescription = new Element("implementation", APAM_NAMESPACE);
                        preferenceDescription.addAttribute(new Attribute("filter", preference));
                        preferenceDescription.addAttribute(new Attribute("priority", Integer.toString(priority++)));
                        preferencesDescription.addElement(preferenceDescription);
                    }

                    priority=0;
                    for (String preference : relationDeclaration.getInstancePreferences()) {
                        Element preferenceDescription = new Element("instance", APAM_NAMESPACE);
                        preferenceDescription.addAttribute(new Attribute("filter", preference));
                        preferenceDescription.addAttribute(new Attribute("priority", Integer.toString(priority++)));
                        preferencesDescription.addElement(preferenceDescription);
                    }
                    relationDescription.addElement(preferencesDescription);

                    relationsDescription.addElement(relationDescription);
                }
                componentDescription.addElement(relationsDescription);

                Element definitionsDescription = new Element("definitions", APAM_NAMESPACE);;
                for (PropertyDefinition propertyDeclaration : declaration.getPropertyDefinitions()) {
                    Element definitionDescription = new Element("property", APAM_NAMESPACE);
                    definitionDescription.addAttribute(new Attribute("name", propertyDeclaration.getName()));
                    definitionDescription.addAttribute(new Attribute("type", propertyDeclaration.getType()));
                    if (propertyDeclaration.hasDefaultValue())
                        definitionDescription.addAttribute(new Attribute("value", propertyDeclaration.getDefaultValue().toString()));
                    definitionsDescription.addElement(definitionDescription);
                }
                componentDescription.addElement(definitionsDescription);

                Element propertiesDescription = new Element("properties", APAM_NAMESPACE);;
                for (Entry<String,String> propertyEntry : declaration.getProperties().entrySet()) {
                    Element propertyDescription = new Element("property", APAM_NAMESPACE);
                    propertyDescription.addAttribute(new Attribute("name", propertyEntry.getKey()));
                    if (propertyEntry.getValue() != null)
                        propertyDescription.addAttribute(new Attribute("value", propertyEntry.getValue().toString()));
                    propertiesDescription.addElement(propertyDescription);
                }
                componentDescription.addElement(propertiesDescription);

                description.addElement(componentDescription);
            }

            return description;
        }

    }


    /**
     * A class to dynamically track the APAM platform. This allows to dynamically register/unregister this
     * component into the platform.
     *
     * NOTE We implement an static binding policy. Once an Apam platform has been found, it will be used until
     * it is no longer available.
     *
     * @author vega
     *
     */
    class ApamTracker extends ServiceTracker {

        private boolean bound;

        public ApamTracker(BundleContext context) {
            super(context, Apam.class.getName(), null);
            this.bound = false;
        }

        @Override
        public Object addingService(ServiceReference reference) {
            if (bound)
                return null;


            this.bound = true;
            Apam apam = (Apam) this.context.getService(reference);
            bindToApam(apam);

            return apam;
        }


        @Override
        public void removedService(ServiceReference reference, Object service) {

            unbindFromApam((Apam) service);
            this.context.ungetService(reference);

            this.bound = false;
        }

    }

    /**
     * Get a reference to APAM
     */
    public final Apam getApam() {
        return apamTracker.size() != 0 ? (Apam) apamTracker.getService() : null;
    }

}
TOP

Related Classes of fr.imag.adele.apam.apform.impl.ApamComponentFactory$ApamTracker

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.