package org.codehaus.mojo.appassembler.booter;
/*
* The MIT License
*
* Copyright 2005-2007 The Codehaus.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import org.codehaus.mojo.appassembler.model.ClasspathElement;
import org.codehaus.mojo.appassembler.model.Daemon;
import org.codehaus.mojo.appassembler.model.JvmSettings;
import org.codehaus.mojo.appassembler.model.io.stax.AppassemblerModelStaxReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import javax.xml.stream.XMLStreamException;
/**
* Reads the appassembler manifest file from the repo, and executes the specified main class.
*
* @author <a href="mailto:kaare.nilsen@gmail.com">Kaare Nilsen</a>
* @todo get rid of all the statics
*/
public class AppassemblerBooter
{
private static boolean debug;
private static Daemon config;
private static String mainClassName;
public static void main( String[] args )
throws Exception
{
URLClassLoader classLoader = setup();
executeMain( classLoader, args );
}
public static URLClassLoader setup()
throws IOException, XMLStreamException
{
// -----------------------------------------------------------------------
// Load and validate environmental settings
// -----------------------------------------------------------------------
String appName = System.getProperty( "app.name" );
if ( appName == null )
{
throw new RuntimeException( "Missing required system property 'app.name'." );
}
debug = Boolean.getBoolean( "app.booter.debug" );
String b = System.getProperty( "basedir" );
if ( b == null )
{
throw new RuntimeException( "Missing required system property 'basedir'." );
}
// TODO: shouldn't this be in the descriptor too?
String r = System.getProperty( "app.repo", b );
File repoDir = new File( r );
// -----------------------------------------------------------------------
// Load and validate the configuration
// -----------------------------------------------------------------------
config = loadConfig( appName );
mainClassName = config.getMainClass();
if ( isEmpty( mainClassName ) )
{
throw new RuntimeException( "Missing required property from configuration: 'mainClass'." );
}
setSystemProperties();
return createClassLoader( repoDir );
}
public static URLClassLoader createClassLoader( File repoDir )
throws MalformedURLException
{
List classpathUrls = new ArrayList();
List classPathElements = config.getAllClasspathElements();
Iterator iter = classPathElements.iterator();
while ( iter.hasNext() )
{
ClasspathElement element = (ClasspathElement) iter.next();
File artifact = new File( repoDir, element.getRelativePath() );
if ( debug )
{
System.err.println( "Adding file to classpath: " + artifact.getAbsolutePath() );
}
classpathUrls.add( artifact.toURL() );
}
URL[] urls = (URL[]) classpathUrls.toArray( new URL[classpathUrls.size()] );
return new URLClassLoader( urls, ClassLoader.getSystemClassLoader() );
}
/**
* Pass any given system properties to the java system properties.
*/
public static void setSystemProperties()
{
JvmSettings jvmSettings = config.getJvmSettings();
if ( jvmSettings != null && jvmSettings.getSystemProperties() != null )
{
List systemProperties = jvmSettings.getSystemProperties();
for ( Iterator i = systemProperties.iterator(); i.hasNext(); )
{
String line = (String) i.next();
try
{
String[] strings = line.split( "=" );
String key = strings[0];
String value = strings[1];
if ( debug )
{
System.err.println( "Setting system property '" + key + "' to '" + value + "'." );
}
System.setProperty( key, value );
}
catch ( Throwable e )
{
if ( debug )
{
System.err.println( "Error Setting system property with value '" + line + "'." );
}
}
}
}
}
private static Daemon loadConfig( String appName )
throws IOException, XMLStreamException
{
String resourceName = "/" + appName + ".xml";
InputStream resource = AppassemblerBooter.class.getResourceAsStream( resourceName );
if ( debug )
{
System.err.println( "Loading configuration file from: " + resourceName );
}
if ( resource == null )
{
throw new RuntimeException( "Could not load configuration resource: '" + resourceName + "'." );
}
try
{
AppassemblerModelStaxReader reader = new AppassemblerModelStaxReader();
return reader.read( new InputStreamReader( resource ) );
}
finally
{
resource.close();
}
}
public static void executeMain( URLClassLoader classLoader, String[] args )
throws Exception
{
List arguments = config.getCommandLineArguments();
// -----------------------------------------------------------------------
// Load the class and main() method
// -----------------------------------------------------------------------
// This will always return an instance or throw an exception
Class mainClass = classLoader.loadClass( mainClassName );
Method main = mainClass.getMethod( "main", new Class[] { String[].class } );
if ( arguments == null )
{
arguments = Arrays.asList( args );
}
else
{
arguments.addAll( Arrays.asList( args ) );
}
String[] commandLineArgs = (String[]) arguments.toArray( new String[0] );
// -----------------------------------------------------------------------
// Setup environment
// -----------------------------------------------------------------------
Thread.currentThread().setContextClassLoader( classLoader );
// -----------------------------------------------------------------------
//
// -----------------------------------------------------------------------
main.invoke( null, new Object[] { commandLineArgs } );
}
// -----------------------------------------------------------------------
// Utils
// -----------------------------------------------------------------------
private static boolean isEmpty( String mainClass )
{
return mainClass == null || mainClass.trim().length() == 0;
}
}