Package org.apache.avalon.fortress.tools

Source Code of org.apache.avalon.fortress.tools.Component

/*
* Copyright 2003-2004 The Apache Software Foundation
* Licensed  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.
*/

package org.apache.avalon.fortress.tools;

import com.thoughtworks.qdox.model.*;
import org.apache.avalon.fortress.MetaInfoEntry;
import org.apache.avalon.fortress.util.dag.Vertex;
import org.apache.tools.ant.BuildException;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.*;

/**
* Represents a component, and output the meta information.
*
* @author <a href="mailto:dev@avalon.apache.org">The Avalon Team</a>
* @version CVS $Revision: 1.20 $ $Date: 2004/02/28 15:16:27 $
*/
final class Component
{
    private static final String SINGLE_THREADED = "org.apache.avalon.framework.thread.SingleThreaded";
    private static final String THREAD_SAFE = "org.apache.avalon.framework.thread.ThreadSafe";
    private static final String POOLABLE = "org.apache.avalon.excalibur.pool.Poolable";
    private static final String RECYCLABLE = "org.apache.avalon.excalibur.pool.Recyclable";
    private static final String SERVICE_MANAGER = "org.apache.avalon.framework.service.ServiceManager";

    static final String ATTR_TYPE = "type";
    static final String ATTR_NAME = "name";

    private static final String TAG_SERVICE = "avalon.service";
    private static final String TAG_DEPENDENCY = "avalon.dependency";
    private static final String TAG_LIFESTYLE = "x-avalon.lifestyle";
    private static final String TAG_HANDLER = "fortress.handler";
    private static final String TAG_INFO = "x-avalon.info";
    private static final String TAG_NAME = "fortress.name";

    private static final String META_NAME = "x-avalon.name";

    private static final String METH_SERVICE = "service";

    /** The repository of components. */
    static final Set m_repository = new HashSet();

    private final JavaClass m_javaClass;
    private final Properties m_attributes;
    private final List m_dependencies;
    private final Vertex m_vertex;
    private final List m_dependencyNames;
    private final List m_serviceNames;

    /**
     * Initialize a service with the type name.
     *
     * @param javaClass
     */
    public Component( final JavaClass javaClass )
    {
        if ( javaClass == null ) throw new NullPointerException( "javaClass" );

        m_javaClass = javaClass;
        m_attributes = new Properties();
        m_dependencies = new ArrayList( 10 );
        m_vertex = new Vertex( this );
        m_dependencyNames = new ArrayList( 10 );
        m_serviceNames = new ArrayList( 10 );

        final DocletTag[] tags = javaClass.getTagsByName( TAG_SERVICE );
        for ( int t = 0; t < tags.length; t++ )
        {
            if ( tags[t].getNamedParameter( Component.ATTR_TYPE ) == null )
            {
                throw new BuildException( "The \"type\" tag is missing from the "
                    + "\"@" + TAG_SERVICE + "\" meta tag in "
                    + javaClass.getName() );
            }

            final String serviceName = resolveClassName( m_javaClass.getParentSource(),
                    tags[t].getNamedParameter( Component.ATTR_TYPE ) );
            m_serviceNames.add( serviceName );
        }

        discoverLifecycleType();
        discoverNameInfo();
        discoverDependencies();

        m_repository.add( this );
    }

    /**
     * Recursively discover dependencies from the local class hierarchy.  This does not, and cannot
     * discover dependencies from classes from other JARs.
     */
    private void discoverDependencies()
    {
        JavaClass currClass = m_javaClass;

        while ( currClass != null && discoverDependencies( currClass ) )
        {
            currClass = currClass.getSuperJavaClass();
        }
    }

