mcconnell 2002/12/08 19:03:47 Modified: assembly/src/java/org/apache/avalon/assembly/engine DefaultRepositoryManager.java Engine.java EngineClassLoader.java RepositoryManager.java Log: Applied some rearrangements of locic between the classloader and component repository to better support classloader extension. Revision Changes Path 1.3 +37 -401 avalon-sandbox/assembly/src/java/org/apache/avalon/assembly/engine/DefaultRepositoryManager.java Index: DefaultRepositoryManager.java =================================================================== RCS file: /home/cvs/avalon-sandbox/assembly/src/java/org/apache/avalon/assembly/engine/DefaultRepositoryManager.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- DefaultRepositoryManager.java 7 Dec 2002 14:00:53 -0000 1.2 +++ DefaultRepositoryManager.java 9 Dec 2002 03:03:47 -0000 1.3 @@ -77,7 +77,6 @@ import org.apache.avalon.assembly.profile.ProfileManager; import org.apache.avalon.assembly.service.ServiceManager; import org.apache.avalon.assembly.engine.model.*; -import org.apache.avalon.assembly.util.DefaultFileFilter; import org.apache.avalon.excalibur.extension.Extension; import org.apache.avalon.excalibur.i18n.ResourceManager; import org.apache.avalon.excalibur.i18n.Resources; @@ -105,32 +104,16 @@ * @author <a href="mailto:[EMAIL PROTECTED]">Gary Shea</a> * @version $Revision$ $Date$ */ -public class DefaultRepositoryManager extends AbstractLogEnabled implements Contextualizable, Initializable, RepositoryManager +public class DefaultRepositoryManager extends AbstractLogEnabled implements Initializable, RepositoryManager { //=================================================================== // static //=================================================================== - private static final FileFilter JAR_FILTER = new DefaultFileFilter( "jar" ); - - - private static final Resources REZ = - ResourceManager.getPackageResources( DefaultRepositoryManager.class ); - - /** - * Optional context key referencing an instance of [EMAIL PROTECTED] LibraryDescriptor} - * that defines the set of extension directories to use. - */ - public static final String EXTENSIONS_DESCRIPTOR_KEY = "urn:assembly:extensions.descriptor"; - - /** - * Optional classpath key referencing an instance of [EMAIL PROTECTED] ClasspathDescriptor} - * that defines the set of jar files to install. - */ - public static final String CLASSPATH_DESCRIPTOR_KEY = "urn:assembly:classpath.descriptor"; - private static final String X_INFO = "xinfo"; + private static final String X_TYPE = "xtype"; + private static final String X_SERVICE = "xservice"; private static final String AVALON_BLOCK_KEY = "Avalon-Block"; @@ -142,27 +125,12 @@ /** * Parent repository. */ - private RepositoryManager m_parent = null; + private RepositoryManager m_parent; /** * Parent repository. */ - private EngineClassLoader m_classloader; - - /** - * The base directory. - */ - private File m_home; - - /** - * Description of the extension directories. - */ - private LibraryDescriptor m_extensions; - - /** - * Utility class to manage extension jar files. - */ - private PackageManager m_manager; + private ClassLoader m_classloader; /** * The registry of installed component types. @@ -180,58 +148,28 @@ private ProfileManager m_profiles; /** - * The bootstrap flag.. + * List of jar files already installed. */ - private Boolean m_bootstrap = new Boolean( false ); - private List m_scanned = new ArrayList(); - //============================================================== - // Contextualizable - //============================================================== - - /** - * <p>Application of a runtime context to the lifestyle service. - * The context value will be passed directly to lifestyle handlers - * established by this service. - * @param context the runtime context - */ - public void contextualize( Context context ) throws ContextException + //=================================================================== + // constructor + //=================================================================== + + DefaultRepositoryManager( ClassLoader classloader ) { - m_classloader = (EngineClassLoader) context.get( "urn:assembly:engine.classloader" ); - m_extensions = (LibraryDescriptor) context.get( "urn:assembly:libraries-descriptor" ); - m_home = (File) context.get( "urn:avalon:home" ); + this( classloader, null ); + } - try - { - m_bootstrap = (Boolean) context.get( "urn:assembly:engine.bootstrap" ); - } - catch( ContextException ce ) - { - // use default value - } - catch( Throwable ce ) - { - throw new IllegalArgumentException( "urn:assembly:engine.bootstrap" ); - } - - try + DefaultRepositoryManager( ClassLoader classloader, RepositoryManager parent ) + { + if( classloader == null ) { - m_parent = (RepositoryManager) context.get( "urn:assembly:repository.parent" ); - m_types = new TypeManager( m_classloader, m_parent.getTypeManager() ); - m_services = new ServiceManager( m_classloader, m_parent.getServiceManager() ); - m_profiles = new ProfileManager( m_classloader, m_parent.getProfileManager() ); - } - catch( ContextException ce ) - { - m_services = new ServiceManager( m_classloader, null ); - m_types = new TypeManager( m_classloader, null ); - m_profiles = new ProfileManager( m_classloader, null ); + throw new NullPointerException( "classloader" ); } - m_services.enableLogging( getLogger().getChildLogger( "services" ) ); - m_types.enableLogging( getLogger().getChildLogger( "types" ) ); - m_profiles.enableLogging( getLogger().getChildLogger( "profiles" ) ); + m_classloader = classloader; + m_parent = parent; } //=================================================================== @@ -249,101 +187,25 @@ throw new IllegalStateException( "logging" ); } - ArrayList list = new ArrayList(); - File anchor = new File( m_home, m_extensions.getBaseDirectory() ); - IncludeDescriptor[] includes = m_extensions.getIncludeDescriptors(); - for( int j = 0; j < includes.length; j++ ) - { - File include = new File( anchor, includes[ j ].getFile() ); - if( include.isDirectory() ) - { - list.add( include ); - getLogger().debug( "including kernel extension dir: " + include ); - } - else - { - final String error = "Invalid include directory: " + include; - throw new IllegalArgumentException( error ); - } - } + ServiceManager services = null; + TypeManager types = null; + ProfileManager profiles = null; - if( m_bootstrap.booleanValue() ) + if( m_parent != null ) { - String sep = System.getProperty( "path.separator" ); - String exts = System.getProperty( "java.ext.dirs" ); - StringTokenizer tokenizer = new StringTokenizer( exts, sep ); - while( tokenizer.hasMoreTokens() ) - { - String token = tokenizer.nextToken(); - File test = new File( token ); - if( test.exists() ) - { - list.add( test ); - if( getLogger().isDebugEnabled() ) - { - getLogger().debug( "including system extension dir: " + test ); - } - } - else - { - File file = new File( m_home, token ); - if( file.exists() ) - { - list.add( file ); - if( getLogger().isDebugEnabled() ) - { - getLogger().debug( "including relative extension dir: " + file ); - } - } - else - { - if( getLogger().isWarnEnabled() ) - { - final String warning = - "The extension directory path: '" + token - + "' deas not refer to a directory."; - getLogger().warn( warning ); - } - } - } - } + services = m_parent.getServiceManager(); + types = m_parent.getTypeManager(); + profiles = m_parent.getProfileManager(); } - File[] files = (File[])list.toArray( new File[ 0 ] ); - ExtensionManager repository = new DefaultExtensionManager( files ); - m_manager = new PackageManager( repository ); - - // - // handle the system bootstrap process - // - - if( m_bootstrap.booleanValue() ) - { - - if( getLogger().isDebugEnabled() ) - { - getLogger().debug( "bootstraping from classpath" ); - } - - // - // handle the classpath - // + m_services = new ServiceManager( m_classloader, services ); + m_services.enableLogging( getLogger().getChildLogger( "services" ) ); - String sep = System.getProperty( "path.separator" ); - String classpath = System.getProperty( "java.class.path" ); + m_types = new TypeManager( m_classloader, types ); + m_types.enableLogging( getLogger().getChildLogger( "types" ) ); - StringTokenizer tokenizer = new StringTokenizer( classpath, sep ); - while( tokenizer.hasMoreTokens() ) - { - String token = tokenizer.nextToken(); - URL jar = new File( token ).toURL(); - if( getLogger().isDebugEnabled() ) - { - getLogger().debug( "path: " + jar ); - } - addLibrary( jar ); - } - } + m_profiles = new ProfileManager( m_classloader, profiles ); + m_profiles.enableLogging( getLogger().getChildLogger( "profiles" ) ); } //======================================================================= @@ -366,121 +228,10 @@ } /** - * Add a classpath to the repository. - * @param base the base directory from which relative classpath entries - * will be resolved. - */ - public void addClasspath( ClasspathDescriptor classpath ) - { - if( classpath == null ) - { - throw new NullPointerException( "classpath" ); - } - - if( getLogger() == null ) - { - throw new IllegalStateException( "logging" ); - } - - if( getLogger().isDebugEnabled() ) - { - getLogger().debug( "adding classpath" ); - } - - List list = new ArrayList(); - Vector stack = new Vector(); - FilesetDescriptor[] dirs = classpath.getFilesetDescriptors(); - for( int i = 0; i < dirs.length; i++ ) - { - FilesetDescriptor descriptor = dirs[ i ]; - File anchor = new File( m_home, descriptor.getBaseDirectory() ); - if( !anchor.exists() ) - { - final String error = - "Classpath base directory does not exist: " - + anchor; - throw new EngineRuntimeException( error ); - } - - IncludeDescriptor[] includes = descriptor.getIncludeDescriptors(); - for( int j = 0; j < includes.length; j++ ) - { - String inc = includes[ j ].getFile(); - try - { - addLibrary( new File( anchor, inc ).toURL() ); - } - catch( Throwable e ) - { - final String error = - "Error processing a classpath include: " - + inc; - throw new EngineRuntimeException( error, e ); - } - } - } - - if( getLogger().isDebugEnabled() ) - { - getLogger().debug( "classpath ok" ); - } - } - - /** * Add a URL to the classpath. - * @param url the URL to add to the classpath - */ - public void addLibrary( URL url ) - { - //if( !m_scanned.contains( url ) ) - //{ - addExtensions( url ); - m_classloader.addLibraryURL( url ); - scan( url ); - //} - } - - private void addExtensions( URL url ) - { - if( isDirectory( url ) ) - { - return; - } - - try - { - String[] path = urlsToStrings( new URL[]{ url } ); - final File[] extensions = getOptionalPackagesFor( path ); - for( int i = 0; i < extensions.length; i++ ) - { - File ext = extensions[ i ]; - try - { - URL target = ext.toURL(); - addLibrary( target ); - } - catch( Throwable e ) - { - final String error = - "Internal error while attempting to add optional package: " + ext; - throw new EngineRuntimeException( error, e ); - } - } - } - catch( Throwable e ) - { - final String error = - "Internal error while attempting to add extension url: " + url; - throw new EngineRuntimeException( error, e ); - } - } - - /** - * Register any components declared in the manifest. - * @param url pointing to the jar file - * @exception EngineRuntimeException if an scanning error occurs + * @param url the URL to add to the repository */ - private void scan( URL url ) throws EngineRuntimeException + public void install( URL url ) { if( isDirectory( url ) ) { @@ -521,8 +272,7 @@ getLogger().debug( "scanning: " + url ); } JarFile base = jar.getJarFile(); - loadComponents( base ); - + load( base ); } catch( IOException e ) { @@ -538,7 +288,7 @@ } } - private void loadComponents( JarFile base ) throws IOException + private void load( JarFile base ) throws IOException { List list = new ArrayList(); @@ -634,118 +384,4 @@ return name.replace( '/', '.' ); } - 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() ] ); - } - - //================================================================================ - // extension libraries - //================================================================================ - - /** - * 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 - * @exception Exception if a extension error occurs - */ - protected File[] getOptionalPackagesFor( final String[] classPath ) - throws Exception - { - if( m_manager == null ) - { - RepositoryManager parent = getParent(); - if( parent != null ) - { - if( parent instanceof DefaultRepositoryManager ) - { - return ( (DefaultRepositoryManager)parent).getOptionalPackagesFor( classPath ); - } - } - 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 EngineException( - message + ": " + element, ioe ); - } - } - } - return (Manifest[])manifests.toArray( new Manifest[ 0 ] ); - } - - RepositoryManager getParent() - { - return m_parent; - } } 1.4 +2 -2 avalon-sandbox/assembly/src/java/org/apache/avalon/assembly/engine/Engine.java Index: Engine.java =================================================================== RCS file: /home/cvs/avalon-sandbox/assembly/src/java/org/apache/avalon/assembly/engine/Engine.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- Engine.java 7 Dec 2002 09:34:28 -0000 1.3 +++ Engine.java 9 Dec 2002 03:03:47 -0000 1.4 @@ -71,7 +71,7 @@ * @author <a href="mailto:avalon-dev@jakarta.apache.org">Avalon Development Team</a> * @version $Revision$ $Date$ */ -public interface Engine extends RepositoryManager, AssemblyService +public interface Engine extends AssemblyService { /** * Creation of a new lifestyle handler. 1.3 +409 -98 avalon-sandbox/assembly/src/java/org/apache/avalon/assembly/engine/EngineClassLoader.java Index: EngineClassLoader.java =================================================================== RCS file: /home/cvs/avalon-sandbox/assembly/src/java/org/apache/avalon/assembly/engine/EngineClassLoader.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- EngineClassLoader.java 7 Dec 2002 14:00:53 -0000 1.2 +++ EngineClassLoader.java 9 Dec 2002 03:03:47 -0000 1.3 @@ -53,9 +53,22 @@ import java.io.File; import java.util.Map; import java.util.Hashtable; +import java.util.StringTokenizer; +import java.util.List; import java.net.URL; import java.net.URLClassLoader; - +import java.util.jar.Manifest; +import java.util.jar.Attributes; +import java.net.JarURLConnection; +import java.util.ArrayList; +import java.io.IOException; + +import org.apache.avalon.excalibur.extension.Extension; +import org.apache.avalon.excalibur.i18n.ResourceManager; +import org.apache.avalon.excalibur.i18n.Resources; +import org.apache.avalon.excalibur.packagemanager.OptionalPackage; +import org.apache.avalon.excalibur.packagemanager.PackageManager; +import org.apache.avalon.excalibur.packagemanager.impl.DefaultExtensionManager; import org.apache.avalon.framework.Version; import org.apache.avalon.framework.activity.Initializable; import org.apache.avalon.framework.logger.Logger; @@ -77,6 +90,8 @@ import org.apache.avalon.meta.info.ReferenceDescriptor; import org.apache.avalon.meta.info.Type; import org.apache.avalon.meta.model.Profile; +import org.apache.avalon.meta.model.LoggingDirective; +import org.apache.avalon.meta.model.Category; import org.apache.avalon.assembly.type.TypeManager; import org.apache.avalon.assembly.profile.ProfileManager; import org.apache.avalon.assembly.appliance.Appliance; @@ -94,9 +109,14 @@ import org.apache.avalon.assembly.lifestyle.LifestyleService; import org.apache.avalon.assembly.lifestyle.DefaultLifestyleService; import org.apache.avalon.assembly.lifestyle.LifestyleHandler; +import org.apache.avalon.assembly.logging.LoggingDescriptor; +import org.apache.avalon.assembly.logging.DefaultLoggingManager; import org.apache.avalon.assembly.logging.LoggingManager; +import org.apache.avalon.assembly.logging.TargetDescriptor; import org.apache.avalon.assembly.engine.model.LibraryDescriptor; import org.apache.avalon.assembly.engine.model.ClasspathDescriptor; +import org.apache.avalon.assembly.engine.model.FilesetDescriptor; +import org.apache.avalon.assembly.engine.model.IncludeDescriptor; import org.apache.excalibur.mpool.DefaultPoolManager; import org.apache.excalibur.mpool.PoolManager; import org.apache.excalibur.event.command.CommandManager; @@ -111,6 +131,13 @@ public class EngineClassLoader extends URLClassLoader implements Engine, LogEnabled, Configurable, Contextualizable, Serviceable, Initializable { //============================================================== + // static + //============================================================== + + private static final Resources REZ = + ResourceManager.getPackageResources( Engine.class ); + + //============================================================== // state //============================================================== @@ -146,7 +173,7 @@ * The repository maanger holds the service, types and profiels associated * with the class loader. */ - private RepositoryManager m_repository; + private DefaultRepositoryManager m_repository; /** * The lifestyle service. @@ -184,25 +211,34 @@ /** * Description of the extension directories. */ - private LibraryDescriptor m_extensions; + private LibraryDescriptor m_descriptor; /** - * Flag indicating if system classpath based bootstrapping should take place. + * The set of facilities. */ - private Boolean m_bootstrap = new Boolean( false ); + private Map m_facilities = new Hashtable(); /** - * The set of facilities. + * Utility class to manage packages. */ - private Map m_facilities = new Hashtable(); + private PackageManager m_packages; + + /** + * Utility class to manage extension paths. + */ + private DefaultExtensionManager m_extensions; + + /** + * Flag indicating if system classpath based bootstrapping should take place. + */ + private boolean m_bootstrap = false; //======================================================================= // constructor //======================================================================= /** - * Creation of a new type manager using the supplied parent class loader. - * @param parent the parent class loader + * Creation of a new type manager using. */ public EngineClassLoader() { @@ -232,7 +268,6 @@ return m_logger; } - //============================================================== // Configurable //============================================================== @@ -274,11 +309,11 @@ try { - m_extensions = (LibraryDescriptor)context.get( "urn:assembly:extensions.descriptor" ); + m_descriptor = (LibraryDescriptor)context.get( "urn:assembly:extensions.descriptor" ); } catch( ContextException e ) { - m_extensions = new LibraryDescriptor(); + m_descriptor = new LibraryDescriptor(); } try @@ -292,11 +327,11 @@ try { - m_bootstrap = (Boolean) context.get( "urn:assembly:engine.bootstrap" ); + m_bootstrap = "true".equals( context.get( "urn:assembly:engine.bootstrap" ) ); } - catch( ContextException e ) + catch( ContextException ce ) { - // default already set + // use default value } } @@ -353,84 +388,240 @@ { getLogger().debug( "initialization" ); } - - m_repository = createRepositoryManager(); + + createRepositoryManager(); + m_lifestyle = createLifestyleService( m_facilities ); m_appliances = createApplianceManager( m_facilities ); m_assembly = createAssemblyService( m_facilities, m_graph ); - if( getLogger().isDebugEnabled() ) + // + // install the set of extensions + // + + ArrayList list = new ArrayList(); + File anchor = new File( m_home, m_descriptor.getBaseDirectory() ); + IncludeDescriptor[] includes = m_descriptor.getIncludeDescriptors(); + for( int j = 0; j < includes.length; j++ ) { - getLogger().debug( "ready" ); + File include = new File( anchor, includes[ j ].getFile() ); + if( include.isDirectory() ) + { + list.add( include ); + getLogger().debug( "including kernel extension dir: " + include ); + } + else + { + final String error = "Invalid include directory: " + include; + throw new IllegalArgumentException( error ); + } } - } + if( m_bootstrap ) + { + String sep = System.getProperty( "path.separator" ); + String exts = System.getProperty( "java.ext.dirs" ); + StringTokenizer tokenizer = new StringTokenizer( exts, sep ); + while( tokenizer.hasMoreTokens() ) + { + String token = tokenizer.nextToken(); + File test = new File( token ); + if( test.exists() ) + { + list.add( test ); + if( getLogger().isDebugEnabled() ) + { + getLogger().debug( "including system extension dir: " + test ); + } + } + else + { + File file = new File( m_home, token ); + if( file.exists() ) + { + list.add( file ); + if( getLogger().isDebugEnabled() ) + { + getLogger().debug( "including relative extension dir: " + file ); + } + } + else + { + if( getLogger().isWarnEnabled() ) + { + final String warning = + "The extension directory path: '" + token + + "' deas not refer to a directory."; + getLogger().warn( warning ); + } + } + } + } + } - //============================================================== - // AssemblyService - //============================================================== + File[] files = (File[])list.toArray( new File[ 0 ] ); + m_extensions = new DefaultExtensionManager( files ); + m_packages = new PackageManager( m_extensions ); - /** - * Assemble the supplied appliance. - * @param appliance the object to assembly - */ - public void assemble( Appliance appliance ) throws AssemblyException - { - m_assembly.assemble( appliance ); + // + // handle the system bootstrap process + // + + if( m_bootstrap ) + { + + if( getLogger().isDebugEnabled() ) + { + getLogger().debug( "bootstraping from classpath" ); + } + + // + // handle the classpath + // + + String sep = System.getProperty( "path.separator" ); + String classpath = System.getProperty( "java.class.path" ); + + StringTokenizer tokenizer = new StringTokenizer( classpath, sep ); + while( tokenizer.hasMoreTokens() ) + { + String token = tokenizer.nextToken(); + URL url = new File( token ).toURL(); + if( getLogger().isDebugEnabled() ) + { + getLogger().debug( "path: " + url ); + } + addURL( url ); + } + } + + if( getLogger().isDebugEnabled() ) + { + getLogger().debug( "ready" ); + } } //============================================================== - // RepositoryManager + // URLClassLoader //============================================================== - /** - * Add a URL to a jar file. A repository implementation is responsible for - * the registration of any declared component services, types and packaged - * profiles. - * - * @param url a url to a jar file - */ - public void addLibrary( URL url ) + /** + * Add a URL to the classpath. + * @param url the URL to add to the classpath + */ + protected void addURL( URL url ) { - m_repository.addLibrary( url ); + addExtensions( url ); + super.addURL( url ); + m_repository.install( url ); } /** * Add a classpath to the repository. * @param base the base directory from which relative classpath entries * will be resolved. - * @param classpath the classpath descriptor */ public void addClasspath( ClasspathDescriptor classpath ) { - m_repository.addClasspath( classpath ); - } + if( classpath == null ) + { + throw new NullPointerException( "classpath" ); + } - /** - * Returns the type manager. - * @return the type manager - */ - public TypeManager getTypeManager() - { - return m_repository.getTypeManager(); + if( getLogger() == null ) + { + throw new IllegalStateException( "logging" ); + } + + if( getLogger().isDebugEnabled() ) + { + getLogger().debug( "adding classpath" ); + } + + List list = new ArrayList(); + FilesetDescriptor[] dirs = classpath.getFilesetDescriptors(); + for( int i = 0; i < dirs.length; i++ ) + { + FilesetDescriptor descriptor = dirs[ i ]; + File anchor = new File( m_home, descriptor.getBaseDirectory() ); + if( !anchor.exists() ) + { + final String error = + "Classpath base directory does not exist: " + + anchor; + throw new EngineRuntimeException( error ); + } + + IncludeDescriptor[] includes = descriptor.getIncludeDescriptors(); + for( int j = 0; j < includes.length; j++ ) + { + String inc = includes[ j ].getFile(); + try + { + addURL( new File( anchor, inc ).toURL() ); + } + catch( Throwable e ) + { + final String error = + "Error processing a classpath include: " + + inc; + throw new EngineRuntimeException( error, e ); + } + } + } + + if( getLogger().isDebugEnabled() ) + { + getLogger().debug( "classpath ok" ); + } } - /** - * Returns the service manager. - * @return the service manager - */ - public org.apache.avalon.assembly.service.ServiceManager getServiceManager() + private void addExtensions( URL url ) { - return m_repository.getServiceManager(); + if( isDirectory( url ) ) + { + return; + } + + try + { + String[] path = urlsToStrings( new URL[]{ url } ); + final File[] extensions = getOptionalPackagesFor( path ); + for( int i = 0; i < extensions.length; i++ ) + { + File ext = extensions[ i ]; + try + { + URL target = ext.toURL(); + addURL( target ); + } + catch( Throwable e ) + { + final String error = + "Internal error while attempting to add optional package: " + ext; + throw new EngineRuntimeException( error, e ); + } + } + } + catch( Throwable e ) + { + final String error = + "Internal error while attempting to add extension url: " + url; + throw new EngineRuntimeException( error, e ); + } } + //============================================================== + // AssemblyService + //============================================================== + /** - * Returns the profile manager. - * @return the profile manager + * Assemble the supplied appliance. + * @param appliance the object to assembly */ - public ProfileManager getProfileManager() + public void assemble( Appliance appliance ) throws AssemblyException { - return m_repository.getProfileManager(); + m_assembly.assemble( appliance ); } //============================================================== @@ -438,6 +629,15 @@ //============================================================== /** + * Returns the repository manager. + * @return the repository manager + */ + public RepositoryManager getRepository() + { + return m_repository; + } + + /** * Creation of a new lifestyle handler. * @param appliance the appliance that the handler will manage * @param context the system context @@ -448,20 +648,6 @@ return m_lifestyle.createHandler( appliance, this, context ); } - /** - * Add a URL to the classpath. - * @param url the URL to add to the classpath - */ - void addLibraryURL( URL url ) - { - addURL( url ); - } - - protected void addURL( URL url ) - { - super.addURL( url ); - } - /** * Register a type and associated profiles with the container. * @param path the path to the appliance implementation class @@ -474,12 +660,14 @@ getLogger().debug( "register:" + path ); } + TypeManager types = getRepository().getTypeManager(); + ProfileManager profiles = getRepository().getProfileManager(); try { - Type type = getTypeManager().createType( path ); - getTypeManager().addType( type ); - Profile[] profiles = getProfileManager().loadProfiles( type ); - getProfileManager().addProfiles( profiles ); + Type type = types.createType( path ); + types.addType( type ); + Profile[] packaged = profiles.loadProfiles( type ); + profiles.addProfiles( packaged ); } catch( Throwable e ) { @@ -510,7 +698,7 @@ Appliance appliance = m_appliances.getAppliance( dependency ); if( appliance == null ) { - Profile profile = getProfileManager().getProfile( dependency ); + Profile profile = getRepository().getProfileManager().getProfile( dependency ); if( profile == null ) { final String error = @@ -547,7 +735,7 @@ Appliance appliance = m_appliances.getAppliance( stage ); if( appliance == null ) { - Profile profile = getProfileManager().getProfile( stage ); + Profile profile = getRepository().getProfileManager().getProfile( stage ); if( profile == null ) { final String error = @@ -607,26 +795,21 @@ // utilities //============================================================== - private RepositoryManager createRepositoryManager() throws Exception + private void createRepositoryManager() throws Exception { - if( getLogger().isDebugEnabled() ) + ClassLoader parent = getParent(); + if(( parent != null ) && ( parent instanceof EngineClassLoader )) { - getLogger().debug( "creating repository manager" ); + m_repository = + new DefaultRepositoryManager( + this, ((EngineClassLoader)parent).getRepository() ); } - - DefaultRepositoryManager manager = new DefaultRepositoryManager(); - - manager.enableLogging( getLogger() ); - DefaultContext context = new DefaultContext( getSystemContext() ); - context.put( "urn:assembly:engine.classloader", this ); - context.put( "urn:assembly:libraries-descriptor", m_extensions ); - context.put( "urn:assembly:engine.bootstrap", m_bootstrap ); - context.put( "urn:avalon:home", m_home ); - context.makeReadOnly(); - manager.contextualize( context ); - manager.initialize(); - - return manager; + else + { + m_repository = new DefaultRepositoryManager( this ); + } + m_repository.enableLogging( getLogger() ); + m_repository.initialize(); } private ApplianceManager createApplianceManager( Map facilities ) @@ -809,5 +992,133 @@ "Internal error during establishment of the default pool manager."; throw new EngineRuntimeException( error, e ); } + } + + private boolean isDirectory( URL url ) + { + if( url.getProtocol().equals( "file" ) ) + { + File file = new File( url.toString().substring( 5 ) ); + return file.isDirectory(); + } + return false; + } + + private String[] urlsToStrings( URL[] urls ) + { + ArrayList list = new ArrayList(); + for( int i = 0; i < urls.length; i++ ) + { + list.add( urls[ i ].toString() ); + } + return (String[])list.toArray( new String[ list.size() ] ); + } + + //================================================================================ + // extension support + //================================================================================ + + /** + * 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 + * @exception Exception if a extension error occurs + */ + protected File[] getOptionalPackagesFor( final String[] classPath ) + throws Exception + { + if( m_packages == null ) + { + ClassLoader parent = getParent(); + if( parent != null ) + { + if( parent instanceof EngineClassLoader ) + { + return ((EngineClassLoader)parent).getOptionalPackagesFor( classPath ); + } + } + 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_packages.scanDependencies( required, available, dependencies, unsatisfied ); + + if(( 0 != unsatisfied.size() ) && ( getLogger().isWarnEnabled() )) + { + 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 EngineException( + message + ": " + element, ioe ); + } + } + } + + return (Manifest[])manifests.toArray( new Manifest[ 0 ] ); + } + + /** + * Strips the ".class" ending off of a Type/Block/Service name. + */ + private final String cleanName( String name ) + { + int end = name.indexOf( ".class" ); + return name.substring( 0, ( end >= 0 ) ? end : name.length() ); } } 1.2 +1 -19 avalon-sandbox/assembly/src/java/org/apache/avalon/assembly/engine/RepositoryManager.java Index: RepositoryManager.java =================================================================== RCS file: /home/cvs/avalon-sandbox/assembly/src/java/org/apache/avalon/assembly/engine/RepositoryManager.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- RepositoryManager.java 7 Dec 2002 09:34:28 -0000 1.1 +++ RepositoryManager.java 9 Dec 2002 03:03:47 -0000 1.2 @@ -55,7 +55,6 @@ import org.apache.avalon.assembly.profile.ProfileManager; import org.apache.avalon.assembly.service.ServiceManager; import org.apache.avalon.assembly.type.TypeManager; -import org.apache.avalon.assembly.engine.model.ClasspathDescriptor; /** * An appliance is a class that encapsulates the deployment criteria @@ -70,23 +69,6 @@ public interface RepositoryManager { - /** - * Add a URL to a jar file. A repository implementation is responsible for - * the registration of any declared component services, types and packaged - * profiles. - * - * @param url a url to a jar file - */ - void addLibrary( URL url ); - - /** - * Add a classpath to the repository. - * @param base the base directory from which relative classpath entries - * will be resolved. - * @param classpath the classpath descriptor - */ - void addClasspath( ClasspathDescriptor classpath ); - /** * Returns the type manager. * @return the type manager
-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>