提交 2a1798e0 编写于 作者: K kohsuke

promoted DescriptorSubList to DescriptorExtensionList so that we can have...

promoted DescriptorSubList to DescriptorExtensionList so that we can have Descriptor-specific methods.

Added a test case

git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@15602 71c3de6d-444a-0410-be80-ed276b4c234a
上级 d4c6a4b0
/*
* The MIT License
*
* Copyright (c) 2004-2009, Sun Microsystems, 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
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package hudson;
import hudson.model.Descriptor;
import hudson.model.Describable;
import hudson.model.Hudson;
import java.util.List;
import java.util.ArrayList;
import java.util.logging.Logger;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ConcurrentHashMap;
import java.lang.reflect.Type;
import java.lang.reflect.ParameterizedType;
import org.jvnet.tiger_types.Types;
/**
* {@link ExtensionList} for holding a set of {@link Descriptor}s, which is a group of descriptors for
* the same extension point.
*
* Use {@link Hudson#getDescriptorList(Class)} to obtain instances.
*
* @since 1.286
*/
public final class DescriptorExtensionList<T extends Describable<T>> extends ExtensionList<Descriptor<T>> {
/**
* Type of the {@link Describable} that this extension list retains.
*/
private final Class<T> describableType;
public DescriptorExtensionList(Hudson hudson, Class<T> describableType) {
super(hudson, (Class)Descriptor.class,allocateLegacyInstanceStore(describableType));
this.describableType = describableType;
}
/**
* Loading the descriptors in this case means filtering the descriptor from the master {@link ExtensionList}.
*/
@Override
protected List<Descriptor<T>> load() {
List r = new ArrayList();
for( Descriptor d : hudson.getExtensionList(Descriptor.class) ) {
Type subTyping = Types.getBaseClass(d.getClass(), Descriptor.class);
if (!(subTyping instanceof ParameterizedType)) {
LOGGER.severe(d.getClass()+" doesn't extend Descriptor with a type parameter");
continue; // skip this one
}
if(Types.getTypeArgument(subTyping,0)==describableType)
r.add(d);
}
return r;
}
/**
* Obtain the statically-scoped storage to store manulaly registered {@link Descriptor}s.
*/
private static List allocateLegacyInstanceStore(Class describableType) {
List r = legacyDescriptors.get(describableType);
if(r!=null) return r;
r = new CopyOnWriteArrayList();
List x = legacyDescriptors.putIfAbsent(describableType, r);
if(x==null) return r;
return x;
}
/**
* Stores manually registered Descriptor instances.
*/
private static final ConcurrentHashMap<Class,List> legacyDescriptors = new ConcurrentHashMap<Class,List>();
private static final Logger LOGGER = Logger.getLogger(DescriptorExtensionList.class.getName());
}
......@@ -24,23 +24,17 @@
package hudson;
import hudson.model.Hudson;
import hudson.model.Descriptor;
import hudson.model.Describable;
import hudson.util.DescriptorList;
import java.util.AbstractCollection;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import java.util.logging.Logger;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ConcurrentHashMap;
import java.lang.reflect.Type;
import java.lang.reflect.ParameterizedType;
import org.jvnet.tiger_types.Types;
import java.util.logging.Logger;
/**
* Retains the known extension instances for the given type 'T'.
......@@ -63,7 +57,7 @@ import org.jvnet.tiger_types.Types;
* @see Hudson#getExtensionList(Class)
* @see Hudson#getDescriptorList(Class)
*/
public class ExtensionList<T> implements Iterable<T> {
public class ExtensionList<T> extends AbstractCollection<T> {
public final Hudson hudson;
public final Class<T> extensionType;
......@@ -93,8 +87,7 @@ public class ExtensionList<T> implements Iterable<T> {
@Override
public int size() {
ensureLoaded();
return extensions.size();
return ExtensionList.this.size();
}
@Override
......@@ -132,7 +125,7 @@ public class ExtensionList<T> implements Iterable<T> {
* Looks for the extension instance of the given type (subclasses excluded),
* or return null.
*/
public <U extends T> U of(Class<U> type) {
public <U extends T> U get(Class<U> type) {
for (T ext : this)
if(ext.getClass()==type)
return type.cast(ext);
......@@ -142,7 +135,11 @@ public class ExtensionList<T> implements Iterable<T> {
public Iterator<T> iterator() {
ensureLoaded();
return extensions.iterator();
}
public int size() {
ensureLoaded();
return extensions.size();
}
/**
......@@ -187,58 +184,6 @@ public class ExtensionList<T> implements Iterable<T> {
return listView;
}
/**
* {@link ExtensionList} for holding a subset of {@link Descriptor}s, which is a group of descriptors for
* the same extension point.
*/
public static final class DescriptorSubList<T extends Describable<T>> extends ExtensionList<Descriptor<T>> {
/**
* Type of the {@link Describable} that this extension list retains.
*/
private final Class<T> describableType;
public DescriptorSubList(Hudson hudson, Class<T> describableType) {
super(hudson, (Class)Descriptor.class,allocateLegacyInstanceStore(describableType));
this.describableType = describableType;
}
/**
* Loading the descriptors in this case means filtering the descriptor from the master {@link ExtensionList}.
*/
@Override
protected List<Descriptor<T>> load() {
List r = new ArrayList();
for( Descriptor d : hudson.getExtensionList(Descriptor.class) ) {
Type subTyping = Types.getBaseClass(d.getClass(), Descriptor.class);
if (!(subTyping instanceof ParameterizedType)) {
LOGGER.severe(d.getClass()+" doesn't extend Descriptor with a type parameter");
continue; // skip this one
}
if(Types.getTypeArgument(subTyping,0)==describableType)
r.add(d);
}
return r;
}
/**
* Obtain the statically-scoped storage to store manulaly registered {@link Descriptor}s.
*/
private static List allocateLegacyInstanceStore(Class describableType) {
List r = legacyDescriptors.get(describableType);
if(r!=null) return r;
r = new CopyOnWriteArrayList();
List x = legacyDescriptors.putIfAbsent(describableType, r);
if(x==null) return r;
return x;
}
/**
* Stores manually registered Descriptor instances.
*/
private static final ConcurrentHashMap<Class,List> legacyDescriptors = new ConcurrentHashMap<Class,List>();
}
public static <T> ExtensionList<T> create(Hudson hudson, Class<T> type) {
if(type==ExtensionFinder.class)
return new ExtensionList<T>(hudson,type) {
......
......@@ -42,7 +42,7 @@ import hudson.XmlFile;
import hudson.UDPBroadcastThread;
import hudson.ExtensionList;
import hudson.ExtensionPoint;
import hudson.ExtensionList.DescriptorSubList;
import hudson.DescriptorExtensionList;
import hudson.logging.LogRecorderManager;
import hudson.lifecycle.WindowsInstallerLink;
import hudson.lifecycle.Lifecycle;
......@@ -130,7 +130,6 @@ import org.kohsuke.stapler.framework.adjunct.AdjunctManager;
import org.kohsuke.stapler.export.Exported;
import org.kohsuke.stapler.export.ExportedBean;
import org.xml.sax.InputSource;
import org.jvnet.tiger_types.Types;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
......@@ -185,8 +184,6 @@ import java.util.logging.LogRecord;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import java.nio.charset.Charset;
import java.lang.reflect.Type;
import java.lang.reflect.ParameterizedType;
import javax.servlet.RequestDispatcher;
/**
......@@ -288,9 +285,9 @@ public final class Hudson extends Node implements ItemGroup<TopLevelItem>, Stapl
private transient final ConcurrentHashMap<Class,ExtensionList> extensionLists = new ConcurrentHashMap<Class,ExtensionList>();
/**
* All {@link DescriptorSubList} keyed by their {@link DescriptorSubList#describableType}.
* All {@link DescriptorExtensionList} keyed by their {@link DescriptorExtensionList#describableType}.
*/
private transient final ConcurrentHashMap<Class,DescriptorSubList> descriptorLists = new ConcurrentHashMap<Class,DescriptorSubList>();
private transient final ConcurrentHashMap<Class, DescriptorExtensionList> descriptorLists = new ConcurrentHashMap<Class, DescriptorExtensionList>();
/**
* Active {@link Cloud}s.
......@@ -1491,14 +1488,14 @@ public final class Hudson extends Node implements ItemGroup<TopLevelItem>, Stapl
* Can be an empty list but never null.
*/
@SuppressWarnings({"unchecked"})
public <T extends Describable<T>> ExtensionList<Descriptor<T>> getDescriptorList(final Class<T> type) {
public <T extends Describable<T>> DescriptorExtensionList<T> getDescriptorList(Class<T> type) {
// by far the common case is where we find an instance already created.
DescriptorSubList<T> r = descriptorLists.get(type);
DescriptorExtensionList r = descriptorLists.get(type);
if(r!=null) return r;
// if we have to create a new one, make sure we don't create two at the same time.
r = new DescriptorSubList<T>(this,type);
ExtensionList x = descriptorLists.putIfAbsent(type, r);
r = new DescriptorExtensionList(this,type);
DescriptorExtensionList x = descriptorLists.putIfAbsent(type, r);
if(x==null) return r;
else return x;
}
......
......@@ -192,7 +192,7 @@ public class SCMTrigger extends Trigger<SCMedItem> {
* activate {@link AdministrativeMonitorImpl}.
*/
public void clogCheck() {
AdministrativeMonitor.all().of(AdministrativeMonitorImpl.class).on = isClogged();
AdministrativeMonitor.all().get(AdministrativeMonitorImpl.class).on = isClogged();
}
/**
......
package hudson;
import org.jvnet.hudson.test.HudsonTestCase;
import hudson.model.Descriptor;
import hudson.model.Describable;
import hudson.model.Hudson;
import hudson.util.DescriptorList;
/**
* @author Kohsuke Kawaguchi
*/
public class ExtensionListTest extends HudsonTestCase {
//
//
// non-Descriptor extension point
//
//
public interface Animal extends ExtensionPoint {
}
@Extension
public static class Dog implements Animal {
}
@Extension
public static class Cat implements Animal {
}
public void testAutoDiscovery() throws Exception {
ExtensionList<Animal> list = hudson.getExtensionList(Animal.class);
assertEquals(2,list.size());
assertNotNull(list.get(Dog.class));
assertNotNull(list.get(Cat.class));
}
//
//
// Descriptor extension point
//
//
public static abstract class FishDescriptor extends Descriptor<Fish> {
public String getDisplayName() {
return clazz.getName();
}
}
public static abstract class Fish implements Describable<Fish> {
public Descriptor<Fish> getDescriptor() {
return Hudson.getInstance().getDescriptor(getClass());
}
}
public static class Tai extends Fish {
@Extension
public static final class DescriptorImpl extends FishDescriptor {}
}
public static class Saba extends Fish {
@Extension
public static final class DescriptorImpl extends FishDescriptor {}
}
public static class Sishamo extends Fish {
public static final class DescriptorImpl extends FishDescriptor {}
}
public void testFishDiscovery() throws Exception {
// imagine that this is a static instance, like it is in many LIST static field in Hudson.
DescriptorList<Fish> LIST = new DescriptorList<Fish>(Fish.class);
DescriptorExtensionList<Fish> list = hudson.getDescriptorList(Fish.class);
assertEquals(2,list.size());
assertNotNull(list.get(Tai.DescriptorImpl.class));
assertNotNull(list.get(Saba.DescriptorImpl.class));
// registration can happen later, and it should be still visible
LIST.add(new Sishamo.DescriptorImpl());
assertEquals(3,list.size());
assertNotNull(list.get(Sishamo.DescriptorImpl.class));
// all 3 should be visisble from LIST, too
assertEquals(3,LIST.size());
assertNotNull(LIST.findByName(Tai.class.getName()));
assertNotNull(LIST.findByName(Sishamo.class.getName()));
assertNotNull(LIST.findByName(Saba.class.getName()));
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册