Package com.ibm.commons.extension

Source Code of com.ibm.commons.extension.ExtensionManager$Provider

/*
* © Copyright IBM Corp. 2012-2013
*
* 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 com.ibm.commons.extension;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.osgi.framework.Bundle;

import com.ibm.commons.log.CommonsLogger;
import com.ibm.commons.util.StringUtil;
import com.ibm.commons.util.TDiag;
import com.ibm.commons.util.io.StreamUtil;


/**
* Extension Manager.
*
* <p>This class is used to manage the extension in an independant manner. It can
* use services like extension or Eclipse extension points, depending on the
* running platform.</p>
*
* <p>As the runtime can be shared by multiple J2EE applications, some extensions
* can be defined globally (e.g. for all the applications) or on a per application
* basis.</p>
*
* @ibm-api
*/
public class ExtensionManager {
 
  /**
   * Interface that defines an application classloader.
   * An ApplicationClassLoader is used to load application specific resources.
   *
   * Not intended to be subclassed
   * @ibm-not-published
   */
  public interface ApplicationClassLoader {
    public Enumeration<URL> findApplicationResources(String resName) throws IOException;
  }

    private static Provider provider;
    static {
        try {
            // We should detect if we are running in an eclipse environment
            // We cannot use the platform object for this, as the platform object is using the
            // extension manager itself to get the actual class to load.
            // => Platform.getInstance().isEclipseBased() doesn't work properly
          // Moreover, in case of the Domino server, the OSGI integration sets the OSGi flgas
          // while we should use the Java services manager. for this reason, we have a flag
          // to set OSGi properly.
            try {
                String osgi = System.getProperty("osgi.framework.version"); // $NON-NLS-1$
                if(StringUtil.isNotEmpty(osgi)) {
                  try {
                    String prop = System.getProperty("com.ibm.common.ExtensionManager"); //$NON-NLS-1$
                    if(StringUtil.isEmpty(prop) || StringUtil.equals(prop, "osgi")) { //$NON-NLS-1$
                      // Make sure that the OSGi framework is actually available
                      // In case of a Domino agent, for example, the properties are set but OSGi is not available
                      // Make sure that it exists - if not, it generates an exception that will be caught.
                      Class.forName("org.eclipse.core.runtime.Platform");
                      provider = new EclipseProvider();
                    }
                  } catch(Throwable t) {}
                }
            } catch (Throwable e) {}
            if(provider==null) {
                provider = new JavaServiceProvider();
            }
        } catch(Throwable t) {
            t.printStackTrace();
        }
    }

   
    /**
     * Find the available implementations of a service for a particular Application.
     *
     * <p>This includes both the globally available services as well as the one defined in the
     * application class loader as well. The global services are generally read from the
     * Eclipse extension points while the per application are read using the services
     * definition (until OSGi will be available everywhere....)</p>
     * <p>The result is a list of service implementations (concrete classes)</p>
     * @param loader the class loader used to load the services
     * @param serviceType the name of the service to load
     * @return a List of services implementation
     * @ibm-api
     */
    public static List<Object> findApplicationServices(ClassLoader loader, String serviceType) {
        return findApplicationServices(null,loader,serviceType);
    }
   
    /**
     * Find the available implementations of a service for a particular Application.
     *
     * <p>Similar to com.ibm.commons.extension.ExtensionManager.findApplicationServices(ClassLoader, String)
     * but it also manages a cache which prevents the resources to be read if not
     * necessary.</p>
     *
     * @param services the Map that holds the cache. Must be one instance per Application
     * @param loader the class loader used to load the services
     * @param serviceType the name of the service to load
     * @return a List of services implementation
     * @ibm-api
     */
    public static List<Object> findApplicationServices(Map<String, List<Object>> services, ClassLoader loader, String serviceType) {
        if(services!=null) {
            List<Object> l = services.get(serviceType);
            if(l!=null) {
                return l;
            }
        }
        List<Object> l = loadServices(loader,serviceType);
        if(services!=null) {
            services.put(serviceType,l);
        }
        return l;
    }

    /**
     * Find the globally available implementations of a service.
     *
     * <p>The list only contained the services that are shared, and not the application
     * specific ones.</p>
     *
     * @param list an optional list containing the services. If not null, then it is returned
     * @param clazz the class to get the class loader for loading the services
     * @param serviceType the name of the service to load
     * @return a List of services implementation
     * @ibm-api
     */
    public static List<Object> findServices(List<Object> list, Class<?> clazz, String serviceType) {
        return findServices(list,clazz.getClassLoader(),serviceType);
    }


