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

org.apache.commons.digester3.annotations.FromAnnotationsRuleModule Maven / Gradle / Ivy

Go to download

The Apache Commons Digester package lets you configure an XML to Java object mapping module which triggers certain actions called rules whenever a particular pattern of nested XML elements is recognized.

The newest version!
package org.apache.commons.digester3.annotations;

/*
 * 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 static org.apache.commons.digester3.annotations.utils.AnnotationUtils.getAnnotationsArrayValue;

import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedAction;

import org.apache.commons.digester3.Rule;
import org.apache.commons.digester3.annotations.reflect.MethodArgument;
import org.apache.commons.digester3.binder.AbstractRulesModule;

/**
 * {@link org.apache.commons.digester3.binder.RulesModule} implementation that allows loading rules from
 * annotated classes.
 *
 * @since 3.0
 */
public abstract class FromAnnotationsRuleModule
    extends AbstractRulesModule
{

    private static final String JAVA_PACKAGE = "java";

    private static final AnnotationHandlerFactory DEFAULT_HANDLER_FACTORY = new DefaultAnnotationHandlerFactory();

    private AnnotationHandlerFactory annotationHandlerFactory = DEFAULT_HANDLER_FACTORY;

    private WithMemoryRulesBinder rulesBinder;

    /**
     * {@inheritDoc}
     */
    @Override
    protected final void configure()
    {
        if ( rulesBinder == null )
        {
            rulesBinder = new WithMemoryRulesBinder( rulesBinder() );
        }

        try
        {
            configureRules();
        }
        finally
        {
            rulesBinder = null;
        }
    }

    /**
     * Configures a {@link org.apache.commons.digester3.binder.RulesBinder} via the exposed methods.
     */
    protected abstract void configureRules();

    /**
     * Allows users plug a different {@link AnnotationHandlerFactory} to create {@link AnnotationHandler} instances.
     *
     * @param annotationHandlerFactory A custom {@link AnnotationHandlerFactory} to create
     *        {@link AnnotationHandler} instances
     */
    protected final void useAnnotationHandlerFactory( AnnotationHandlerFactory annotationHandlerFactory )
    {
        if ( annotationHandlerFactory == null )
        {
            throw new IllegalArgumentException( "Argument 'annotationHandlerFactory' must be not null" );
        }

        this.annotationHandlerFactory = annotationHandlerFactory;
    }

    /**
     * Allows users to switch back to the default {@link AnnotationHandlerFactory} implementation.
     */
    protected final void useDefaultAnnotationHandlerFactory()
    {
        useAnnotationHandlerFactory( DEFAULT_HANDLER_FACTORY );
    }

    /**
     * Scan the input Class, looking for Digester rules expressed via annotations, and binds them.
     *
     * @param type the type has to be analyzed
     * @see DigesterRule
     */
    protected final void bindRulesFrom( final Class type )
    {
        if ( type == null || type.getPackage().getName().startsWith( JAVA_PACKAGE )
            || rulesBinder.isAlreadyBound( type ) )
        {
            return;
        }

        // TYPE
        visitElements( type );

        if ( !type.isInterface() )
        {
            // CONSTRUCTOR
            visitElements( new PrivilegedAction[]>()
            {
                public Constructor[] run()
                {
                    return type.getDeclaredConstructors();
                }
            } );

            // FIELD
            visitElements( new PrivilegedAction()
            {
                public Field[] run()
                {
                    return type.getDeclaredFields();
                }
            } );
        }

        // METHOD
        visitElements( new PrivilegedAction()
        {
            public Method[] run()
            {
                return type.getDeclaredMethods();
            }
        } );

        rulesBinder.markAsBound( type );
        bindRulesFrom( type.getSuperclass() );
    }

    /**
     *
     *
     * @param 
     * @param action
     */
    private  void visitElements( PrivilegedAction action )
    {
        AE[] annotatedElements = null;
        if ( System.getSecurityManager() != null )
        {
            annotatedElements = AccessController.doPrivileged( action );
        }
        else
        {
            annotatedElements = action.run();
        }
        visitElements( annotatedElements );
    }

    /**
     *
     *
     * @param annotatedElements
     */
    private void visitElements( AnnotatedElement... annotatedElements )
    {
        for ( AnnotatedElement element : annotatedElements )
        {
            for ( Annotation annotation : element.getAnnotations() )
            {
                handle( annotation, element );
            }

            if ( element instanceof Constructor || element instanceof Method )
            {
                Annotation[][] parameterAnnotations;
                Class[] parameterTypes;

                if ( element instanceof Constructor )
                {
                    // constructor args
                    Constructor construcotr = (Constructor) element;
                    parameterAnnotations = construcotr.getParameterAnnotations();
                    parameterTypes = construcotr.getParameterTypes();
                }
                else
                {
                    // method args
                    Method method = (Method) element;
                    parameterAnnotations = method.getParameterAnnotations();
                    parameterTypes = method.getParameterTypes();
                }

                for ( int i = 0; i < parameterTypes.length; i++ )
                {
                    visitElements( new MethodArgument( i, parameterTypes[i], parameterAnnotations[i] ) );
                }
            }
        }
    }

    /**
     * Handles the current visited element and related annotation, invoking the
     * right handler putting the rule provider in the rule set.
     *
     * @param annotation the current visited annotation.
     * @param element the current visited element.
     */
    @SuppressWarnings( "unchecked" )
    private  void handle( A annotation, E element )
    {
        Class annotationType = annotation.annotationType();

        // check if it is one of the @*.List annotation
        if ( annotationType.isAnnotationPresent( DigesterRuleList.class ) )
        {
            Annotation[] annotations = getAnnotationsArrayValue( annotation );
            if ( annotations != null && annotations.length > 0 )
            {
                // if it is an annotations array, process them
                for ( Annotation ptr : annotations )
                {
                    handle( ptr, element );
                }
            }
        }
        else if ( annotationType.isAnnotationPresent( DigesterRule.class ) )
        {
            DigesterRule digesterRule = annotationType.getAnnotation( DigesterRule.class );

            // the default behavior if the handler is not specified
            Class> handlerType =
                (Class>) digesterRule.handledBy();
            try
            {
                AnnotationHandler handler =
                    annotationHandlerFactory.newInstance( handlerType );

                // run!
                handler.handle( annotation, element, this.rulesBinder );
            }
            catch ( Exception e )
            {
                rulesBinder.addError( e );
            }
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy