You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@avalon.apache.org by mc...@apache.org on 2002/07/25 20:05:52 UTC
cvs commit: jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/model/builder DefaultLoggerManager.java DefaultTypeManager.java TypeException.java TypeRegistry.java TypeRuntimeException.java TypeTable.java
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:mcconnell@apache.org">Stephen McConnell</a>
* @author <a href="mailto:colus@isoft.co.kr">Eung-ju Park</a>
* @author <a href="mailto:peter@apache.org">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:mcconnell@apache.org">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:mcconnell@apache.org">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:mcconnell@apache.org">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:mcconnell@apache.org">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:mcconnell@apache.org">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: <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>