001/**
002 * Logback: the reliable, generic, fast and flexible logging framework.
003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
004 *
005 * This program and the accompanying materials are dual-licensed under
006 * either the terms of the Eclipse Public License v1.0 as published by
007 * the Eclipse Foundation
008 *
009 *   or (per the licensee's choosing)
010 *
011 * under the terms of the GNU Lesser General Public License version 2.1
012 * as published by the Free Software Foundation.
013 */
014package ch.qos.logback.core.joran.spi;
015
016
017import java.lang.annotation.Annotation;
018import java.util.HashSet;
019import java.util.Set;
020import ch.qos.logback.core.spi.LifeCycle;
021
022public class NoAutoStartUtil {
023
024    /**
025     * Returns true if the class of the object 'o' passed as parameter is *not*
026     * marked with the NoAutoStart annotation. Return true otherwise.
027     *
028     * @param o
029     * @return true for classes not marked with the NoAutoStart annotation
030     */
031    public static boolean notMarkedWithNoAutoStart(Object o) {
032        if (o == null) {
033            return false;
034        }
035        Class<?> clazz = o.getClass();
036        NoAutoStart a = findAnnotation(clazz, NoAutoStart.class);
037        return a == null;
038    }
039
040        /**
041         * Find a single {@link Annotation} of {@code annotationType} on the
042         * supplied {@link Class}, traversing its interfaces, annotations, and
043         * superclasses if the annotation is not <em>directly present</em> on
044         * the given class itself.
045         * <p>This method explicitly handles class-level annotations which are not
046         * declared as {@link java.lang.annotation.Inherited inherited} <em>as well
047         * as meta-annotations and annotations on interfaces</em>.
048         * <p>The algorithm operates as follows:
049         * <ol>
050         * <li>Search for the annotation on the given class and return it if found.
051         * <li>Recursively search through all interfaces that the given class declares.
052         * <li>Recursively search through the superclass hierarchy of the given class.
053         * </ol>
054         * <p>Note: in this context, the term <em>recursively</em> means that the search
055         * process continues by returning to step #1 with the current interface,
056         * annotation, or superclass as the class to look for annotations on.
057         * @param clazz the class to look for annotations on
058         * @param annotationType the type of annotation to look for
059         * @return the first matching annotation, or {@code null} if not found
060         */
061        private static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType) {
062                return findAnnotation(clazz, annotationType, new HashSet<>());
063        }
064
065        /**
066         * Perform the search algorithm for {@link #findAnnotation(Class, Class)},
067         * avoiding endless recursion by tracking which annotations have already
068         * been <em>visited</em>.
069         * @param clazz the class to look for annotations on
070         * @param annotationType the type of annotation to look for
071         * @param visited the set of annotations that have already been visited
072         * @return the first matching annotation, or {@code null} if not found
073         */
074        @SuppressWarnings("unchecked")
075        private static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType, Set<Annotation> visited) {
076
077                Annotation foundAnnotation = clazz.getAnnotation(annotationType);
078                if(foundAnnotation != null) {
079                        return (A) foundAnnotation;
080                }
081
082
083                for (Class<?> ifc : clazz.getInterfaces()) {
084                        A annotation = findAnnotation(ifc, annotationType, visited);
085                        if (annotation != null) {
086                                return annotation;
087                        }
088                }
089
090                Class<?> superclass = clazz.getSuperclass();
091                if (superclass == null || Object.class == superclass) {
092                        return null;
093                }
094                return findAnnotation(superclass, annotationType, visited);
095        }
096
097  /**
098     * Is the object a {@link LifeCycle} and is it marked not marked with
099     * 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}