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 }