Skip to content

Commit d4c6a4b

Browse files
author
kohsuke
committed
added an auto-discovery mechanism for extension points (and most notably Descriptors.)
- extensions are now stored in ExtensionList. - discovery is extensible, but by default we use Sezpoz for annotation-based injection. This requires JDK6 for build. - a care has been taken to preserve backward compatibility. DescriptorList and manually adding to it continues to work. - AdministrativeMonitor is converted to use the new approach entirely, as a guinea pig of this feature. - Descriptors for View is partially switched to this new approach, where some classes register automatically while others do manually. This tests the compatibility aspect of this feature. A pluggable discovery is an attempt to embrace Plexus integration work, although for that to really work we need more coding. Next stop, more tests. git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@15601 71c3de6d-444a-0410-be80-ed276b4c234a
1 parent 836b436 commit d4c6a4b

File tree

15 files changed

+660
-74
lines changed

15 files changed

+660
-74
lines changed

core/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,11 @@ THE SOFTWARE.
708708
<artifactId>embedded_su4j</artifactId>
709709
<version>1.1</version>
710710
</dependency>
711+
<dependency>
712+
<groupId>net.java.sezpoz</groupId>
713+
<artifactId>sezpoz</artifactId>
714+
<version>1.0</version>
715+
</dependency>
711716
<dependency>
712717
<groupId>org.jvnet.hudson</groupId>
713718
<artifactId>jinterop-wmi</artifactId>
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* The MIT License
3+
*
4+
* Copyright (c) 2004-2009, Sun Microsystems, Inc.
5+
*
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:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
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
22+
* THE SOFTWARE.
23+
*/
24+
package hudson;
25+
26+
import net.java.sezpoz.Indexable;
27+
28+
import java.lang.annotation.Documented;
29+
import static java.lang.annotation.ElementType.*;
30+
import java.lang.annotation.Retention;
31+
import java.lang.annotation.RetentionPolicy;
32+
import java.lang.annotation.Target;
33+
34+
import hudson.ExtensionFinder.Sezpoz;
35+
36+
/**
37+
* Marks a field, a method, or a class for automatic discovery, so that Hudson can locate
38+
* implementations of {@link ExtensionPoint}s automatically.
39+
*
40+
* <p>
41+
* (In contrast, in earlier Hudson, the registration was manual.)
42+
*
43+
* <p>
44+
* In a simplest case, put this on your class, and Hudson will create an instance of it
45+
* and register it to the appropriate {@link ExtensionList}.
46+
*
47+
* <p>
48+
* If you'd like Hudson to call
49+
* a factory method instead of a constructor, put this annotation on your static factory
50+
* method. Hudson will invoke it and if the method returns a non-null instance, it'll be
51+
* registered. The return type of the method is used to determine which {@link ExtensionList}
52+
* will get the instance.
53+
*
54+
* Finally, you can put this annotation on a static field if the field contains a reference
55+
* to an instance that you'd like to register.
56+
*
57+
* <p>
58+
* This is the default way of having your implementations auto-registered to Hudson,
59+
* but Hudson also supports arbitrary DI containers for hosting your implementations.
60+
* See {@link ExtensionFinder} for more details.
61+
*
62+
* @author Kohsuke Kawaguchi
63+
* @since 1.286
64+
* @see Sezpoz
65+
* @see ExtensionFinder
66+
* @see ExtensionList
67+
*/
68+
@Indexable
69+
@Retention(RetentionPolicy.RUNTIME)
70+
@Target({TYPE, FIELD, METHOD})
71+
@Documented
72+
public @interface Extension {
73+
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/*
2+
* The MIT License
3+
*
4+
* Copyright (c) 2004-2009, Sun Microsystems, Inc.
5+
*
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:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
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
22+
* THE SOFTWARE.
23+
*/
24+
package hudson;
25+
26+
import net.java.sezpoz.Index;
27+
import net.java.sezpoz.IndexItem;
28+
import hudson.model.Hudson;
29+
import hudson.model.Descriptor;
30+
31+
import java.util.logging.Logger;
32+
import java.util.logging.Level;
33+
import java.util.List;
34+
import java.util.ArrayList;
35+
import java.util.Collection;
36+
import java.lang.reflect.AnnotatedElement;
37+
import java.lang.reflect.Field;
38+
import java.lang.reflect.Method;
39+
40+
/**
41+
* Discovers the implementations of an extension point.
42+
*
43+
* <p>
44+
* This extension point allows you to write your implementations of {@link ExtensionPoint}s
45+
* in arbitrary DI containers, and have Hudson discover them.
46+
*
47+
* <p>
48+
* {@link ExtensionFinder} itself is an extension point, but to avoid infinite recursion,
49+
* Hudson discovers {@link ExtensionFinder}s through {@link Sezpoz} and that alone.
50+
*
51+
* @author Kohsuke Kawaguchi
52+
* @since 1.286
53+
*/
54+
public abstract class ExtensionFinder implements ExtensionPoint {
55+
/**
56+
* Discover extensions of the given type.
57+
*
58+
* <p>
59+
* This method is called only once per the given type after all the plugins are loaded,
60+
* so implementations need not worry about caching.
61+
*
62+
* @param <T>
63+
* The type of the extension points. This is not bound to {@link ExtensionPoint} because
64+
* of {@link Descriptor}, which by itself doesn't implement {@link ExtensionPoint} for
65+
* a historical reason.
66+
* @param hudson
67+
* Hudson whose behalf this extension finder is performing lookup.
68+
* @return
69+
* Can be empty but never null.
70+
*/
71+
public abstract <T> Collection<T> findExtensions(Class<T> type, Hudson hudson);
72+
73+
/**
74+
* The default implementation that looks for the {@link Extension} marker.
75+
*
76+
* <p>
77+
* Uses Sezpoz as the underlying mechanism.
78+
*/
79+
@Extension
80+
public static final class Sezpoz extends ExtensionFinder {
81+
public <T> Collection<T> findExtensions(Class<T> type, Hudson hudson) {
82+
List<T> result = new ArrayList<T>();
83+
84+
ClassLoader cl = hudson.getPluginManager().uberClassLoader;
85+
for (IndexItem<Extension,Object> item : Index.load(Extension.class, Object.class, cl)) {
86+
try {
87+
AnnotatedElement e = item.element();
88+
Class<?> extType;
89+
if (e instanceof Class) {
90+
extType = (Class) e;
91+
} else
92+
if (e instanceof Field) {
93+
extType = ((Field)e).getType();
94+
} else
95+
if (e instanceof Method) {
96+
extType = ((Method)e).getReturnType();
97+
} else
98+
throw new AssertionError();
99+
100+
if(type.isAssignableFrom(extType)) {
101+
Object instance = item.instance();
102+
if(instance!=null)
103+
result.add(type.cast(instance));
104+
}
105+
} catch (InstantiationException e) {
106+
LOGGER.log(Level.WARNING, "Failed to load "+item.className(),e);
107+
}
108+
}
109+
110+
return result;
111+
}
112+
}
113+
114+
private static final Logger LOGGER = Logger.getLogger(ExtensionFinder.class.getName());
115+
}

0 commit comments

Comments
 (0)