File D:\maven-qcr-plugin-testsunitaires\qcr4java\jenkins-master\target\site\qc\core\src\main\java\hudson\ExtensionFinder.java.html

1 /*
2 * The MIT License
3 *
4 * Copyright (c) 2004-2010, Sun Microsystems, Inc., InfraDNA, Inc., CloudBees, 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 com.google.common.collect.Iterables;
27 import com.google.common.collect.Lists;
28 import com.google.common.collect.Maps;
29 import com.google.inject.AbstractModule;
30 import com.google.inject.Binding;
31 import com.google.inject.Guice;
32 import com.google.inject.Injector;
33 import com.google.inject.Key;
34 import com.google.inject.Module;
35 import com.google.inject.Provider;
36 import com.google.inject.Scope;
37 import com.google.inject.Scopes;
38 import com.google.inject.name.Names;
39 import com.google.common.collect.ImmutableList;
40 import hudson.init.InitMilestone;
41 import hudson.model.Descriptor;
42 import hudson.model.Hudson;
43 import jenkins.ExtensionComponentSet;
44 import jenkins.ExtensionFilter;
45 import jenkins.ExtensionRefreshException;
46 import jenkins.ProxyInjector;
47 import jenkins.model.Jenkins;
48 import net.java.sezpoz.Index;
49 import net.java.sezpoz.IndexItem;
50 import org.kohsuke.accmod.Restricted;
51 import org.kohsuke.accmod.restrictions.NoExternalUse;
52
53 import java.lang.annotation.Annotation;
54 import java.util.Collections;
55 import java.util.HashMap;
56 import java.util.Map;
57 import java.util.Map.Entry;
58 import java.util.logging.Logger;
59 import java.util.logging.Level;
60 import java.util.List;
61 import java.util.ArrayList;
62 import java.util.Collection;
63 import java.lang.reflect.AnnotatedElement;
64 import java.lang.reflect.Field;
65 import java.lang.reflect.Method;
66
67 /**
68 * Discovers the implementations of an extension point.
69 *
70 * <p>
71 * This extension point allows you to write your implementations of {@link ExtensionPoint}s
72 * in arbitrary DI containers, and have Hudson discover them.
73 *
74 * <p>
75 * {@link ExtensionFinder} itself is an extension point, but to avoid infinite recursion,
76 * Jenkins discovers {@link ExtensionFinder}s through {@link Sezpoz} and that alone.
77 *
78 * @author Kohsuke Kawaguchi
79 * @since 1.286
80 * @see ExtensionFilter
81 */
82 public abstract class ExtensionFinder implements ExtensionPoint {
83 /**
84 * @deprecated as of 1.356
85 * Use and implement {@link #find(Class,Hudson)} that allows us to put some metadata.
86 */
87 @Restricted(NoExternalUse.class)
88 public <T> Collection<T> findExtensions(Class<T> type, Hudson hudson) {
89 return Collections.emptyList();
90 }
91
92 /**
93 * Returns true if this extension finder supports the {@link #refresh()} operation.
94 */
95 public boolean isRefreshable() {
96 try {
97 return getClass().getMethod("refresh").getDeclaringClass()!=ExtensionFinder.class;
98 } catch (NoSuchMethodException e) {
99 return false;
100 }
101 }
102
103 /**
104 * Rebuilds the internal index, if any, so that future {@link #find(Class, Hudson)} calls
105 * will discover components newly added to {@link PluginManager#uberClassLoader}.
106 *
107 * <p>
108 * The point of the refresh operation is not to disrupt instances of already loaded {@link ExtensionComponent}s,
109 * and only instantiate those that are new. Otherwise this will break the singleton semantics of various
110 * objects, such as {@link Descriptor}s.
111 *
112 * <p>
113 * The behaviour is undefined if {@link #isRefreshable()} is returning false.
114 *
115 * @since 1.442
116 * @see #isRefreshable()
117 * @return never null
118 */
119 public abstract ExtensionComponentSet refresh() throws ExtensionRefreshException;
120
121 /**
122 * Discover extensions of the given type.
123 *
124 * <p>
125 * This method is called only once per the given type after all the plugins are loaded,
126 * so implementations need not worry about caching.
127 *
128 * <p>
129 * This method should return all the known components at the time of the call, including
130 * those that are discovered later via {@link #refresh()}, even though those components
131 * are separately returned in {@link ExtensionComponentSet}.
132 *
133 * @param <T>
134 * The type of the extension points. This is not bound to {@link ExtensionPoint} because
135 * of {@link Descriptor}, which by itself doesn't implement {@link ExtensionPoint} for
136 * a historical reason.
137 * @param jenkins
138 * Jenkins whose behalf this extension finder is performing lookup.
139 * @return
140 * Can be empty but never null.
141 * @since 1.356
142 * Older implementations provide {@link #findExtensions(Class,Hudson)}
143 */
144 public abstract <T> Collection<ExtensionComponent<T>> find(Class<T> type, Hudson jenkins);
145
146 /**
147 * A pointless function to work around what appears to be a HotSpot problem. See JENKINS-5756 and bug 6933067
148 * on BugParade for more details.
149 */
150 public <T> Collection<ExtensionComponent<T>> _find(Class<T> type, Hudson hudson) {
151 return find(type, hudson);
152 }
153
154 /**
155 * Performs class initializations without creating instances.
156 *
157 * If two threads try to initialize classes in the opposite order, a dead lock will ensue,
158 * and we can get into a similar situation with {@link ExtensionFinder}s.
159 *
160 * <p>
161 * That is, one thread can try to list extensions, which results in {@link ExtensionFinder}
162 * loading and initializing classes. This happens inside a context of a lock, so that
163 * another thread that tries to list the same extensions don't end up creating different
164 * extension instances. So this activity locks extension list first, then class initialization next.
165 *
166 * <p>
167 * In the mean time, another thread can load and initialize a class, and that initialization
168 * can eventually results in listing up extensions, for example through static initializer.
169 * Such activity locks class initialization first, then locks extension list.
170 *
171 * <p>
172 * This inconsistent locking order results in a dead lock, you see.
173 *
174 * <p>
175 * So to reduce the likelihood, this method is called in prior to {@link #find(Class,Hudson)} invocation,
176 * but from outside the lock. The implementation is expected to perform all the class initialization activities
177 * from here.
178 *
179 * <p>
180 * See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6459208 for how to force a class initialization.
181 * Also see http://kohsuke.org/2010/09/01/deadlock-that-you-cant-avoid/ for how class initialization
182 * can results in a dead lock.
183 */
184 public void scout(Class extensionType, Hudson hudson) {
185 }
186
187 @Extension
188 public static final class DefaultGuiceExtensionAnnotation extends GuiceExtensionAnnotation<Extension> {
189 public DefaultGuiceExtensionAnnotation() {
190 super(Extension.class);
191 }
192
193 @Override
194 protected boolean isOptional(Extension annotation) {
195 return annotation.optional();
196 }
197
198 @Override
199 protected double getOrdinal(Extension annotation) {
200 return annotation.ordinal();
201 }
202
203 @Override
204 protected boolean isActive(AnnotatedElement e) {
205 return true;
206 }
207 }
208
209
210 /**
211 * Captures information about the annotation that we use to mark Guice-instantiated components.
212 */
213 public static abstract class GuiceExtensionAnnotation<T extends Annotation> {
214 public final Class<T> annotationType;
215
216 protected GuiceExtensionAnnotation(Class<T> annotationType) {
217 this.annotationType = annotationType;
218 }
219
220 protected abstract double getOrdinal(T annotation);
221
222 /**
223 * Hook to enable subtypes to control which ones to pick up and which ones to ignore.
224 */
225 protected abstract boolean isActive(AnnotatedElement e);
226
227 protected abstract boolean isOptional(T annotation);
228 }
229
230 /**
231 * Discovers components via sezpoz but instantiates them by using Guice.
232 */
233 @Extension
234 public static class GuiceFinder extends ExtensionFinder {
235 /**
236 * Injector that we find components from.
237 * <p>
238 * To support refresh when Guice doesn't let us alter the bindings, we'll create
239 * a child container to house newly discovered components. This field points to the
240 * youngest such container.
241 */
242 private volatile Injector container;
243
244 /**
245 * Sezpoz index we are currently using in {@link #container} (and its ancestors.)
246 * Needed to compute delta.
247 */
248 private List<IndexItem<?,Object>> sezpozIndex;
249
250 private final Map<Key,Annotation> annotations = new HashMap<Key,Annotation>();
251 private final Sezpoz moduleFinder = new Sezpoz();
252
253 /**
254 * Map from {@link GuiceExtensionAnnotation#annotationType} to {@link GuiceExtensionAnnotation}
255 */
256 private Map<Class<? extends Annotation>,GuiceExtensionAnnotation<?>> extensionAnnotations = Maps.newHashMap();
257
258 public GuiceFinder() {
259 for (ExtensionComponent<GuiceExtensionAnnotation> ec : moduleFinder.find(GuiceExtensionAnnotation.class, Hudson.getInstance())) {
260 GuiceExtensionAnnotation gea = ec.getInstance();
261 extensionAnnotations.put(gea.annotationType,gea);
262 }
263
264 sezpozIndex = loadSezpozIndices(Jenkins.getInstance().getPluginManager().uberClassLoader);
265
266 List<Module> modules = new ArrayList<Module>();
267 modules.add(new AbstractModule() {
268 @Override
269 protected void configure() {
270 Jenkins j = Jenkins.getInstance();
271 bind(Jenkins.class).toInstance(j);
272 bind(PluginManager.class).toInstance(j.getPluginManager());
273 }
274 });
275 modules.add(new SezpozModule(sezpozIndex));
276
277 for (ExtensionComponent<Module> ec : moduleFinder.find(Module.class, Hudson.getInstance())) {
278 modules.add(ec.getInstance());
279 }
280
281 try {
282 container = Guice.createInjector(modules);
283 } catch (Throwable e) {
284 LOGGER.log(Level.SEVERE, "Failed to create Guice container from all the plugins",e);
285 // failing to load all bindings are disastrous, so recover by creating minimum that works
286 // by just including the core
287 container = Guice.createInjector(new SezpozModule(loadSezpozIndices(Jenkins.class.getClassLoader())));
288 }
289
290 // expose Injector via lookup mechanism for interop with non-Guice clients
291 Jenkins.getInstance().lookup.set(Injector.class,new ProxyInjector() {
292 protected Injector resolve() {
293 return getContainer();
294 }
295 });
296 }
297
298 private ImmutableList<IndexItem<?, Object>> loadSezpozIndices(ClassLoader classLoader) {
299 List<IndexItem<?,Object>> indices = Lists.newArrayList();
300 for (GuiceExtensionAnnotation<?> gea : extensionAnnotations.values()) {
301 Iterables.addAll(indices, Index.load(gea.annotationType, Object.class, classLoader));
302 }
303 return ImmutableList.copyOf(indices);
304 }
305
306 public Injector getContainer() {
307 return container;
308 }
309
310 /**
311 * The basic idea is:
312 *
313 * <ul>
314 * <li>List up delta as a series of modules
315 * <li>
316 * </ul>
317 */
318 @Override
319 public synchronized ExtensionComponentSet refresh() throws ExtensionRefreshException {
320 // figure out newly discovered sezpoz components
321 List<IndexItem<?, Object>> delta = Lists.newArrayList();
322 for (Class<? extends Annotation> annotationType : extensionAnnotations.keySet()) {
323 delta.addAll(Sezpoz.listDelta(annotationType,sezpozIndex));
324 }
325 List<IndexItem<?, Object>> l = Lists.newArrayList(sezpozIndex);
326 l.addAll(delta);
327 sezpozIndex = l;
328
329 List<Module> modules = new ArrayList<Module>();
330 modules.add(new SezpozModule(delta));
331 for (ExtensionComponent<Module> ec : moduleFinder.refresh().find(Module.class)) {
332 modules.add(ec.getInstance());
333 }
334
335 try {
336 final Injector child = container.createChildInjector(modules);
337 container = child;
338
339 return new ExtensionComponentSet() {
340 @Override
341 public <T> Collection<ExtensionComponent<T>> find(Class<T> type) {
342 List<ExtensionComponent<T>> result = new ArrayList<ExtensionComponent<T>>();
343 _find(type, result, child);
344 return result;
345 }
346 };
347 } catch (Throwable e) {
348 LOGGER.log(Level.SEVERE, "Failed to create Guice container from newly added plugins",e);
349 throw new ExtensionRefreshException(e);
350 }
351 }
352
353 private Object instantiate(IndexItem<?,Object> item) {
354 try {
355 return item.instance();
356 } catch (LinkageError e) {
357 // sometimes the instantiation fails in an indirect classloading failure,
358 // which results in a LinkageError
359 LOGGER.log(isOptional(item.annotation()) ? Level.FINE : Level.WARNING,
360 "Failed to load "+item.className(), e);
361 } catch (InstantiationException e) {
362 LOGGER.log(isOptional(item.annotation()) ? Level.FINE : Level.WARNING,
363 "Failed to load "+item.className(), e);
364 }
365 return null;
366 }
367
368 private boolean isOptional(Annotation annotation) {
369 GuiceExtensionAnnotation gea = extensionAnnotations.get(annotation.annotationType());
370 return gea.isOptional(annotation);
371 }
372
373 private boolean isActive(Annotation annotation, AnnotatedElement e) {
374 GuiceExtensionAnnotation gea = extensionAnnotations.get(annotation.annotationType());
375 return gea.isActive(e);
376 }
377
378 public <U> Collection<ExtensionComponent<U>> find(Class<U> type, Hudson jenkins) {
379 // the find method contract requires us to traverse all known components
380 List<ExtensionComponent<U>> result = new ArrayList<ExtensionComponent<U>>();
381 for (Injector i=container; i!=null; i=i.getParent()) {
382 _find(type, result, i);
383 }
384 return result;
385 }
386
387 private <U> void _find(Class<U> type, List<ExtensionComponent<U>> result, Injector container) {
388 for (Entry<Key<?>, Binding<?>> e : container.getBindings().entrySet()) {
389 if (type.isAssignableFrom(e.getKey().getTypeLiteral().getRawType())) {
390 Annotation a = annotations.get(e.getKey());
391 Object o = e.getValue().getProvider().get();
392 if (o!=null) {
393 GuiceExtensionAnnotation gea = a!=null ? extensionAnnotations.get(a.annotationType()) : null;
394 result.add(new ExtensionComponent<U>(type.cast(o),gea!=null?gea.getOrdinal(a):0));
395 }
396 }
397 }
398 }
399
400 /**
401 * TODO: need to learn more about concurrent access to {@link Injector} and how it interacts
402 * with classloading.
403 */
404 @Override
405 public void scout(Class extensionType, Hudson hudson) {
406 }
407
408 /**
409 * {@link Scope} that allows a failure to create a component,
410 * and change the value to null.
411 *
412 * <p>
413 * This is necessary as a failure to load one plugin shouldn't fail the startup of the entire Jenkins.
414 * Instead, we should just drop the failing plugins.
415 */
416 public static final Scope FAULT_TOLERANT_SCOPE = new Scope() {
417 public <T> Provider<T> scope(final Key<T> key, final Provider<T> unscoped) {
418 final Provider<T> base = Scopes.SINGLETON.scope(key,unscoped);
419 return new Provider<T>() {
420 public T get() {
421 try {
422 return base.get();
423 } catch (Exception e) {
424 LOGGER.log(Level.WARNING,"Failed to instantiate. Skipping this component",e);
425 return null;
426 } catch (LinkageError e) {
427 LOGGER.log(Level.WARNING,"Failed to instantiate. Skipping this component",e);
428 return null;
429 }
430 }
431 };
432 }
433 };
434
435 private static final Logger LOGGER = Logger.getLogger(GuiceFinder.class.getName());
436
437 /**
438 * {@link Module} that finds components via sezpoz index.
439 * Instead of using SezPoz to instantiate, we'll instantiate them by using Guice,
440 * so that we can take advantage of dependency injection.
441 */
442 private class SezpozModule extends AbstractModule {
443 private final List<IndexItem<?,Object>> index;
444
445 public SezpozModule(List<IndexItem<?,Object>> index) {
446 this.index = index;
447 }
448
449 /**
450 * Guice performs various reflection operations on the class to figure out the dependency graph,
451 * and that process can cause additional classloading problems, which will fail the injector creation,
452 * which in turn has disastrous effect on the startup.
453 *
454 * <p>
455 * Ultimately I'd like to isolate problems to plugins and selectively disable them, allowing
456 * Jenkins to start with plugins that work, but I haven't figured out how.
457 *
458 * So this is an attempt to detect subset of problems eagerly, by invoking various reflection
459 * operations and try to find non-existent classes early.
460 */
461 private void resolve(Class c) {
462 try {
463 c.getGenericSuperclass();
464 c.getGenericInterfaces();
465 ClassLoader ecl = c.getClassLoader();
466 Method m = ClassLoader.class.getDeclaredMethod("resolveClass", Class.class);
467 m.setAccessible(true);
468 m.invoke(ecl, c);
469 c.getMethods();
470 c.getFields();
471 while (c != Object.class) {
472 c.getGenericSuperclass();
473 c = c.getSuperclass();
474 }
475 } catch (Exception x) {
476 throw (LinkageError)new LinkageError("Failed to resolve "+c).initCause(x);
477 }
478 }
479
480 @SuppressWarnings({"unchecked", "ChainOfInstanceofChecks"})
481 @Override
482 protected void configure() {
483 int id=0;
484
485 for (final IndexItem<?,Object> item : index) {
486 id++;
487 try {
488 AnnotatedElement e = item.element();
489 Annotation a = item.annotation();
490 if (!isActive(a,e)) continue;
491
492 if (e instanceof Class) {
493 Key key = Key.get((Class)e);
494 resolve((Class)e);
495 annotations.put(key,a);
496 bind(key).in(FAULT_TOLERANT_SCOPE);
497 } else {
498 Class extType;
499 if (e instanceof Field) {
500 extType = ((Field)e).getType();
501 } else
502 if (e instanceof Method) {
503 extType = ((Method)e).getReturnType();
504 } else
505 throw new AssertionError();
506
507 resolve(extType);
508
509 // use arbitrary id to make unique key, because Guice wants that.
510 Key key = Key.get(extType, Names.named(String.valueOf(id)));
511 annotations.put(key,a);
512 bind(key).toProvider(new Provider() {
513 public Object get() {
514 return instantiate(item);
515 }
516 }).in(FAULT_TOLERANT_SCOPE);
517 }
518 } catch (LinkageError e) {
519 // sometimes the instantiation fails in an indirect classloading failure,
520 // which results in a LinkageError
521 LOGGER.log(isOptional(item.annotation()) ? Level.FINE : Level.WARNING,
522 "Failed to load "+item.className(), e);
523 } catch (InstantiationException e) {
524 LOGGER.log(isOptional(item.annotation()) ? Level.FINE : Level.WARNING,
525 "Failed to load "+item.className(), e);
526 }
527 }
528 }
529 }
530 }
531
532 /**
533 * The bootstrap implementation that looks for the {@link Extension} marker.
534 *
535 * <p>
536 * Uses Sezpoz as the underlying mechanism.
537 */
538 public static final class Sezpoz extends ExtensionFinder {
539
540 private volatile List<IndexItem<Extension,Object>> indices;
541
542 /**
543 * Loads indices (ideally once but as few times as possible), then reuse them later.
544 * {@link ExtensionList#ensureLoaded()} guarantees that this method won't be called until
545 * {@link InitMilestone#PLUGINS_PREPARED} is attained, so this method is guaranteed to
546 * see all the classes and indices.
547 */
548 private List<IndexItem<Extension,Object>> getIndices() {
549 // this method cannot be synchronized because of a dead lock possibility in the following order of events:
550 // 1. thread X can start listing indices, locking this object 'SZ'
551 // 2. thread Y starts loading a class, locking a classloader 'CL'
552 // 3. thread X needs to load a class, now blocked on CL
553 // 4. thread Y decides to load extensions, now blocked on SZ.
554 // 5. dead lock
555 if (indices==null) {
556 ClassLoader cl = Jenkins.getInstance().getPluginManager().uberClassLoader;
557 indices = ImmutableList.copyOf(Index.load(Extension.class, Object.class, cl));
558 }
559 return indices;
560 }
561
562 /**
563 * {@inheritDoc}
564 *
565 * <p>
566 * SezPoz implements value-equality of {@link IndexItem}, so
567 */
568 @Override
569 public synchronized ExtensionComponentSet refresh() {
570 final List<IndexItem<Extension,Object>> old = indices;
571 if (old==null) return ExtensionComponentSet.EMPTY; // we haven't loaded anything
572
573 final List<IndexItem<Extension, Object>> delta = listDelta(Extension.class,old);
574
575 List<IndexItem<Extension,Object>> r = Lists.newArrayList(old);
576 r.addAll(delta);
577 indices = ImmutableList.copyOf(r);
578
579 return new ExtensionComponentSet() {
580 @Override
581 public <T> Collection<ExtensionComponent<T>> find(Class<T> type) {
582 return _find(type,delta);
583 }
584 };
585 }
586
587 static <T extends Annotation> List<IndexItem<T,Object>> listDelta(Class<T> annotationType, List<? extends IndexItem<?,Object>> old) {
588 // list up newly discovered components
589 final List<IndexItem<T,Object>> delta = Lists.newArrayList();
590 ClassLoader cl = Jenkins.getInstance().getPluginManager().uberClassLoader;
591 for (IndexItem<T,Object> ii : Index.load(annotationType, Object.class, cl)) {
592 if (!old.contains(ii)) {
593 delta.add(ii);
594 }
595 }
596 return delta;
597 }
598
599 public <T> Collection<ExtensionComponent<T>> find(Class<T> type, Hudson jenkins) {
600 return _find(type,getIndices());
601 }
602
603 /**
604 * Finds all the matching {@link IndexItem}s that match the given type and instantiate them.
605 */
606 private <T> Collection<ExtensionComponent<T>> _find(Class<T> type, List<IndexItem<Extension,Object>> indices) {
607 List<ExtensionComponent<T>> result = new ArrayList<ExtensionComponent<T>>();
608
609 for (IndexItem<Extension,Object> item : indices) {
610 try {
611 AnnotatedElement e = item.element();
612 Class<?> extType;
613 if (e instanceof Class) {
614 extType = (Class) e;
615 } else
616 if (e instanceof Field) {
617 extType = ((Field)e).getType();
618 } else
619 if (e instanceof Method) {
620 extType = ((Method)e).getReturnType();
621 } else
622 throw new AssertionError();
623
624 if(type.isAssignableFrom(extType)) {
625 Object instance = item.instance();
626 if(instance!=null)
627 result.add(new ExtensionComponent<T>(type.cast(instance),item.annotation()));
628 }
629 } catch (LinkageError e) {
630 // sometimes the instantiation fails in an indirect classloading failure,
631 // which results in a LinkageError
632 LOGGER.log(logLevel(item), "Failed to load "+item.className(), e);
633 } catch (InstantiationException e) {
634 LOGGER.log(logLevel(item), "Failed to load "+item.className(), e);
635 }
636 }
637
638 return result;
639 }
640
641 @Override
642 public void scout(Class extensionType, Hudson hudson) {
643 for (IndexItem<Extension,Object> item : getIndices()) {
644 try {
645 // we might end up having multiple threads concurrently calling into element(),
646 // but we can't synchronize this --- if we do, the one thread that's supposed to load a class
647 // can block while other threads wait for the entry into the element call().
648 // looking at the sezpoz code, it should be safe to do so
649 AnnotatedElement e = item.element();
650 Class<?> extType;
651 if (e instanceof Class) {
652 extType = (Class) e;
653 } else
654 if (e instanceof Field) {
655 extType = ((Field)e).getType();
656 } else
657 if (e instanceof Method) {
658 extType = ((Method)e).getReturnType();
659 } else
660 throw new AssertionError();
661 // according to http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6459208
662 // this appears to be the only way to force a class initialization
663 Class.forName(extType.getName(),true,extType.getClassLoader());
664 } catch (InstantiationException e) {
665 LOGGER.log(logLevel(item), "Failed to scout "+item.className(), e);
666 } catch (ClassNotFoundException e) {
667 LOGGER.log(logLevel(item), "Failed to scout "+item.className(), e);
668 } catch (LinkageError e) {
669 LOGGER.log(logLevel(item), "Failed to scout "+item.className(), e);
670 }
671 }
672 }
673
674 private Level logLevel(IndexItem<Extension, Object> item) {
675 return item.annotation().optional() ? Level.FINE : Level.WARNING;
676 }
677 }
678
679 private static final Logger LOGGER = Logger.getLogger(ExtensionFinder.class.getName());
680 }
681