Package org.codehaus.loom.classman.verifier

Source Code of org.codehaus.loom.classman.verifier.ClassLoaderVerifier

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

import org.codehaus.loom.classman.metadata.ClassLoaderMetaData;
import org.codehaus.loom.classman.metadata.ClassLoaderSetMetaData;
import org.codehaus.loom.classman.metadata.JoinMetaData;
import org.codehaus.spice.salt.i18n.ResourceManager;
import org.codehaus.spice.salt.i18n.Resources;

/**
* Verify ClassLoader set is valid. Validity is defined as <ul> <li>With
* exception of predefined names, all ClassLoader names should be defined
* starting with letters or '_' and then continuing with Alpha-Numeric
* characters, '-', '.' or '_'.</li> <li>No ClassLoader can have a parent
* ClassLoader that is not predefined or not defined in ClassLoaderSet.</li>
* <li>No "join" ClassLoader can link against a non-existent ClassLoader.</li>
* <li>No "join" ClassLoader can join multiple instances of same
* ClassLoader.</li> <li>No ClassLoader can have multiple entrys that point to
* the same location.</li> <li>No ClassLoader (either predefined, join or
* regular) can have the same name.</li> <li>The default ClassLoader must
* exist.</li> <li>There must be no circular dependencies between join
* classloaders.</li> </ul>
*
* @author Peter Donald
* @version $Revision: 1.1 $ $Date: 2004/04/19 22:19:26 $
*/
public class ClassLoaderVerifier
{
    /** i18n resources for used to present messages. */
    private static final Resources REZ =
        ResourceManager.getPackageResources( ClassLoaderVerifier.class );

    public void verifyClassLoaderSet( final ClassLoaderSetMetaData set )
        throws Exception
    {
        String message = null;

        message = REZ.getString( "valid-names.notice" );
        info( message );
        verifyNames( set );

        message = REZ.getString( "valid-parents.notice" );
        info( message );
        verifyParents( set );

        message = REZ.getString( "valid-links.notice" );
        info( message );
        verifyLinks( set );

        message = REZ.getString( "default-loader.notice" );
        info( message );
        verifyDefaultLoaderExists( set );

        message = REZ.getString( "unique-classloader.notice" );
        info( message );
        verifyUniqueClassLoaderNames( set );

        message = REZ.getString( "unique-joins.notice" );
        info( message );
        verifyUniqueJoinNames( set );

        message = REZ.getString( "unique-predefined.notice" );
        info( message );
        verifyUniquePredefinedNames( set );

        message = REZ.getString( "unique-joins-entrys.notice" );
        info( message );
        verifyUniqueJoinEntrys( set );

        message = REZ.getString( "unique-classpath-entrys.notice" );
        info( message );
        verifyUniqueClassLoaderEntrys( set );

        //TODO: Verify that the joins form a directed graph with no loops
    }

    /**
     * Log an informational message. Sub-classes should overide this.
     *
     * @param message the message
     */
    protected void info( final String message )
    {
        //noop
    }

    /**
     * Verify that all the classloaders have valid names.
     *
     * @throws Exception if validity check fails
     */
    private void verifyNames( ClassLoaderSetMetaData set )
        throws Exception
    {
        final ClassLoaderMetaData[] classLoaders = set.getClassLoaders();
        for( int i = 0; i < classLoaders.length; i++ )
        {
            final String name = classLoaders[ i ].getName();
            verifyName( name );
        }

        final JoinMetaData[] joins = set.getJoins();
        for( int i = 0; i < joins.length; i++ )
        {
            final String name = joins[ i ].getName();
            verifyName( name );
        }
    }

    /**
     * Verify that all the classloaders have valid parents.
     *
     * @throws Exception if validity check fails
     */
    private void verifyParents( ClassLoaderSetMetaData set )
        throws Exception
    {
        final ClassLoaderMetaData[] classLoaders = set.getClassLoaders();
        for( int i = 0; i < classLoaders.length; i++ )
        {
            final ClassLoaderMetaData classLoader = classLoaders[ i ];
            final String parent = classLoader.getParent();
            if( !isLoaderDefined( parent, set ) )
            {
                final String message =
                    REZ.format( "invalid-parent.error",
                                classLoader.getName(),
                                parent );
                throw new Exception( message );
            }
        }
    }

    /**
     * Verify that each join ClassLoader only links to ClassLoaders that exist.
     *
     * @throws Exception if validity check fails
     */
    private void verifyLinks( final ClassLoaderSetMetaData set )
        throws Exception
    {
        final JoinMetaData[] joins = set.getJoins();
        for( int i = 0; i < joins.length; i++ )
        {
            verifyLinks( joins[ i ], set );
        }
    }

    /**
     * Verify that each join ClassLoader only links to ClassLoaders that exist.
     *
     * @throws Exception if validity check fails
     */
    private void verifyLinks( final JoinMetaData join,
                              final ClassLoaderSetMetaData set )
        throws Exception
    {
        final String[] classloaders = join.getClassloaders();
        for( int i = 0; i < classloaders.length; i++ )
        {
            final String classloader = classloaders[ i ];
            if( !isLoaderDefined( classloader, set ) )
            {
                final String message =
                    REZ.format( "bad-join-link.error",
                                join.getName(),
                                classloader );
                throw new Exception( message );
            }
        }
    }

    /**
     * Verify that all the classloaders have valid names.
     *
     * @throws Exception if validity check fails
     */
    private void verifyName( final String name )
        throws Exception
    {
        final int size = name.length();
        if( 0 == size )
        {
            final String message =
                REZ.format( "empty-name.error",
                            name );
            throw new Exception( message );
        }
        final char ch = name.charAt( 0 );
        if( !Character.isLetter( ch ) &&
            '_' != ch )
        {
            final String message =
                REZ.format( "name-invalid-start.error",
                            name );
            throw new Exception( message );
        }

        for( int i = 1; i < size; i++ )
        {
            final char c = name.charAt( i );
            if( !Character.isLetterOrDigit( c ) &&
                '_' != c &&
                '-' != c &&
                '.' != c )
            {
                final String message =
                    REZ.format( "name-invalid-char.error",
                                name,
                                String.valueOf( c ) );
                throw new Exception( message );
            }
        }
    }

    /**
     * Verify that each regular ClassLoader only contains unique entrys.
     *
     * @throws Exception if validity check fails
     */
    private void verifyUniqueClassLoaderEntrys(
        final ClassLoaderSetMetaData set )
        throws Exception
    {
        final ClassLoaderMetaData[] classLoaders = set.getClassLoaders();
        for( int i = 0; i < classLoaders.length; i++ )
        {
            verifyUniqueClassLoaderEntrys( classLoaders[ i ] );
        }
    }

    /**
     * Verify that each regular ClassLoader only contains unique entrys.
     *
     * @throws Exception if validity check fails
     */
    private void verifyUniqueClassLoaderEntrys(
        final ClassLoaderMetaData classLoader )
        throws Exception
    {
        final String[] entrys = classLoader.getEntrys();
        for( int i = 0; i < entrys.length; i++ )
        {
            final String location = entrys[ i ];
            for( int j = i + 1; j < entrys.length; j++ )
            {
                if( location.equals( entrys[ j ] ) )
                {
                    final String message =
                        REZ.format( "classloader-dup-entrys.error",
                                    classLoader.getName(),
                                    location );
                    throw new Exception( message );
                }
            }
        }
    }

    /**
     * Verify that each join only contains unique classloaders.
     *
     * @throws Exception if validity check fails
     */
    private void verifyUniqueJoinEntrys( final ClassLoaderSetMetaData set )
        throws Exception
    {
        final JoinMetaData[] joins = set.getJoins();
        for( int i = 0; i < joins.length; i++ )
        {
            verifyUniqueJoinEntrys( joins[ i ] );
        }
    }

    /**
     * Verify that specified join only contains unique classloaders.
     *
     * @throws Exception if validity check fails
     */
    private void verifyUniqueJoinEntrys( final JoinMetaData join )
        throws Exception
    {
        final String[] classloaders = join.getClassloaders();
        for( int j = 0; j < classloaders.length; j++ )
        {
            final String name = classloaders[ j ];
            for( int k = j + 1; k < classloaders.length; k++ )
            {
                final String other = classloaders[ k ];
                if( other.equals( name ) )
                {
                    final String message =
                        REZ.format( "join-dup-entrys.error",
                                    join.getName(),
                                    name );
                    throw new Exception( message );
                }
            }
        }
    }

