Package org.knopflerfish.util.metatype

Source Code of org.knopflerfish.util.metatype.SystemMetatypeProvider

/*
* Copyright (c) 2003-2010, KNOPFLERFISH project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
*   notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
*   copyright notice, this list of conditions and the following
*   disclaimer in the documentation and/or other materials
*   provided with the distribution.
*
* - Neither the name of the KNOPFLERFISH project nor the names of its
*   contributors may be used to endorse or promote products derived
*   from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/**
* @author Erik Wistrand
* @author Philippe Laporte
*/

package org.knopflerfish.util.metatype;

import org.osgi.framework.*;
import org.osgi.service.metatype.*;
import org.osgi.service.cm.*;
import org.osgi.util.tracker.*;
import org.knopflerfish.service.log.LogRef;

import java.util.*;
import java.util.zip.ZipEntry;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.*;

/**
* Class which monitors installed bundles for metatype and CM default data.
*
* <p>
* When instanciated, SystemMetatypeProvider will listen for installed
* bundles and try to extract metatype and Cm defaults XML from the
* bundle jar files. This data will then be available using the
* <tt>getServicePIDs</tt>, <tt>getFactoryPIDs</tt> and
* <tt>getObjectClassDefinition</tt> methods.
* </p>
*/
public class SystemMetatypeProvider extends MTP implements MetaTypeService {

  /**
   * Default URL to metatype XML.
   *
   * <p>
   * Value is "!/metatype.xml"
   * </p>
   */
  public static final String METATYPE_RESOURCE    = "/metatype.xml";

  /**
   * Default URL to default CM values.
   *
   * <p>
   * Value is "!/cmdefaults.xml"
   * </p>
   */
  public static final String CMDEFAULTS_RESOURCE  = "/cmdefaults.xml";

  /**
   * Manifest attribute name specifying metatype XML URL.
   *
   * <p>
   * Value is "Bundle-MetatypeURL"
   * </p>
   */
  public static final String ATTRIB_METATYPEURL   = "Bundle-MetatypeURL";

  /**
   * Manifest attribute name specifying CM defaults XML URL.
   *
   * <p>
   * Value is "Bundle-CMDefaultsURL"
   * </p>
   */
  public static final String ATTRIB_CMDEFAULTSURL = "Bundle-CMDefaultsURL";

  BundleContext  bc;
  LogRef         log;

  // Bundle -> MTP
  Map            providers = new Hashtable();

  ServiceTracker cmTracker;


  // Special MTP which tracks CM configuration instances
  MTP            cmMTP;


  // String (pid) -> OCD
  Map cmOCDMap = new HashMap();

  /**
   * Create a SystemMetatypeProvider, using the specified bundle context
   * for listeners.
   */
  public SystemMetatypeProvider(BundleContext bc) {
    super("system");
    this.bc = bc;
    log = new LogRef(bc);
  }

  SynchronousBundleListener bl = null;

