mcconnell 2002/07/25 11:05:52 Added: assembly/src/java/org/apache/excalibur/merlin/model/builder DefaultLoggerManager.java DefaultTypeManager.java TypeException.java TypeRegistry.java TypeRuntimeException.java TypeTable.java Log: Part of meta-data optimization. Revision Changes Path 1.1 jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/model/builder/DefaultLoggerManager.java Index: DefaultLoggerManager.java =================================================================== /* * Copyright (C) The Apache Software Foundation. All rights reserved. * * This software is published under the terms of the Apache Software License * version 1.1, a copy of which has been included with this distribution in * the LICENSE.txt file. */ package org.apache.excalibur.merlin.model.builder; import java.io.File; import java.io.IOException; import java.util.HashMap; import org.apache.log.Hierarchy; import org.apache.log.LogTarget; import org.apache.log.Logger; import org.apache.log.Priority; import org.apache.log.output.io.FileTarget; import org.apache.log.output.io.StreamTarget; import org.apache.avalon.excalibur.i18n.ResourceManager; import org.apache.avalon.excalibur.i18n.Resources; import org.apache.avalon.excalibur.logger.LoggerManager; import org.apache.avalon.framework.configuration.Configurable; import org.apache.avalon.framework.configuration.Configuration; import org.apache.avalon.framework.configuration.ConfigurationException; import org.apache.avalon.framework.context.Context; import org.apache.avalon.framework.context.ContextException; import org.apache.avalon.framework.context.Contextualizable; import org.apache.avalon.framework.logger.AbstractLogEnabled; import org.apache.avalon.framework.logger.AvalonFormatter; import org.apache.avalon.framework.logger.LogKitLogger; import org.apache.excalibur.merlin.model.Category; import org.apache.excalibur.merlin.model.CategoriesDescriptor; import org.apache.excalibur.merlin.model.TargetDescriptor; import org.apache.excalibur.merlin.model.LoggingDescriptor; import org.apache.excalibur.merlin.model.TargetProvider; import org.apache.excalibur.merlin.model.FileTargetProvider; import org.apache.excalibur.merlin.model.Parent; /** * A <code>LoggerManager</code> that supports management of a logging hierarchy. * * @author <a href="mailto:[EMAIL PROTECTED]">Stephen McConnell</a> * @author <a href="mailto:[EMAIL PROTECTED]">Eung-ju Park</a> * @author <a href="mailto:[EMAIL PROTECTED]">Peter Donald</a> */ public class DefaultLoggerManager implements LoggerManager { public static final String DEFAULT_PRIORITY = "INFO"; public static final String DEFAULT_TARGET = "default"; public static final String HOME_KEY = "app.home"; private static final Resources REZ = ResourceManager.getPackageResources( DefaultLoggerManager.class ); private static final String DEFAULT_FORMAT = "[%7.7{priority}] (%{category}): %{message}\\n%{throwable}"; /** * Base directory of file targets. */ private File m_baseDirectory; /** * log hierarchy. */ private Hierarchy m_logHierarchy; /** * default logger */ private org.apache.avalon.framework.logger.Logger m_logger; /** * default logger target */ private StreamTarget m_stream; private final HashMap m_targets = new HashMap(); private DefaultLoggerManager m_parent; private String m_category; //=============================================================== // constructor //=============================================================== /** * Creation of a new LoggerManager. * @param descriptor the logging system description * @exception Exception is an error occurs */ public DefaultLoggerManager( final LoggingDescriptor descriptor ) throws Exception { // // setup the hierarchy, default logging target, and default priority // m_stream = new StreamTarget( System.out, new AvalonFormatter( DEFAULT_FORMAT ) ); m_baseDirectory = new File( System.getProperty("user.dir") ); m_logHierarchy = new Hierarchy(); getHierarchy().setDefaultLogTarget( m_stream ); m_targets.put( DEFAULT_TARGET, m_stream ); if( descriptor.getPriority() != null ) { getLogger().debug("supplied system priority: " + descriptor.getPriority() ); getHierarchy().setDefaultPriority( Priority.getPriorityForName( descriptor.getPriority( ) ) ); } else { getLogger().debug("internal system priority: " + DEFAULT_PRIORITY ); getHierarchy().setDefaultPriority( Priority.getPriorityForName( DEFAULT_PRIORITY ) ); } // // build targets based on the information contained in the descriptor // TargetDescriptor[] targets = descriptor.getTargetDescriptors(); for( int i=0; i<targets.length; i++ ) { addTarget( targets[i] ); } // // set the default target // String name = descriptor.getTarget(); if( name != null ) { LogTarget target = (LogTarget) m_targets.get( name ); if( target != null ) { getHierarchy().setDefaultLogTarget( target ); } else { throw new TypeException( "Supplied default logging target: '" + name + "' does not exist." ); } } } /** * Add a set of category entries using the system wide defaults. * @param path the category header * @param descriptor a set of category descriptors to be added under the path */ public void addCategories( CategoriesDescriptor descriptor ) { addCategories( null, descriptor ); } /** * Add a set of category entries using the system wide defaults. * @param path the category header * @param descriptor a set of category descriptors to be added under the path */ public void addCategories( Parent parent, CategoriesDescriptor descriptor ) { String path = null; final String name = descriptor.getName(); if( parent != null ) { path = parent.getPath().replace('/','.').substring(1) + "." + name; } else { path = name; } addSingleCategory( path, descriptor.getPriority(), descriptor.getTarget( ) ); Category[] categories = descriptor.getCategories(); for( int i=0; i<categories.length; i++ ) { Category category = categories[i]; final String priority = category.getPriority(); final String target = category.getTarget(); addSingleCategory( path + "." + category.getName(), priority, target ); } } private Logger addSingleCategory( String path, String priority, String target ) { final Logger logger = getHierarchy().getLoggerFor( path ); if( priority != null ) { final Priority priorityValue = Priority.getPriorityForName( priority ); if( !priorityValue.getName().equals( priority ) ) { final String message = REZ.getString( "unknown-priority", priority, path ); throw new IllegalArgumentException( message ); } logger.setPriority( priorityValue ); } if( target != null ) { final LogTarget logTarget = (LogTarget) m_targets.get( target ); if( logTarget != null ) logger.setLogTargets( new LogTarget[]{ logTarget } ); } else { logger.setLogTargets( new LogTarget[]{ (LogTarget) m_targets.get( DEFAULT_TARGET ) } ); } if( getLogger().isDebugEnabled() ) { final String message = REZ.getString( "category-create", path, target, logger.getPriority() ); getLogger().info( message ); } return logger; } private void addTarget( TargetDescriptor target ) throws Exception { File base = new File( System.getProperty("user.dir") ); final String name = target.getName(); TargetProvider provider = target.getProvider(); if( provider instanceof FileTargetProvider ) { FileTargetProvider fileProvider = (FileTargetProvider) provider; String filename = fileProvider.getLocation(); final AvalonFormatter formatter = new AvalonFormatter( DEFAULT_FORMAT ); try { File file = new File( base, filename ); FileTarget logTarget = new FileTarget( file.getAbsoluteFile(), false, formatter ); m_targets.put( name, logTarget ); } catch( final IOException ioe ) { final String message = REZ.getString( "target.nocreate", name, filename, ioe.getMessage() ); throw new TypeException( message, ioe ); } } else { final String error = "Unrecognized logging provider: " + provider.getClass().getName(); throw new IllegalArgumentException( error ); } } /** * Configure Logging categories. * * @param categories configuration data for categories * @param targets a hashmap containing the already existing taregt * @throws ConfigurationException if an error occurs */ public org.apache.avalon.framework.logger.Logger getLoggerForCategory( final String name, String target, String priority ) throws Exception { return new LogKitLogger( addSingleCategory( name, target, priority ) ); } /** * Configure Logging categories. * * @param categories configuration data for categories * @param targets a hashmap containing the already existing taregt * @throws ConfigurationException if an error occurs */ public org.apache.avalon.framework.logger.Logger getLoggerForCategory( final Category category ) throws Exception { return new LogKitLogger( addSingleCategory( category.getName(), category.getPriority(), category.getTarget() ) ); } //=============================================================== // LoggerManager //=============================================================== /** * Return the Logger for the specified category. */ public org.apache.avalon.framework.logger.Logger getLoggerForCategory( final String category ) { if( category == null ) { return new LogKitLogger( getHierarchy().getLoggerFor( "" ) ); } else { return new LogKitLogger( getHierarchy().getLoggerFor( category ) ); } } /** * Return the default Logger. This is the same * as getting the Logger for the "" category. */ public org.apache.avalon.framework.logger.Logger getDefaultLogger( ) { if( m_logger == null ) m_logger = getLoggerForCategory(""); return m_logger; } /** * Return the default Logger. This is the same * as getting the Logger for the "" category. */ public org.apache.avalon.framework.logger.Logger getLogger( ) { if( m_logger == null ) m_logger = getLoggerForCategory("kernel.logging"); return m_logger; } private Hierarchy getHierarchy() { if( m_parent != null ) { return m_parent.getHierarchy(); } return m_logHierarchy; } } 1.1 jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/model/builder/DefaultTypeManager.java Index: DefaultTypeManager.java =================================================================== /* * Copyright (C) The Apache Software Foundation. All rights reserved. * * This software is published under the terms of the Apache Software License * version 1.1, a copy of which has been included with this distribution in * the LICENSE.txt file. */ package org.apache.excalibur.merlin.model.builder; import java.io.File; import java.io.IOException; import java.util.jar.Attributes; import java.util.jar.Manifest; import java.util.Dictionary; import java.util.Hashtable; import java.util.Enumeration; import java.util.Vector; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.Map; import java.util.List; import java.util.LinkedList; import java.net.URLClassLoader; import java.net.URL; import java.net.JarURLConnection; import org.apache.avalon.framework.logger.Logger; import org.apache.avalon.framework.logger.LogEnabled; import org.apache.avalon.framework.CascadingRuntimeException; import org.apache.avalon.framework.configuration.Configuration; import org.apache.avalon.framework.activity.Initializable; import org.apache.avalon.framework.context.Context; import org.apache.avalon.framework.context.Contextualizable; import org.apache.avalon.framework.context.ContextException; import org.apache.avalon.framework.activity.Initializable; import org.apache.avalon.excalibur.i18n.ResourceManager; import org.apache.avalon.excalibur.i18n.Resources; import org.apache.avalon.excalibur.extension.Extension; import org.apache.avalon.excalibur.extension.PackageManager; import org.apache.avalon.excalibur.extension.PackageRepository; import org.apache.avalon.excalibur.extension.OptionalPackage; import org.apache.avalon.excalibur.extension.DefaultPackageRepository; import org.apache.excalibur.meta.info.Type; import org.apache.excalibur.meta.info.ServiceDesignator; import org.apache.excalibur.merlin.model.ClasspathDescriptor; import org.apache.excalibur.merlin.model.FilesetDescriptor; import org.apache.excalibur.merlin.model.IncludeDescriptor; import org.apache.excalibur.merlin.model.ExtensionsDescriptor; import org.apache.excalibur.merlin.model.DirsetDescriptor; /** * Classloader for an assembly of components. * * @author <a href="mailto:[EMAIL PROTECTED]">Stephen McConnell</a> * @version $Revision: 1.1 $ $Date: 2002/07/25 18:05:52 $ */ public class DefaultTypeManager extends TypeManager implements LogEnabled, Contextualizable, Initializable { //=================================================================== // static //=================================================================== private static final Resources REZ = ResourceManager.getPackageResources( DefaultTypeManager.class ); //=================================================================== // state //=================================================================== private File[] m_stack; /** * List of names of block implementation classes. */ private final List m_blocks = new LinkedList(); private PackageManager m_manager; private Logger m_logger; private ExtensionsDescriptor m_extensions; private ClasspathDescriptor m_classpath; private TypeRegistry m_types; //=================================================================== // constructor //=================================================================== public DefaultTypeManager( ) { super( new URL[ 0 ], Thread.currentThread().getContextClassLoader() ); } public DefaultTypeManager( ClassLoader parent ) { super( new URL[ 0 ], parent ); } //=================================================================== // LogEnabled //=================================================================== public void enableLogging( Logger logger ) { m_logger = logger; } public Logger getLogger() { return m_logger; } //======================================================================= // Contextualizable //======================================================================= /** * Declaration of the extensions and classpath descriptors. * @param context the context object containing the inital parameters * @exception ContextException if the supplied does not contain a DESCRIPTOR_KEY value */ public void contextualize( Context context ) throws ContextException { getLogger().debug( "contextualize" ); try { m_extensions = (ExtensionsDescriptor) context.get( EXTENSIONS_DESCRIPTOR_KEY ); } catch( ContextException e ) { // ignore - optional context element } try { m_classpath = (ClasspathDescriptor) context.get( CLASSPATH_DESCRIPTOR_KEY ); } catch( ContextException e ) { // ignore - optional context element } } //======================================================================= // Initializable //======================================================================= public void initialize() throws Exception { getLogger().debug("initilize"); m_types = new TypeRegistry( this ); m_types.enableLogging( getLogger().getChildLogger( "types" ) ); if( m_extensions != null ) initializeExtensions(); if( m_classpath != null ) initializeClasspath(); } private void initializeExtensions() throws Exception { getLogger().debug( "initializing extensions" ); ArrayList list = new ArrayList(); File dir = new File( System.getProperty("user.dir") ); DirsetDescriptor[] dirs = m_extensions.getDirsetDescriptors(); for( int i=0; i<dirs.length; i++ ) { DirsetDescriptor descriptor = dirs[i]; File base = new File( dir, descriptor.getBaseDirectory() ); IncludeDescriptor[] includes = descriptor.getIncludeDescriptors(); for( int j=0; j<includes.length; j++ ) { File include = new File( base, includes[j].getFile() ); if( include.isDirectory() ) { list.add( include ); } else { throw new IllegalArgumentException( "Include dir does not refer to a directory: " + include ); } } } File[] files = (File[]) list.toArray( new File[0] ); PackageRepository repository = new DefaultPackageRepository( files ); m_manager = new PackageManager( repository ); } private void initializeClasspath() throws Exception { addClasspath( m_classpath ); } //=================================================================== // ClassLoader //=================================================================== /** * Add a URL to the classpath. * @param url the URL to add to the classpath */ protected void addURL( URL url ) { super.addURL( url ); checkForComponents( url ); } /** * Add a URL to the classpath. * @param url the URL to add to the classpath */ protected void checkForComponents( URL url ) { String[] entries = getBlocksEntries( url ); for( int j=0; j<entries.length; j++ ) { getLogger().debug("located: " + entries[j] ); String classname = entries[j].replace('/','.'); try { m_types.register( classname ); } catch( Throwable e ) { final String warning = "Ignoring component: " + classname ; getLogger().warn( warning, e ); } } } //=================================================================== // TypeManager //=================================================================== /** * Add classes to the manager declared within a classpath structure. * @param classpath the classpath descriptor * @exception Exception if an exception occurs during class loading */ void addClasspath( ClasspathDescriptor classpath ) throws Exception { getLogger().debug( "adding classpath" ); List list = new ArrayList(); Vector stack = new Vector(); File dir = new File( System.getProperty("user.dir") ); FilesetDescriptor[] dirs = classpath.getFilesetDescriptors(); for( int i=0; i<dirs.length; i++ ) { FilesetDescriptor descriptor = dirs[i]; File base = new File( dir, descriptor.getBaseDirectory() ); IncludeDescriptor[] includes = descriptor.getIncludeDescriptors(); for( int j=0; j<includes.length; j++ ) { File include = new File( base, includes[j].getFile() ); list.add( include.toURL() ); stack.add( include ); } } URL[] urls = (URL[]) list.toArray( new URL[0] ); String[] path = urlsToStrings( urls ); final File[] extensions = getOptionalPackagesFor( path ); for( int i = 0; i < extensions.length; i++ ) { URL url = extensions[ i ].toURL(); getLogger().info("extension: " + extensions[ i ].toURL() ); super.addURL( url ); } load( stack ); for( int i = 0; i < urls.length; i++ ) { getLogger().info("adding: " + urls[i] ); checkForComponents( urls[i] ); } getLogger().debug( "classpath addition complete" ); } /** * Load the supplied jar files under the pipeline classloader. * For each entry in the stack, try to load it and * if sucessfull, remove it from the stack - on completion * the stack should be less than its original size - recursivly * invoke load until the stack is empty. * @param stack a <code>Vector</code> containing a sequence of jar files * to be added to the classloader. */ private void load( Vector stack ) { int size = stack.size(); getLogger().debug( "Stack size: " + stack.size() ); Hashtable errors = new Hashtable(); Enumeration enum = stack.elements(); while( enum.hasMoreElements() ) { File file = (File)enum.nextElement(); getLogger().debug( "Loading resource: " + file ); try { super.addURL( file.toURL() ); stack.remove( file ); } catch( Throwable error ) { getLogger().warn( "Encountered error while loading resource: " + file, error ); errors.put( file, error ); } } if( stack.size() == 0 ) { return; } if( stack.size() < size ) { load( stack ); } else { Enumeration keys = errors.keys(); getLogger().error( "Load error count = " + errors.size() ); while( keys.hasMoreElements() ) { File key = (File)keys.nextElement(); getLogger().error( "Error while loading file." + "\n\tfile: " + key.toString(), (Throwable)errors.get( key ) ); } throw new RuntimeException( "Unable to load file stack - see trace for details." ); } } private String[] urlsToStrings( URL[] urls ) { Vector vector = new Vector(); for( int i=0; i<urls.length; i++ ) { vector.add( urls[i].toString() ); } return (String[]) vector.toArray( new String[ vector.size() ] ); } /** * Resolve a {@link Type} from a classname. * * @param classname the component type * @return the component type */ public Type lookup( String classname ) throws Exception { getLogger().debug("LOOKUP: " + classname ); Type type = m_types.lookup( classname ); if( type != null ) { return type; } else { ClassLoader parent = getParent(); if( parent instanceof TypeManager ) { return ((TypeManager)parent).lookup( classname ); } else { throw new TypeException("type not found, classname: " + classname ); } } } /** * Returns the set of component types know to the registry. * @return the set of component types registered with the registry */ public Type[] getTypes() { return m_types.getTypes( ); } /** * Returns the set of component types know to the registry that are capable of * supporting the supplied service. * @return the set of candidate component types */ public Type[] getTypes( ServiceDesignator service ) { return m_types.getTypes( service ); } /** * Returns a registered component type. * @return the component type from the registry or null if the type is unknown */ public Type getType( String classname ) { return m_types.getType( classname ); } //=================================================================== // ClassLoader extensions //=================================================================== /** * Returns TRUE is the component classname is know by the classloader. * @return a component availablity status */ public boolean hasComponent( String classname ) { return m_blocks.contains( classname ); } /** * Return the array of component implementation class names within the scope * of the classloader. * @return the block names array */ public String[] getComponentClassnames() { return (String[]) m_blocks.toArray( new String[0] ); } //=================================================================== // internals //=================================================================== /** * Returns an array of <code>String</code>s corresponding to the set of classnames * where each classname is a declared block within the supplied jar file. * @param file a jar file * @exception TypeRuntimeException if a general exception occurs */ private String[] getBlocksEntries( URL base ) throws TypeRuntimeException { Vector vector = new Vector(); try { final URL url = new URL( "jar:" + base.toString() + "!/" ); final JarURLConnection jar = (JarURLConnection)url.openConnection(); final Map map = jar.getManifest().getEntries(); final Iterator iterator = map.keySet().iterator(); while( iterator.hasNext() ) { final String name = (String)iterator.next(); final Attributes attributes = (Attributes)map.get( name ); final Iterator it = attributes.keySet().iterator(); while( it.hasNext() ) { final Object entry = it.next(); if( entry.toString().equals( "Avalon-Block" ) ) { if( attributes.get( entry ).equals( "true" ) ) { vector.add( name.substring( 0, name.indexOf( ".class" ) ) ); } } } } } catch( IOException e ) { final String error = "IO exception while attempt to read block manifest."; throw new TypeRuntimeException( error, e ); } catch( Throwable e ) { final String error = "Unexpected exception while inspecting manifest on file: "; throw new TypeRuntimeException( error + base, e ); } finally { return (String[]) vector.toArray( new String[0] ); } } /** * Retrieve the files for the optional packages required by * the jars in ClassPath. * * @param classPath the Classpath array * @return the files that need to be added to ClassLoader */ private File[] getOptionalPackagesFor( final String[] classPath ) throws Exception { if( m_manager == null ) { ClassLoader parent = getParent(); if( parent != null ) { if( parent instanceof DefaultTypeManager ) { return ((DefaultTypeManager)parent).getOptionalPackagesFor( classPath ); } } else { return new File[0]; } } final Manifest[] manifests = getManifests( classPath ); final Extension[] available = Extension.getAvailable( manifests ); final Extension[] required = Extension.getRequired( manifests ); final ArrayList dependencies = new ArrayList(); final ArrayList unsatisfied = new ArrayList(); m_manager.scanDependencies( required, available, dependencies, unsatisfied ); if( 0 != unsatisfied.size() ) { final int size = unsatisfied.size(); for( int i = 0; i < size; i++ ) { final Extension extension = (Extension)unsatisfied.get( i ); final Object[] params = new Object[] { extension.getExtensionName(), extension.getSpecificationVendor(), extension.getSpecificationVersion(), extension.getImplementationVendor(), extension.getImplementationVendorID(), extension.getImplementationVersion(), extension.getImplementationURL() }; final String message = REZ.format( "missing.extension", params ); getLogger().warn( message ); } final String message = REZ.getString( "unsatisfied.extensions", new Integer( size ) ); throw new Exception( message ); } final OptionalPackage[] packages = (OptionalPackage[])dependencies.toArray( new OptionalPackage[ 0 ] ); return OptionalPackage.toFiles( packages ); } private Manifest[] getManifests( final String[] classPath ) throws Exception { final ArrayList manifests = new ArrayList(); for( int i = 0; i < classPath.length; i++ ) { final String element = classPath[ i ]; if( element.endsWith( ".jar" ) ) { try { final URL url = new URL( "jar:" + element + "!/" ); final JarURLConnection connection = (JarURLConnection)url.openConnection(); final Manifest manifest = connection.getManifest(); manifests.add( manifest ); } catch( final IOException ioe ) { final String message = REZ.getString( "bad-classpath-entry", element ); throw new Exception( message ); } } } return (Manifest[])manifests.toArray( new Manifest[ 0 ] ); } } 1.1 jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/model/builder/TypeException.java Index: TypeException.java =================================================================== /* * Copyright (C) The Apache Software Foundation. All rights reserved. * * This software is published under the terms of the Apache Software License * version 1.1, a copy of which has been included with this distribution in * the LICENSE.txt file. */ package org.apache.excalibur.merlin.model.builder; import org.apache.avalon.framework.CascadingException; /** * Exception to indicate that there was a model related error. * * @author <a href="mailto:[EMAIL PROTECTED]">Stephen McConnell</a> * @version $Revision: 1.1 $ $Date: 2002/07/25 18:05:52 $ */ public final class TypeException extends CascadingException { /** * Construct a new <code>TypeException</code> instance. * * @param message The detail message for this exception. */ public TypeException( final String message ) { this( message, null ); } /** * Construct a new <code>TypeException</code> instance. * * @param message The detail message for this exception. * @param throwable the root cause of the exception */ public TypeException( final String message, final Throwable throwable ) { super( message, throwable ); } } 1.1 jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/model/builder/TypeRegistry.java Index: TypeRegistry.java =================================================================== /* * Copyright (C) The Apache Software Foundation. All rights reserved. * * This software is published under the terms of the Apache Software License * version 1.1, a copy of which has been included with this distribution in * the LICENSE.txt file. */ package org.apache.excalibur.merlin.model.builder; import java.util.List; import java.util.LinkedList; import java.util.Hashtable; import java.util.Vector; import java.util.Iterator; import org.apache.avalon.framework.CascadingException; import org.apache.avalon.framework.logger.Logger; import org.apache.avalon.framework.logger.LogEnabled; import org.apache.avalon.framework.logger.AbstractLogEnabled; import org.apache.avalon.framework.configuration.Configuration; import org.apache.excalibur.meta.info.ServiceDescriptor; import org.apache.excalibur.meta.info.ServiceDesignator; import org.apache.excalibur.meta.info.DependencyDescriptor; import org.apache.excalibur.meta.info.Type; import org.apache.excalibur.meta.info.builder.TypeBuilder; import org.apache.excalibur.merlin.model.Profile; import org.apache.excalibur.meta.verifier.ComponentVerifier; import org.apache.excalibur.configuration.ConfigurationUtil; /** * Internal table that holds available component type keyed relative * to the service it provides. * * @author <a href="mailto:[EMAIL PROTECTED]">Stephen McConnell</a> * @version $Revision: 1.1 $ $Date: 2002/07/25 18:05:52 $ */ final class TypeRegistry extends AbstractLogEnabled { //======================================================================= // state //======================================================================= private TypeBuilder m_infoBuilder = new TypeBuilder(); private ClassLoader m_classloader; /** * Component types keyed by classname. */ private Hashtable m_types = new Hashtable(); /** * List of TypeTable instances. */ private List m_services = new LinkedList(); //======================================================================= // constructor //======================================================================= /** * Creation of a new service registry. * @param registry the registry that will be supplied to new component defintions * @param loader the registry class loader * @param profiles the configuration fragment containing explicit component profiles */ public TypeRegistry( ClassLoader loader ) { m_classloader = loader; } //======================================================================= // LogEnabled //======================================================================= /** * Set the logging channel for the service registry. * @param logger the logging channel */ public void enableLogging( Logger logger ) { super.enableLogging( logger ); m_infoBuilder.enableLogging( logger.getChildLogger("builder") ); } //======================================================================= // implemetation (TypeManager handler) //======================================================================= /** * Resolve a {@link Type} from a classname. * * @param classname the component type * @return the component type */ public Type lookup( String classname ) throws Exception { //return register( classname ); return getType( classname ); } /** * Register a potential supplier component type. The implementation will * create a component type instance for the entry if not already known and * return the existing or new instance to the invoking client. * * @param classname the component class name * @return the component type */ public Type register( String classname ) throws Exception { getLogger().info("register: " + classname ); Type type = getType( classname ); if( type == null ) { type = m_infoBuilder.build( classname, m_classloader ); String name = type.getInfo().getName(); Class clazz = getComponentClass( type ); Class[] classes = getServiceClasses( type ); ComponentVerifier verifier = new ComponentVerifier(); verifier.enableLogging( getLogger().getChildLogger( "verifier" )); verifier.verifyComponent( name, clazz, classes ); register( type ); } return type; } //======================================================================= // TypeRegistry (private) //======================================================================= private Class[] getServiceClasses( Type type ) { Vector vector = new Vector(); ServiceDescriptor[] services = type.getServices(); for( int i=0; i<services.length; i++ ) { vector.add( getServiceClass( services[i] ) ); } return (Class[]) vector.toArray( new Class[0] ); } /** * Returns the component type implementation class. * @param type the component type descriptor * @return the class implementing the component type */ private Class getComponentClass( Type type ) throws TypeException { if( null == type ) throw new NullPointerException("Illegal null component type argument."); final String classname = type.getInfo().getImplementationKey(); try { return m_classloader.loadClass( classname ); } catch( Throwable e ) { final String error = "Could not load implementation class for component type: " + classname; throw new TypeException( error, e ); } } /** * Returns the service type implementation class. * @param service the service type descriptor * @return the class implementing the service type */ private Class getServiceClass( ServiceDescriptor service ) throws TypeRuntimeException { final String classname = service.getService().getClassname(); try { return m_classloader.loadClass( classname ); } catch( Throwable e ) { final String error = "Could not load implementation class for service type: " + classname; throw new TypeRuntimeException( error, e ); } } /** * Returns the set of component types know to the registry. * @return the set of component types registered with the registry */ public Type[] getTypes() { return (Type[]) m_types.values().toArray( new Type[0] ); } /** * Returns the set of component types know to the registry that are capable of * supporting the supplied service. * @return the set of candidate component types */ public Type[] getTypes( ServiceDesignator service ) { return getTable( service ).getTypes(); } /** * Returns a registered component type. * @return the component type from the registry or null if the type is unknown */ public Type getType( String classname ) { return (Type) m_types.get( classname ); } /** * Register the type resulting in the cross-referencing of the type with the set of * service tables that the type is is capable of supporting. */ private void register( Type type ) { String key = type.getInfo().getImplementationKey(); m_types.put( key, type ); getLogger().debug( "Type: '" + key + "' registered."); ServiceDescriptor[] services = type.getServices(); for( int i=0; i<services.length; i++ ) { register( services[i].getService(), type ); } } /** * Register a type under a service cross-reference. */ private void register( ServiceDesignator service, Type type ) { TypeTable table = getTable( service ); table.add( type ); } /** * Return a table holding table capable of supply the supplied service. */ private TypeTable getTable( ServiceDesignator service ) { TypeTable table = null; Iterator iterator = m_services.iterator(); while( iterator.hasNext() ) { table = (TypeTable) iterator.next(); if( table.matches( service ) ) return table; } // otherwise create a new table table = new TypeTable( service, getLogger().getChildLogger("table") ); m_services.add( table ); return table; } } 1.1 jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/model/builder/TypeRuntimeException.java Index: TypeRuntimeException.java =================================================================== /* * Copyright (C) The Apache Software Foundation. All rights reserved. * * This software is published under the terms of the Apache Software License * version 1.1, a copy of which has been included with this distribution in * the LICENSE.txt file. */ package org.apache.excalibur.merlin.model.builder; import org.apache.avalon.framework.CascadingRuntimeException; /** * Exception to indicate that there was a model related runtime error. * * @author <a href="mailto:[EMAIL PROTECTED]">Stephen McConnell</a> * @version $Revision: 1.1 $ $Date: 2002/07/25 18:05:52 $ */ public final class TypeRuntimeException extends CascadingRuntimeException { /** * Construct a new <code>TypeRuntimeException</code> instance. * * @param message The detail message for this exception. */ public TypeRuntimeException( final String message ) { this( message, null ); } /** * Construct a new <code>TypeRuntimeException</code> instance. * * @param message The detail message for this exception. * @param throwable the root cause of the exception */ public TypeRuntimeException( final String message, final Throwable throwable ) { super( message, throwable ); } } 1.1 jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/model/builder/TypeTable.java Index: TypeTable.java =================================================================== /* * Copyright (C) The Apache Software Foundation. All rights reserved. * * This software is published under the terms of the Apache Software License * version 1.1, a copy of which has been included with this distribution in * the LICENSE.txt file. */ package org.apache.excalibur.merlin.model.builder; import java.util.List; import java.util.LinkedList; import org.apache.avalon.framework.logger.Logger; import org.apache.avalon.framework.logger.AbstractLogEnabled; import org.apache.excalibur.meta.info.ServiceDesignator; import org.apache.excalibur.meta.info.Type; /** * Internal table that holds references to the available component types * that represent candidate providers for a single service type. * * @author <a href="mailto:[EMAIL PROTECTED]">Stephen McConnell</a> * @version $Revision: 1.1 $ $Date: 2002/07/25 18:05:52 $ */ final class TypeTable extends AbstractLogEnabled { //======================================================================= // state //======================================================================= /** * Component type lists keyed by service designator. */ private List m_providers = new LinkedList(); /** * Identification of the service type that this table is supporting. */ private ServiceDesignator m_designator; public TypeTable( ServiceDesignator designator, Logger logger ) { m_designator = designator; super.enableLogging( logger ); } //======================================================================= // ServiceTable //======================================================================= /** * Add a service provider to the set of provider managed by this table. * * @param classname the component class name * @return the component type */ public void add( Type type ) { m_providers.add( type ); } /** * Returns the set of providers currently registered in the table. * @return the set of component types capable of acting as a provider for the * service managed by the table */ public Type[] getTypes() { return (Type[]) m_providers.toArray( new Type[0] ); } /** * Return the service type for the table. * @return the service designator */ public ServiceDesignator getService() { return m_designator; } /** * Return the number of entries in the table. * @return the number of providers */ public int getSize() { return m_providers.size(); } /** * Returns true if the table service designator matches the supplied designator. * @param service a service type designator * @return TRUE if the supplied service type matches the the service type for * this table. */ public boolean matches( ServiceDesignator service ) { return m_designator.matches( service ); } public String toString() { return "TypeTable:" + System.identityHashCode( this ) + ", " + m_designator; } }
-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>