    /**
     * Find the globally available implementations of a service.
     *
     * <p>The list only contained the services that are shared, and not the application
     * specific ones.</p>
     *
     * @param list an optional list containing the services. If not null, then it is returned
     * @param classloader The class loader to look for the services
     * @param serviceType the name of the service to load
     * @return a List of services implementation
     * @ibm-api
     */
    public static List<Object> findServices(List<Object> list, ClassLoader loader, String serviceType) {
        if(list!=null) {
            return list;
        }
        // In case of an application class loader, ignores it
        // Note that this is only for a Domino environment and the XPages runtime
        ApplicationClassLoader ac = adaptApplicationClassloader(loader);
      if(ac!=null) {
          loader = loader.getParent();
        }
        list = loadServices(loader,serviceType);
        return list;
    }

    /**
     * Find the globally available implementations of a service.
     *
     * <p>This is the type safety implementation of the method using generics. The content
     * of the list is checked to ensure that all the implementations belong to the correct
     * type.</p>
     *
     * @param <T>
     * @param existingList
     *            already loaded service list; the services will only be loaded
     *            if list is <code>null</code>.
     * @param loader
     *            ClassLoader to use when loading the classes in a non-OSGI
     *            environment.
     * @param serviceType
     *            service id.
     * @param requiredType
     *            {@link Class} to be implemented by all contributing services.
     *            Services which do not implement that class will generate a
     *            warning and will not be included in the result {@link List}.
     *            When <code>null</code> no class validation is performed.
     * @return
     * @ibm-api
     */
    @SuppressWarnings("unchecked")//$NON-NLS-1$
    public static <T> List<T> findServices(List<T> existingList, ClassLoader loader, String serviceType, Class<T> requiredType){
        if(existingList!=null) {
            return (List<T>) existingList;
        }
       
        List<T> items = (List<T>)findServices(null, loader, serviceType);
        if( null != requiredType){
            for (int i = 0; i < items.size(); i++) {
                Object item = items.get(i);
               
                if( ! (requiredType.isAssignableFrom(item.getClass())) ){
                    logServiceNotInstanceOf(serviceType, item, requiredType);
                   
                    items.remove(i);
                    i--;
                }
            }
        }
        return items;
    }
    private static void logServiceNotInstanceOf(String extensionPointId, Object obj, Class<?> requiredType) {
        // this is a problem
        if( CommonsLogger.STANDARD.isWarnEnabled() ){
            String warnMsg = "The object {0} cannot contribute to the service {1}, as it is not an instance of {2}"// $NLW-ExtensionManager.ServiceObjectNotInstanceOfExpectedClass-1$
            CommonsLogger.STANDARD.warnp(ExtensionManager.class,
                    "logClassNotLibrary", warnMsg,//$NON-NLS-1$
                    obj,
                    extensionPointId,
                    requiredType.getName());
        }
    }

    /**
     * Load the available implementation of a service for a particular class loader.
     */
    private static List<Object> loadServices(final ClassLoader loader, final String serviceType) {
        List<Object> list = new ArrayList<Object>();
        provider.findInitializer(loader, list, serviceType);
        return list;
    }

    private interface Provider {
        public void findInitializer(ClassLoader loader, List<Object> initializers, String serviceType);
    }
    private static class JavaServiceProvider implements Provider {
        final String PREFIX = "META-INF/services/"; //$NON-NLS-1$
        public void findInitializer(ClassLoader loader, List<Object> initializers, String serviceType) {
            try {
                //PHIL: JDK 1.6 is providing a class to do that: java.util.ServiceLoader. Might
                // use that later
               
                // Look for all the resources in the class path
              Enumeration<URL> e = getResourcesList(loader, serviceType);
              if(e!=null) {
                  while( e.hasMoreElements() ) {
                      URL url = e.nextElement();
                      parseResource(loader,initializers,url, serviceType);
                  }
              }
            } catch( Throwable t ) {
                t.printStackTrace();
            }
        }
        Enumeration<URL> getResourcesList(ClassLoader loader, String serviceType) throws IOException {
          return loader.getResources(PREFIX+serviceType);
        }
        void parseResource(ClassLoader loader, List<Object> initializers, URL url, String serviceType) throws IOException {
            BufferedReader r = new BufferedReader(new InputStreamReader(url.openStream(), "utf-8")); //$NON-NLS-1$
            try {
                while(true) {
                    String s = r.readLine();
                    if(s==null) {
                        return;
                    }
                    int comment = s.indexOf('#');
                    if(comment>=0) {
                        s = s.substring(0,comment);
                    }
                    s = s.trim();
                   
                    // Try to load the class
                    if(StringUtil.isNotEmpty(s)) {
                        try {
                            Class<?> c = loader.loadClass(s);
                            Object o = c.newInstance();
                            initializers.add(o);
                        } catch(Throwable ex) {
                            logCouldNotCreateService(ex, s, serviceType);
                            TDiag.trace("Designer runtime: Error while parsing service file {0}", url.toString()); //$NON-NLS-1$
                        }
                    }
                }
            } finally {
                StreamUtil.close(r);
            }
        }
        private void logCouldNotCreateService(Throwable ex,
                String className, String serviceType) {
            if( CommonsLogger.STANDARD.isWarnEnabled() ){
                String warnMsg = "Could not create an instance of {0}, contributed to the service {1}."; // $NLW-ExtensionManager.Couldnotcreateaninstanceof0contri.1-1$
                CommonsLogger.STANDARD.warnp(this, "logCouldNotCreateService", ex, warnMsg, //$NON-NLS-1$
                        className, serviceType);
            }
        }
    }
   
    private static class EclipseProvider extends JavaServiceProvider {
        public void findInitializer(ClassLoader loader, List<Object> initializers, String serviceType) {
          // Load the global providers, from the platform
            try {
                IExtensionRegistry reg = org.eclipse.core.runtime.Platform.getExtensionRegistry();
                if (reg != null) {
                  // Services defined individually
                    // Look if someone implemented an extension point to retrieve the platform
                    IConfigurationElement[] elt = reg.getConfigurationElementsFor("com.ibm.commons.Extension"); // $NON-NLS-1$
                    for( int i=0; i<elt.length; i++ ) {
                        if( "service".equalsIgnoreCase(elt[i].getName()) ) { // $NON-NLS-1$
                            String type = elt[i].getAttribute("type"); //$NON-NLS-1$
                            if(StringUtil.equals(type, serviceType)) {
                                try {
                                    Object o = elt[i].createExecutableExtension("class"); // $NON-NLS-1$
                                    initializers.add(o);
                                } catch(Throwable ex) {
                                    logCouldNotCreateContribution(ex, elt[i], type);
                                }
                            }
                        }
                    }
                // Services read from META-INF/services
                //
                Set<URL> urls = new HashSet<URL>();
                    elt = reg.getConfigurationElementsFor("com.ibm.commons.ExtensionBundle")// $NON-NLS-1$
                    for( int i=0; i<elt.length; i++ ) {
                        try {
                            OSGiExtensionService o = (OSGiExtensionService)elt[i].createExecutableExtension("class");
                            Bundle bundle = o.getBundle();
                            if(bundle!=null) {
                              findServicesClassLoader(o.getClass().getClassLoader(), urls, initializers, serviceType);
                            }
                        } catch(Throwable ex) {
                            logCouldNotCreateContribution(ex, elt[i], serviceType);
                        }
                    }
                }
            } catch( Throwable t ) {
                t.printStackTrace();
            }
           
            // Then load the specific providers, from the current class loader
            // Change made for WAS environment
            ApplicationClassLoader ac = adaptApplicationClassloader(loader);
          if(ac!=null) {
            // Domino
            super.findInitializer(loader, initializers, serviceType);
          } else {
            // WAS
            if(loader==Thread.currentThread().getContextClassLoader()) {
              super.findInitializer(loader, initializers, serviceType);
            }
        }
        }
        Enumeration<URL> getResourcesList(ClassLoader loader, String serviceType) throws IOException {
          // In case of a Domino class loader, only return the resources from that class loader
            ApplicationClassLoader ac = adaptApplicationClassloader(loader);
          if(ac!=null) {
            return ac.findApplicationResources(PREFIX+serviceType);
          }
          // Else, return a enumeration for all of them
          return loader.getResources(PREFIX+serviceType);
        }
      private void findServicesClassLoader(ClassLoader loader, Set<URL> urls, List<Object> list, String serviceType) throws IOException {
          // Look for all the resources in the class path
            final String PREFIX = "META-INF/services/";
          for( Enumeration<URL> e=loader.getResources(PREFIX+serviceType); e.hasMoreElements(); ) {
            URL url = e.nextElement();
            findServicesClassLoader(list,loader, urls, url, serviceType);
          }
      }
      private void findServicesClassLoader(List<Object> list, ClassLoader loader, Set<URL> urls, URL url, String serviceType) throws IOException {
        if(url!=null && (urls==null || !urls.contains(url))) {
               parseResource(loader,list,url,serviceType);
              if(urls!=null) {
                urls.add(url);
          }
        }
        }
        void logCouldNotCreateContribution(Throwable ex,
                IConfigurationElement ext, String type) {
            if( CommonsLogger.STANDARD.isWarnEnabled() ){
                String extensionPointId = "com.ibm.commons.Extension"; //$NON-NLS-1$
                String className = ext.getAttribute("class"); //$NON-NLS-1$
                String warnMsg = "Could not create an instance of {0}, contributed to the extension point {1} with type {2}."; // $NLW-ExtensionManager.Couldnotcreateaninstanceof0contri-1$
                CommonsLogger.STANDARD.warnp(this, "logCouldNotCreateContribution", ex, warnMsg, //$NON-NLS-1$
                        className, extensionPointId, type);
            }
        }
    }

    // Helper
    private static ApplicationClassLoader adaptApplicationClassloader(ClassLoader loader) {
      if(loader instanceof ApplicationClassLoader) {
        return (ApplicationClassLoader)loader;
      }
      return null;
    }
   
}
TOP

Related Classes of com.ibm.commons.extension.ExtensionManager$Provider

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.