  /**
   * Start listening for bundles.
   */
  public void open() {
    if(bl != null) {
      return;
    }

    bl = new SynchronousBundleListener() {
      public void bundleChanged(BundleEvent ev) {
          switch(ev.getType()) {
          case BundleEvent.INSTALLED:
          case BundleEvent.RESOLVED:
          case BundleEvent.UNRESOLVED:
          case BundleEvent.UPDATED:
            //NYI! Reduce the number of loadMTPs by combining U* events.
            //We can't read properties from the system bundle
            if(ev.getBundle().getBundleId() != 0) {
              try {
                loadMTP(ev.getBundle());
              }
              catch (Exception e) {
                log.error("Failed to handle bundle " + ev.getBundle().getBundleId(), e);
                //e.printStackTrace(System.out);
              }
            }
            break;
          case BundleEvent.UNINSTALLED:
            Bundle b = ev.getBundle();
            if(b.getBundleId() != 0) {
              providers.remove(b);
            }
            break;
          }
      }
    };

    Bundle[] bs = bc.getBundles();
    for(int i = 0; i < bs.length; i++) {
      bl.bundleChanged(new BundleEvent(BundleEvent.INSTALLED, bs[i]));
    }
    bc.addBundleListener(bl);


    cmTracker = new ServiceTracker(bc, ConfigurationAdmin.class.getName(), null);
    cmTracker.open();

    // track CM configuration instances as MTPs on the system bundle.

    cmMTP = new MTP("[CM]") {
    public String[] getPids() {
      return MTP.toStringArray(getCMServicePIDs());
    }

    public String[] getFactoryPids() {
      return  MTP.toStringArray(getCMFactoryPIDs());
    }

    public String[] getLocales() {
      return null;
    }

    public ObjectClassDefinition getObjectClassDefinition(String pid, String locale) {

      OCD ocd = (OCD)cmOCDMap.get(pid);
      if(ocd != null) {
        //cached
        return ocd;
      }

      ConfigurationAdmin ca = (ConfigurationAdmin)cmTracker.getService();
      if(ca != null) {
        try {
          Configuration[] configs = ca.listConfigurations(null);
          Configuration conf = null;
          for(int i = 0; configs != null && i < configs.length; i++) {
            if(pid.equals(configs[i].getPid()) ||
               pid.equals(configs[i].getFactoryPid())) {
              conf = configs[i];
            }
          }
          if(conf != null) {
            Dictionary props = conf.getProperties();
            ocd = new OCD(pid, pid, pid + " from CM", props);
            cmOCDMap.put(pid, ocd);
            return ocd;
          }
          else {
            throw new RuntimeException("No config for pid " + pid);
          }
        }
        catch (Exception e) {
          log.error("Failed to get service pid " + pid, e);
          return null;
        }
      }
      else {
        log.warn("Failed to get CA when getting pid " + pid);
        return null;
      }
    }
  };

    setupMTListener();
  }


  /**
   * Stop listening for bundles.
   */
  public void close() {
    if(cmTracker != null) {
      cmTracker.close();
      cmTracker = null;
    }
    if(bl != null) {
      bc.removeBundleListener(bl);
    }
    bl = null;
  }

  /**
   * Explictly load a metatype provider from a bundle and cache
   * it for later retrival by <tt>getMTP</tt>.
   *
   * @throws Exception if loading fails
   */
  public void loadMTP(Bundle b) throws Exception {

    URL url;

    //try R4 first
    Enumeration metaTypeFiles;
    if (b.getState() == Bundle.INSTALLED) {
      Enumeration p = b.getEntryPaths(MetaTypeService.METATYPE_DOCUMENTS_LOCATION);
      if (p != null) {
        Vector tmp = new Vector();
      while(p.hasMoreElements()){
          tmp.addElement(b.getEntry((String)p.nextElement()));
      }
        metaTypeFiles = tmp.elements();
      } else {
        metaTypeFiles = null;
      }
    } else {
      metaTypeFiles = b.findEntries(MetaTypeService.METATYPE_DOCUMENTS_LOCATION, "*", false);
    }
    if(metaTypeFiles != null){
      BundleMetaTypeResource bmtr = new BundleMetaTypeResource(b);

      while(metaTypeFiles.hasMoreElements()){
        url = (URL)metaTypeFiles.nextElement();
        bmtr.mergeWith(Loader.loadBMTIfromUrl(bc, b, url));
      }

      bmtr.prepare();

      providers.put(b, bmtr);
    }
    else{
      //proprietary legacy

      MTP mtp = null;

      String defStr = (String)b.getHeaders().get(ATTRIB_METATYPEURL);

      if(defStr == null || "".equals(defStr)) {
        defStr = METATYPE_RESOURCE;
      }

      if(defStr.startsWith("!")) {
        url = b.getEntry(defStr.substring(1));
      }
      else if(defStr.startsWith("/")) {
        url = b.getEntry(defStr);
      }
      else {
        url = new URL(defStr);
      }

      if(url != null) {
        try {
          mtp = Loader.loadMTPFromURL(b, url);
          providers.put(b, mtp);
        }
        catch (Exception e) {
          log.info("Failed to load metatype XML from bundle " + b.getBundleId(), e);
          //throw e;
        }
      }

      //defaults are specified in the file itself in R4

      String valStr = (String)b.getHeaders().get(ATTRIB_CMDEFAULTSURL);

      if(valStr == null || "".equals(valStr)) {
        valStr = CMDEFAULTS_RESOURCE;
      }

      if(valStr.startsWith("!")) {
        url = b.getEntry(valStr.substring(1));
      }
      else if(valStr.startsWith("/")) {
        url = b.getEntry(valStr);
      }
      else {
        url = new URL(valStr);
      }

      if(url != null) {
        try {
          Loader.loadDefaultsFromURL(mtp, url);
          log.info("Bundle " + b.getBundleId() + ": loaded default values");
        }
        catch (Exception e) {
          log.info("Failed to load cm defaults XML from bundle " + b.getBundleId(), e);
          //throw e;
        }
      }
    } //proprietary legacy

  }

  public String[] getPids() {
    synchronized(providers) {
      Set set = new HashSet();
      for(Iterator it = providers.keySet().iterator(); it.hasNext();) {
        Bundle b   = (Bundle)it.next();
        MetaTypeInformation    mtp = (MetaTypeInformation)providers.get(b);
        String[] pids = mtp.getPids();
        for(int i = 0; pids != null && i < pids.length; i++) {
          set.add(pids[i]);
        }
      }
      for(Iterator it = mtMap.keySet().iterator(); it.hasNext();) {
        ServiceReference sr = (ServiceReference)it.next();
        try {
          String[] pids = (String[])sr.getProperty("service.pids");
          for(int i = 0; pids != null && i < pids.length; i++) {
            set.add(pids[i]);
          }
        }
        catch (Exception e) {
          log.warn("No service.pids property on " + sr);
        }
      }
      return MTP.toStringArray(set);
    }
  }

  public String[] getFactoryPids() {
    synchronized(providers) {
      Set set = new HashSet();
      for(Iterator it = providers.keySet().iterator(); it.hasNext();) {
  Bundle b   = (Bundle)it.next();
  MetaTypeInformation mtp = (MetaTypeInformation)providers.get(b);
  String[] pids = mtp.getFactoryPids();
  for(int i = 0; pids != null && i < pids.length; i++) {
    set.add(pids[i]);
  }
      }
      for(Iterator it = mtMap.keySet().iterator(); it.hasNext();) {
  ServiceReference sr = (ServiceReference)it.next();
  try {
    String[] pids = (String[])sr.getProperty("factory.pids");
    for(int i = 0; pids != null && i < pids.length; i++) {
      set.add(pids[i]);
    }
  } catch (Exception e) {
    log.warn("No factory.pids property on " + sr);
  }
      }
      return MTP.toStringArray(set);
    }
  }

  public String[] getLocales() {
    return null;
  }


  /**
   * Get a loaded metatype provider, given a bundle.
   *
   * @return Provider if such provider is found, otherwise <tt>null</tt>.
   */
  public MetaTypeInformation getMTP(Bundle b) {
    ServiceReference cmSR = cmTracker.getServiceReference();

    MetaTypeInformation mti = null;

    if(cmSR != null && cmSR.getBundle() == b) {
      mti = cmMTP;
    }
    else if(b.getBundleId() == 0) {
      mti = this;
    }
    else {
      mti = (MetaTypeInformation)providers.get(b);
    }

    return mti;
  }

  /**
   * Get an ObjectClassDefinition given a PID.
   *
   * @return ObjectClassDefinition if PID exists, otherwise <tt>null</tt>.
   */
  public ObjectClassDefinition getObjectClassDefinition(String pid, String locale) {

    synchronized(providers) {
      for(Iterator it = providers.keySet().iterator(); it.hasNext();) {
        Bundle b   = (Bundle)it.next();
        MetaTypeProvider    mtp = (MetaTypeProvider)providers.get(b);

        ObjectClassDefinition  ocd = mtp.getObjectClassDefinition(pid, locale);
        if(ocd != null) {
          return ocd;
        }
      }

      synchronized(mtMap) {
        for(Iterator it = mtMap.keySet().iterator(); it.hasNext();) {
          ServiceReference sr = (ServiceReference)it.next();
          MetaTypeProvider mt = (MetaTypeProvider)mtMap.get(sr);
          ObjectClassDefinition ocd = mt.getObjectClassDefinition(pid, locale);
          if(ocd != null) {
            return ocd;
          }
        }
      }
      return null;
    }
  }

  ServiceListener mtListener = null;

  // ServiceReference -> MetatypeProvider
  Map mtMap = new HashMap();

