Package org.codehaus.loom.components.util.verifier

Source Code of org.codehaus.loom.components.util.verifier.ComponentVerifier

/*
* Copyright (C) The Loom Group. All rights reserved.
*
* This software is published under the terms of the Loom
* Software License version 1.1, a copy of which has been included
* with this distribution in the LICENSE.txt file.
*/
package org.codehaus.loom.components.util.verifier;

import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;

import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.activity.Initializable;
import org.apache.avalon.framework.activity.Startable;
import org.apache.avalon.framework.activity.Suspendable;
import org.apache.avalon.framework.component.Composable;
import org.apache.avalon.framework.component.Recomposable;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Reconfigurable;
import org.apache.avalon.framework.context.Contextualizable;
import org.apache.avalon.framework.context.Recontextualizable;
import org.apache.avalon.framework.logger.LogEnabled;
import org.apache.avalon.framework.parameters.Parameterizable;
import org.apache.avalon.framework.parameters.Reparameterizable;
import org.apache.avalon.framework.service.Serviceable;

import org.codehaus.spice.salt.i18n.ResourceManager;
import org.codehaus.spice.salt.i18n.Resources;
import org.codehaus.dna.AbstractLogEnabled;
import org.codehaus.metaclass.Attributes;
import org.codehaus.metaclass.model.Attribute;

/**
* Utility class to help verify that component respects the rules of an Avalon component.
*
* @author Peter Donald
* @version $Revision: 1.2 $ $Date: 2004/05/01 12:48:34 $
*/
public class ComponentVerifier extends AbstractLogEnabled
{
    /**
     * I18n utils.
     */
    private static final Resources REZ =
        ResourceManager.getPackageResources( ComponentVerifier.class );

    /**
     * Constant for array of 0 classes. Saves recreating array everytime look up constructor with no args.
     */
    private static final Class[] EMPTY_TYPES = new Class[0];

    /**
     * The interfaces representing lifecycle stages.
     */
    private static final Class[] FRAMEWORK_CLASSES = new Class[]
    {
        LogEnabled.class,
        Contextualizable.class,
        Recontextualizable.class,
        Composable.class,
        Recomposable.class,
        Serviceable.class,
        Configurable.class,
        Reconfigurable.class,
        Parameterizable.class,
        Reparameterizable.class,
        Initializable.class,
        Startable.class,
        Suspendable.class,
        Disposable.class
    };

    /**
     * Verfiy that specified components designate classes that implement the advertised interfaces.
     *
     * @param name the name of component
     * @param type the component type
     *
     * @throws java.lang.Exception if an error occurs
     */
    public void verifyType( final String name, final Class type )
        throws Exception
    {
        final Attribute attribute =
            Attributes.getAttribute( type, "dna.component" );
        if( null == attribute )
        {
            final String msg = "Legacy? component " + name
                + " does not specify correct metadata. Skipping type verification";

            getLogger().warn( msg );

//            final String message =
//                "Component " + name + " does not specify correct metadata";
//            throw new Exception( message );
        }
        final Class[] interfaces = getServiceClasses( name, type );
        verifyComponent( name, type, interfaces, false );
    }

    /**
     * Verify that the supplied implementation class and service classes are valid for a component.
     *
     * @param name           the name of component
     * @param implementation the implementation class of component
     * @param services       the classes representing services
     * @param buildable      if true will verify that it is instantiateable via class.newInstance(). May not be required
     *                       for some components that are created via a factory.
     *
     * @throws java.lang.Exception if error thrown on failure and component fails check
     */
    public void verifyComponent( final String name,
                                 final Class implementation,
                                 final Class[] services,
                                 final boolean buildable )
        throws Exception
    {
        if( buildable )
        {
            verifyClass( name, implementation );
        }
        verifyLifecycles( name, implementation );
        verifyServices( name, services );
        verifyImplementsServices( name, implementation, services );
    }

    /**
     * Verify that the supplied implementation implements the specified services.
     *
     * @param name           the name of component
     * @param implementation the class representign component
     * @param services       the services that the implementation must provide
     *
     * @throws java.lang.Exception if error thrown on failure and component fails check
     */
    public void verifyImplementsServices( final String name,
                                          final Class implementation,
                                          final Class[] services )
        throws Exception
    {
        for( int i = 0; i < services.length; i++ )
        {
            if( !services[i].isAssignableFrom( implementation ) )
            {
                final String message =
                    REZ.format( "verifier.noimpl-service.error",
                                name,
                                implementation.getName(),
                                services[i].getName() );
                throw new Exception( message );
            }
        }
    }

