Package fr.imag.adele.apam.apform.legacy.ipojo

Source Code of fr.imag.adele.apam.apform.legacy.ipojo.ApformIpojoTracker$WaitingThread

/**
* 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.legacy.ipojo;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.apache.felix.ipojo.ComponentInstance;
import org.apache.felix.ipojo.Factory;
import org.apache.felix.ipojo.HandlerFactory;
import org.apache.felix.ipojo.IPojoFactory;
import org.apache.felix.ipojo.Pojo;
import org.apache.felix.ipojo.annotations.Bind;
import org.apache.felix.ipojo.annotations.Instantiate;
import org.apache.felix.ipojo.annotations.Invalidate;
import org.apache.felix.ipojo.annotations.Requires;
import org.apache.felix.ipojo.annotations.Unbind;
import org.apache.felix.ipojo.annotations.Validate;
import org.apache.felix.ipojo.extender.queue.JobInfo;
import org.apache.felix.ipojo.extender.queue.QueueListener;
import org.apache.felix.ipojo.extender.queue.QueueService;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Filter;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;

import fr.imag.adele.apam.Apam;
import fr.imag.adele.apam.ApamManagers;
import fr.imag.adele.apam.CST;
import fr.imag.adele.apam.Component;
import fr.imag.adele.apam.DynamicManager;
import fr.imag.adele.apam.Implementation;
import fr.imag.adele.apam.Instance;
import fr.imag.adele.apam.Link;
import fr.imag.adele.apam.Specification;
import fr.imag.adele.apam.apform.Apform2Apam;
import fr.imag.adele.apam.apform.Apform2Apam.PendingThread;
import fr.imag.adele.apam.apform.ApformImplementation;
import fr.imag.adele.apam.apform.impl.ApamComponentFactory;
import fr.imag.adele.apam.apform.impl.ApamInstanceManager;
import fr.imag.adele.apam.declarations.SpecificationDeclaration;
import fr.imag.adele.apam.declarations.references.components.VersionedReference;
import fr.imag.adele.apam.declarations.references.resources.InterfaceReference;
import fr.imag.adele.apam.declarations.references.resources.MessageReference;
import fr.imag.adele.apam.declarations.references.resources.ResourceReference;
import fr.imag.adele.apam.impl.ComponentBrokerImpl;

/**
* This class tracks iPojo legacy implementations and instances and register
* them in APAM
*
* @author vega
*
*/
@org.apache.felix.ipojo.annotations.Component(name = "ApformIpojoTracker" , immediate=true)
@Instantiate(name = "ApformIpojoTracker-Instance")

public class ApformIpojoTracker implements DynamicManager, Apform2Apam.Platform, ServiceTrackerCustomizer,  QueueListener {

    /**
     * The reference to the APAM platform
     */
  @Requires(id="apam",proxy=false)
    private Apam                apam;

  /**
   * The reference to the iPOJO queue service instances
   */
    @Requires(id="iPOJO-queueServices", optional=false, proxy=false)
    private List<QueueService> queueServices;

    /**
     * The instances service tracker.
     */
    private ServiceTracker      instancesServiceTracker;

    /**
     * The bundle context associated with this tracker
     */
    private final BundleContext context;


    public ApformIpojoTracker(BundleContext context) {
        this.context = context;
        this.queueServices = new ArrayList<QueueService>();
    }
   

  @Override
  public String getName() {
    return "ApformIpojoTracker";
  }
   
    @Bind(id="apam")
    private void bindToApam() {
      Apform2Apam.setPlatform(this);
    }

    @Unbind(id="apam")
    private void unbindFromApam() {
      Apform2Apam.setPlatform(null);
    }

    @Bind(id="iPOJO-queueServices")
    private void bindToQueue(QueueService queueService) {
    queueService.addQueueListener(this);
    }

    @Unbind(id="iPOJO-queueServices")
    private void unbindToQueue(QueueService queueService) {
    queueService.removeQueueListener(this);
    }

    /**
     * Starting.
     */
    @Validate
    public void start() {
    ApamManagers.addDynamicManager(this);

        try {
            Filter filter = context.createFilter("(instance.name=*)");
            instancesServiceTracker = new ServiceTracker(context, filter, this);
            instancesServiceTracker.open();


        } catch (InvalidSyntaxException e) {
            e.printStackTrace(System.err);
        }
    }

    /**
     * Stopping.
     */
    @Invalidate
    public void stop() {
    ApamManagers.removeDynamicManager(this);
    instancesServiceTracker.close();
   }

  @Override
  public void addedComponent(Component component) {
   
    /*
     * If a new specification is defined we need to try match existing factories in the registry 
     */
    if (component instanceof Specification) {

      Specification specification = (Specification) component;
      if (!isMatchable(specification))
        return;


      /*
       * Get the registered factories and bind all factories matching the specification
       */
      ServiceReference[] factoryReferences = searchFactories(null);
      for (ServiceReference factoryReference : factoryReferences != null ? factoryReferences : new ServiceReference[0]) {
       
        Factory factory = (Factory) context.getService(factoryReference);
       
        if (factory != null && isEligible(factory) && matchingScore((IPojoFactory)factory, specification) > 0) {
          factoryBound((IPojoFactory)factory,specification);
        }
       
        context.ungetService(factoryReference);
      }
     
    }
   
    /*
     * If an iPOJO implementation is defined, we create all delayed tracked instances
     */
    if ((component instanceof Implementation) && (component.getProperty("ipojo.factory") != null)) {
     
      ServiceReference[] trackedReferences = instancesServiceTracker.getServiceReferences();
      for (ServiceReference serviceReference : trackedReferences != null ? trackedReferences : new ServiceReference[0]) {

        Object factoryName = serviceReference.getProperty("factory.name");
        if ( factoryName != null && component.getName().equals(factoryName)) {

          Pojo pojo = (Pojo) instancesServiceTracker.getService(serviceReference);
          if (pojo != null) {
                instanceBound(serviceReference,pojo.getComponentInstance());
          }
        }
      }
    }
   
  }
   
  /**
   * Determines if the specification is a possible candidate to be matched to an iPOJO factory
   */
  private static boolean isMatchable(Specification specification) {
   
    if (!specification.getRelations().isEmpty())
      return false;
   
    if (! specification.getDeclaration().getProvidedResources(MessageReference.class).isEmpty())
      return false;

    if (specification.getDeclaration().getProvidedResources(InterfaceReference.class).isEmpty())
      return false;
   
    return true;
  }
   
 
  /**
   * Determines if the iPOJO factory is eligible to become an APAM implementation
   */
  private static boolean isEligible(Factory factory) {
    return (factory instanceof IPojoFactory) && !(factory instanceof ApamComponentFactory);
  }

  /**
   * Determines if the specified factory matches the specification.
   *
   * Return a number that represents how well the factory matches the interface.
   *
   * The returned number is zero if the factory doesn't match the specification.
   */
  private static int matchingScore(IPojoFactory factory, Specification specification) {

    if (!isMatchable(specification)) {
      return 0;
    }
   
      Set<ResourceReference> providedResources = new HashSet<ResourceReference>();
     
    for (String providedResource : factory.getComponentDescription().getprovidedServiceSpecification()) {
      providedResources.add(new InterfaceReference(providedResource));
    }

    Set<ResourceReference> matchedResources = new HashSet<ResourceReference>(specification.getProvidedResources());
    matchedResources.retainAll(providedResources);

    return matchedResources.size();
  }
 
    /**
     * Select the specification that best matches the iPOJO factory
     */
    private Specification getBestMatchingSpecification(IPojoFactory factory) {
     
      Set<ResourceReference> providedResources = new HashSet<ResourceReference>();
     
    for (String providedResource : factory.getComponentDescription().getprovidedServiceSpecification()) {
      providedResources.add(new InterfaceReference(providedResource));
    }

    Specification best   = null;
    int bestScore    = 0;
   
    for (Specification specification : CST.componentBroker.getSpecs()) {
     
      int score = matchingScore(factory, specification);
      if (score > bestScore) {
        best     =  specification;
        bestScore   =  score;
      }
    }
   
    return best;
    }
 
    /**
     * Callback to handle factory binding
     */
    @Bind(id="factories", aggregate=true, optional=true, proxy=false)
    public void factoryBound(Factory factory) {
      if (isEligible(factory)) {
        factoryBound((IPojoFactory)factory,getBestMatchingSpecification((IPojoFactory)factory));
        }
    }

    /**
     * Creates an APAM implementation corresponding to the given factory and specification
     */
    public void factoryBound(IPojoFactory factory, Specification specification) {
        if (specification != null &&  CST.componentBroker.getImpl(factory.getName()) == null) {
          VersionedReference<SpecificationDeclaration> specificationReference = specification != null ? VersionedReference.any(specification.getApformSpec().getDeclaration().getReference()) : null;
          ApformImplementation implementation = new ApformIPojoImplementation((IPojoFactory) factory, specificationReference);
            Apform2Apam.newImplementation(implementation);
        }
    }
   
    /**
     * Callback to handle factory unbinding
     */
    @Unbind(id="factories", aggregate=true, optional=true, proxy=false)
    public void factoryUnbound(Factory factory) {
        if (isEligible(factory) && CST.componentBroker.getImpl(factory.getName()) != null) {
          ((ComponentBrokerImpl)CST.componentBroker).disappearedComponent(factory.getName()) ;
        }
    }


    /**
     * Search OSGI for all registered iPOJO factories, optionally a filter for the name can
     * be specified
     */
    private ServiceReference[] searchFactories(String name) {
        try {
            String nameFilter = name != null ? "(factory.name=" + name + ")" : null;
            return context.getServiceReferences(Factory.class.getName(),nameFilter);
        } catch (InvalidSyntaxException ignored) {
          return null;
        }
    }
   
    /**
     * Callback to handle instance binding
     */
    public boolean instanceBound(ServiceReference reference, ComponentInstance ipojoInstance) {
        /*
         * ignore handler instances
         */
        if (ipojoInstance.getFactory() instanceof HandlerFactory)
            return false;

       /*
        * In the case of APAM instances registered in the registry (hybrid components), registration
        * in APAM has already be done by the Instance Manager
        */
       if (ipojoInstance instanceof ApamInstanceManager)
           return false;

       /*
        * ignore already bound instances
        */
       if (CST.componentBroker.getInst(ipojoInstance.getInstanceName()) != null)
         return false;
      
       /*
        * If the implementation is not yet in APAM, just delay registration, instances will be automatically
        * created later (see #addedComponent)
        */
       Implementation implementation = CST.componentBroker.getImpl(ipojoInstance.getFactory().getName());
       if (implementation == null)
         return true;
      
        /*
         * Register the corresponding declaration in APAM
         */
        ApformIpojoInstance apformInstance = new ApformIpojoInstance(ipojoInstance, reference);
        Apform2Apam.newInstance(apformInstance);

        return true;
    }
   
    /**
     * Callback to handle instance unbinding
     */
    public void instanceUnbound(ComponentInstance ipojoInstance) {
      if (CST.componentBroker.getInst(ipojoInstance.getInstanceName()) != null) {
            ((ComponentBrokerImpl)CST.componentBroker).disappearedComponent(ipojoInstance.getInstanceName()) ;
      }
    }

    @Override
    public Object addingService(ServiceReference reference) {

        /*
         * Ignore events while APAM is not available
         */
        if (apam == null)
            return null;

        /*
         * ignore services that are not iPojo
         */
        Object service = context.getService(reference);
        if ((service instanceof Pojo) && instanceBound(reference,((Pojo) service).getComponentInstance()))
            return service;

        /*
         * If service is not a recognized iPojo instance, don't track it
         */
        context.ungetService(reference);
        return null;
    }

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

        /*
         * This should never happen, but there seems to be some bug in the service tracker
         */
        if (!(service instanceof Pojo)) {
            return;
        }

        ComponentInstance ipojoInstance = ((Pojo) service).getComponentInstance();
       
        /*
         * Ignore hybrid APAM+iPOJO instances
         */
        if (service instanceof ApamInstanceManager) {
          return;
        }       
       
