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>