    /**
     * Discover the dependencies that this component class requires.
     *
     * @param fromClass  The JavaClass object to gather the dependency set from.
     */
    private boolean discoverDependencies( final JavaClass fromClass )
    {
        boolean isSuccessful = true;

        JavaMethod[] methods = fromClass.getMethods();
        for ( int i = 0; i < methods.length; i++ )
        {
            if ( methods[i].getName().equals( METH_SERVICE ) )
            {
                if ( methods[i].getParameters().length == 1 && methods[i].getParameters()[0].getType().getValue().equals( SERVICE_MANAGER ) )
                {
                    DocletTag[] dependencies = methods[i].getTagsByName( TAG_DEPENDENCY );
                    for ( int d = 0; d < dependencies.length; d++ )
                    {
                        if ( dependencies[d].getNamedParameter( ATTR_TYPE ) == null )
                        {
                            throw new BuildException( "The \"type\" tag is missing from a "
                                + "\"@" + TAG_DEPENDENCY + "\" meta tag of the " + METH_SERVICE
                                + " method in " + fromClass.getName() );
                        }

                        String type = resolveClassName( fromClass.getParentSource(),
                                dependencies[d].getNamedParameter( ATTR_TYPE ) );
                        //String optional = dependencies[d].getNamedParameter("optional");

                        if ( null == type )
                        {
                            isSuccessful = false;
                        }
                        else
                        {
                            m_dependencyNames.add( type );
                        }
                    }
                }
            }
        }

        return isSuccessful;
    }

    private void discoverNameInfo()
    {
        DocletTag avalonConfigName = m_javaClass.getTagByName( TAG_INFO );
        if ( null == avalonConfigName ) avalonConfigName = m_javaClass.getTagByName( TAG_NAME );

        String name = MetaInfoEntry.createShortName(m_javaClass.getName());

        if ( avalonConfigName != null )
        {
            name = avalonConfigName.getNamedParameter( ATTR_NAME );
        }

        setAttribute( META_NAME, name );
    }

    private void discoverLifecycleType()
    {
        final DocletTag avalonLifecycle = m_javaClass.getTagByName( TAG_LIFESTYLE );
        final DocletTag fortressHandler = m_javaClass.getTagByName( TAG_HANDLER );
        String lifecycle = null;
        String handler = null;

        if ( avalonLifecycle == null && fortressHandler == null )
        {
            final Type[] interfaces = m_javaClass.getImplements();
            for ( int i = 0; i < interfaces.length && handler != null; i++ )
            {
                if ( interfaces[i].getClass().getName().equals( THREAD_SAFE ) )
                {
                    handler = MetaInfoEntry.THREADSAFE_HANDLER;
                }
                else if ( interfaces[i].getClass().getName().equals( POOLABLE ) ||
                        interfaces[i].getClass().getName().equals( RECYCLABLE ) )
                {
                    handler = MetaInfoEntry.POOLABLE_HANDLER;
                }
                else if ( interfaces[i].getClass().getName().equals( SINGLE_THREADED ) )
                {
                    handler = MetaInfoEntry.FACTORY_HANDLER;
                }
            }
        }

        if ( null != avalonLifecycle )       // lifecycle specified directly
        {
            lifecycle = stripQuotes( avalonLifecycle.getNamedParameter( ATTR_TYPE ) );
        }
        else if ( null != fortressHandler // handler specified directly
        {
            handler = stripQuotes( fortressHandler.getNamedParameter( ATTR_TYPE ) );
        }
        else // no lifecycle or handler specified, and no inspection match
        {
            handler = MetaInfoEntry.PER_THREAD_HANDLER;
        }

        if ( null != lifecycle ) setAttribute( TAG_LIFESTYLE, lifecycle );
        if ( null != handler ) setAttribute( TAG_HANDLER, handler );
    }

    /**
     * Get the type name.
     *
     * @return String
     */
    public String getType()
    {
        return m_javaClass.getFullyQualifiedName();
    }

    public Iterator getDependencyNames()
    {
        return m_dependencyNames.iterator();
    }

    public Iterator getServiceNames()
    {
        return m_serviceNames.iterator();
    }

    /**
     * Add a dependency to this type.
     *
     * @param service  The name of the service that depends on this.
     */
    public void addDependency( Service service )
    {
        if ( !m_dependencies.contains( service ) )
        {
            m_dependencies.add( service );
        }
    }

    public Vertex getVertex()
    {
        if ( m_vertex.getDependencies().size() != 0 )
        {
            Iterator it = m_dependencies.iterator();
            while ( it.hasNext() )
            {
                Service service = (Service) it.next();

                Iterator cit = service.getComponents();
                while ( cit.hasNext() )
                {
                    Component component = (Component) cit.next();
                    m_vertex.addDependency( component.getVertex() );
                }
            }
        }
        return m_vertex;
    }

    /**
     * Set the component attribute.
     *
     * @param name   The name of the attribute
     * @param value  The attribute value
     */
    public void setAttribute( final String name, final String value )
    {
        m_attributes.setProperty( name, value );
    }

    /**
     * Output the meta information.
     *
     * @param rootDir
     * @throws IOException
     */
    public void serialize( final File rootDir ) throws IOException
    {
        final String fileName = getType().replace( '.', '/' ).concat( ".meta" );
        final String depsName = getType().replace( '.', '/' ).concat( ".deps" );
        File output = new File( rootDir, fileName );
        FileOutputStream writer = null;

        try
        {
            writer = new FileOutputStream( output );
            m_attributes.store( writer, "Meta information for " + getType() );

            if ( m_dependencies.size() > 0 )
            {
                writer.close();
                output = new File( rootDir, depsName );
                writer = new FileOutputStream( output );

                Iterator it = m_dependencies.iterator();
                while ( it.hasNext() )
                {
                    Service service = (Service) it.next();
                    String name = service.getType() + "\n";
                    writer.write( name.getBytes() );
                }
            }
        }
        finally
        {
            if ( null != writer )
            {
                writer.close();
            }
        }
    }

    private String stripQuotes( final String value )
    {
        if ( null == value ) return null;
        if ( value.length() < 2 ) return value;

        String retVal = value.trim();

        if ( retVal.startsWith( "\"" ) && retVal.endsWith( "\"" ) )
        {
            retVal = retVal.substring( 1, retVal.length() - 1 );
        }

        return retVal;
    }

    /**
     * Resolve the classname from the "@avalon.service" javadoc tags.
     *
     * @param serviceName  The service type name
     * @return  The fully qualified class name
     */
    protected String resolveClassName( final JavaSource sourceCode, final String serviceName )
    {
        if ( null == sourceCode )
        {
            return null;
        }
        if ( null == serviceName )
        {
            // This should be checked by the caller so that a message which better
            //  describes the problem in a given context can be given.
            throw new IllegalStateException( "The serviceName parameter was null." );
        }

        final String className = stripQuotes( serviceName );

        if ( className != null || className.length() > 0 )
        {
            if ( className.indexOf( '.' ) < 0 )
            {
                String checkName = checkPackage(sourceCode, sourceCode.getPackage(), className);
                if ( ! checkName.equals(className) ) return checkName;

                String[] imports = sourceCode.getImports();
                for ( int t = 0; t < imports.length; t++ )
                {
                    checkName = checkImport( sourceCode, imports[t], className);
                    if ( ! checkName.equals( className ) ) return checkName;
                }
            }
        }

        return className;
    }

    private String checkImport ( final JavaSource sourceCode, final String type, final String className)
    {
        final String tail = type.substring( type.lastIndexOf( '.' ) + 1 );

        if ( tail.equals( className ) )
        {
            return type;
        }
        else if ( tail.equals( "*" ) )
        {
            final String pack = type.substring( 0, type.lastIndexOf( '.' ) );

            String checkName = checkPackage( sourceCode, pack, className );
            if ( !checkName.equals( className ) ) return checkName;
        }

        return className;
    }

    private String checkPackage( final JavaSource sourceCode, final String pack, final String serviceName )
    {
        String className = serviceName;
        final JavaClass klass = sourceCode.getClassLibrary().getClassByName( pack + "." + serviceName );
        if ( null !=  klass )
            className = klass.getFullyQualifiedName();
        return className;
    }
}
TOP

Related Classes of org.apache.avalon.fortress.tools.Component

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.