mcconnell 2003/02/16 05:02:02 Modified: merlin-bootstrap/src/java Merlin.java Resources.properties Log: Optimization of the kernel/block seperation and enhanced command line management. Revision Changes Path 1.2 +299 -81 avalon-sandbox/merlin-bootstrap/src/java/Merlin.java Index: Merlin.java =================================================================== RCS file: /home/cvs/avalon-sandbox/merlin-bootstrap/src/java/Merlin.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- Merlin.java 12 Feb 2003 11:51:18 -0000 1.1 +++ Merlin.java 16 Feb 2003 13:02:02 -0000 1.2 @@ -57,6 +57,8 @@ import java.util.Date; import java.util.List; import java.util.ArrayList; +import java.util.Map; +import java.util.Hashtable; import java.util.Locale; import java.net.URL; import java.net.URLClassLoader; @@ -84,9 +86,9 @@ // static //-------------------------------------------------------------------------- - private static final String PRODUCT = "Merlin"; + private static final String PRODUCT = "Merlin CLI"; - private static final String VERSION = "2.1"; + private static final String VERSION = "1.0"; private static final File HOME = new File( System.getProperty( "user.dir" ) ); @@ -139,18 +141,32 @@ .withDescription( I18N.getString( "cli-system-description" ) ) .create( "system" ); - Option profile = OptionBuilder + Option block = OptionBuilder .hasArg() .withArgName( I18N.getString( "file" ) ) - .withDescription( I18N.getString( "cli-profile-description" ) ) - .create( "profile" ); + .withDescription( I18N.getString( "cli-block-description" ) ) + .create( "block" ); + + Option config = OptionBuilder + .hasArg() + .withArgName( I18N.getString( "file" ) ) + .withDescription( I18N.getString( "cli-config-description" ) ) + .create( "config" ); + + Option kernel = OptionBuilder + .hasArg() + .withArgName( I18N.getString( "file" ) ) + .withDescription( I18N.getString( "cli-kernel-description" ) ) + .create( "kernel" ); options.addOption( help ); options.addOption( version ); options.addOption( debug ); options.addOption( system ); options.addOption( home ); - options.addOption( profile ); + options.addOption( block ); + options.addOption( config ); + options.addOption( kernel ); options.addOption( locale ); return options; @@ -172,6 +188,8 @@ */ public static void main( String[] args ) { + Map map = new Hashtable(); + CommandLineParser parser = new BasicParser(); try { @@ -199,95 +217,116 @@ return; } + if( !line.hasOption( "block" ) ) + { + doHelp(); + return; + } + + boolean debug = line.hasOption( "debug" ); + // - // it's this is a genuine deployment scenario - we need to resolve + // this is a genuine deployment scenario - we need to resolve // the home and system directories, and the filename of the kernel - // profile we are using + // and block profiles we are using // - File home = getHomePath( line ); - File system = getSystemPath( line ); - File profile = getProfile( home, line ); + // + // the the system directory that we use internally to build the + // classloaders + File system = getSystemPath( line ); - if( !profile.exists() ) - { - File base = profile.getParentFile(); - if( !base.exists() ) - { - final String error = - "Deployment path directory does not exist.\ndirectory: " + base; - throw new IllegalArgumentException( error ); - } - else - { - final String error = - "Deployment profile does not exist\nfile: " + profile; - throw new IllegalArgumentException( error ); - } - } + // + // the working home directory + File home = getHomePath( system, line ); - if( !system.exists() ) + // + // the actual block base URL + File base = getBlockPath( system, home, line ); + + URL block = null; + if( base.toString().endsWith(".jar") ) { - final String error = - "System directory does not exist.\ndirectory: " + system; - throw new IllegalArgumentException( error ); + block = new URL( "jar:" + base.toURL() + "!/" ); } - - if( !home.exists() ) + else { - final String error = - "Home directory does not exist.\ndirectory: " + home; - throw new IllegalArgumentException( error ); + block = base.toURL(); } // - // if we get this far we have a valid system, home and profile - // so we can not go ahead with bootstrap classpath construction + // an optional configuration override + File config = getConfigPath( base, line ); + + // + // the kernel configuration (used by the kernel loader) + File kernel = getKernelPath( system, line ); + + // + // build the classloaders // - BASE = home; - PROFILE = profile; - boolean debug = line.hasOption( "debug" ); + File lib = new File( system, "lib" ); + File shared = new File( lib, "shared" ); + File sys = new File( lib, "system" ); + URL[] targets = getJarFiles( shared ); + URL[] libs = getJarFiles( sys, targets ); + ClassLoader current = Thread.currentThread().getContextClassLoader(); + COMMON = new URLClassLoader( targets, current ); + CLASSLOADER = new URLClassLoader( libs, current ); + + // + // build the kernel loader context + // + + map.put( "urn:merlin:classloader.common", COMMON ); + map.put( "urn:merlin:classloader.system", CLASSLOADER); + map.put( "urn:merlin:home", home ); + map.put( "urn:merlin:kernel.profile", kernel ); + map.put( "urn:merlin:block.url", block ); if( debug ) { - System.out.println( "\n " + getVersionString() ); - System.out.println( " " + new Date() ); - System.out.println( "\n urn:merlin:system.dir: " + system ); - System.out.println( " urn:merlin:system.profile: " + profile ); - System.out.println( " urn:merlin:home.dir: " + home ); + map.put( "urn:merlin:debug", "debug" ); } + if( config != null ) + { + map.put( "urn:merlin:block.config", config.toURL() ); + } + + // + // if the -debug switch is on then dump the context information + // that we will supply to the kernel loader + // - File common = new File( system, "common" ); - URL[] targets = getJarFiles( common ); - COMMON = new URLClassLoader( targets ); if( debug ) { + System.out.println( "\n " + getVersionString() ); + System.out.println( " " + new Date() + "\n" ); + System.out.println( " urn:merlin:system.dir: " + system ); + System.out.println( " urn:merlin:kernel.profile: " + kernel ); + + System.out.println( " urn:merlin:block.url: " + block ); + if( config != null ) + { + System.out.println( " urn:merlin:block.config: " + config.toURL() ); + } + System.out.println( " urn:merlin:home: " + home ); + System.out.println( "\n " ); + System.out.println( "\n shared libraries:\n" ); - for( int i=0; i<targets.length; i++ ) + URL[] list = COMMON.getURLs(); + for( int i=0; i<list.length; i++ ) { - System.out.println(" " + targets[i] ); + System.out.println(" " + list[i] ); } - } - - File lib = new File( system, "lib" ); - URL[] libs = getJarFiles( lib ); - CLASSLOADER = new URLClassLoader( libs, COMMON ); - if( debug ) - { System.out.println( "\n system libraries:\n" ); - for( int i=0; i<libs.length; i++ ) + list = CLASSLOADER.getURLs(); + for( int i=0; i<list.length; i++ ) { - System.out.println(" " + libs[i] ); + System.out.println(" " + list[i] ); } - } - - if( debug ) - { System.out.println( "\n" ); } - - Thread.currentThread().setContextClassLoader( CLASSLOADER ); - } catch( ParseException e ) { @@ -313,7 +352,20 @@ System.err.println( error ); return; } + catch( Throwable e ) + { + final String error = "\n" + e.toString(); + System.err.println( error ); + e.printStackTrace(); + return; + } + + // + // if we get this far we have a valid system, home and profile + // so we can not go ahead with bootstrap classpath construction + // + Thread.currentThread().setContextClassLoader( CLASSLOADER ); Object kernelLoader = null; Class clazz; try @@ -330,8 +382,8 @@ try { Constructor constructor = clazz.getConstructor( - new Class[]{ClassLoader.class, ClassLoader.class, File.class, File.class } ); - kernelLoader = constructor.newInstance( new Object[]{ CLASSLOADER, COMMON, BASE, PROFILE } ); + new Class[]{ Map.class } ); + kernelLoader = constructor.newInstance( new Object[]{ map } ); } catch( Throwable e ) { @@ -353,6 +405,162 @@ formatter.printHelp( "merlin", CL_OPTIONS ); } + private static File getConfigPath( File block, CommandLine command ) throws IOException + { + String filename = null; + final String key = "config"; + if( command.hasOption( key ) ) + { + filename = command.getOptionValue( key ); + } + else + { + filename = "config.xml"; + } + File file = getFile( HOME, filename ); + if( file.exists() ) + { + return file; + } + else + { + File info = new File( block, "block-inf" ); + File config = new File( info, "config.xml" ); + if( config.exists() ) + { + return config; + } + else + { + return null; + } + } + } + + private static File getKernelPath( File system, CommandLine command ) throws IOException + { + String filename = null; + final String key = "kernel"; + if( command.hasOption( key ) ) + { + filename = command.getOptionValue( key ); + File file = getFile( HOME, filename ); + if( file.exists() ) + { + return file; + } + else + { + final String error = + "Supplied kernel configuration file does not exist: " + + file; + throw new IOException( error ); + } + } + else + { + File conf = new File( system, "config" ); + File kernel = new File( conf, "kernel.xml" ); + if( !kernel.exists() ) + { + final String error = + "Could not locate the kernel configuration ${merlin.kernel}/config/kernel.xml"; + throw new IOException( error ); + } + else + { + return kernel; + } + } + } + + private static File getBlockPath( File system, File home, CommandLine command ) throws IOException + { + boolean flag = false; + String filename = null; + final String key = "block"; + if( command.hasOption( key ) ) + { + filename = command.getOptionValue( key ); + } + else + { + // check if there is a file in the current directory called block.xml + // and if so, we will use that as the deployment scanario + + filename = "block.xml"; + File local = getFile( HOME, "block.xml" ); + if( local.exists() ) + { + // + // the current directory is equivalent to the info directory + // so the base directory is the parent of the current directory + + return local.getParentFile(); + } + } + + // + // if the filename is a jar file then return the filename as a URL + // + + boolean resolved = false; + File file = getFile( HOME, filename ); + if( file.exists() ) + { + return file; + } + + /* + if( file.exists() ) + { + if( file.isDirectory() ) + { + // + // this is a simulated block - makle sure the structure is valid + // before return the URL + // + + File info = new File( file, "block-inf" ); + if( info.isDirectory() ) + { + // check for the block.xml file + + File block = new File( info, "block.xml" ); + if( block.exists() ) + { + // its a good reference + return file; + } + else + { + final String error = + "Invalid block simulation - the supplied directory '" + + file + "' does not contain a 'block-inf/block.xml' defintion."; + throw new IllegalArgumentException( error ); + } + + } + else + { + final String error = + "Invalid block simulation - the supplied directory '" + + file + "' does not contain a 'block-inf' subdirectory."; + throw new IllegalArgumentException( error ); + } + } + else + { + // its an existing file + return file; + } + } + */ + final String error = + "Unable to locate a block defintion relative to the paths: " + file; + throw new IllegalArgumentException( error ); + } + private static File getProfile( File home, CommandLine command ) throws IOException { boolean flag = false; @@ -386,7 +594,16 @@ } } - private static File getHomePath( CommandLine command ) throws IOException + /** + * Return the directory to be used as the working home directory. If not command line + * argument is supplied, the home directory defaults to ${merlin.system.dir}/home. + * + * @param system the fallback system directory + * @param command the command line arguments + * @return the home directory + * @exception IOException if an error occurs in directory resolution + */ + private static File getHomePath( File system, CommandLine command ) throws IOException { String path = null; File file = null; @@ -394,13 +611,12 @@ if( command.hasOption( key ) ) { path = command.getOptionValue( key ); - file = getFile( HOME, path ); + return getFile( HOME, path ); } else { - file = HOME; + return system; } - return file; } private static File getSystemPath( CommandLine command ) throws IOException @@ -418,13 +634,6 @@ "Supplied system path does not refer to a directory: " + file; throw new IllegalArgumentException( error ); } - File common = new File( file, "common" ); - if( !common.exists() ) - { - final String error = - "Supplied system path does not contain a 'common' subdirectory: " + file; - throw new IllegalArgumentException( error ); - } File lib = new File( file, "lib" ); if( !lib.exists() ) { @@ -483,7 +692,16 @@ private static URL[] getJarFiles( File base ) { + return getJarFiles( base, new URL[0] ); + } + + private static URL[] getJarFiles( File base, URL[] urls ) + { List list = new ArrayList(); + for( int i=0; i<urls.length; i++ ) + { + list.add( urls[i] ); + } populateJars( list, base ); return (URL[]) list.toArray( new URL[0] ); } @@ -505,7 +723,7 @@ catch( Throwable e ) { final String error = - "Unexpected error while scanning files in common directory: " + base; + "Unexpected error while scanning files in shared directory: " + base; throw new RuntimeException( error, e ); } } 1.2 +14 -2 avalon-sandbox/merlin-bootstrap/src/java/Resources.properties Index: Resources.properties =================================================================== RCS file: /home/cvs/avalon-sandbox/merlin-bootstrap/src/java/Resources.properties,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- Resources.properties 12 Feb 2003 11:51:18 -0000 1.1 +++ Resources.properties 16 Feb 2003 13:02:02 -0000 1.2 @@ -1,12 +1,24 @@ directory=directory + file=file cli-help-description=Prints this message. + cli-language-description=A two-letter language code. -cli-version-description=Prints the Merlin system version number. + +cli-version-description=Prints Merlin version information. + cli-debug-description=Enable debug messages during the bootstrap phase. + cli-home-description=A relative or absolute path to a working home directory. If not suppled, the system will default to the current directory. If the resolved home path does not exist it will be created. + +cli-kernel-description=The filename of the kernel configuration. The value defaults to the system kernel.xml file. + +cli-block-description=An absolute or relative filename of a block descriptor or block jar file (required). + +cli-config-description=The filename of the block configuration. If not specified the value defaults to a file name config.xml in the same directory as the block. + cli-system-description=An absolute or relative path to the directory containining the /common and /lib system directories. If not supplied the default value shall correspond to the value System "user.work". A relative path name will be resolved relative the System "user.work" directory. -cli-profile-description=An absolute or relative filename of a configuration containing the kernel and block deployment information. If the supplied filename is relative it will resolved relative to the home directory. If not supplied, the system will attempt to locate a file named "profile.xml" in the home directory. +
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]