All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.turbine.annotation.AnnotationProcessor Maven / Gradle / Ivy

Go to download

Turbine is a servlet based framework that allows experienced Java developers to quickly build secure web applications. Parts of Turbine can also be used independently of the web portion of Turbine as well. In other words, we strive to make portions of Turbine easily available for use in other applications.

There is a newer version: 6.0
Show newest version
package org.apache.turbine.annotation;

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import java.lang.annotation.Annotation;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.apache.commons.configuration2.Configuration;
import org.apache.commons.lang3.StringUtils;
import org.apache.fulcrum.security.model.turbine.TurbineAccessControlList;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.turbine.Turbine;
import org.apache.turbine.modules.Loader;
import org.apache.turbine.services.ServiceManager;
import org.apache.turbine.services.TurbineServices;
import org.apache.turbine.services.assemblerbroker.AssemblerBrokerService;
import org.apache.turbine.util.TurbineException;

/**
 * AnnotationProcessor contains static helper methods that handle the
 * Turbine annotations for objects
 *
 * @author Thomas Vandahl
 * @version $Id: TurbineAssemblerBrokerService.java 1521103 2013-09-09 13:38:07Z tv $
 */
public class AnnotationProcessor
{
    /** Logging */
    private static Logger log = LogManager.getLogger(AnnotationProcessor.class);

    /** Annotation cache */
    private static ConcurrentMap annotationCache = new ConcurrentHashMap();

    /**
     * Get cached annotations for field, class or method
     *
     * @param object a field, class or method
     *
     * @return the declared annotations for the object
     */
    public static Annotation[] getAnnotations(AccessibleObject object)
    {
        String key = object.getClass() + object.toString();
        Annotation[] annotations = annotationCache.get(key);
        if (annotations == null)
        {
            Annotation[] newAnnotations = object.getDeclaredAnnotations();
            annotations = annotationCache.putIfAbsent(key, newAnnotations);
            if (annotations == null)
            {
                annotations = newAnnotations;
            }
        }
        return annotations;
    }

    public enum ConditionType
    {
        COMPOUND, ANY;
    }

    /**
     * Check if the object given is authorized to be executed based on its annotations
     *
     * The method will return false if one of the annotations denies execution
     *
     * @see #isAuthorized(AccessibleObject, TurbineAccessControlList, ConditionType)
     *
     * @param  ACL instance
     * @param object accessible object to test
     * @param acl access control list
     * @return true if the execution is allowed
     */
    public static > boolean isAuthorized(AccessibleObject object, A acl)
    {
        return isAuthorized( object, acl, ConditionType.COMPOUND );
    }

    /**
     * Check if the object given is authorized to be executed based on its annotations
     * The method's return value depends on the conditonType, refer to the ConditionType
     *
     * @param  ACL instance
     * @param object the object
     * @param acl access control list
     * @param conditonType either {@link ConditionType#COMPOUND}: The method will return false if one of the annotations denies execution
     *                     or {@link ConditionType#ANY} : The method will return true if one of the annotations allows execution
     * @return true if the execution is allowed
     */
    public static > boolean isAuthorized(AccessibleObject object, A acl, ConditionType conditonType)
    {
        Annotation[] annotations = getAnnotations(object);

        for (Annotation annotation : annotations)
        {
            if (annotation instanceof TurbineRequiredRole)
            {
                TurbineRequiredRole trr = (TurbineRequiredRole) annotation;
                String[] roleNames = trr.value();
                String group = trr.group();

                if (StringUtils.isEmpty(group)) // global group
                {
                    for (String roleName : roleNames)
                    {
                        switch ( conditonType ) {
                            case COMPOUND: default:
                                if (!acl.hasRole(roleName))
                                {
                                    return false;
                                }
                                break;
                            case ANY:
                                if (acl.hasRole(roleName))
                                {
                                    return true;
                                }
                                break;
                        }
                    }
                    if (conditonType == ConditionType.ANY) { // nothing matched
                        return false;
                    }
                }
                else
                {
                    for (String roleName : roleNames)
                    {
                        switch ( conditonType ) {
                            case COMPOUND: default:
                                if (!acl.hasRole(roleName, group))
                                {
                                    return false;
                                }
                                break;
                            case ANY:
                                if (acl.hasRole(roleName, group))
                                {
                                    return true;
                                }
                                break;
                        }
                    }
                }
            }
            else if (annotation instanceof TurbineRequiredPermission)
            {
                TurbineRequiredPermission trp = (TurbineRequiredPermission) annotation;
                String[] permissionNames = trp.value();
                String group = trp.group();

                if (StringUtils.isEmpty(group)) // global group
                {
                    for (String permissionName : permissionNames)
                    {
                        switch ( conditonType ) {
                            case COMPOUND: default:
                                if (!acl.hasPermission(permissionName))
                                {
                                    return false;
                                }
                                break;
                            case ANY:
                                if (acl.hasPermission(permissionName))
                                {
                                    return true;
                                }
                                break;
                        }
                    }
                }
                else
                {
                    for (String permissionName : permissionNames)
                    {
                        switch ( conditonType ) {
                            case COMPOUND: default:
                                if (!acl.hasPermission(permissionName, group))
                                {
                                    return false;
                                }
                                break;
                            case ANY:
                                if (acl.hasPermission(permissionName, group))
                                {
                                    return true;
                                }
                                break;
                        }

                    }
                }
            }
        }

        return true;
    }

    /**
     * Search for annotated fields of the object and inject the appropriate
     * objects
     *
     * @param object the object
     * @throws TurbineException if the objects could not be injected
     */
    public static void process(Object object) throws TurbineException
    {
        ServiceManager manager = null;
        Configuration config = null;
        AssemblerBrokerService assembler = null;
        Class clazz = object.getClass();

        while (clazz != null)
        {
            Field[] fields = clazz.getDeclaredFields();

            for (Field field : fields)
            {
                Annotation[] annotations = getAnnotations(field);

                for (Annotation a : annotations)
                {
                    if (a instanceof TurbineService)
                    {
                        if (manager == null)
                        {
                            manager = TurbineServices.getInstance();
                        }
                        injectTurbineService(object, manager, field, (TurbineService) a);
                    }
                    else if (a instanceof TurbineConfiguration)
                    {
                        if (config == null)
                        {
                            config = Turbine.getConfiguration();
                        }
                        injectTurbineConfiguration(object, config, field, (TurbineConfiguration) a);
                    }
                    else if (a instanceof TurbineLoader)
                    {
                        if (assembler == null)
                        {
                            assembler = (AssemblerBrokerService) TurbineServices.getInstance().
                                getService(AssemblerBrokerService.SERVICE_NAME);
                        }
                        injectTurbineLoader(object, assembler, field, (TurbineLoader) a);
                    }
                }
            }

            clazz = clazz.getSuperclass();
        }
    }

    /**
     * Inject Turbine configuration into field of object
     *
     * @param object the object to process
     * @param assembler AssemblerBrokerService, provides the loader
     * @param field the field
     * @param annotation the value of the annotation
     *
     * @throws TurbineException if loader cannot be set
     */
    private static void injectTurbineLoader(Object object, AssemblerBrokerService assembler, Field field, TurbineLoader annotation) throws TurbineException
    {
        Loader loader = assembler.getLoader(annotation.value());
        field.setAccessible(true);

        try
        {
            log.debug("Injection of {} into object {}", loader, object);

            field.set(object, loader);
        }
        catch (IllegalArgumentException | IllegalAccessException e)
        {
            throw new TurbineException("Could not inject loader "
                    + loader + " into object " + object, e);
        }
    }