    /**
     * Verify that the Predefined names are unique set.
     *
     * @throws Exception if validity check fails
     */
    private void verifyUniquePredefinedNames( final ClassLoaderSetMetaData set )
        throws Exception
    {
        final String[] predefined = set.getPredefined();
        for( int i = 0; i < predefined.length; i++ )
        {
            final String name = predefined[ i ];
            for( int j = i + 1; j < predefined.length; j++ )
            {
                final String other = predefined[ j ];
                if( other.equals( name ) )
                {
                    final String message =
                        REZ.format( "duplicate-name.error",
                                    "predefined",
                                    "predefined",
                                    name );
                    throw new Exception( message );
                }
            }
        }
    }

    /**
     * Verify that the ClassLoader names are unique throughout the set.
     *
     * @param set the set of ClassLoader defs to search in
     * @throws Exception if validity check fails
     */
    private void verifyUniqueClassLoaderNames(
        final ClassLoaderSetMetaData set )
        throws Exception
    {
        final ClassLoaderMetaData[] classLoaders = set.getClassLoaders();
        for( int i = 0; i < classLoaders.length; i++ )
        {
            final ClassLoaderMetaData classLoader = classLoaders[ i ];
            verifyUniqueName( set,
                              classLoader.getName(),
                              "classloader",
                              classLoader );
        }
    }

    /**
     * Verify that the specified name is unique in set except for specified
     * entity.
     *
     * @param set the set of classloaders
     * @param name the name
     * @param type the type of classloder (used for exception messages)
     * @param entity the entity to skip (ie the one the name refers to)
     * @throws Exception if validity check fails
     */
    private void verifyUniqueName( final ClassLoaderSetMetaData set,
                                   final String name,
                                   final String type,
                                   final Object entity )
        throws Exception
    {
        //Make sure our join does not have same name as a
        //predefined ClassLoader
        if( set.isPredefined( name ) )
        {
            final String message =
                REZ.format( "duplicate-name.error",
                            type,
                            "predefined",
                            name );
            throw new Exception( message );
        }

        //Make sure no joins have same name as our join
        final JoinMetaData[] joins = set.getJoins();
        for( int j = 0; j < joins.length; j++ )
        {
            final JoinMetaData other = joins[ j ];
            if( other == entity )
            {
                continue;
            }
            if( other.getName().equals( name ) )
            {
                final String message =
                    REZ.format( "duplicate-name.error",
                                type,
                                "join",
                                name );
                throw new Exception( message );
            }
        }

        final ClassLoaderMetaData[] classLoaders = set.getClassLoaders();
        for( int j = 0; j < classLoaders.length; j++ )
        {
            final ClassLoaderMetaData other = classLoaders[ j ];
            if( other == entity )
            {
                continue;
            }
            if( other.getName().equals( name ) )
            {
                final String message =
                    REZ.format( "duplicate-name.error",
                                type,
                                "classloader",
                                name );
                throw new Exception( message );
            }
        }
    }

    /**
     * Verify that the join names are unique throughout the set.
     *
     * @param set the set of ClassLoader defs to search in
     * @throws Exception if validity check fails
     */
    private void verifyUniqueJoinNames( final ClassLoaderSetMetaData set )
        throws Exception
    {
        final JoinMetaData[] joins = set.getJoins();
        for( int i = 0; i < joins.length; i++ )
        {
            final JoinMetaData join = joins[ i ];
            verifyUniqueName( set,
                              join.getName(),
                              "join",
                              join );
        }
    }

    /**
     * Verify that the default loader is defined.
     *
     * @param set the set of ClassLoader defs to search in
     * @throws Exception if validity check fails
     */
    private void verifyDefaultLoaderExists( final ClassLoaderSetMetaData set )
        throws Exception
    {
        final String name = set.getDefault();
        if( !isLoaderDefined( name, set ) )
        {
            final String message =
                REZ.format( "missing-default-loader.error",
                            name );
            throw new Exception( message );
        }
    }

    /**
     * Return true if specified loader is defined in set.
     *
     * @param name the name of loader
     * @param set the set to search
     * @return true if specified loader is defined in set.
     */
    private boolean isLoaderDefined( final String name,
                                     final ClassLoaderSetMetaData set )
    {
        if( set.isPredefined( name ) )
        {
            return true;
        }
        else if( null != set.getClassLoader( name ) )
        {
            return true;
        }
        else if( null != set.getJoin( name ) )
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}
TOP

Related Classes of org.codehaus.loom.classman.verifier.ClassLoaderVerifier

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.