Package org.locationtech.udig.catalog.internal

Source Code of org.locationtech.udig.catalog.internal.ResolveManager$BrokenIResolveAdapaterFactory

/* uDig - User Friendly Desktop Internet GIS client
* http://udig.refractions.net
* (C) 2004-2012, Refractions Research Inc.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD
* License v1.0 (http://udig.refractions.net/files/bsd3-v10.html).
*/
package org.locationtech.udig.catalog.internal;

import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.locationtech.udig.catalog.CatalogPlugin;
import org.locationtech.udig.catalog.IResolve;
import org.locationtech.udig.catalog.IResolveAdapterFactory;
import org.locationtech.udig.catalog.IResolveManager;
import org.locationtech.udig.catalog.ResolveAdapterFactory;
import org.locationtech.udig.core.internal.ExtensionPointList;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.ILog;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;

/**
* Default implementation of {@link IResolveManager}
* @author Jesse
* @since 1.1.0
* @version 1.3.2
*/
public class ResolveManager implements IResolveManager {

    private static final String LIST_ID = "org.locationtech.udig.catalog.resolvers"; //$NON-NLS-1$

    /**
     * Resolver configuration elements mapped to resulting factory, used to lazily
     * create factories as needed without reprocessing the extention point again and again.
     * <p>
     * This represents IResolveAdapterFactories that have been registered using xml.
     */
    Map<IConfigurationElement,IResolveAdapterFactory> factories=new HashMap<IConfigurationElement, IResolveAdapterFactory>();

    /**
     * Is this a cache of exceptions thrown?
     */
    Map<IResolveAdapterFactory,Set<Class<?>>> exceptions=new HashMap<IResolveAdapterFactory,Set<Class<?>>>();

    /**
     * Set of registered factories.
     * This represents IResolveAdapterFactories that have been registered using code.
     */
    Set<IResolveAdapterFactory> registeredFactories=new HashSet<IResolveAdapterFactory>();
   
    public ResolveManager() {
        List<IConfigurationElement> extensionList = ExtensionPointList.getExtensionPointList(LIST_ID);
       
        for( IConfigurationElement element : extensionList ) {
            factories.put(element, null);
        }
    }
   
    /**
     * Check with the registered IResolveAdaptorFactories to see
     * if any of them can convert provided handle to requested target class.
     * @param resolve Resolve handle to convert
     * @param adapter Requested target interface
     */
    public boolean canResolve( IResolve resolve, Class<?> adapter ) {
      for( Map.Entry<IConfigurationElement,IResolveAdapterFactory> entry : factories.entrySet() ){
        IConfigurationElement element = entry.getKey();
        try {
          // check the configuration information before making a factory
          if( isResolvableType( element, resolve ) &&
            isTargetTypeSupported(element, adapter)){
            // Use the extension point information as a quick sanity check to ensure
            // the factory is relevant to the problem at hand
            IResolveAdapterFactory factory = getResolveAdapterFactory( entry );
            if( factory.canAdapt( resolve, adapter) ){
              return true;
            }
          }
        }
        catch( RuntimeException ignore ){
          // problem encountered with entry; depending
          // on the problem we may consider disabling the entry
          // and logging a warning?
          CatalogPlugin.log( ignore.getLocalizedMessage(), ignore );
        }
      }
     
      // Go through registered factories second, ensuring that
      // XML can always override something that has been hard coded
      //
      for( IResolveAdapterFactory factory : registeredFactories ) {
        try {
          Set<Class<?>> ignoreSet = exceptions.get(factory);
          if( ignoreSet != null && ignoreSet.contains(adapter) ){
            continue; // skip this as it is listed as an exception
          }
          if( factory.canAdapt( resolve, adapter)){
            return true;
          }
        }
        catch( RuntimeException ignore ){
          // problem encountered with factory; depending
          // on the problem we may consider removing the factory
          CatalogPlugin.log( ignore.getLocalizedMessage(), ignore );
        }
        }
      return false; // nobody can adapat to the requested interface
    }
   
    /**
     * This method goes through all the factories registered by hand and checks to see
     * if any of them are willing to adapt to the target class.
     * @param resolve
     * @param targetClass
     * @return The first factory that is willing to adapat to the target classs
     */
    /*
    private IResolveAdapterFactory findRegisteredFactory( IResolve resolve, Class<?> targetClass ) {
        for( IResolveAdapterFactory factory : registeredFactories ) {
            if( factory.canAdapt(resolve, targetClass) ){
                Set<Class<?>> set = exceptions.get(factory);
                if( set==null || !set.contains(targetClass) )
                    return factory;
            }
        }
        return null;
    }
    */
    /**
     * XML check on the "resolveableType" entry to ensure the provided resolve handle
     * meets the basic requirements.
     *
     * @param entry
     * @param resolve
     * @return true if we resolve handle is applicable ot this factory
     */
    private boolean isResolvableType( IConfigurationElement element, IResolve resolve ){
      String requiredType=element.getAttribute("resolveableType"); //$NON-NLS-1$
    if (requiredType == null) {
      String badPuppy = element.getContributor().getName();
      if (badPuppy == null) {
        badPuppy = "A plugin";
      }
      System.out.println(badPuppy + " failed to configure ResolveAdaptorFactory: requiredType missing ");
      return false; // this should not happen! did you forget to fill in
              // their XML resoleableType info?
    }
        try {
            Class< ? > clazz=resolve.getClass().getClassLoader().loadClass(requiredType);
            return clazz.isAssignableFrom(resolve.getClass() );
        }
        catch (ClassNotFoundException huh){
          return false;
        }
    }
    /**
     * XML check on the "resolve" entries to ensure the target type is supported
     * (we will still have to check with canResolve but hopefully we can rule
     *  out a few before hand).
     *
     * @param entry
     * @param target
     * @return true if the target should be considered
     */
    private boolean isTargetTypeSupported( IConfigurationElement element, Class<?> target ){
      IConfigurationElement[] resolveList  = element.getChildren("resolve"); //$NON-NLS-1$
        for( IConfigurationElement child : resolveList ) {
            String resolveType=child.getAttribute("type"); //$NON-NLS-1$
            if( !resolveType.startsWith("net.refractions") && !resolveType.startsWith("org.locationtech.udig") ){
                // We first try a class loader trick to grab the target class
                // without forcing the load of the plugin where the element
                // comes from (this works in may cases where the type is something
                // common from org.locationtech.udig.libs)
                try{
                    ClassLoader classLoader = target.getClassLoader();
                    if( classLoader==null ){
                        classLoader=ClassLoader.getSystemClassLoader();
                    }
                    Class< ? > resolvedClass = classLoader.loadClass(resolveType);
                   
                    if( target.isAssignableFrom(resolvedClass) ){
                        return true;
                    }
                    else {                 
                      continue; // we were able to load the class and it did not match
                    }
                } catch(ClassNotFoundException e2){
                    // that is no good, let's try using the RCP classloader
                }
            }
            // Okay that optimisation failed; lets use the platform facilities
            // like a good RCP programmer
            try {             
              // only way to check is to actually make the factory, and use
              // the factory's class loader to grab the target class
              IResolveAdapterFactory factory = getResolveAdapterFactory( element );
              if( factory instanceof BrokenIResolveAdapaterFactory){
                // not even this factory can be loaded ... skip
                continue;
              }
              ClassLoader classLoader = factory.getClass().getClassLoader();
                if( classLoader != null ){
                  Class< ? > resolvedClass = classLoader.loadClass(resolveType);
                  if( target.isAssignableFrom(resolvedClass) ){
                        return true;
                    }
                    else {
                      continue; // we were able to load the class and it did not match
                    }
                }             
                else {
                  // we can not figure out what the resolvedClass is
                  // (probably a configuration error)
                  throw new ClassNotFoundException( resolveType );
                }
            }
            catch(ClassNotFoundException notFound){
              ILog log = CatalogPlugin.getDefault().getLog();
              Status status = new Status(
                  IStatus.WARNING,
                  element.getContributor().getName(),
                  "Cannot determine resolve class for "+element.getDeclaringExtension().getUniqueIdentifier(), //$NON-NLS-1$
                  notFound );
        log.log( status );
            }
        }
        return false;
    }
   
    /*
    @SuppressWarnings("unchecked")
    private boolean canResolve( IConfigurationElement element, IResolve resolve, Class targetClass ) {
      // Do a couple of quick sanity checks against the XML
      if( !isResolvableType(element, resolve)){
        return false;
      }
      if( !isTargetTypeSupported( element, targetClass )){
        return false;
      }
      // okay now it is worth asking the factory if it canResolve
      IResolveAdapterFactory factory = getResolveAdapterFactory( element );
      return factory.canAdapt( resolve, targetClass );
    }
    */
    /**
     * Register the provided adapater factory with the resolve manager.
     * <p>
     * The provided factory will be checked by all IResolve implementations
     * as part of their API contract. You can use your factory to wrap
     * additional interfaces around existing IResolve implementations.
     */
    public void registerResolves( IResolveAdapterFactory factory ) {
        registeredFactories.add(factory);
    }

    @Override
    public void register(ResolveAdapterFactory factory) {
        registeredFactories.add( factory );
    }
    /**
     * Used as a placeholder to mark broken IResolveAdapatorFactory instances.
     * <p>
     * This only occurs when the configuration element "class" has a failure
     * on being constructed.
     *
     * @author Jody
     */
    static class BrokenIResolveAdapaterFactory implements IResolveAdapterFactory {
      CoreException problem;
      public BrokenIResolveAdapaterFactory( CoreException coreException ){
        problem = coreException;
      }
    public <T> T adapt(IResolve resolve, Class<T> adapter,
        IProgressMonitor monitor) throws IOException {
      if( monitor == null ) monitor = new NullProgressMonitor();

      monitor.beginTask( problem.toString(), 1);
      monitor.done();
      throw (IOException) new IOException("This factory is broken:"+problem).initCause(problem); //$NON-NLS-1$
    }

    /** This factory is broken and cannot adapt anything */
    public boolean canAdapt(IResolve resolve,
        Class<? extends Object> adapter) {
      return false;
    }
    }
   
    protected IResolveAdapterFactory getResolveAdapterFactory( Map.Entry<IConfigurationElement,IResolveAdapterFactory> entry ){
      synchronized (factories) {
        if( entry.getValue() != null ) return entry.getValue();

        IConfigurationElement element = entry.getKey();
        IResolveAdapterFactory factory;
          try {
            factory= (IResolveAdapterFactory)
              element.createExecutableExtension("class"); //$NON-NLS-1$         
          } catch (CoreException e) {
            CatalogPlugin.log( e.toString(), e );
            factory = new BrokenIResolveAdapaterFactory(e);
          }
          entry.setValue( factory );         
          return factory;
      }
    }

    protected IResolveAdapterFactory getResolveAdapterFactory(IConfigurationElement element) {
        synchronized (factories) {
            IResolveAdapterFactory factory = factories.get(element);
            if (factory != null)
                return factory;

            try {
                factory = (IResolveAdapterFactory) element.createExecutableExtension("class"); //$NON-NLS-1$         
            } catch (CoreException e) {
                String message = "Marking IResolveAdaptorFactory as unavaiable:"+e;
                IStatus status = new Status( IStatus.WARNING, element.getContributor().getName(), message, e);
                CatalogPlugin.getDefault().getLog().log(status);
                factory = new BrokenIResolveAdapaterFactory(e);
            }
            factories.put(element, factory);
            return factory;
        }
    }
   
