diff --git a/core/src/main/java/hudson/ExtensionFinder.java b/core/src/main/java/hudson/ExtensionFinder.java index 516a4d5bd5..106d70dd77 100644 --- a/core/src/main/java/hudson/ExtensionFinder.java +++ b/core/src/main/java/hudson/ExtensionFinder.java @@ -133,12 +133,11 @@ public abstract class ExtensionFinder implements ExtensionPoint { } /** - * The default implementation that looks for the {@link Extension} marker. + * The bootstrap implementation that looks for the {@link Extension} marker. * *

* Uses Sezpoz as the underlying mechanism. */ - @Extension public static final class Sezpoz extends ExtensionFinder { public Collection> find(Class type, Hudson hudson) { List> result = new ArrayList>(); @@ -210,125 +209,5 @@ public abstract class ExtensionFinder implements ExtensionPoint { } } - @Extension - public static final class GuiceFinder extends ExtensionFinder { - private Injector container; - - public GuiceFinder() { - Module m = new AbstractModule() { - @Override - protected void configure() { - ClassLoader cl = Hudson.getInstance().getPluginManager().uberClassLoader; - int id=0; - for (final IndexItem item : Index.load(Extension.class, Object.class, cl)) { - id++; - try { - AnnotatedElement e = item.element(); - Class extType; - if (e instanceof Class) { - extType = (Class) e; - bind((Class)e); - continue; - } else - if (e instanceof Field) { - extType = ((Field)e).getType(); - bind(extType).annotatedWith(Names.named(String.valueOf(id))) - .toInstance(item.instance()); - } else - if (e instanceof Method) { - extType = ((Method)e).getReturnType(); - } else - throw new AssertionError(); - - if(type.isAssignableFrom(extType)) { - Object instance = item.instance(); - if(instance!=null) - result.add(new ExtensionComponent(type.cast(instance),item.annotation())); - } - } catch (LinkageError e) { - // sometimes the instantiation fails in an indirect classloading failure, - // which results in a LinkageError - LOGGER.log(item.annotation().optional() ? Level.FINE : Level.WARNING, - "Failed to load "+item.className(), e); - } catch (InstantiationException e) { - LOGGER.log(item.annotation().optional() ? Level.FINE : Level.WARNING, - "Failed to load "+item.className(), e); - } - } - } - }; - container = Guice.createInjector(m); - } - - public Collection> find(Class type, Hudson hudson) { - List> result = new ArrayList>(); - - ClassLoader cl = hudson.getPluginManager().uberClassLoader; - for (IndexItem item : Index.load(Extension.class, Object.class, cl)) { - try { - AnnotatedElement e = item.element(); - Class extType; - if (e instanceof Class) { - extType = (Class) e; - } else - if (e instanceof Field) { - extType = ((Field)e).getType(); - } else - if (e instanceof Method) { - extType = ((Method)e).getReturnType(); - } else - throw new AssertionError(); - - if(type.isAssignableFrom(extType)) { - Object instance = item.instance(); - if(instance!=null) - result.add(new ExtensionComponent(type.cast(instance),item.annotation())); - } - } catch (LinkageError e) { - // sometimes the instantiation fails in an indirect classloading failure, - // which results in a LinkageError - LOGGER.log(item.annotation().optional() ? Level.FINE : Level.WARNING, - "Failed to load "+item.className(), e); - } catch (InstantiationException e) { - LOGGER.log(item.annotation().optional() ? Level.FINE : Level.WARNING, - "Failed to load "+item.className(), e); - } - } - - return result; - } - - @Override - public void scout(Class extensionType, Hudson hudson) { - ClassLoader cl = hudson.getPluginManager().uberClassLoader; - for (IndexItem item : Index.load(Extension.class, Object.class, cl)) { - try { - AnnotatedElement e = item.element(); - Class extType; - if (e instanceof Class) { - extType = (Class) e; - } else - if (e instanceof Field) { - extType = ((Field)e).getType(); - } else - if (e instanceof Method) { - extType = ((Method)e).getReturnType(); - } else - throw new AssertionError(); - // accroding to http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6459208 - // this appears to be the only way to force a class initialization - Class.forName(extType.getName(),true,extType.getClassLoader()); - } catch (InstantiationException e) { - LOGGER.log(item.annotation().optional() ? Level.FINE : Level.WARNING, - "Failed to scout "+item.className(), e); - } catch (ClassNotFoundException e) { - LOGGER.log(Level.WARNING,"Failed to scout "+item.className(), e); - } catch (LinkageError e) { - LOGGER.log(Level.WARNING,"Failed to scout "+item.className(), e); - } - } - } - } - private static final Logger LOGGER = Logger.getLogger(ExtensionFinder.class.getName()); } diff --git a/core/src/main/java/hudson/guice/FaultTorelantScope.java b/core/src/main/java/hudson/guice/FaultTorelantScope.java new file mode 100644 index 0000000000..0ad3a53183 --- /dev/null +++ b/core/src/main/java/hudson/guice/FaultTorelantScope.java @@ -0,0 +1,38 @@ +package hudson.guice; + +import com.google.inject.Key; +import com.google.inject.Provider; +import com.google.inject.Scope; +import com.google.inject.Scopes; + +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Decorating {@link Scope} that tolerates a failure to instantiate an object. + * + *

+ * This is necessary as a failure to load one plugin shouldn't fail the startup of the entire Hudson. + * Instead, we should just drop the failing plugins. + * + * @author Kohsuke Kawaguchi + */ +public class FaultTorelantScope implements Scope { + public static final Scope INSTANCE = new FaultTorelantScope(); + + public Provider scope(Key key, Provider unscoped) { + final Provider base = Scopes.SINGLETON.scope(key,unscoped); + return new Provider() { + public T get() { + try { + return base.get(); + } catch (Exception e) { + LOGGER.log(Level.WARNING,"Failed to instantiate",e); + return null; + } + } + }; + } + + private static final Logger LOGGER = Logger.getLogger(FaultTorelantScope.class.getName()); +} diff --git a/core/src/main/java/hudson/guice/GuiceFinder.java b/core/src/main/java/hudson/guice/GuiceFinder.java new file mode 100644 index 0000000000..314dcfde7d --- /dev/null +++ b/core/src/main/java/hudson/guice/GuiceFinder.java @@ -0,0 +1,124 @@ +package hudson.guice; + +import com.google.inject.AbstractModule; +import com.google.inject.Binding; +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.google.inject.Key; +import com.google.inject.Module; +import com.google.inject.Provider; +import com.google.inject.Scopes; +import com.google.inject.name.Names; +import hudson.Extension; +import hudson.ExtensionComponent; +import hudson.ExtensionFinder; +import hudson.model.Hudson; +import net.java.sezpoz.Index; +import net.java.sezpoz.IndexItem; + +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map.Entry; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** +* @author Kohsuke Kawaguchi +*/ +@Extension +public final class GuiceFinder extends ExtensionFinder { + private Injector container; + + public GuiceFinder() { + List modules = new ArrayList(); + modules.add(new AbstractModule() { + @SuppressWarnings({"unchecked", "ChainOfInstanceofChecks"}) + @Override + protected void configure() { + ClassLoader cl = Hudson.getInstance().getPluginManager().uberClassLoader; + int id=0; + + for (final IndexItem item : Index.load(Extension.class, Object.class, cl)) { + id++; + try { + AnnotatedElement e = item.element(); + Class extType; + if (e instanceof Class) { + bind((Class)e).in(FaultTorelantScope.INSTANCE); + } else { + if (e instanceof Field) { + extType = ((Field)e).getType(); + } else + if (e instanceof Method) { + extType = ((Method)e).getReturnType(); + } else + throw new AssertionError(); + + // use arbitrary + bind(extType).annotatedWith(Names.named(String.valueOf(id))) + .toProvider(new Provider() { + public Object get() { + return instantiate(item); + } + }).in(FaultTorelantScope.INSTANCE); + } + } catch (LinkageError e) { + // sometimes the instantiation fails in an indirect classloading failure, + // which results in a LinkageError + LOGGER.log(item.annotation().optional() ? Level.FINE : Level.WARNING, + "Failed to load "+item.className(), e); + } catch (InstantiationException e) { + LOGGER.log(item.annotation().optional() ? Level.FINE : Level.WARNING, + "Failed to load "+item.className(), e); + } + } + } + }); + + for (ExtensionComponent ec : new Sezpoz().find(Module.class, Hudson.getInstance())) { + modules.add(ec.getInstance()); + } + + container = Guice.createInjector(modules); + } + + private Object instantiate(IndexItem item) { + try { + return item.instance(); + } catch (LinkageError e) { + // sometimes the instantiation fails in an indirect classloading failure, + // which results in a LinkageError + LOGGER.log(item.annotation().optional() ? Level.FINE : Level.WARNING, + "Failed to load "+item.className(), e); + } catch (InstantiationException e) { + LOGGER.log(item.annotation().optional() ? Level.FINE : Level.WARNING, + "Failed to load "+item.className(), e); + } + return null; + } + + public Collection> find(Class type, Hudson hudson) { + List> result = new ArrayList>(); + + for (Entry, Binding> e : container.getBindings().entrySet()) { + if (type.isAssignableFrom(e.getKey().getTypeLiteral().getRawType())) { + // TODO: how do we get ordinal? + Object o = e.getValue().getProvider().get(); + if (o!=null) + result.add(new ExtensionComponent(type.cast(o))); + } + } + + return result; + } + + @Override + public void scout(Class extensionType, Hudson hudson) { + } + + private static final Logger LOGGER = Logger.getLogger(GuiceFinder.class.getName()); +}