Coverage Report - org.apache.turbine.annotation.AnnotationProcessor
 
Classes in this File Line Coverage Branch Coverage Complexity
AnnotationProcessor
57%
107/187
48%
54/112
13,333
 
 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.fulcrum.security.model.turbine.TurbineAccessControlList;
 34  
 import org.apache.turbine.Turbine;
 35  
 import org.apache.turbine.modules.Loader;
 36  
 import org.apache.turbine.services.ServiceManager;
 37  
 import org.apache.turbine.services.TurbineServices;
 38  
 import org.apache.turbine.services.assemblerbroker.AssemblerBrokerService;
 39  
 import org.apache.turbine.util.TurbineException;
 40  
 
 41  
 /**
 42  
  * AnnotationProcessor contains static helper methods that handle the
 43  
  * Turbine annotations for objects
 44  
  *
 45  
  * @author <a href="mailto:tv@apache.org">Thomas Vandahl</a>
 46  
  * @version $Id: TurbineAssemblerBrokerService.java 1521103 2013-09-09 13:38:07Z tv $
 47  
  */
 48  0
 public class AnnotationProcessor
 49  
 {
 50  
     /** Logging */
 51  33
     private static Log log = LogFactory.getLog(AnnotationProcessor.class);
 52  
 
 53  
     /** Annotation cache */
 54  33
     private static ConcurrentMap<String, Annotation[]> annotationCache = new ConcurrentHashMap<String, Annotation[]>();
 55  
 
 56  
     /**
 57  
      * Get cached annotations for field, class or method
 58  
      *
 59  
      * @param object a field, class or method
 60  
      *
 61  
      * @return the declared annotations for the object
 62  
      */
 63  
     public static Annotation[] getAnnotations(AccessibleObject object)
 64  
     {
 65  3139
         String key = object.getClass() + object.toString();
 66  3139
         Annotation[] annotations = annotationCache.get(key);
 67  3139
         if (annotations == null)
 68  
         {
 69  1562
             Annotation[] newAnnotations = object.getDeclaredAnnotations();
 70  1562
             annotations = annotationCache.putIfAbsent(key, newAnnotations);
 71  1562
             if (annotations == null)
 72  
             {
 73  1562
                 annotations = newAnnotations;
 74  
             }
 75  
         }
 76  3139
         return annotations;
 77  
     }
 78  
 
 79  
     /**
 80  
      * Check if the object given is authorized to be executed based on its annotations
 81  
      * The method will return false if one of the annotations denies execution
 82  
      *
 83  
      * @param object the object
 84  
      * @param acl
 85  
      * @return true if the execution is allowed
 86  
      */
 87  
     public static <A extends TurbineAccessControlList> boolean isAuthorized(AccessibleObject object, A acl)
 88  
     {
 89  0
         Annotation[] annotations = getAnnotations(object);
 90  
 
 91  0
         for (Annotation annotation : annotations)
 92  
         {
 93  0
             if (annotation instanceof TurbineRequiredRole)
 94  
             {
 95  0
                 TurbineRequiredRole trr = (TurbineRequiredRole) annotation;
 96  0
                 String[] roleNames = trr.value();
 97  0
                 String group = trr.group();
 98  
                 
 99  0
                 if (StringUtils.isEmpty(group)) // global group
 100  
                 {
 101  0
                     for (String roleName : roleNames)
 102  
                     {
 103  0
                         if (!acl.hasRole(roleName))
 104  
                         {
 105  0
                             return false;
 106  
                         }
 107  
                     }
 108  
                 }
 109  
                 else
 110  
                 {
 111  0
                     for (String roleName : roleNames)
 112  
                     {
 113  0
                         if (!acl.hasRole(roleName, group))
 114  
                         {
 115  0
                             return false;
 116  
                         }
 117  
                     }
 118  
                 }
 119  0
             }
 120  0
             else if (annotation instanceof TurbineRequiredPermission)
 121  
             {
 122  0
                 TurbineRequiredPermission trp = (TurbineRequiredPermission) annotation;
 123  0
                 String[] permissionNames = trp.value();
 124  0
                 String group = trp.group();
 125  
                 
 126  0
                 if (StringUtils.isEmpty(group)) // global group
 127  
                 {
 128  0
                     for (String permissionName : permissionNames)
 129  
                     {
 130  0
                         if (!acl.hasPermission(permissionName))
 131  
                         {
 132  0
                             return false;
 133  
                         }
 134  
                     }
 135  
                 }
 136  
                 else
 137  
                 {
 138  0
                     for (String permissionName : permissionNames)
 139  
                     {
 140  0
                         if (!acl.hasPermission(permissionName, group))
 141  
                         {
 142  0
                             return false;
 143  
                         }
 144  
                     }
 145  
                 }
 146  
             }
 147  
         }
 148  
         
 149  0
         return true;
 150  
     }
 151  
     
 152  
     /**
 153  
      * Search for annotated fields of the object and inject the appropriate
 154  
      * objects
 155  
      *
 156  
      * @param object the object
 157  
      * @throws TurbineException if the objects could not be injected
 158  
      */
 159  
     public static void process(Object object) throws TurbineException
 160  
     {
 161  565
         ServiceManager manager = null;
 162  565
         Configuration config = null;
 163  565
         AssemblerBrokerService assembler = null;
 164  565
         Class<?> clazz = object.getClass();
 165  
 
 166  2336
         while (clazz != null)
 167  
         {
 168  1775
             Field[] fields = clazz.getDeclaredFields();
 169  
 
 170  4770
             for (Field field : fields)
 171  
             {
 172  2999
                 Annotation[] annotations = getAnnotations(field);
 173  
 
 174  3708
                 for (Annotation a : annotations)
 175  
                 {
 176  713
                     if (a instanceof TurbineService)
 177  
                     {
 178  156
                         if (manager == null)
 179  
                         {
 180  124
                             manager = TurbineServices.getInstance();
 181  
                         }
 182  156
                         injectTurbineService(object, manager, field, (TurbineService) a);
 183  
                     }
 184  557
                     else if (a instanceof TurbineConfiguration)
 185  
                     {
 186  349
                         if (config == null)
 187  
                         {
 188  256
                             config = Turbine.getConfiguration();
 189  
                         }
 190  349
                         injectTurbineConfiguration(object, config, field, (TurbineConfiguration) a);
 191  
                     }
 192  208
                     else if (a instanceof TurbineLoader)
 193  
                     {
 194  208
                         if (assembler == null)
 195  
                         {
 196  200
                             assembler = (AssemblerBrokerService) TurbineServices.getInstance().
 197  
                                 getService(AssemblerBrokerService.SERVICE_NAME);
 198  
                         }
 199  208
                         injectTurbineLoader(object, assembler, field, (TurbineLoader) a);
 200  
                     }
 201  
                 }
 202  
             }
 203  
 
 204  1771
             clazz = clazz.getSuperclass();
 205  1771
         }
 206  561
     }
 207  
 
 208  
     /**
 209  
      * Inject Turbine configuration into field of object
 210  
      *
 211  
      * @param object the object to process
 212  
      * @param assembler AssemblerBrokerService, provides the loader
 213  
      * @param field the field
 214  
      * @param annotation the value of the annotation
 215  
      *
 216  
      * @throws TurbineException if loader cannot be set
 217  
      */
 218  
     private static void injectTurbineLoader(Object object, AssemblerBrokerService assembler, Field field, TurbineLoader annotation) throws TurbineException
 219  
     {
 220  208
         Loader<?> loader = assembler.getLoader(annotation.value());
 221  208
         field.setAccessible(true);
 222  
 
 223  
         try
 224  
         {
 225  208
             if (log.isDebugEnabled())
 226  
             {
 227  208
                 log.debug("Injection of " + loader + " into object " + object);
 228  
             }
 229  
 
 230  208
             field.set(object, loader);
 231  
         }
 232  0
         catch (IllegalArgumentException e)
 233  
         {
 234  0
             throw new TurbineException("Could not inject loader "
 235  
                     + loader + " into object " + object, e);
 236  
         }
 237  0
         catch (IllegalAccessException e)
 238  
         {
 239  0
             throw new TurbineException("Could not inject loader "
 240  
                     + loader + " into object " + object, e);
 241  208
         }
 242  208
     }
 243  
 
 244  
     /**
 245  
      * Inject Turbine configuration into field of object
 246  
      *
 247  
      * @param object the object to process
 248  
      * @param conf the configuration to use
 249  
      * @param field the field
 250  
      * @param annotation the value of the annotation
 251  
      *
 252  
      * @throws TurbineException if configuration cannot be set
 253  
      */
 254  
     private static void injectTurbineConfiguration(Object object, Configuration conf, Field field, TurbineConfiguration annotation) throws TurbineException
 255  
     {
 256  349
         Class<?> type = field.getType();
 257  349
         String key = annotation.value();
 258  
 
 259  
         try
 260  
         {
 261  349
             if (Configuration.class.isAssignableFrom(type))
 262  
             {
 263  
                 // Check for annotation value
 264  2
                 if (StringUtils.isNotEmpty(key))
 265  
                 {
 266  1
                     conf = conf.subset(key);
 267  
                 }
 268  
 
 269  2
                 if (log.isDebugEnabled())
 270  
                 {
 271  2
                     log.debug("Injection of " + conf + " into object " + object);
 272  
                 }
 273  
 
 274  2
                 field.setAccessible(true);
 275  2
                 field.set(object, conf);
 276  
             }
 277  347
             else if (conf.containsKey(key))
 278  
             {
 279  156
                 if ( String.class.isAssignableFrom( type ) )
 280  
                 {
 281  134
                     String value = conf.getString(key);
 282  134
                     if (log.isDebugEnabled())
 283  
                     {
 284  134
                         log.debug("Injection of " + value + " into object " + object);
 285  
                     }
 286  
 
 287  134
                     field.setAccessible(true);
 288  134
                     field.set(object, value);
 289  134
                 }
 290  22
                 else if ( Boolean.TYPE.isAssignableFrom( type ) )
 291  
                 {
 292  19
                     boolean value = conf.getBoolean(key);
 293  19
                     if (log.isDebugEnabled())
 294  
                     {
 295  19
                         log.debug("Injection of " + value + " into object " + object);
 296  
                     }
 297  
 
 298  19
                     field.setAccessible(true);
 299  19
                     field.setBoolean(object, value);
 300  19
                 }
 301  3
                 else if ( Integer.TYPE.isAssignableFrom( type ) )
 302  
                 {
 303  2
                     int value = conf.getInt(key);
 304  2
                     if (log.isDebugEnabled())
 305  
                     {
 306  2
                         log.debug("Injection of " + value + " into object " + object);
 307  
                     }
 308  
 
 309  2
                     field.setAccessible(true);
 310  2
                     field.setInt(object, value);
 311  2
                 }
 312  1
                 else if ( Long.TYPE.isAssignableFrom( type ) )
 313  
                 {
 314  0
                     long value = conf.getLong(key);
 315  0
                     if (log.isDebugEnabled())
 316  
                     {
 317  0
                         log.debug("Injection of " + value + " into object " + object);
 318  
                     }
 319  
 
 320  0
                     field.setAccessible(true);
 321  0
                     field.setLong(object, value);
 322  0
                 }
 323  1
                 else if ( Short.TYPE.isAssignableFrom( type ) )
 324  
                 {
 325  0
                     short value = conf.getShort(key);
 326  0
                     if (log.isDebugEnabled())
 327  
                     {
 328  0
                         log.debug("Injection of " + value + " into object " + object);
 329  
                     }
 330  
 
 331  0
                     field.setAccessible(true);
 332  0
                     field.setShort(object, value);
 333  0
                 }
 334  1
                 else if ( Long.TYPE.isAssignableFrom( type ) )
 335  
                 {
 336  0
                     long value = conf.getLong(key);
 337  0
                     if (log.isDebugEnabled())
 338  
                     {
 339  0
                         log.debug("Injection of " + value + " into object " + object);
 340  
                     }
 341  
 
 342  0
                     field.setAccessible(true);
 343  0
                     field.setLong(object, value);
 344  0
                 }
 345  1
                 else if ( Float.TYPE.isAssignableFrom( type ) )
 346  
                 {
 347  0
                     float value = conf.getFloat(key);
 348  0
                     if (log.isDebugEnabled())
 349  
                     {
 350  0
                         log.debug("Injection of " + value + " into object " + object);
 351  
                     }
 352  
 
 353  0
                     field.setAccessible(true);
 354  0
                     field.setFloat(object, value);
 355  0
                 }
 356  1
                 else if ( Double.TYPE.isAssignableFrom( type ) )
 357  
                 {
 358  0
                     double value = conf.getDouble(key);
 359  0
                     if (log.isDebugEnabled())
 360  
                     {
 361  0
                         log.debug("Injection of " + value + " into object " + object);
 362  
                     }
 363  
 
 364  0
                     field.setAccessible(true);
 365  0
                     field.setDouble(object, value);
 366  0
                 }
 367  1
                 else if ( Byte.TYPE.isAssignableFrom( type ) )
 368  
                 {
 369  0
                     byte value = conf.getByte(key);
 370  0
                     if (log.isDebugEnabled())
 371  
                     {
 372  0
                         log.debug("Injection of " + value + " into object " + object);
 373  
                     }
 374  
 
 375  0
                     field.setAccessible(true);
 376  0
                     field.setByte(object, value);
 377  0
                 }
 378  1
                 else if ( List.class.isAssignableFrom( type ) )
 379  
                 {
 380  1
                     List<Object> values = conf.getList(key);
 381  1
                     if (log.isDebugEnabled())
 382  
                     {
 383  1
                         log.debug("Injection of " + values + " into object " + object);
 384  
                     }
 385  
 
 386  1
                     field.setAccessible(true);
 387  1
                     field.set(object, values);
 388  
                 }
 389  
             }
 390  
         }
 391  0
         catch (IllegalArgumentException e)
 392  
         {
 393  0
             throw new TurbineException("Could not inject configuration "
 394  
                     + conf + " into object " + object, e);
 395  
         }
 396  0
         catch (IllegalAccessException e)
 397  
         {
 398  0
             throw new TurbineException("Could not inject configuration "
 399  
                     + conf + " into object " + object, e);
 400  349
         }
 401  349
     }
 402  
 
 403  
     /**
 404  
      * Inject Turbine service into field of object
 405  
      *
 406  
      * @param object the object to process
 407  
      * @param manager the service manager
 408  
      * @param field the field
 409  
      * @param annotation the value of the annotation
 410  
      *
 411  
      * @throws TurbineException if service is not available
 412  
      */
 413  
     private static void injectTurbineService(Object object, ServiceManager manager, Field field, TurbineService annotation) throws TurbineException
 414  
     {
 415  156
         String serviceName = null;
 416  
         // Check for annotation value
 417  156
         if (StringUtils.isNotEmpty(annotation.value()))
 418  
         {
 419  1
             serviceName = annotation.value();
 420  
         }
 421  
         // Check for fields SERVICE_NAME and ROLE
 422  
         else
 423  
         {
 424  155
             Field[] typeFields = field.getType().getFields();
 425  155
             for (Field f : typeFields)
 426  
             {
 427  155
                 if (TurbineService.SERVICE_NAME.equals(f.getName()))
 428  
                 {
 429  
                     try
 430  
                     {
 431  138
                         serviceName = (String)f.get(null);
 432  
                     }
 433  0
                     catch (Exception e)
 434  
                     {
 435  0
                         continue;
 436  138
                     }
 437  
                     break;
 438  
                 }
 439  17
                 else if (TurbineService.ROLE.equals(f.getName()))
 440  
                 {
 441  
                     try
 442  
                     {
 443  17
                         serviceName = (String)f.get(null);
 444  
                     }
 445  0
                     catch (Exception e)
 446  
                     {
 447  0
                         continue;
 448  17
                     }
 449  
                     break;
 450  
                 }
 451  
             }
 452  
         }
 453  
 
 454  156
         if (StringUtils.isEmpty(serviceName))
 455  
         {
 456  
             // Try interface class name
 457  0
             serviceName = field.getType().getName();
 458  
         }
 459  
 
 460  156
         if (log.isDebugEnabled())
 461  
         {
 462  156
             log.debug("Looking up service for injection: " + serviceName + " for object " + object);
 463  
         }
 464  
 
 465  156
         Object service = manager.getService(serviceName); // throws Exception on unknown service
 466  152
         field.setAccessible(true);
 467  
 
 468  
         try
 469  
         {
 470  152
             if (log.isDebugEnabled())
 471  
             {
 472  152
                 log.debug("Injection of " + serviceName + " into object " + object);
 473  
             }
 474  
 
 475  152
             field.set(object, service);
 476  
         }
 477  0
         catch (IllegalArgumentException e)
 478  
         {
 479  0
             throw new TurbineException("Could not inject service "
 480  
                     + serviceName + " into object " + object, e);
 481  
         }
 482  0
         catch (IllegalAccessException e)
 483  
         {
 484  0
             throw new TurbineException("Could not inject service "
 485  
                     + serviceName + " into object " + object, e);
 486  152
         }
 487  152
     }
 488  
 }