    /**
     * Go through the available factories and ask them to resolve to the provided
     * targetType.
     */
    public <T> T resolve( IResolve resolve, Class<T> adapter, IProgressMonitor monitor ) throws IOException {
      if( monitor == null ) monitor = new NullProgressMonitor();
      int count = registeredFactories.size() + factories.size();
     
      monitor.beginTask("Searching for "+adapter.getCanonicalName(), count*10 ); //$NON-NLS-1$
      try {
        for( Map.Entry<IConfigurationElement,IResolveAdapterFactory> entry : factories.entrySet() ){
          IConfigurationElement element = entry.getKey();
          try {
            // check the configuration information before making a factory
            if( isResolvableType( element, resolve ) &&
              isTargetTypeSupported(element, adapter)){
              // Use the extension point information as a quick sanity check to ensure
              // the factory is relevant to the problem at hand
              IResolveAdapterFactory factory = getResolveAdapterFactory( entry );
              if( factory.canAdapt( resolve, adapter)){
                // we think we can do this one...
                IProgressMonitor subMonitor = SubMonitor.convert(monitor, factory.getClass().getCanonicalName(), 10 );
              Object value = factory.adapt( resolve, adapter, subMonitor );
              if( value != null ){
                return adapter.cast( value );
              }
              }
              else {
                monitor.worked(10);
              }
            }
            else {
              monitor.worked(10);
            }
          }
          catch( RuntimeException ignore ){
            // problem encountered with entry; depending
            // on the problem we may consider disabling the entry
            // and logging a warning?
            CatalogPlugin.log( ignore.getLocalizedMessage(), ignore );
          }
        }
       
        // Go through registered factories second, ensuring that
        // XML can always override something that has been hard coded
        //
        for( IResolveAdapterFactory factory : registeredFactories ) {
          try {
            Set<Class<?>> ignoreSet = exceptions.get(factory);
            if( ignoreSet != null && ignoreSet.contains(adapter) ){
              monitor.worked(10);
              continue; // skip this as it is listed as an exception
            }
            if( factory.canAdapt( resolve, adapter)){
              // we think we can do this one...
              IProgressMonitor subMonitor = SubMonitor.convert(monitor, factory.getClass().getCanonicalName(), 10 );
            Object value = factory.adapt( resolve, adapter, subMonitor );
            if( value != null ){
              return adapter.cast( value );
            }
            }
            else {
              monitor.worked(10);
            }           
          }
          catch( RuntimeException ignore ){
            // problem encountered with factory; depending
            // on the problem we may consider removing the factory
            CatalogPlugin.log( ignore.getLocalizedMessage(), ignore );
          }
          }
        return null; // we have nothing to offer
      }
      finally {
        monitor.done();
      }
    }
    /*
    private IResolveAdapterFactory findFactory( IResolve resolve, Class<?> targetType ) {
        IResolveAdapterFactory factory = findRegisteredFactory(resolve, targetType);
        if( factory!=null )
            return factory;

        Set<IConfigurationElement> elements = factories.keySet();
        IConfigurationElement found=null;
       
        for( IConfigurationElement element : elements ) {
            if( canResolve(resolve, targetType) ){
                found=element;
                break;
            }
        }
       
        if( found==null )
            return null;
       
        factory=factories.get(found);
        if( factory!=null )
            return factory;
       
        try {
            factory=(IResolveAdapterFactory) found.createExecutableExtension("class"); //$NON-NLS-1$
            factories.put(found, factory);
        } catch (CoreException e) {
          String target = found.getAttribute("class"); //$NON-NLS-1$
            throw (RuntimeException) new RuntimeException( target ).initCause( e );
        }       
        return factory;
    }
    */
    /**
     * Remove the indicated factory from further consideration.
     * @param factory
     */
    public void unregisterResolves( IResolveAdapterFactory factory ) {
        registeredFactories.remove(factory);
        exceptions.remove(registeredFactories);
    }
   
    @Override
    public void unregister(ResolveAdapterFactory factory) {
        registeredFactories.remove(factory);
        exceptions.remove(registeredFactories);
    }
    /**
     * Register a couple of interfaces that should be skipped for the provided factory.
     * @param factory factory previous registered
     * @pram resolveType Please skip the resolve target
     */
    public void unregisterResolves( IResolveAdapterFactory factory, Class<?> resolveType ) {
        if( !registeredFactories.contains(factory) )
            throw new IllegalArgumentException(factory+" is not a registered factory"); //$NON-NLS-1$
       
        Set<Class<?>> set = exceptions.get(factory);
        if( set==null ){
            set=new HashSet<Class<?>>();
            exceptions.put(factory, set);
        }       
        set.add(resolveType);
    }

}
TOP

Related Classes of org.locationtech.udig.catalog.internal.ResolveManager$BrokenIResolveAdapaterFactory

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.