diff --git a/core/src/main/java/hudson/DescriptorExtensionList.java b/core/src/main/java/hudson/DescriptorExtensionList.java index 0856c686df462c47e9e253338830604363f7e493..3a570dc02309c0b3b9dcf4ebe2e7b9fed9cae4dd 100644 --- a/core/src/main/java/hudson/DescriptorExtensionList.java +++ b/core/src/main/java/hudson/DescriptorExtensionList.java @@ -29,12 +29,15 @@ import hudson.model.Hudson; import hudson.model.ViewDescriptor; import hudson.model.Descriptor.FormException; import hudson.util.Memoizer; +import hudson.util.Iterators; +import hudson.util.Iterators.FlattenIterator; import hudson.slaves.NodeDescriptor; import hudson.tasks.Publisher; import hudson.tasks.Publisher.DescriptorExtensionListImpl; import java.util.List; import java.util.ArrayList; +import java.util.Iterator; import java.util.logging.Logger; import java.util.concurrent.CopyOnWriteArrayList; import java.lang.reflect.Type; @@ -138,7 +141,7 @@ public class DescriptorExtensionList, D extends Descrip } /** - * Stores manually registered Descriptor instances. + * Stores manually registered Descriptor instances. Keyed by the {@link Describable} type. */ private static final Memoizer legacyDescriptors = new Memoizer() { public CopyOnWriteArrayList compute(Class key) { @@ -146,5 +149,20 @@ public class DescriptorExtensionList, D extends Descrip } }; + /** + * List up all the legacy instances currently in use. + */ + public static Iterable listLegacyInstances() { + return new Iterable() { + public Iterator iterator() { + return new FlattenIterator(legacyDescriptors.values()) { + protected Iterator expand(CopyOnWriteArrayList v) { + return v.iterator(); + } + }; + } + }; + } + private static final Logger LOGGER = Logger.getLogger(DescriptorExtensionList.class.getName()); } diff --git a/core/src/main/java/hudson/model/Hudson.java b/core/src/main/java/hudson/model/Hudson.java index 6ba59691b573c205a27b4ffe631d0a80d20fe328..adcb5b6b04d08bc70e92de4a89e8bb62697ffe86 100644 --- a/core/src/main/java/hudson/model/Hudson.java +++ b/core/src/main/java/hudson/model/Hudson.java @@ -103,6 +103,7 @@ import hudson.util.HudsonIsRestarting; import hudson.util.DescribableList; import hudson.util.Futures; import hudson.util.Memoizer; +import hudson.util.Iterators; import hudson.widgets.Widget; import net.sf.json.JSONObject; import org.acegisecurity.*; @@ -691,7 +692,8 @@ public final class Hudson extends Node implements ItemGroup, Stapl * this just doesn't scale. */ public Descriptor getDescriptor(String fullyQualifiedClassName) { - for( Descriptor d : getExtensionList(Descriptor.class) ) + // legacy descriptors that are reigstered manually doesn't show up in getExtensionList, so check them explicitly. + for( Descriptor d : Iterators.sequence(getExtensionList(Descriptor.class),DescriptorExtensionList.listLegacyInstances()) ) if(d.clazz.getName().equals(fullyQualifiedClassName)) return d; return null; diff --git a/core/src/main/java/hudson/tasks/BuildStep.java b/core/src/main/java/hudson/tasks/BuildStep.java index 3fdb7b62c26f02bca906d0c451885ea8e5530b83..c893759df22bcffe1daf09103697960496124337 100644 --- a/core/src/main/java/hudson/tasks/BuildStep.java +++ b/core/src/main/java/hudson/tasks/BuildStep.java @@ -219,5 +219,10 @@ public interface BuildStep { public Iterator> iterator() { return core.iterator(); } + + @Override + public boolean remove(Object o) { + return core.remove(o); + } } } diff --git a/core/src/main/java/hudson/util/DescriptorList.java b/core/src/main/java/hudson/util/DescriptorList.java index a04ba4dcccf7756139dcc569f0582d594c88793a..e0a94d1970800f0dd24092efd8dbccae9682542a 100644 --- a/core/src/main/java/hudson/util/DescriptorList.java +++ b/core/src/main/java/hudson/util/DescriptorList.java @@ -130,6 +130,11 @@ public final class DescriptorList> extends AbstractList add(element); // order is ignored } + @Override + public boolean remove(Object o) { + return store().remove(o); + } + /** * Gets the actual data store. This is the key to control the dual-mode nature of {@link DescriptorList} */ diff --git a/core/src/main/java/hudson/util/Memoizer.java b/core/src/main/java/hudson/util/Memoizer.java index 3cb063ab7df659f66061761e17894c6718c75504..d150040906130569d79ab5b003b70d7f3d3489ae 100644 --- a/core/src/main/java/hudson/util/Memoizer.java +++ b/core/src/main/java/hudson/util/Memoizer.java @@ -65,4 +65,11 @@ public abstract class Memoizer { public void clear() { store.clear(); } + + /** + * Provides a snapshot view of all {@code V}s. + */ + public Iterable values() { + return store.values(); + } } diff --git a/test/src/test/java/hudson/model/HudsonTest.java b/test/src/test/java/hudson/model/HudsonTest.java index 26ce1a6b91c1cab497b0fe8ef6b2e72760f2ac8d..98d9d1e359ca6c879a08cdc4b3e1fc95857ecc3e 100644 --- a/test/src/test/java/hudson/model/HudsonTest.java +++ b/test/src/test/java/hudson/model/HudsonTest.java @@ -36,6 +36,7 @@ import hudson.search.SearchTest; import hudson.security.AuthorizationStrategy; import hudson.security.SecurityRealm; import hudson.tasks.Ant; +import hudson.tasks.BuildStep; import hudson.tasks.Ant.AntInstallation; import hudson.tasks.Ant.DescriptorImpl; import org.jvnet.hudson.test.Email; @@ -145,4 +146,22 @@ public class HudsonTest extends HudsonTestCase { // the master computer object should be still here wc.goTo("computer/(master)/"); } + + /** + * Legacy descriptors should be visible in the /descriptor/xyz URL. + */ + @Email("http://www.nabble.com/1.286-version-and-description-The-requested-resource-%28%29-is-not--available.-td22233801.html") + public void testLegacyDescriptorLookup() throws Exception { + Descriptor dummy = new Descriptor(HudsonTest.class) { + public String getDisplayName() { + return "dummy"; + } + }; + + BuildStep.PUBLISHERS.addRecorder(dummy); + assertSame(dummy,hudson.getDescriptor(HudsonTest.class.getName())); + + BuildStep.PUBLISHERS.remove(dummy); + assertNull(hudson.getDescriptor(HudsonTest.class.getName())); + } }