diff --git a/core/src/main/java/hudson/ExtensionFinder.java b/core/src/main/java/hudson/ExtensionFinder.java index 106d70dd77..af318d6d5f 100644 --- a/core/src/main/java/hudson/ExtensionFinder.java +++ b/core/src/main/java/hudson/ExtensionFinder.java @@ -1,7 +1,7 @@ /* * The MIT License * - * Copyright (c) 2004-2010, Sun Microsystems, Inc., InfraDNA, Inc. + * Copyright (c) 2004-2010, Sun Microsystems, Inc., InfraDNA, Inc., CloudBees, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,11 +24,14 @@ package hudson; 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.Singleton; +import com.google.inject.Scope; +import com.google.inject.Scopes; import com.google.inject.name.Names; import net.java.sezpoz.Index; import net.java.sezpoz.IndexItem; @@ -38,6 +41,7 @@ import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; import java.util.Collections; +import java.util.Map.Entry; import java.util.logging.Logger; import java.util.logging.Level; import java.util.List; @@ -132,6 +136,131 @@ public abstract class ExtensionFinder implements ExtensionPoint { public void scout(Class extensionType, Hudson hudson) { } + /** + * Discovers components via sezpoz but instantiates them by using Guice. + */ + @Extension + public static 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(FAULT_TOLERANT_SCOPE); + } 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(FAULT_TOLERANT_SCOPE); + } + } 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; + } + + /** + * TODO: need to learn more about concurrent access to {@link Injector} and how it interacts + * with classloading. + */ + @Override + public void scout(Class extensionType, Hudson hudson) { + } + + /** + * {@link Scope} that allows a failure to create a component, + * and change the value to null. + * + *

+ * 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. + */ + public static final Scope FAULT_TOLERANT_SCOPE = new Scope() { + 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(GuiceFinder.class.getName()); + } + /** * The bootstrap implementation that looks for the {@link Extension} marker. * diff --git a/core/src/main/java/hudson/guice/FaultTorelantScope.java b/core/src/main/java/hudson/guice/FaultTorelantScope.java deleted file mode 100644 index 0ad3a53183..0000000000 --- a/core/src/main/java/hudson/guice/FaultTorelantScope.java +++ /dev/null @@ -1,38 +0,0 @@ -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 deleted file mode 100644 index 314dcfde7d..0000000000 --- a/core/src/main/java/hudson/guice/GuiceFinder.java +++ /dev/null @@ -1,124 +0,0 @@ -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()); -}