1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.codehaus.plexus.metadata.gleaner;
18
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.lang.reflect.Modifier;
22 import java.net.URL;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.Enumeration;
26 import java.util.List;
27
28 import org.codehaus.plexus.component.annotations.Component;
29 import org.codehaus.plexus.component.annotations.Configuration;
30 import org.codehaus.plexus.component.annotations.Requirement;
31 import org.codehaus.plexus.component.repository.ComponentDescriptor;
32 import org.codehaus.plexus.component.repository.ComponentRequirement;
33 import org.codehaus.plexus.component.repository.ComponentRequirementList;
34 import org.codehaus.plexus.configuration.PlexusConfiguration;
35 import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
36 import org.codehaus.plexus.metadata.ann.AnnClass;
37 import org.codehaus.plexus.metadata.ann.AnnField;
38 import org.codehaus.plexus.metadata.ann.AnnReader;
39 import org.codehaus.plexus.util.IOUtil;
40
41
42
43
44
45
46 public class AnnotationComponentGleaner extends ComponentGleanerSupport implements ClassComponentGleaner {
47 private static final String OBJECT_SLASHED_NAME = Object.class.getName().replace('.', '/');
48
49 public ComponentDescriptor<?> glean(String className, ClassLoader cl) throws ComponentGleanerException {
50 assert className != null;
51 assert cl != null;
52
53 AnnClass annClass = readClass(className.replace('.', '/'), cl);
54
55
56 if (Modifier.isAbstract(annClass.getAccess())) {
57 return null;
58 }
59
60 Component anno = annClass.getAnnotation(Component.class);
61
62 if (anno == null) {
63 return null;
64 }
65
66 ComponentDescriptor<?> component = new ComponentDescriptor<Object>();
67
68 component.setRole(anno.role().getName());
69
70 component.setRoleHint(filterEmptyAsNull(anno.hint()));
71
72 component.setImplementation(className);
73
74 component.setVersion(filterEmptyAsNull(anno.version()));
75
76 component.setComponentType(filterEmptyAsNull(anno.type()));
77
78 component.setInstantiationStrategy(filterEmptyAsNull(anno.instantiationStrategy()));
79
80 component.setLifecycleHandler(filterEmptyAsNull(anno.lifecycleHandler()));
81
82 component.setComponentProfile(filterEmptyAsNull(anno.profile()));
83
84 component.setComponentComposer(filterEmptyAsNull(anno.composer()));
85
86 component.setComponentConfigurator(filterEmptyAsNull(anno.configurator()));
87
88 component.setComponentFactory(filterEmptyAsNull(anno.factory()));
89
90 component.setDescription(filterEmptyAsNull(anno.description()));
91
92 component.setAlias(filterEmptyAsNull(anno.alias()));
93
94 component.setIsolatedRealm(anno.isolatedRealm());
95
96 for (AnnClass c : getClasses(annClass, cl)) {
97 for (AnnField field : c.getFields().values()) {
98 ComponentRequirement requirement = findRequirement(field, c, cl);
99
100 if (requirement != null) {
101 component.addRequirement(requirement);
102 }
103
104 PlexusConfiguration config = findConfiguration(field, c, cl);
105
106 if (config != null) {
107 addChildConfiguration(component, config);
108 }
109 }
110
111
112
113
114 }
115
116 return component;
117 }
118
119 private AnnClass readClass(String className, ClassLoader cl) throws ComponentGleanerException {
120 InputStream is = null;
121
122 try {
123
124 Enumeration<URL> en = cl.getResources(className + ".class");
125 while (en.hasMoreElements()) {
126 URL url = en.nextElement();
127 if (url.toString().startsWith("file:")) {
128 is = url.openStream();
129 return AnnReader.read(is, cl);
130 }
131 }
132 throw new ComponentGleanerException("Can't find class " + className);
133 } catch (IOException ex) {
134 throw new ComponentGleanerException("Can't read class " + className, ex);
135 } finally {
136 IOUtil.close(is);
137 }
138 }
139
140 private AnnClass readClass2(String className, ClassLoader cl) throws ComponentGleanerException {
141 InputStream is = null;
142 try {
143 is = cl.getResourceAsStream(className + ".class");
144 return AnnReader.read(is, cl);
145 } catch (IOException ex) {
146 throw new ComponentGleanerException("Can't read class " + className, ex);
147 } finally {
148 IOUtil.close(is);
149 }
150 }
151
152
153
154
155 private List<AnnClass> getClasses(AnnClass annClass, ClassLoader cl) throws ComponentGleanerException {
156 assert annClass != null;
157
158 List<AnnClass> classes = new ArrayList<AnnClass>();
159
160 while (annClass != null) {
161 classes.add(annClass);
162 String superName = annClass.getSuperName();
163 if (superName != null && !superName.equals(OBJECT_SLASHED_NAME)) {
164 annClass = readClass2(superName, cl);
165 } else {
166 break;
167 }
168
169
170
171
172 }
173
174 return classes;
175 }
176
177 private ComponentRequirement findRequirement(final AnnField field, AnnClass annClass, ClassLoader cl)
178 throws ComponentGleanerException {
179 assert field != null;
180
181 Requirement anno = field.getAnnotation(Requirement.class);
182
183 if (anno == null) {
184 return null;
185 }
186
187 String fieldType = field.getType();
188
189
190 Class<?> type;
191 try {
192 type = Class.forName(fieldType, false, cl);
193 } catch (ClassNotFoundException ex) {
194
195 throw new ComponentGleanerException("Can't load class " + fieldType);
196 }
197
198 ComponentRequirement requirement;
199
200 if (isRequirementListType(type)) {
201 requirement = new ComponentRequirementList();
202
203 String[] hints = anno.hints();
204
205 if (hints != null && hints.length > 0) {
206 ((ComponentRequirementList) requirement).setRoleHints(Arrays.asList(hints));
207 }
208
209
210
211
212 } else {
213 requirement = new ComponentRequirement();
214
215 requirement.setRoleHint(filterEmptyAsNull(anno.hint()));
216 }
217
218
219
220 if (anno.role().isAssignableFrom(Object.class)) {
221 requirement.setRole(type.getName());
222 } else {
223 requirement.setRole(anno.role().getName());
224 }
225
226 requirement.setFieldName(field.getName());
227
228 requirement.setFieldMappingType(type.getName());
229
230 requirement.setOptional(anno.optional());
231
232 return requirement;
233 }
234
235 private PlexusConfiguration findConfiguration(AnnField field, AnnClass c, ClassLoader cl) {
236 assert field != null;
237
238 Configuration anno = field.getAnnotation(Configuration.class);
239
240 if (anno == null) {
241 return null;
242 }
243
244 String name = filterEmptyAsNull(anno.name());
245 if (name == null) {
246 name = field.getName();
247 }
248 name = deHump(name);
249
250 XmlPlexusConfiguration config = new XmlPlexusConfiguration(name);
251
252 String value = filterEmptyAsNull(anno.value());
253 if (value != null) {
254 config.setValue(value);
255 }
256
257 return config;
258 }
259 }