Package fr.imag.adele.apam.declarations.repository.acr

Source Code of fr.imag.adele.apam.declarations.repository.acr.ApamComponentRepository

package fr.imag.adele.apam.declarations.repository.acr;

import java.net.URL;
import java.text.ParseException;
import java.util.List;

import org.apache.felix.bundlerepository.Capability;
import org.apache.felix.bundlerepository.RepositoryAdmin;
import org.apache.felix.bundlerepository.Requirement;
import org.apache.felix.bundlerepository.Resource;
import org.osgi.framework.Version;

import fr.imag.adele.apam.CST;
import fr.imag.adele.apam.declarations.ComponentDeclaration;
import fr.imag.adele.apam.declarations.PropertyDefinition;
import fr.imag.adele.apam.declarations.Reporter;
import fr.imag.adele.apam.declarations.Reporter.Severity;
import fr.imag.adele.apam.declarations.encoding.Decoder;
import fr.imag.adele.apam.declarations.encoding.capability.CapabilityParser;
import fr.imag.adele.apam.declarations.references.components.ComponentReference;
import fr.imag.adele.apam.declarations.references.components.VersionedReference;
import fr.imag.adele.apam.declarations.repository.ComponentIndex;
import fr.imag.adele.apam.declarations.repository.Repository;

/**
* This class handles a component repository backed up by the felix OSGi Bundle Repository extended
* with APAM metadata.
*
* It is intended to be used both at build and runtime. It only relies on the OBR's ability to query
* its index, and not on installation or runtime platform resolution.
*
*
* TODO This class can be used at build-time by mocking-up some of the runtime OSGi dependencies,
* we rather should try to directly reuse the felix OBR resolver, even if that means depending
* on private classes.
*/
public class ApamComponentRepository implements Repository {


    private final Reporter       reporter;

    private final RepositoryAdmin   manager;
    private final ComponentIndex  cache;
   
    
    public ApamComponentRepository(RepositoryAdmin manager, List<URL> repositories, Reporter reporter) throws Exception {
     
      this.reporter   = reporter;
        this.cache     = new ComponentIndex();

     
        if (repositories == null || repositories.isEmpty()) {
          info("No repository URLs specified");
          this.manager = null;
          return;
        }
        else {
          this.manager = manager;
        }
       
        for (URL repository : repositories) {
            try {
              manager.addRepository(repository);
              info("Repository location "+repository+ " added to ACR");
            } catch (Exception exc) {
                warning("Error when adding repository " + repository + ", reason " + exc.getMessage());
            }
        }

        if (manager.listRepositories().length == 0) {
            warning("No valid repository");
        }

    }

    /**
     * Get the bundle repository manager used by this component repository
     */
    public RepositoryAdmin getManager() {
      return manager;
    }
   
  /**
   * Get the OBR filter corresponding to a given version range specification
   */
  public static String filter(VersionedReference<?> referenceRange) throws ParseException {
       
    String name    = referenceRange.getName();
    String range  = referenceRange.getRange();
   
    StringBuilder filter  = new StringBuilder();
   
   
    if (range == null) {
      filter.append("(name=").append(name).append(")");
    }
    else {
     
      filter.append("(& ");
     
      filter.append("(name=").append(name).append(")");
     
     
          int rangeSeparator   = range.indexOf(",");
          if(rangeSeparator != -1) {

            if ( !range.startsWith("(") && !range.startsWith("["))
                throw new ParseException("VersionedReference range does not start with a correct  delimiter",1);
               
            if ( !range.endsWith(")") && !range.endsWith("]"))
              throw new ParseException("VersionedReference range does not end with a correct  delimiter",range.length());

            String start   = range.substring(1,rangeSeparator).trim();
            String end    = range.substring(rangeSeparator+1,range.length()-1).trim();
               
            version(start);
            version(end);
               
              limit(filter,start,true,range.startsWith("["));
              limit(filter,end,false,range.endsWith("]"));
                 
          } else {
            version(range);
            filter.append("("+CST.VERSION+"=").append(range).append(")");
          }
     
          filter.append(")");
    }
   
        return filter.toString();
  }
 
