1 /**
2 * Logback: the reliable, generic, fast and flexible logging framework.
3 * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
4 *
5 * This program and the accompanying materials are dual-licensed under
6 * either the terms of the Eclipse Public License v1.0 as published by
7 * the Eclipse Foundation
8 *
9 * or (per the licensee's choosing)
10 *
11 * under the terms of the GNU Lesser General Public License version 2.1
12 * as published by the Free Software Foundation.
13 */
14 package ch.qos.logback.core.joran.spi;
15
16
17 import java.lang.annotation.Annotation;
18 import java.util.HashSet;
19 import java.util.Set;
20 import ch.qos.logback.core.spi.LifeCycle;
21
22 public class NoAutoStartUtil {
23
24 /**
25 * Returns true if the class of the object 'o' passed as parameter is *not*
26 * marked with the NoAutoStart annotation. Return true otherwise.
27 *
28 * @param o
29 * @return true for classes not marked with the NoAutoStart annotation
30 */
31 public static boolean notMarkedWithNoAutoStart(Object o) {
32 if (o == null) {
33 return false;
34 }
35 Class<?> clazz = o.getClass();
36 NoAutoStart a = findAnnotation(clazz, NoAutoStart.class);
37 return a == null;
38 }
39
40 /**
41 * Find a single {@link Annotation} of {@code annotationType} on the
42 * supplied {@link Class}, traversing its interfaces, annotations, and
43 * superclasses if the annotation is not <em>directly present</em> on
44 * the given class itself.
45 * <p>This method explicitly handles class-level annotations which are not
46 * declared as {@link java.lang.annotation.Inherited inherited} <em>as well
47 * as meta-annotations and annotations on interfaces</em>.
48 * <p>The algorithm operates as follows:
49 * <ol>
50 * <li>Search for the annotation on the given class and return it if found.
51 * <li>Recursively search through all interfaces that the given class declares.
52 * <li>Recursively search through the superclass hierarchy of the given class.
53 * </ol>
54 * <p>Note: in this context, the term <em>recursively</em> means that the search
55 * process continues by returning to step #1 with the current interface,
56 * annotation, or superclass as the class to look for annotations on.
57 * @param clazz the class to look for annotations on
58 * @param annotationType the type of annotation to look for
59 * @return the first matching annotation, or {@code null} if not found
60 */
61 private static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType) {
62 return findAnnotation(clazz, annotationType, new HashSet<>());
63 }
64
65 /**
66 * Perform the search algorithm for {@link #findAnnotation(Class, Class)},
67 * avoiding endless recursion by tracking which annotations have already
68 * been <em>visited</em>.
69 * @param clazz the class to look for annotations on
70 * @param annotationType the type of annotation to look for
71 * @param visited the set of annotations that have already been visited
72 * @return the first matching annotation, or {@code null} if not found
73 */
74 @SuppressWarnings("unchecked")
75 private static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType, Set<Annotation> visited) {
76
77 Annotation foundAnnotation = clazz.getAnnotation(annotationType);
78 if(foundAnnotation != null) {
79 return (A) foundAnnotation;
80 }
81
82
83 for (Class<?> ifc : clazz.getInterfaces()) {
84 A annotation = findAnnotation(ifc, annotationType, visited);
85 if (annotation != null) {
86 return annotation;
87 }
88 }
89
90 Class<?> superclass = clazz.getSuperclass();
91 if (superclass == null || Object.class == superclass) {
92 return null;
93 }
94 return findAnnotation(superclass, annotationType, visited);
95 }
96
97 /**
98 * Is the object a {@link LifeCycle} and is it marked not marked with
99 * the NoAutoStart annotation.
100 * @param o
101 * @return
102 * @ since 1.5.2
103 */
104 static public boolean shouldBeStarted(Object o) {
105 if(o instanceof LifeCycle) {
106 return notMarkedWithNoAutoStart(o);
107 } else
108 return false;
109 }
110 }