  void setupMTListener() {

    mtListener = new ServiceListener() {

      public void serviceChanged(ServiceEvent ev) {
        ServiceReference sr = ev.getServiceReference();
        synchronized(mtMap) {
          switch(ev.getType()) {
            case ServiceEvent.REGISTERED:
              MetaTypeProvider mt = (MetaTypeProvider)bc.getService(sr);
              if(mt != SystemMetatypeProvider.this) {
                mtMap.put(sr, mt);
              }
              break;
            case ServiceEvent.UNREGISTERING:
              bc.ungetService(sr);
              mtMap.remove(sr);
              break;
          }
        }
      }
    };

    try {
      String filter = "(objectclass=" + MetaTypeProvider.class.getName() + ")";

      ServiceReference[] srl = bc.getServiceReferences(null, filter);

      for(int i = 0; srl != null && i < srl.length; i++) {
        mtListener.serviceChanged(new ServiceEvent(ServiceEvent.REGISTERED, srl[i]));
      }
      bc.addServiceListener(mtListener, filter);

    }
    catch(Exception e) {
      log.error("Failed to get other providers", e);
    }

  }

  Set getCMServicePIDs() {
    Set pids = new HashSet();
    ConfigurationAdmin ca = (ConfigurationAdmin)cmTracker.getService();
    if(ca != null) {
      try {
        Configuration[] configs = ca.listConfigurations("(service.pid=*)");
        for(int i = 0; configs != null && i < configs.length; i++) {
          if(configs[i].getFactoryPid() == null) {
            pids.add(configs[i].getPid());
          }
        }
      }
      catch (Exception e) {
        log.error("Failed to get service pids", e);
      }
    }
    return pids;
  }

  Set getCMFactoryPIDs() {
    Set pids = new HashSet();
    ConfigurationAdmin ca = (ConfigurationAdmin)cmTracker.getService();
    if(ca != null) {
      try {
        Configuration[] configs = ca.listConfigurations("(service.pid=*)");
        for(int i = 0; configs != null && i < configs.length; i++) {
          if(configs[i].getFactoryPid() != null) {
            pids.add(configs[i].getFactoryPid());
          }
        }
      }
      catch (Exception e) {
        log.error("Failed to get service pids", e);
      }
    }
    return pids;
  }

  public MetaTypeInformation getMetaTypeInformation(Bundle bundle) {

    MetaTypeInformation mti;

    mti = (MetaTypeInformation)providers.get(bundle);
    if(mti != null){
      return mti;
    }

    synchronized(mtMap) {
      for(Iterator it = mtMap.keySet().iterator(); it.hasNext();) {
        ServiceReference sr = (ServiceReference)it.next();
        if(sr.getBundle() == bundle){
          MetaTypeProvider mtp = (MetaTypeProvider)mtMap.get(sr);
          if(!(mtp instanceof MetaTypeInformation)){
            return new BundleMetaTypeProvider(mtp, sr);
          }
          else{
            return (MetaTypeInformation) mtp;
          }
        }
        }
        return null;
    }
  }
}

class BundleMetaTypeProvider implements MetaTypeInformation{

  private MetaTypeProvider mtp;
  private Bundle bundle;

  //id -> MetaData
  private String[] pids;
  private String[] factoryPids;

  public BundleMetaTypeProvider(MetaTypeProvider mtp, ServiceReference sr){
    this.mtp = mtp;
    this.bundle = sr.getBundle();

    if(mtp instanceof ManagedService){
      pids = new String[1];
      pids[0] = (String) sr.getProperty(Constants.SERVICE_PID);
      factoryPids = new String[0];
    }
    else if(mtp instanceof ManagedServiceFactory){
      factoryPids = new String[1];
      factoryPids[0] = (String) sr.getProperty(Constants.SERVICE_PID);
      pids = new String[0];
    }
  }

  public Bundle getBundle() {
    return bundle;
  }

  public String[] getFactoryPids() {
    return factoryPids;
  }

  public String[] getPids() {
    return pids;
  }

  public String[] getLocales() {
    return mtp.getLocales();
  }

  public ObjectClassDefinition getObjectClassDefinition(String id, String locale) {
    return mtp.getObjectClassDefinition(id, locale);
  }

} //class
TOP

Related Classes of org.knopflerfish.util.metatype.SystemMetatypeProvider

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.