1 package org.apache.onami.logging.core;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import static java.lang.String.format;
23
24 import java.lang.reflect.Array;
25 import java.lang.reflect.Constructor;
26 import java.lang.reflect.Field;
27 import java.lang.reflect.GenericArrayType;
28 import java.lang.reflect.ParameterizedType;
29 import java.lang.reflect.Type;
30 import java.lang.reflect.TypeVariable;
31
32 import com.google.inject.Binder;
33 import com.google.inject.MembersInjector;
34 import com.google.inject.Module;
35 import com.google.inject.ProvisionException;
36 import com.google.inject.TypeLiteral;
37 import com.google.inject.matcher.Matcher;
38 import com.google.inject.spi.TypeEncounter;
39 import com.google.inject.spi.TypeListener;
40
41
42
43
44
45
46
47
48
49
50 public class AbstractLoggingModule<L>
51 extends TypeLiteral<L>
52 implements Module, TypeListener
53 {
54
55
56
57
58 private final Matcher<? super TypeLiteral<?>> matcher;
59
60
61
62
63 private final Class<?> loggerClass;
64
65
66
67
68
69 private final Constructor<? extends MembersInjector<L>> logInjectorConstructor;
70
71
72
73
74
75
76
77
78
79 public <LI extends AbstractLoggerInjector<L>> AbstractLoggingModule( Matcher<? super TypeLiteral<?>> matcher,
80 Class<LI> loggerInjectorClass )
81 {
82 if ( matcher == null )
83 {
84 throw new IllegalArgumentException( "Parameter 'matcher' must not be null" );
85 }
86 if ( loggerInjectorClass == null )
87 {
88 throw new IllegalArgumentException( "Parameter 'loggerInjectorClass' must not be null" );
89 }
90
91 this.matcher = matcher;
92 loggerClass = getRawType( getType() );
93 try
94 {
95 logInjectorConstructor = loggerInjectorClass.getConstructor( Field.class );
96 }
97 catch ( SecurityException e )
98 {
99 throw new ProvisionException( format( "Impossible to access to '%s(%s)' public constructor due to security violation: %s",
100 loggerInjectorClass.getName(), Field.class.getName(), e.getMessage() ) );
101 }
102 catch ( NoSuchMethodException e )
103 {
104 throw new ProvisionException( format( "Class '%s' doesn't have a public construcor with <%s> parameter type: %s",
105 loggerInjectorClass.getName(), Field.class.getName(), e.getMessage() ) );
106 }
107 }
108
109
110
111
112 public final void configure( Binder binder )
113 {
114 binder.bindListener( matcher, this );
115 }
116
117
118
119
120 public final <I> void hear( TypeLiteral<I> type, TypeEncounter<I> encounter )
121 {
122 hear( type.getRawType(), encounter );
123 }
124
125 @SuppressWarnings("unchecked")
126 private <I> void hear( Class<?> klass, TypeEncounter<I> encounter )
127 {
128 if ( Object.class == klass )
129 {
130 return;
131 }
132
133 for ( Field field : klass.getDeclaredFields() )
134 {
135 if ( loggerClass == field.getType() && field.isAnnotationPresent( InjectLogger.class ) )
136 {
137 try
138 {
139 encounter.register( (MembersInjector<? super I>) logInjectorConstructor.newInstance( field ) );
140 }
141 catch ( Exception e )
142 {
143 throw new RuntimeException( format( "Impossible to register '%s' for field '%s', see nested exception",
144 logInjectorConstructor.getName(),
145 field ), e );
146 }
147 }
148 }
149
150 hear( klass.getSuperclass(), encounter );
151 }
152
153 private static Class<?> getRawType( Type type )
154 {
155 if ( type instanceof Class<?> )
156 {
157
158 return (Class<?>) type;
159 }
160 else if ( type instanceof ParameterizedType )
161 {
162 ParameterizedType parameterizedType = (ParameterizedType) type;
163
164
165
166
167 Type rawType = parameterizedType.getRawType();
168 if ( !(rawType instanceof Class) )
169 {
170 throw new IllegalArgumentException( format( "Expected a Class, but <%s> is of type %s",
171 type,
172 type.getClass().getName() ) );
173 }
174 return (Class<?>) rawType;
175 }
176 else if ( type instanceof GenericArrayType )
177 {
178 Type componentType = ( (GenericArrayType) type ).getGenericComponentType();
179 return Array.newInstance( getRawType( componentType ), 0 ).getClass();
180 }
181 else if ( type instanceof TypeVariable )
182 {
183
184
185 return Object.class;
186 }
187 else
188 {
189 throw new IllegalArgumentException( format( "Expected a Class, ParameterizedType, or GenericArrayType, but <%s> is of type %s",
190 type,
191 type.getClass().getName() ) );
192 }
193 }
194
195 }