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}