    /**
     * Verify that the supplied class is a valid class for a Component.
     *
     * @param name  the name of component
     * @param clazz the class representing component
     *
     * @throws java.lang.Exception if error thrown on failure and component fails check
     */
    public void verifyClass( final String name,
                             final Class clazz )
        throws Exception
    {
        verifyNoArgConstructor( name, clazz );
        verifyNonAbstract( name, clazz );
        verifyNonArray( name, clazz );
        verifyNonInterface( name, clazz );
        verifyNonPrimitive( name, clazz );
        verifyPublic( name, clazz );
    }

    /**
     * Verify that the supplied classes are valid classes for a service.
     *
     * @param name    the name of component
     * @param classes the classes representign services
     *
     * @throws java.lang.Exception if error thrown on failure and component fails check
     */
    public void verifyServices( final String name,
                                final Class[] classes )
        throws Exception
    {
        for( int i = 0; i < classes.length; i++ )
        {
            verifyService( name, classes[i] );
        }
    }

    /**
     * Verify that the supplied class is a valid class for a service.
     *
     * @param name  the name of component
     * @param clazz the class representign service
     *
     * @throws java.lang.Exception if error thrown on failure and component fails check
     */
    public void verifyService( final String name,
                               final Class clazz )
        throws Exception
    {
        verifyServiceIsaInterface( name, clazz );
        verifyServiceIsPublic( name, clazz );
        verifyServiceNotALifecycle( name, clazz );
    }

    /**
     * Verify that the implementation class does not implement incompatible lifecycle interfaces.
     *
     * @param name           the name of component
     * @param implementation the implementation class
     *
     * @throws java.lang.Exception if error thrown on failure and component fails check
     */
    public void verifyLifecycles( final String name,
                                  final Class implementation )
        throws Exception
    {
        final boolean composable =
            Composable.class.isAssignableFrom( implementation ) ||
            Recomposable.class.isAssignableFrom( implementation );
        final boolean serviceable = Serviceable.class.isAssignableFrom( implementation );
        if( serviceable && composable )
        {
            final String message =
                REZ.format( "verifier.incompat-serviceable.error",
                            name,
                            implementation.getName() );
            throw new Exception( message );
        }

        final boolean configurable =
            Configurable.class.isAssignableFrom( implementation ) ||
            Reconfigurable.class.isAssignableFrom( implementation );
        final boolean parameterizable =
            Parameterizable.class.isAssignableFrom( implementation ) ||
            Reparameterizable.class.isAssignableFrom( implementation );
        if( parameterizable && configurable )
        {
            final String message =
                REZ.format( "verifier.incompat-config.error",
                            name,
                            implementation.getName() );
            throw new Exception( message );
        }
    }

    /**
     * Verify that the service implemented by specified component is an interface.
     *
     * @param name  the name of component
     * @param clazz the class representign service
     *
     * @throws java.lang.Exception if error thrown on failure and component fails check
     */
    public void verifyServiceIsaInterface( final String name,
                                           final Class clazz )
        throws Exception
    {
        if( !clazz.isInterface() )
        {
            final String message =
                REZ.format( "verifier.non-interface-service.error",
                            name,
                            clazz.getName() );
            throw new Exception( message );
        }
    }

    /**
     * Verify that the service implemented by specified component is public.
     *
     * @param name  the name of component
     * @param clazz the class representign service
     *
     * @throws java.lang.Exception if error thrown on failure and component fails check
     */
    public void verifyServiceIsPublic( final String name,
                                       final Class clazz )
        throws Exception
    {
        final boolean isPublic =
            Modifier.isPublic( clazz.getModifiers() );
        if( !isPublic )
        {
            final String message =
                REZ.format( "verifier.non-public-service.error",
                            name,
                            clazz.getName() );
            throw new Exception( message );
        }
    }

    /**
     * Verify that the service implemented by specified component does not extend any lifecycle interfaces.
     *
     * @param name  the name of component
     * @param clazz the class representign service
     *
     * @throws java.lang.Exception if error thrown on failure and component fails check
     */
    public void verifyServiceNotALifecycle( final String name,
                                            final Class clazz )
        throws Exception
    {
        for( int i = 0; i < FRAMEWORK_CLASSES.length; i++ )
        {
            final Class lifecycle = FRAMEWORK_CLASSES[i];
            if( lifecycle.isAssignableFrom( clazz ) )
            {
                final String message =
                    REZ.format( "verifier.service-isa-lifecycle.error",
                                name,
                                clazz.getName(),
                                lifecycle.getName() );
                throw new Exception( message );
            }
        }
    }

    /**
     * Verify that the component has a no-arg aka default constructor.
     *
     * @param name  the name of component
     * @param clazz the class representign component
     *
     * @throws java.lang.Exception if error thrown on failure and component fails check
     */
    public void verifyNoArgConstructor( final String name,
                                        final Class clazz )
        throws Exception
    {
        try
        {
            final Constructor ctor = clazz.getConstructor( EMPTY_TYPES );
            if( !Modifier.isPublic( ctor.getModifiers() ) )
            {
                final String message =
                    REZ.format( "verifier.non-public-ctor.error",
                                name,
                                clazz.getName() );
                throw new Exception( message );
            }
        }
        catch( final NoSuchMethodException nsme )
        {
            final String message =
                REZ.format( "verifier.missing-noargs-ctor.error",
                            name,
                            clazz.getName() );
            throw new Exception( message );
        }
    }

    /**
     * Verify that the component is not represented by abstract class.
     *
     * @param name  the name of component
     * @param clazz the class representign component
     *
     * @throws java.lang.Exception if error thrown on failure and component fails check
     */
    public void verifyNonAbstract( final String name,
                                   final Class clazz )
        throws Exception
    {
        final boolean isAbstract =
            Modifier.isAbstract( clazz.getModifiers() );
        if( isAbstract )
        {
            final String message =
                REZ.format( "verifier.abstract-class.error",
                            name,
                            clazz.getName() );
            throw new Exception( message );
        }
    }

    /**
     * Verify that the component is not represented by abstract class.
     *
     * @param name  the name of component
     * @param clazz the class representign component
     *
     * @throws java.lang.Exception if error thrown on failure and component fails check
     */
    public void verifyPublic( final String name,
                              final Class clazz )
        throws Exception
    {
        final boolean isPublic =
            Modifier.isPublic( clazz.getModifiers() );
        if( !isPublic )
        {
            final String message =
                REZ.format( "verifier.nonpublic-class.error",
                            name,
                            clazz.getName() );
            throw new Exception( message );
        }
    }

    /**
     * Verify that the component is not represented by primitive class.
     *
     * @param name  the name of component
     * @param clazz the class representign component
     *
     * @throws java.lang.Exception if error thrown on failure and component fails check
     */
    public void verifyNonPrimitive( final String name,
                                    final Class clazz )
        throws Exception
    {
        if( clazz.isPrimitive() )
        {
            final String message =
                REZ.format( "verifier.primitive-class.error",
                            name,
                            clazz.getName() );
            throw new Exception( message );
        }
    }

    /**
     * Verify that the component is not represented by interface class.
     *
     * @param name  the name of component
     * @param clazz the class representign component
     *
     * @throws java.lang.Exception if error thrown on failure and component fails check
     */
    public void verifyNonInterface( final String name,
                                    final Class clazz )
        throws Exception
    {
        if( clazz.isInterface() )
        {
            final String message =
                REZ.format( "verifier.interface-class.error",
                            name,
                            clazz.getName() );
            throw new Exception( message );
        }
    }

    /**
     * Verify that the component is not represented by an array class.
     *
     * @param name  the name of component
     * @param clazz the class representign component
     *
     * @throws java.lang.Exception if error thrown on failure and component fails check
     */
    public void verifyNonArray( final String name,
                                final Class clazz )
        throws Exception
    {
        if( clazz.isArray() )
        {
            final String message =
                REZ.format( "verifier.array-class.error",
                            name,
                            clazz.getName() );
            throw new Exception( message );
        }
    }

    /**
     * Retrieve an array of Classes for all the services that a Component offers. This method also makes sure all
     * services offered are interfaces.
     *
     * @param name the name of component
     * @param type the component type
     *
     * @return an array of Classes for all the services
     *
     * @throws java.lang.Exception if an error occurs
     */
    protected Class[] getServiceClasses( final String name,
                                         final Class type )
        throws Exception
    {
        final ClassLoader classLoader = type.getClassLoader();
        final Attribute[] attributes =
            Attributes.getAttributes( type, "dna.service" );
        final Class[] classes = new Class[attributes.length];
        for( int i = 0; i < attributes.length; i++ )
        {
            final String classname = attributes[i].getParameter( "type" );
            try
            {
                classes[i] = classLoader.loadClass( classname );
            }
            catch( final Throwable t )
            {
                final String message =
                    "Unable to load service class \"" +
                    classname +
                    "\" for Component named \"" +
                    name + "\". (Reason: " + t + ").";
                throw new Exception( message );
            }
        }

        return classes;
    }
}
TOP

Related Classes of org.codehaus.loom.components.util.verifier.ComponentVerifier

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.