        /*
         * unbound the instance
         */
        instanceUnbound(ipojoInstance);
        context.ungetService(reference);
    }

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

        if (!(service instanceof Pojo))
            return;

        ComponentInstance ipojoInstance = ((Pojo) service).getComponentInstance();

        /*
         * If the service is not reified in APAM, just ignore event
         */
        Instance instance = CST.componentBroker.getInst(ipojoInstance.getInstanceName());
        if (instance == null)
            return;

        /*
         * Otherwise propagate property changes to Apam, we only propagate properties that are defined
         * in APAM and that are not inherited from the implementtaion
         */
        for (String key : reference.getPropertyKeys()) {
            if (instance.getImpl().getPropertyDefinition(key) != null && instance.getImpl().getProperty(key) == null) {
                String value = reference.getProperty(key).toString();
                if (value != instance.getProperty(key))
                    instance.setProperty(key, value);
            }
        }
    }
   
    /*
     *  Implementation of the ApformToApam platform API
     */
  private final static boolean DEBUG = false;


    /**
     * Whether there is pending declarations currently being deployed in the iPOJO platform
     */
  @Override
  public boolean hasPendingDeclarations() {
    return  getPendingJobs() > 0;
  }

  /**
   * Determines if iPOJO is currently processing bundle declarations
   */
  private int getPendingJobs() {
    int pending = 0;
    for (QueueService queueService : queueServices) {
      pending += queueService.getWaiters()+queueService.getCurrents();
    }
   
    return  pending;
  }
 
  /**
   * Waits for all pending declarations to be processed by the iPOJO platform
   */
  @Override
  public void waitForDeclarations() {
    synchronized (this) {
      try {
       
        WaitingThread thread = new WaitingThread();
       
        while (hasPendingDeclarations()) {
          if (DEBUG)
            System.err.println(Thread.currentThread()+" waiting for "+getPendingJobs()+" iPOJO jobs");
         
          thread.pending(getPendingJobs()+" iPOJO jobs");
          this.wait();
          thread.resumed();
        }
      } catch (InterruptedException e) {
        e.printStackTrace();
      }

    }
  }

  /**
   * The list of threads waiting for a iPOJO completion if processing
   */
  static private final List<WaitingThread> pending = new ArrayList<WaitingThread>();

  /**
   * The list of threads waiting for a component in APAM
   */
  @Override
  public List<? extends PendingThread> getPending() {
    return Collections.unmodifiableList(pending);
  }

  /**
   * A description of a thread that needs to wait for iPOJO processing declarations
   *
   * @author vega
   */
  private static class WaitingThread extends PendingThread {

    private String condition;
   
    public WaitingThread() {
      super("Thread " + Thread.currentThread().getName());
    }

    /**
     * The condition this thread is waiting for
     */
    public String getCondition() {
      return condition;
    }


    /**
     * Mark this thread as pending for a codition
     */
    protected void pending(String condition) {
      this.condition = condition;
      this.stack = getCurrentStack();
      pending.add(this);
    }

    /**
     * Mark this request as resumed after the condition is satisfied
     */
    protected void resumed() {
      this.condition = null;
      this.stack = null;

      pending.remove(this);
    }

    @Override
    public String toString() {
      return description;
    }
  }

  /**
   * The stack of the thread currently executing inside this class, and that is going to wait for a platform condition
   *
   */
  private static List<StackTraceElement> getCurrentStack() {

    List<StackTraceElement> stack = new ArrayList<StackTraceElement>(Arrays.asList(new Throwable().getStackTrace()));

    /*
     * Remove ourselves from the top of the stack, to increase the readability of the stack trace
     */
    Iterator<StackTraceElement> frames = stack.iterator();
    while (frames.hasNext()) {
      if (frames.next().getClassName().startsWith(ApformIpojoTracker.class.getName())) {
        frames.remove();
        continue;
      }

      break;
    }
    return stack;
  }

 
 
  private void jobStausChanged(String state, JobInfo info) {

    if (DEBUG)
      System.err.println(Thread.currentThread()+" job change event :"+state+" "+info.getDescription());

    synchronized (this) {
      this.notifyAll();
    }
  }
 
  @Override
  public void enlisted(JobInfo info) {
    jobStausChanged("enlisted",info);
  }

  @Override
  public void started(JobInfo info) {
    jobStausChanged("started",info);
  }

  @Override
  public void executed(JobInfo info, Object result) {
    jobStausChanged("executed",info);
  }

  @Override
  public void failed(JobInfo info, Throwable throwable) {
    jobStausChanged("failed",info);
  }
   
  @Override
  public void removedComponent(Component lostComponent) {
  }

  @Override
  public void addedLink(Link wire) {
  }

  @Override
  public void removedLink(Link wire) {
  }

}
TOP

Related Classes of fr.imag.adele.apam.apform.legacy.ipojo.ApformIpojoTracker$WaitingThread

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.