View Javadoc
1   package org.apache.turbine.annotation;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.lang.annotation.Annotation;
23  import java.lang.reflect.AccessibleObject;
24  import java.lang.reflect.Field;
25  import java.util.List;
26  import java.util.concurrent.ConcurrentHashMap;
27  import java.util.concurrent.ConcurrentMap;
28  
29  import org.apache.commons.configuration.Configuration;
30  import org.apache.commons.lang.StringUtils;
31  import org.apache.commons.logging.Log;
32  import org.apache.commons.logging.LogFactory;
33  import org.apache.turbine.Turbine;
34  import org.apache.turbine.modules.Loader;
35  import org.apache.turbine.services.ServiceManager;
36  import org.apache.turbine.services.TurbineServices;
37  import org.apache.turbine.services.assemblerbroker.AssemblerBrokerService;
38  import org.apache.turbine.util.TurbineException;
39  
40  /**
41   * AnnotationProcessor contains static helper methods that handle the
42   * Turbine annotations for objects
43   *
44   * @author <a href="mailto:tv@apache.org">Thomas Vandahl</a>
45   * @version $Id: TurbineAssemblerBrokerService.java 1521103 2013-09-09 13:38:07Z tv $
46   */
47  public class AnnotationProcessor
48  {
49      /** Logging */
50      private static Log log = LogFactory.getLog(AnnotationProcessor.class);
51  
52      /** Annotation cache */
53      private static ConcurrentMap<String, Annotation[]> annotationCache = new ConcurrentHashMap<String, Annotation[]>();
54  
55      /**
56       * Get cached annotations for field, class or method
57       *
58       * @param object a field, class or method
59       *
60       * @return the declared annotations for the object
61       */
62      public static Annotation[] getAnnotations(AccessibleObject object)
63      {
64          String key = object.getClass() + object.toString();
65          Annotation[] annotations = annotationCache.get(key);
66          if (annotations == null)
67          {
68              Annotation[] newAnnotations = object.getDeclaredAnnotations();
69              annotations = annotationCache.putIfAbsent(key, newAnnotations);
70              if (annotations == null)
71              {
72                  annotations = newAnnotations;
73              }
74          }
75          return annotations;
76      }
77  
78      /**
79       * Search for annotated fields of the object and inject the appropriate
80       * objects
81       *
82       * @param object the object
83       * @throws TurbineException if the objects could not be injected
84       */
85      public static void process(Object object) throws TurbineException
86      {
87          ServiceManager manager = null;
88          Configuration config = null;
89          AssemblerBrokerService assembler = null;
90          Class<?> clazz = object.getClass();
91  
92          while (clazz != null)
93          {
94              Field[] fields = clazz.getDeclaredFields();
95  
96              for (Field field : fields)
97              {
98                  Annotation[] annotations = getAnnotations(field);
99  
100                 for (Annotation a : annotations)
101                 {
102                     if (a instanceof TurbineService)
103                     {
104                         if (manager == null)
105                         {
106                             manager = TurbineServices.getInstance();
107                         }
108                         injectTurbineService(object, manager, field, (TurbineService) a);
109                     }
110                     else if (a instanceof TurbineConfiguration)
111                     {
112                         if (config == null)
113                         {
114                             config = Turbine.getConfiguration();
115                         }
116                         injectTurbineConfiguration(object, config, field, (TurbineConfiguration) a);
117                     }
118                     else if (a instanceof TurbineLoader)
119                     {
120                         if (assembler == null)
121                         {
122                             assembler = (AssemblerBrokerService) TurbineServices.getInstance().
123                                 getService(AssemblerBrokerService.SERVICE_NAME);
124                         }
125                         injectTurbineLoader(object, assembler, field, (TurbineLoader) a);
126                     }
127                 }
128             }
129 
130             clazz = clazz.getSuperclass();
131         }
132     }
133 
134     /**
135      * Inject Turbine configuration into field of object
136      *
137      * @param object the object to process
138      * @param assembler AssemblerBrokerService, provides the loader
139      * @param field the field
140      * @param annotation the value of the annotation
141      *
142      * @throws TurbineException if loader cannot be set
143      */
144     private static void injectTurbineLoader(Object object, AssemblerBrokerService assembler, Field field, TurbineLoader annotation) throws TurbineException
145     {
146         Loader<?> loader = assembler.getLoader(annotation.value());
147         field.setAccessible(true);
148 
149         try
150         {
151             if (log.isDebugEnabled())
152             {
153                 log.debug("Injection of " + loader + " into object " + object);
154             }
155 
156             field.set(object, loader);
157         }
158         catch (IllegalArgumentException e)
159         {
160             throw new TurbineException("Could not inject loader "
161                     + loader + " into object " + object, e);
162         }
163         catch (IllegalAccessException e)
164         {
165             throw new TurbineException("Could not inject loader "
166                     + loader + " into object " + object, e);
167         }
168     }
169 
170     /**
171      * Inject Turbine configuration into field of object
172      *
173      * @param object the object to process
174      * @param conf the configuration to use
175      * @param field the field
176      * @param annotation the value of the annotation
177      *
178      * @throws TurbineException if configuration cannot be set
179      */
180     private static void injectTurbineConfiguration(Object object, Configuration conf, Field field, TurbineConfiguration annotation) throws TurbineException
181     {
182         Class<?> type = field.getType();
183         String key = annotation.value();
184 
185         try
186         {
187             if (Configuration.class.isAssignableFrom(type))
188             {
189                 // Check for annotation value
190                 if (StringUtils.isNotEmpty(key))
191                 {
192                     conf = conf.subset(key);
193                 }
194 
195                 if (log.isDebugEnabled())
196                 {
197                     log.debug("Injection of " + conf + " into object " + object);
198                 }
199 
200                 field.setAccessible(true);
201                 field.set(object, conf);
202             }
203             else if (conf.containsKey(key))
204             {
205                 if ( String.class.isAssignableFrom( type ) )
206                 {
207                     String value = conf.getString(key);
208                     if (log.isDebugEnabled())
209                     {
210                         log.debug("Injection of " + value + " into object " + object);
211                     }
212 
213                     field.setAccessible(true);
214                     field.set(object, value);
215                 }
216                 else if ( Boolean.TYPE.isAssignableFrom( type ) )
217                 {
218                     boolean value = conf.getBoolean(key);
219                     if (log.isDebugEnabled())
220                     {
221                         log.debug("Injection of " + value + " into object " + object);
222                     }
223 
224                     field.setAccessible(true);
225                     field.setBoolean(object, value);
226                 }
227                 else if ( Integer.TYPE.isAssignableFrom( type ) )
228                 {
229                     int value = conf.getInt(key);
230                     if (log.isDebugEnabled())
231                     {
232                         log.debug("Injection of " + value + " into object " + object);
233                     }
234 
235                     field.setAccessible(true);
236                     field.setInt(object, value);
237                 }
238                 else if ( Long.TYPE.isAssignableFrom( type ) )
239                 {
240                     long value = conf.getLong(key);
241                     if (log.isDebugEnabled())
242                     {
243                         log.debug("Injection of " + value + " into object " + object);
244                     }
245 
246                     field.setAccessible(true);
247                     field.setLong(object, value);
248                 }
249                 else if ( Short.TYPE.isAssignableFrom( type ) )
250                 {
251                     short value = conf.getShort(key);
252                     if (log.isDebugEnabled())
253                     {
254                         log.debug("Injection of " + value + " into object " + object);
255                     }
256 
257                     field.setAccessible(true);
258                     field.setShort(object, value);
259                 }
260                 else if ( Long.TYPE.isAssignableFrom( type ) )
261                 {
262                     long value = conf.getLong(key);
263                     if (log.isDebugEnabled())
264                     {
265                         log.debug("Injection of " + value + " into object " + object);
266                     }
267 
268                     field.setAccessible(true);
269                     field.setLong(object, value);
270                 }
271                 else if ( Float.TYPE.isAssignableFrom( type ) )
272                 {
273                     float value = conf.getFloat(key);
274                     if (log.isDebugEnabled())
275                     {
276                         log.debug("Injection of " + value + " into object " + object);
277                     }
278 
279                     field.setAccessible(true);
280                     field.setFloat(object, value);
281                 }
282                 else if ( Double.TYPE.isAssignableFrom( type ) )
283                 {
284                     double value = conf.getDouble(key);
285                     if (log.isDebugEnabled())
286                     {
287                         log.debug("Injection of " + value + " into object " + object);
288                     }
289 
290                     field.setAccessible(true);
291                     field.setDouble(object, value);
292                 }
293                 else if ( Byte.TYPE.isAssignableFrom( type ) )
294                 {
295                     byte value = conf.getByte(key);
296                     if (log.isDebugEnabled())
297                     {
298                         log.debug("Injection of " + value + " into object " + object);
299                     }
300 
301                     field.setAccessible(true);
302                     field.setByte(object, value);
303                 }
304                 else if ( List.class.isAssignableFrom( type ) )
305                 {
306                     List<Object> values = conf.getList(key);
307                     if (log.isDebugEnabled())
308                     {
309                         log.debug("Injection of " + values + " into object " + object);
310                     }
311 
312                     field.setAccessible(true);
313                     field.set(object, values);
314                 }
315             }
316         }
317         catch (IllegalArgumentException e)
318         {
319             throw new TurbineException("Could not inject configuration "
320                     + conf + " into object " + object, e);
321         }
322         catch (IllegalAccessException e)
323         {
324             throw new TurbineException("Could not inject configuration "
325                     + conf + " into object " + object, e);
326         }
327     }
328 
329     /**
330      * Inject Turbine service into field of object
331      *
332      * @param object the object to process
333      * @param manager the service manager
334      * @param field the field
335      * @param annotation the value of the annotation
336      *
337      * @throws TurbineException if service is not available
338      */
339     private static void injectTurbineService(Object object, ServiceManager manager, Field field, TurbineService annotation) throws TurbineException
340     {
341         String serviceName = null;
342         // Check for annotation value
343         if (StringUtils.isNotEmpty(annotation.value()))
344         {
345             serviceName = annotation.value();
346         }
347         // Check for fields SERVICE_NAME and ROLE
348         else
349         {
350             Field[] typeFields = field.getType().getFields();
351             for (Field f : typeFields)
352             {
353                 if (TurbineService.SERVICE_NAME.equals(f.getName()))
354                 {
355                     try
356                     {
357                         serviceName = (String)f.get(null);
358                     }
359                     catch (Exception e)
360                     {
361                         continue;
362                     }
363                     break;
364                 }
365                 else if (TurbineService.ROLE.equals(f.getName()))
366                 {
367                     try
368                     {
369                         serviceName = (String)f.get(null);
370                     }
371                     catch (Exception e)
372                     {
373                         continue;
374                     }
375                     break;
376                 }
377             }
378         }
379 
380         if (StringUtils.isEmpty(serviceName))
381         {
382             // Try interface class name
383             serviceName = field.getType().getName();
384         }
385 
386         if (log.isDebugEnabled())
387         {
388             log.debug("Looking up service for injection: " + serviceName + " for object " + object);
389         }
390 
391         Object service = manager.getService(serviceName); // throws Exception on unknown service
392         field.setAccessible(true);
393 
394         try
395         {
396             if (log.isDebugEnabled())
397             {
398                 log.debug("Injection of " + serviceName + " into object " + object);
399             }
400 
401             field.set(object, service);
402         }
403         catch (IllegalArgumentException e)
404         {
405             throw new TurbineException("Could not inject service "
406                     + serviceName + " into object " + object, e);
407         }
408         catch (IllegalAccessException e)
409         {
410             throw new TurbineException("Could not inject service "
411                     + serviceName + " into object " + object, e);
412         }
413     }
414 }