4
* Copyright (c) 2004-2009, Sun Microsystems, Inc.
6
* Permission is hereby granted, free of charge, to any person obtaining a copy
7
* of this software and associated documentation files (the "Software"), to deal
8
* in the Software without restriction, including without limitation the rights
9
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
* copies of the Software, and to permit persons to whom the Software is
11
* furnished to do so, subject to the following conditions:
13
* The above copyright notice and this permission notice shall be included in
14
* all copies or substantial portions of the Software.
16
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26
import hudson.model.Descriptor;
27
import hudson.model.Describable;
28
import hudson.model.Hudson;
29
import jenkins.ExtensionComponentSet;
30
import jenkins.model.Jenkins;
31
import hudson.model.ViewDescriptor;
32
import hudson.model.Descriptor.FormException;
33
import hudson.util.AdaptedIterator;
34
import hudson.util.Memoizer;
35
import hudson.util.Iterators.FlattenIterator;
36
import hudson.slaves.NodeDescriptor;
37
import hudson.tasks.Publisher;
38
import hudson.tasks.Publisher.DescriptorExtensionListImpl;
40
import java.util.Collection;
41
import java.util.List;
42
import java.util.ArrayList;
43
import java.util.Iterator;
44
import java.util.logging.Level;
45
import java.util.logging.Logger;
46
import java.util.concurrent.CopyOnWriteArrayList;
48
import org.kohsuke.stapler.Stapler;
49
import net.sf.json.JSONObject;
52
* {@link ExtensionList} for holding a set of {@link Descriptor}s, which is a group of descriptors for
53
* the same extension point.
55
* Use {@link jenkins.model.Jenkins#getDescriptorList(Class)} to obtain instances.
58
* Represents the descriptor type. This is {@code Descriptor<T>} normally but often there are subtypes
59
* of descriptors, like {@link ViewDescriptor}, {@link NodeDescriptor}, etc, and this parameter points
60
* to those for better type safety of users.
62
* The actual value of 'D' is not necessary for the operation of this code, so it's purely for convenience
63
* of the users of this class.
67
public class DescriptorExtensionList<T extends Describable<T>, D extends Descriptor<T>> extends ExtensionList<D> {
69
* Creates a new instance.
71
@SuppressWarnings({"unchecked", "rawtypes"})
72
public static <T extends Describable<T>,D extends Descriptor<T>>
73
DescriptorExtensionList<T,D> createDescriptorList(Jenkins jenkins, Class<T> describableType) {
74
if (describableType == (Class) Publisher.class) {
75
return (DescriptorExtensionList) new DescriptorExtensionListImpl(jenkins);
77
return new DescriptorExtensionList<T,D>(jenkins,describableType);
81
* @deprecated as of 1.416
82
* Use {@link #create(Jenkins, Class)}
84
public static <T extends Describable<T>,D extends Descriptor<T>>
85
DescriptorExtensionList<T,D> createDescriptorList(Hudson hudson, Class<T> describableType) {
86
return createDescriptorList((Jenkins)hudson,describableType);
90
* Type of the {@link Describable} that this extension list retains.
92
private final Class<T> describableType;
95
* @deprecated as of 1.416
96
* Use {@link #DescriptorExtensionList(Jenkins, Class)}
98
protected DescriptorExtensionList(Hudson hudson, Class<T> describableType) {
99
this((Jenkins)hudson,describableType);
102
protected DescriptorExtensionList(Jenkins jenkins, Class<T> describableType) {
103
super(jenkins, (Class)Descriptor.class, (CopyOnWriteArrayList)getLegacyDescriptors(describableType));
104
this.describableType = describableType;
108
* Finds the descriptor that has the matching fully-qualified class name.
111
* Fully qualified name of the descriptor, not the describable.
113
public D find(String fqcn) {
114
return Descriptor.find(this,fqcn);
118
* Finds the descriptor that describes the given type.
119
* That is, if this method returns d, {@code d.clazz==type}
121
public D find(Class<? extends T> type) {
129
* Creates a new instance of a {@link Describable}
130
* from the structured form submission data posted
131
* by a radio button group.
133
public T newInstanceFromRadioList(JSONObject config) throws FormException {
134
if(config.isNullObject())
135
return null; // none was selected
136
int idx = config.getInt("value");
137
return get(idx).newInstance(Stapler.getCurrentRequest(),config);
140
public T newInstanceFromRadioList(JSONObject parent, String name) throws FormException {
141
return newInstanceFromRadioList(parent.getJSONObject(name));
145
* Finds a descriptor by their {@link Descriptor#getId()}.
147
* If none is found, null is returned.
149
public D findByName(String id) {
151
if(d.getId().equals(id))
157
public boolean add(D d) {
158
boolean r = super.add(d);
159
hudson.getExtensionList(Descriptor.class).add(d);
164
public boolean remove(Object o) {
165
hudson.getExtensionList(Descriptor.class).remove(o);
166
return super.remove(o);
170
* {@link #load()} in the descriptor is not a real load activity, so locking against "this" is enough.
173
protected Object getLoadLock() {
178
* Loading the descriptors in this case means filtering the descriptor from the master {@link ExtensionList}.
181
protected List<ExtensionComponent<D>> load() {
182
return _load(jenkins.getExtensionList(Descriptor.class).getComponents());
186
protected Collection<ExtensionComponent<D>> load(ExtensionComponentSet delta) {
187
return _load(delta.find(Descriptor.class));
190
private List<ExtensionComponent<D>> _load(Iterable<ExtensionComponent<Descriptor>> set) {
191
List<ExtensionComponent<D>> r = new ArrayList<ExtensionComponent<D>>();
192
for( ExtensionComponent<Descriptor> c : set ) {
193
Descriptor d = c.getInstance();
195
if(d.getT()==describableType)
196
r.add((ExtensionComponent)c);
197
} catch (IllegalStateException e) {
198
LOGGER.log(Level.SEVERE, d.getClass() + " doesn't extend Descriptor with a type parameter", e); // skip this one
205
* Stores manually registered Descriptor instances. Keyed by the {@link Describable} type.
207
private static final Memoizer<Class,CopyOnWriteArrayList<ExtensionComponent<Descriptor>>> legacyDescriptors = new Memoizer<Class,CopyOnWriteArrayList<ExtensionComponent<Descriptor>>>() {
208
public CopyOnWriteArrayList compute(Class key) {
209
return new CopyOnWriteArrayList();
213
private static <T extends Describable<T>> CopyOnWriteArrayList<ExtensionComponent<Descriptor<T>>> getLegacyDescriptors(Class<T> type) {
214
return (CopyOnWriteArrayList)legacyDescriptors.get(type);
218
* List up all the legacy instances currently in use.
220
public static Iterable<Descriptor> listLegacyInstances() {
221
return new Iterable<Descriptor>() {
222
public Iterator<Descriptor> iterator() {
223
return new AdaptedIterator<ExtensionComponent<Descriptor>,Descriptor>(
224
new FlattenIterator<ExtensionComponent<Descriptor>,CopyOnWriteArrayList<ExtensionComponent<Descriptor>>>(legacyDescriptors.values()) {
225
protected Iterator<ExtensionComponent<Descriptor>> expand(CopyOnWriteArrayList<ExtensionComponent<Descriptor>> v) {
230
protected Descriptor adapt(ExtensionComponent<Descriptor> item) {
231
return item.getInstance();
239
* Exposed just for the test harness. Clear legacy instances.
241
public static void clearLegacyInstances() {
242
legacyDescriptors.clear();
245
private static final Logger LOGGER = Logger.getLogger(DescriptorExtensionList.class.getName());