    /**
     * Inject Turbine configuration into field of object
     *
     * @param object the object to process
     * @param conf the configuration to use
     * @param field the field
     * @param annotation the value of the annotation
     *
     * @throws TurbineException if configuration cannot be set
     */
    @SuppressWarnings("boxing")
    private static void injectTurbineConfiguration(Object object, Configuration conf, Field field, TurbineConfiguration annotation) throws TurbineException
    {
        Class type = field.getType();
        String key = annotation.value();

        try
        {
            if (Configuration.class.isAssignableFrom(type))
            {
                final Configuration injectConfiguration;
                // Check for annotation value
                if (StringUtils.isNotEmpty(key))
                {
                    injectConfiguration = conf.subset(key);
                }
                else
                {
                    injectConfiguration = conf;
                }

                log.debug("Injection of {} into object {}", injectConfiguration, object);

                field.setAccessible(true);
                field.set(object, injectConfiguration);
            }
            else if (conf.containsKey(key))
            {
                if ( String.class.isAssignableFrom( type ) )
                {
                    String value = conf.getString(key);
                    log.debug("Injection of {} into object {}", value, object);

                    field.setAccessible(true);
                    field.set(object, value);
                }
                else if ( Boolean.TYPE.isAssignableFrom( type ) )
                {
                    boolean value = conf.getBoolean(key);
                    log.debug("Injection of {} into object {}", value, object);

                    field.setAccessible(true);
                    field.setBoolean(object, value);
                }
                else if ( Integer.TYPE.isAssignableFrom( type ) )
                {
                    int value = conf.getInt(key);
                    log.debug("Injection of {} into object {}", value, object);

                    field.setAccessible(true);
                    field.setInt(object, value);
                }
                else if ( Long.TYPE.isAssignableFrom( type ) )
                {
                    long value = conf.getLong(key);
                    log.debug("Injection of {} into object {}", value, object);

                    field.setAccessible(true);
                    field.setLong(object, value);
                }
                else if ( Short.TYPE.isAssignableFrom( type ) )
                {
                    short value = conf.getShort(key);
                    log.debug("Injection of {} into object {}", value, object);

                    field.setAccessible(true);
                    field.setShort(object, value);
                }
                else if ( Long.TYPE.isAssignableFrom( type ) )
                {
                    long value = conf.getLong(key);
                    log.debug("Injection of {} into object {}", value, object);

                    field.setAccessible(true);
                    field.setLong(object, value);
                }
                else if ( Float.TYPE.isAssignableFrom( type ) )
                {
                    float value = conf.getFloat(key);
                    log.debug("Injection of {} into object {}", value, object);

                    field.setAccessible(true);
                    field.setFloat(object, value);
                }
                else if ( Double.TYPE.isAssignableFrom( type ) )
                {
                    double value = conf.getDouble(key);
                    log.debug("Injection of {} into object {}", value, object);

                    field.setAccessible(true);
                    field.setDouble(object, value);
                }
                else if ( Byte.TYPE.isAssignableFrom( type ) )
                {
                    byte value = conf.getByte(key);
                    log.debug("Injection of {} into object {}", value, object);

                    field.setAccessible(true);
                    field.setByte(object, value);
                }
                else if ( List.class.isAssignableFrom( type ) )
                {
                    List values = conf.getList(key);
                    log.debug("Injection of {} into object {}", values, object);

                    field.setAccessible(true);
                    field.set(object, values);
                }
            }
        }
        catch (IllegalArgumentException | IllegalAccessException e)
        {
            throw new TurbineException("Could not inject configuration "
                    + conf + " into object " + object, e);
        }
    }

    /**
     * Inject Turbine service into field of object
     *
     * @param object the object to process
     * @param manager the service manager
     * @param field the field
     * @param annotation the value of the annotation
     *
     * @throws TurbineException if service is not available
     */
    private static void injectTurbineService(Object object, ServiceManager manager, Field field, TurbineService annotation) throws TurbineException
    {
        String serviceName = null;
        // Check for annotation value
        if (StringUtils.isNotEmpty(annotation.value()))
        {
            serviceName = annotation.value();
        }
        // Check for fields SERVICE_NAME and ROLE
        else
        {
            Field[] typeFields = field.getType().getFields();
            for (Field f : typeFields)
            {
                if (TurbineService.SERVICE_NAME.equals(f.getName()))
                {
                    try
                    {
                        serviceName = (String)f.get(null);
                    }
                    catch (IllegalArgumentException | IllegalAccessException e)
                    {
                        continue;
                    }
                    break;
                }
                else if (TurbineService.ROLE.equals(f.getName()))
                {
                    try
                    {
                        serviceName = (String)f.get(null);
                    }
                    catch (IllegalArgumentException | IllegalAccessException e)
                    {
                        continue;
                    }
                    break;
                }
            }
        }

        if (StringUtils.isEmpty(serviceName))
        {
            // Try interface class name
            serviceName = field.getType().getName();
        }

        log.debug("Looking up service for injection: {} for object {}", serviceName, object);

        Object service = manager.getService(serviceName); // throws Exception on unknown service
        field.setAccessible(true);

        try
        {
            log.debug("Injection of {} into object {}", serviceName, object);

            field.set(object, service);
        }
        catch (IllegalArgumentException | IllegalAccessException e)
        {
            throw new TurbineException("Could not inject service "
                    + serviceName + " into object " + object, e);
        }
    }
}