    private static void limit(StringBuilder filter, String limit, boolean inferior, boolean closed) throws ParseException {
       
      filter.append("(").append(CST.VERSION).append(inferior ? ">=" : "<=").append(limit).append(")");
       
      if( !closed ) {
            filter.append("(!").append("(").append(CST.VERSION).append("=").append(limit).append(")").append(")");
        }
       
    }

    private static Version version(String version) throws ParseException {
       
      if(version == null || version.isEmpty()) {
            throw new ParseException("Version is empty ",0);
        }
       
        try{
            return Version.parseVersion(version);
        } catch (IllegalArgumentException exc) {
            throw new ParseException(exc.getMessage(),0);
        }
    }
   
  @Override
  public <C extends ComponentDeclaration> C getComponent(ComponentReference<C> reference) {
    return reference != null? getComponent(VersionedReference.any(reference)) : null;
  }

  @Override
  public <C extends ComponentDeclaration> C getComponent(VersionedReference<C> referenceRange) {
   
    /*
     * Try to find a cached component declaration
     */
    C component = cache.getComponent(referenceRange);
   
    if (component != null)
      return component;
   
    /*
     * If not found, look directly in the repository and load the cache
     */
    try {
      loadResources(referenceRange);
    } catch (Exception error) {
      error("Error loading resources from repository: "+error.getMessage());
    }
   
    return cache.getComponent(referenceRange);
  }

    /**
     * Loads in the cache all declarations found in resources of ACR that contain the specified
     * component version.
     */
  private void loadResources(VersionedReference<?> referenceRange) throws Exception {

   
        info("loading resources containing apam-component : "+referenceRange.getName()+", version range :"+referenceRange.getRange());

        if(manager == null || manager.listRepositories() == null || manager.listRepositories().length == 0) {
            info("No valid repository, returning empty capability list");
            return;
        }

        info("requirement research (ldap filter) "+ filter(referenceRange));
        Resource[] resources = manager.discoverResources(new Requirement[] {
                      manager.getHelper().requirement("apam-component", filter(referenceRange))}
                    );

        if(resources == null || resources.length<1) {
            return;
        }
       
        Decoder<Capability> parser = new CapabilityParser();
       
        for(Resource resource : resources) {
            info("Resource found : "+resource.getId());

            for(Capability capability : resource.getCapabilities()) {
             
              if (!CapabilityParser.isComponent(capability))
                continue;

              ComponentDeclaration component = parser.decode(capability,reporter);

            /*
             * Components coming from the ACR have inherited properties and default values added
             * at build time, and the declaration stored in the repository is actually effective.
             *
             * However, we must allow members of a group to define properties that are not valued
             * in the group, sowe remove then automatically the default values
             *
             * TODO We need a way to distinguish default values added at build time, from explicitly
             * defined properties that happen to have the same value
             */
          for (PropertyDefinition property : component.getPropertyDefinitions()) {
           
            String defaultValue = property.getDefaultValue();
            String value    = component.getProperty(property.getName());
           
            if (value != null &&  defaultValue != null && defaultValue.equals(value)) {
              component.getProperties().remove(property.getName());
            }
          }
             
              /*
               * Add version if not specified
               */
              addProperty(component,CST.VERSION, "version", resource.getVersion().toString());
             
             
                 cache.put(component);
            }
           
        }
       
    }

  /**
   * Add a property to an existing component
   *
   * NOTE We may be modifying a component that has already property information attached (either because the
   * component has already been built, and we are loading it as a dependency, or because the user has added
   * the information manually) so we need to be careful not to override it
   *
   */
  private static final void addProperty(ComponentDeclaration component, String property, String type, String value) {
   
    /*
     */
    PropertyDefinition defintition = component.getPropertyDefinition(property);
    if (defintition == null) {
      defintition = new PropertyDefinition(component.getReference(), property, type, null);
      component.getPropertyDefinitions().add(defintition);
    }

    String currentValue = component.getProperty(property);
    if (currentValue == null) {
      component.getProperties().put(property, value);
    }
  }

  public final void error(String message) {
    reporter.report(Severity.ERROR, message);
  }
 
  public final void warning(String message) {
    reporter.report(Severity.WARNING, message);
  }

  public final void info(String message) {
    reporter.report(Severity.INFO, message);
  }


}
TOP

Related Classes of fr.imag.adele.apam.declarations.repository.acr.ApamComponentRepository

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.