All Downloads are FREE. Search and download functionalities are using the official Maven repository.

uk.org.retep.kernel.Bootstrap Maven / Gradle / Ivy

/*
 * 

Copyright (c) 1998-2008, Peter T Mount
* All rights reserved.

* *

Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met:

* *
    *
  • Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer.
  • * *
  • Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution.
  • * *
  • Neither the name of the retep.org.uk nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission.
  • * *
* *

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

*/ package uk.org.retep.kernel; // Implementation note: this class cannot access anything outside of what is // available to just the JVM... import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; 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.Collections; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Properties; import java.util.concurrent.Semaphore; /** * This class runs before the Kernel. It configures core system features like * Log4J, and the relevant ClassLoaders * @author peter */ public class Bootstrap { private static final Bootstrap instance = new Bootstrap(); private List arguments = new ArrayList(); private String applicationName; private Thread bootStrapThread; private File libDir; private File appDir; private File homeDir; private File etcDir; private File data1Dir; private File data2Dir; private ClassLoader kernelLoader; private ClassLoader appLoader; private Class kernelClass; private Object kernel; private Semaphore semaphore; public static Bootstrap getInstance() { return instance; } private Bootstrap() { } public String getApplicationName() { return applicationName; } public void setApplicationName( final String applicationName ) { this.applicationName = applicationName; // On Linux and Darwin, applicationName is just that, but on Win32 // when run from inside Cygwin it's the full path to the .exe so // we have to do an inline StringUtils.basename() in that case if( File.separatorChar == '\\' ) { final int i = applicationName.lastIndexOf( '\\' ); if( i > -1 ) { this.applicationName = applicationName.substring( i + 1 ); } } } private URL getJarURL( Class clazz ) throws MalformedURLException { URL classURL = clazz.getResource( clazz.getSimpleName() + ".class" ); if( classURL == null ) { return null; } String path = classURL.toString(); int i = path.indexOf( '!' ); if( i > -1 ) { path = path.substring( 0, i ); } if( path.startsWith( "jar:" ) ) { path = path.substring( 4 ); } return new URL( path ); } private File getJarFile( Class clazz ) { try { URL jarURL = getJarURL( clazz ); if( jarURL != null ) { return new File( jarURL.getPath() ).getAbsoluteFile(); } return null; } catch( MalformedURLException ex ) { ex.printStackTrace(); return null; } } public void bootstrap() { try { final long startTime = System.currentTimeMillis(); final Date applicationStartDate = new Date( startTime ); if( bootStrapThread == null ) { bootStrapThread = Thread.currentThread(); } else { throw new SecurityException( "Only the BootStrap Thread may call this method" ); } // Where the core jar is located homeDir = getJarFile( getClass() ).getParentFile().getParentFile(); libDir = new File( homeDir, "lib" ); appDir = new File( libDir, applicationName ); etcDir = new File( homeDir, "etc" ); data1Dir = new File( homeDir, "data" ); data2Dir = new File( data1Dir, applicationName ); data1Dir = new File( data1Dir, "common" ); // Create the Kernel ClassLoader kernelLoader = createClassLoader( libDir, null ); // Now the application ClassLoader appLoader = createClassLoader( appDir, kernelLoader ); // Terracotta classloader support final boolean terracottaPresent = TerracottaSupport.terracottaPresent(); if( terracottaPresent ) { TerracottaSupport.initClassLoader( kernelLoader, "kernel" ); TerracottaSupport.initClassLoader( appLoader, applicationName ); } // Create the Kernel using the application's ClassLoader kernelClass = kernelLoader.loadClass( "uk.org.retep.kernel.Kernel" ); kernel = kernelClass.getMethod( "getInstance" ).invoke( null ); // inject various parameters inject( "bootStrapThread", bootStrapThread ); inject( "applicationName", applicationName ); inject( "applicationStartDate", applicationStartDate ); inject( "kernelClassLoader", kernelLoader ); inject( "applicationClassLoader", appLoader ); inject( "homeDirectory", homeDir ); inject( "configDirectory", etcDir ); inject( "arguments", Collections.unmodifiableList( arguments ) ); inject( "dataDirectory", data2Dir.exists() ? data2Dir : data1Dir ); // Load build time configuration final Properties props = getProperties(); inject( "kernelVersion", props.getProperty( "kernel.version" ) ); // Set the GlobalThreadPool to run with the appLoader final Class globalThreadPool = kernelLoader.loadClass( "uk.org.retep.util.thread.GlobalThreadPool" ); final Method setContextClassLoader = globalThreadPool.getMethod( "setContextClassLoader", ClassLoader.class ); setContextClassLoader.invoke( null, appLoader ); // Semaphore used to terminate the main thread semaphore = new Semaphore( 0 ); inject( "bootstrapSemaphore", semaphore ); // Start the kernel final Method bootstrap = kernelClass.getDeclaredMethod( "bootstrap" ); bootstrap.setAccessible( true ); bootstrap.invoke( kernel ); // Now wait on the semaphore semaphore.acquire(); } catch( Throwable t ) { if( t instanceof InvocationTargetException ) { t = t.getCause(); } // Some voodo, remove all traces of Reflection, hiding how the bootstrap works Throwable t1 = t; while( t1 != null ) { final List ste = Arrays.asList( t1.getStackTrace() ); final Iterator it = ste.iterator(); while( it.hasNext() ) { final StackTraceElement s = it.next(); if( s.getClassName().contains( "reflect" ) ) { try { it.remove(); } catch( UnsupportedOperationException uoe ) { // Ignore } } } t1.setStackTrace( ste.toArray( new StackTraceElement[ ste.size() ] ) ); t1 = t.getCause(); } t.printStackTrace(); System.exit( 1 ); } } private Properties getProperties() throws IOException { final InputStream is = getClass().getResourceAsStream( "bootstrap.properties" ); try { final Properties props = new Properties(); props.load( is ); return props; } finally { is.close(); } } private ClassLoader createClassLoader( final File dir, final ClassLoader parent ) throws MalformedURLException { // Get a list of files final File[] files = dir.listFiles( new FileFilter() { @Override public boolean accept( final File file ) { final String name = file.getName(); return file.isFile() && name.endsWith( ".jar" ); } } ); final URL urls[] = new URL[ files.length ]; for( int i = 0; i < files.length; i++ ) { urls[i] = files[i].toURI().toURL(); } if( parent == null ) { return new URLClassLoader( urls ); } else { return new URLClassLoader( urls, parent ); } } private void inject( final String field, final Object value ) { try { final Field f = kernelClass.getDeclaredField( field ); f.setAccessible( true ); f.set( kernel, value ); } catch( Exception ex ) { throw new RuntimeException( "Failed to inject " + field, ex ); } } /** * Used by JNI to add a command line argument * @param arg command line argument */ public void addArgument( final String arg ) { arguments.add( arg ); } /** * Proxy isRestart() to the kernel instance. This is called by JNI * @return */ public boolean isRestart() { if( kernel == null ) { return false; } try { return (Boolean) kernel.getClass().getMethod( "isRestart" ).invoke( kernel ); } catch( Exception ex ) { return false; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy