Package net.sourceforge.javautil.classloader.boot

Source Code of net.sourceforge.javautil.classloader.boot.EntryPoint$ExitPoint

package net.sourceforge.javautil.classloader.boot;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.lang.Thread.UncaughtExceptionHandler;
import java.net.URL;
import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.ServiceLoader;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
import java.util.logging.LogManager;

import net.sourceforge.javautil.classloader.boot.IEntryPointType.TargetType;
import net.sourceforge.javautil.classloader.impl.ClassContext;
import net.sourceforge.javautil.classloader.impl.StandardClassLoaderHeiarchy;
import net.sourceforge.javautil.classloader.impl.maven.MavenEntryPoint;
import net.sourceforge.javautil.classloader.source.ClassSource;
import net.sourceforge.javautil.classloader.source.CompositeClassSource;
import net.sourceforge.javautil.classloader.source.LibDirectoryClassSource;
import net.sourceforge.javautil.classloader.source.VirtualDirectoryClassSource;
import net.sourceforge.javautil.classloader.source.ZipClassSource;
import net.sourceforge.javautil.common.CollectionUtil;
import net.sourceforge.javautil.common.ReflectionUtil;
import net.sourceforge.javautil.common.ThrowableUtil;
import net.sourceforge.javautil.common.URLStreamHandlerFactoryComposite;
import net.sourceforge.javautil.common.classloader.ClassLoaderResource;
import net.sourceforge.javautil.common.classloader.ClassLoaderScanner;
import net.sourceforge.javautil.common.classloader.IResourceObjectFactory;
import net.sourceforge.javautil.common.exception.ThrowableManagerRegistry;
import net.sourceforge.javautil.common.io.InputStreamRegistry;
import net.sourceforge.javautil.common.io.OutputStreamRegistry;
import net.sourceforge.javautil.common.io.impl.SystemDirectory;
import net.sourceforge.javautil.common.logging.LoggingContext;
import net.sourceforge.javautil.common.logging.jdk.LoggingFrameworkJDK;
import net.sourceforge.javautil.common.reflection.cache.ClassCache;
import net.sourceforge.javautil.common.reflection.cache.ClassDescriptor;
import net.sourceforge.javautil.common.shutdown.Shutdown;
import net.sourceforge.javautil.common.shutdown.IShutdownHandler;
import net.sourceforge.javautil.common.shutdown.IShutdownHook;

/**
* The entry point (boot strapper) which will setup a class loader for applications.<br/><br/>
*
* You can specify the following java system properties:<br/>
* <b><code> -D{@link #MAIN_OUTPUT}=[true|false]</code></b><br/>
* If true (by default) it will make sure that the standard System.out
* and System.err continue to receive the output as normal, otherwise
* they will simply be redirected, allowing runtime intervention and
* enabling/disabling.<br/><br/>
*
* <b><code> -D{@link #MAIN_INPUT}=[true|false]</code></b><br/>
* If true (by default) it will make sure that the standard System.in
* continues to receive the input as normal, otherwise they will simply be
* redirected, allowing runtime intervention and enabling/disabling.<br/><br/>
*
* <b><code> -D{@link #MAIN_TYPE_PROPERTY}=[type class name|abbreviation]</code></b><br/>
* This tells the system to use a particular entry point type. For instance
* you can specify <code>net.sourceforge.javautil.classloader.impl.maven.MavenEntryPoint</code>
* which will make the startup use the pom.xml of the current directory
* to load an application. See {@link MavenEntryPoint} for details on maven
* specific properties.<br/><br/>
*
* <b><code> -D{@link #MAIN_CLASS_PROPERTY}=[main class]</code></b><br/>
* This tells the system which main class to use once the class loader has been
* configured, and will be passed to the {@link IEntryPointType} used.<br/><br/>
*
* <b>Standard Entry Point Type</b><br/>
* When not specifying the {@value #MAIN_TYPE_PROPERTY}, the standard type will be
* used. The standard entry point will attempt to load an internal jar packaged with
* the main jar.<br/><br/>
*
* The following parameter(s) can be used in connection with it:<br/><br/>
* <b><code> -D{value #MAIN_JAR_PROPERTY}=[jar path]</code></b><br/>
* A jar (when no internal jar is packaged) that should be loaded in order to load application level classes.
* This can be helpful when running the application in an IDE environment in which you have not yet
* packaged/jarred your application.<br/><br/>
*
* The following parameter can be used to have the entry point set the {@link URLStreamHandlerFactoryComposite} for runtime registration:<br/><br/>
* <b><code> -D{@link #MAIN_URLSFOVERRIDE}=[true|false]</code></b><br/>
* Since the standard {@link URL} class only allows one stream handler factory to be registered
* it must be specified early on in order to allow override of the original/default factory. If not false
* the composite will be set and it can be used in order to register more factories at runtime.<br/><br/>
* The following parameter can be used in connection with the previous one in order to setup a default {@link URLStreamHandlerFactory}:<br/><br/>
* <b><code> -D{@link #MAIN_URLSFCLASS}=[class name]</code></b><br/>
* The previous setting must be enabled in order for this one to work. {@link IEntryPointType}'s will be responsible for
* registering the specified class with the {@link URLStreamHandlerFactoryComposite}.<br/><br/>
*
* @author elponderador
* @author $Author: ponderator $
* @version $Id: EntryPoint.java 2709 2010-12-31 00:46:45Z ponderator $
*
* @see IEntryPointType
* @see EntryPointConfiguration
*/
public class EntryPoint extends EntryPointTypeAbstract implements IEntryPointType, UncaughtExceptionHandler, IResourceObjectFactory<IEntryPointType> {
 
  /**
   * The library directories settings for specifying library directories.<br/><br/>
   *
   * A semi-colon (;) separated list of optionally recursive directories containing jars/java archives
   */
  public static final String LIBDIRS_PROPERTY = "net.sf.javautil.libdirs";
 
  public static final String MAIN_JAR_PROPERTY = "net.sf.javautil.jar";
  public static final String MAIN_CLASS_PROPERTY = "net.sf.javautil.main";
  public static final String MAIN_TYPE_PROPERTY = "net.sf.javautil.type";
  public static final String MAIN_LOG_CONFIGDIR = "net.sf.javautil.logconfigdir";
 
  public static final String MAIN_OUTPUT = "net.sf.javautil.output.standard";
  public static final String MAIN_INPUT = "net.sf.javautil.input.standard";
 
  public static final String MAIN_URLSFOVERRIDE = "net.sf.javautil.urlsf.override";
  public static final String MAIN_URLSFCLASS = "net.sf.javautil.urlsf.default";
 
  public static final String VERSION = EntryPoint.class.getPackage().getSpecificationVersion();
 
  /**
   * @return A routed input stream if an {@link EntryPoint} was used for this thread, otherwise the standard {@link System#in}
   */
  public static InputStream getStandardInputStream () {
    IEntryPointType ep = EntryPoint.getEntryPointType();
    if (ep != null && ep.getEntryPoint().inputRegistry != null) {
      return ep.getEntryPoint().getInputRegistry();
    }
    return System.in;
  }
 
  /**
   * @return A routed system.out stream from the registry if an {@link EntryPoint} was used for this thread, otherwise the standard {@link System#out}
   */
  public static PrintStream getStandardOutputStream () {
    IEntryPointType ep = EntryPoint.getEntryPointType();
    if (ep != null && ep.getEntryPoint().outputRegistry != null) {
      return new PrintStream( ep.getEntryPoint().getOutputRegistry().getStream("System.out", true) );
    }
    return System.out;
  }

  /**
   * @return A routed system.err stream from the registry if an {@link EntryPoint} was used for this thread, otherwise the standard {@link System#err}
   */
  public static PrintStream getStandardErrorStream () {
    IEntryPointType ep = EntryPoint.getEntryPointType();
    if (ep != null && ep.getEntryPoint().outputRegistry != null) {
      return new PrintStream( ep.getEntryPoint().getOutputRegistry().getStream("System.err", true) );
    }
    return System.err;
  }
 
  /**
   * The main entry point
   */
  private static IEntryPointType main;
 
  /**
   * Thread locals of the entry points for boot strapping
   */
  private static ThreadLocal<IEntryPointType> entryPoints = new ThreadLocal<IEntryPointType>();
 
  /**
   * @return The entry point used in the main thread, or null if {@link EntryPoint} was not used for the main thread bootstrapping
   */
  public static IEntryPointType getMainEntryPointType () { return main; }
 
  /**
   * @return The entry point for the current thread, the {@link #main} entry point, or null if the current thread or the
   * main thread did not use {@link EntryPoint} for boot strapping
   */
  public static IEntryPointType getEntryPointType () { return entryPoints.get() == null ? main : entryPoints.get(); }
 
  /**
   * @param hook The hook to be called when the entry point returned by {@link #getEntryPointType()} exits
   */
  public static void registerExitHook (IExitPointHook hook) { getEntryPointType().registerExitPointHook(hook); }
 
  /**
   * @param hook The hook no longer to be called when the entry point returned by {@link #getEntryPointType()} exits
   */
  public static void unregisterExitHook (IExitPointHook hook) { getEntryPointType().unregisterExitPointHook(hook); }
 
  /**
   * This should only be called once during the lifecycle of a JVM. It will create
   * an {@link EntryPoint} which will handle the startup of an application class loader.
   *
   * @param args The arguments from the command line
   * @throws Exception
   */
  public static void main (String[] args) throws Throwable { new EntryPoint(args).boot(); }
 
  /**
   * Print a help message to {@link System#err}, then exit the JVM.
   *
   * @param error The error message to display
   */
  protected static void printHelp (String error) {
    System.err.println(error);
    System.err.println();
    System.exit(-1);
  }
 
  private final String[] originalArguments;
 
  private final PrintStream originalOut;
  private final PrintStream originalErr;
 
  private final InputStream originalIn;
 
  private boolean loggingSetup = false;
 
  private final OutputStreamRegistry outputRegistry;
  private final InputStreamRegistry inputRegistry;
 
  private URLStreamHandlerFactoryComposite urlsfOverride;
 
  /**
   * @return The number of arguments available via {@link #getOriginalArgument(int)}
   */
  public int getOriginalArgumentCount() { return originalArguments.length; }
 
  /**
   * @param idx The index of the corresponding argument
   * @return The corresponding argument value
   *
   * @see #getOriginalArgumentCount()
   */
  public String getOriginalArgument (int idx) { return originalArguments[idx]; }

  /**
   * @return The standard output when this entry point was created
   */
  public PrintStream getOriginalOut() { return originalOut; }

  /**
   * @return The standard error output when this entry point was created
   */
  public PrintStream getOriginalErr() { return originalErr; }
  /**
   * @return The standard input when this entry point was created
   */
  public InputStream getOriginalIn() { return originalIn; }

  /**
   * There will be two standard streams registered, System.out and System.err
   *
   * @return The output regisry for the entry point
   */
  public OutputStreamRegistry getOutputRegistry() { return outputRegistry; }

  /**
   * @return The input regitry for the entry point
   */
  protected InputStreamRegistry getInputRegistry() { return inputRegistry; }

  /**
   * @return True if the default {@link URLStreamHandlerFactory} has been overriden with {@link URLStreamHandlerFactoryComposite}, otherwise false
   */
  public boolean isUrlsfOverride() { return urlsfOverride != null; }
 
  /**
   * If {@link #isUrlsfOverride()} returns true then this method can be used to register a {@link URLStreamHandlerFactory}
   * with the composite override, otherwise it will throw a {@link IllegalStateException}.
   *
   * @param factory The factory to register
   */
  public void registerURLStreamHandlerFactory (URLStreamHandlerFactory factory) {
    if (this.urlsfOverride == null) throw new IllegalStateException("The default stream handler factory was not overriden, registry disabled");
   
    this.urlsfOverride.factories.add(factory);
  }
 
  /**
   * If {@link #isUrlsfOverride()} returns true then this can be used to map a protocol to a {@link URLStreamHandler}
   * otherwise it will throw an {@link IllegalStateException}.
   *
   * @param protocol The protocol to map the handler to
   * @param handler The handler to map to the protocol
   * @param override True if any existing protocol handler should be overridden, otherwise false
   */
  public void registerURLStreamHandler (String protocol, URLStreamHandler handler, boolean override) {
    if (this.urlsfOverride == null) throw new IllegalStateException("The default stream handler factory was not overriden, registry disabled");
   
    if (!this.urlsfOverride.handlers.containsKey(protocol) || override)
      this.urlsfOverride.handlers.put(protocol, handler);
  }

  /**
   * This can only be instantiated once per thread. You can instantiate in different threads to
   * setup different applications using this same technique inside the same JVM.<br/><br/>
   *
   * @param args The 'command line' arguments to pass to the application.
   */
  private EntryPoint (String[] args) {
    super(null, new EntryPointSettings());
   
    Thread.currentThread().setUncaughtExceptionHandler(this);
   
    if (entryPoints.get() != null)
      throw new UnsupportedOperationException("An application has already been started for this thread: " + Thread.currentThread().getName());

    originalIn = System.in;
    originalOut = System.out;
    originalErr = System.err;
    originalArguments = args;
   
    String stdout = this.getSetting(MAIN_OUTPUT);
    if (stdout != null && "false".equalsIgnoreCase(stdout)) {
      outputRegistry = new OutputStreamRegistry();

      System.setOut( new PrintStream( outputRegistry.getStream("System.out", true), true ) );
      System.setErr( new PrintStream( outputRegistry.getStream("System.err", true), true ) );
     
      outputRegistry.addListener("System.out", originalOut, false);
      outputRegistry.addListener("System.err", originalErr, false);
    } else {
      outputRegistry = null;
    }
   
    String stdin = this.getSetting(MAIN_INPUT);
    if (stdin != null && "false".equalsIgnoreCase(stdin)) {
      inputRegistry = new InputStreamRegistry("Standard Input", System.in);
      inputRegistry.start();
      System.setIn(inputRegistry);
    } else {
      inputRegistry = null;
    }
   
    if (!"false".equalsIgnoreCase(this.getSetting(MAIN_URLSFOVERRIDE)) && main == null)
      try {
        URL.setURLStreamHandlerFactory(this.urlsfOverride = new URLStreamHandlerFactoryComposite());
      } catch (Throwable t) {
        this.urlsfOverride = null;
      }
  }
 
  public EntryPoint getEntryPoint() { return this; }

  /**
   * This will first determine the {@link IEntryPointType} to be used for class loader
   * configuration. Then determine the main class specified. After that it will call
   * {@link IEntryPointType#main(EntryPointConfiguration)} on the specified type.
   *
   * @throws Exception
   */
  private void boot () throws Throwable {
    if (log.isDebug())
      log.debug("BOOTING START: " + System.currentTimeMillis());
   
    this.setupDefaultLogging(true);
   
    if (log.isDebug())
      log.debug("Using JavaUtil's EntryPoint Bootstrapping " + (VERSION == null ? "" : "[" + VERSION + "]"));
     
    IEntryPointType type = this;
    String bootType = this.getSetting(MAIN_TYPE_PROPERTY);
   
    if ("main".equals( Thread.currentThread().getName() ))
      main = type;
   
    entryPoints.set(type);
   
    Shutdown.setGlobalHandler(ExitPoint.class);
   
    EntryPointConfiguration config = new EntryPointConfiguration(this);
   
    if (bootType != null) {
      ClassDescriptor<? extends IEntryPointType> typeClass = ClassCache.getFor( ReflectionUtil.getClass(bootType) );
      type = typeClass.newInstance(this, settings);
    } else {
      EntryPointTypeComposite composite = this.detectEntryPoints(config);
      if (composite != null) type = composite;
    }
   
    try {
      while (true) {
        try {
          if (log.isDebug())
            log.debug("BOOTING LEVEL 1: " + type + ": " + System.currentTimeMillis());
         
          type.main(config);
          type.cleanup(false);
        } catch (Throwable t) {
          EntryPointRebootException reboot = ThrowableUtil.getWrapped(t, EntryPointRebootException.class);
          if (reboot != null) {
            Shutdown.shutdown();
            type.cleanup(true);
            continue;
          } else {
            if (type.getExceptionHandler() != null) {
              Shutdown.shutdown();
              type.getExceptionHandler().handle(type, t);
            }
            else throw t;
          }
        }
        break;
      }
    } finally {
      if (type.getEntryPoint().inputRegistry != null)
        type.getEntryPoint().getInputRegistry().stop();
    }
   
  }
 
  public IEntryPointType generate(ClassLoaderResource resource) {
    try {
      return (IEntryPointType) ClassCache.getFor( resource.loadClass() ).newInstance(this, settings);
    } catch (ClassNotFoundException e) {
      throw ThrowableManagerRegistry.caught(e);
    }
  }
 
  public EntryPointTypeComposite detectEntryPoints (EntryPointConfiguration config) {
    ServiceLoader<IEntryPointType> located = ServiceLoader.load(IEntryPointType.class);
    Iterator<IEntryPointType> types = located.iterator();
   
    if (types.hasNext()) {
      List<IEntryPointType> bootstrappers = new ArrayList<IEntryPointType>();
      IEntryPointType endpoint = null;
     
      while (types.hasNext()) {
        IEntryPointType etype = types.next();
       
        etype.setEntryPoint(this);
        etype.setSettings(settings);
       
        if (config.isAlreadyExecuted(etype.getClass()) || !etype.canBoot()) continue;
        if (etype.getTargetType() == TargetType.Bootstrapper) {
          bootstrappers.add(etype);
        } else if (endpoint == null) {
          endpoint = etype;
        }
      }
     
      if (bootstrappers.size() > 0 || endpoint != null) {
        return new EntryPointTypeComposite(this, settings, bootstrappers, endpoint);
      }
    }
   
    return null;
  }

  /**
   * This will allow auto detection of double boot classes, where the main class is
   * actually another {@link IEntryPointType}. Also it will detect if the class is of type
   * {@link Runnable} and if so, instantiate it and call {@link Runnable#run()}, otherwise it
   * will assume that the class is a normal {@link #main(String[])} class.
   *
   * @param mainDescriptor The descriptor for the main class
   * @param type The entry point type that is currently booting
   * @param mainClass The next main class to be called in the boot chain (only used if mainDescriptor is another {@link IEntryPointType}
   */
  public void boot (ClassDescriptor mainDescriptor, IEntryPointType type) throws Throwable {
    if (IEntryPointType.class.isAssignableFrom( mainDescriptor.getDescribedClass() )) {
      EntryPointConfiguration config = new EntryPointConfiguration(type, this)
      if (log.isDebug())
        log.debug("BOOTING LEVEL 2: " + System.currentTimeMillis());
     
      IEntryPointType ept = (IEntryPointType) mainDescriptor.newInstance(this, this.settings);
      ept.main(config);
    } else if (Runnable.class.isAssignableFrom( mainDescriptor.getDescribedClass() )) {
     
      if (log.isDebug())
        log.debug("BOOTING LEVEL 3: " + System.currentTimeMillis());
     
      Runnable runnable = (Runnable) mainDescriptor.newInstance();
      runnable.run();
    } else {
     
      if (log.isDebug())
        log.debug("BOOTING LEVEL 4: " + System.currentTimeMillis());
     
      mainDescriptor.invoke("main", null, new Object[] { CollectionUtil.copy( this.originalArguments ) });
    }
  }
 
  /**
   * @param type The type that is booting the instance
   * @param instance The instance to boot
   */
  public void boot (IEntryPointType type, Object instance) throws Throwable {
    if (instance instanceof IEntryPointType) {
      EntryPointConfiguration config = new EntryPointConfiguration(type, this);
     
      ((IEntryPointType) instance).main(config);
    } else if (instance instanceof Runnable) {
      ((Runnable) instance).run();
    } else {
      ClassCache.getFor(instance.getClass()).invoke("main", instance, new Object[] { CollectionUtil.copy( this.originalArguments ) });
    }
  }
 
  /**
   * If the {@link #MAIN_URLSFCLASS} is specified and the {@link #isUrlsfOverride()} returns true
   * this will load the specified class using the provided class loader and register it using
   * {@link #registerURLStreamHandlerFactory(URLStreamHandlerFactory)}.
   *
   * @param cl The class loader to use for loading the specified factory class
   */
  public void setupDefaultURLStreamHandlerFactory (ClassLoader cl) {
    if (this.getSetting(MAIN_URLSFCLASS) != null) {
      this.registerURLStreamHandlerFactory(
        (URLStreamHandlerFactory) ReflectionUtil.newInstance(
          ReflectionUtil.getClass(this.getSetting(MAIN_URLSFCLASS), cl), new Class[0]
        )
      );
    }
  }
 
  /**
   * Detect a logging.properties in the local directory or in a specified directory (default "config")
   * and setup parameters.
   */
  public void setupDefaultLogging (boolean retry) {
    if (this.loggingSetup || !retry) return;
    this.loggingSetup = true;
   
    File configDir = new File(this.getSetting(MAIN_LOG_CONFIGDIR) == null ? "conf" : this.getSetting(MAIN_LOG_CONFIGDIR)).getAbsoluteFile();
    for (File config : new File[] {
      new File("logging.properties").getAbsoluteFile(),
      new File(configDir, "logging.properties")
    }) {
      if (config.exists()) {
        try {
          LogManager.getLogManager().readConfiguration(new FileInputStream(config));
          new LoggingContext(LoggingFrameworkJDK.getInstance()).setGlobal();
        } catch (Exception e) {
          ThrowableManagerRegistry.caught(e);
        }
      }
    }
  }
 
  public TargetType getTargetType() {
    return TargetType.Bootstrapper;
  }

  public boolean canBoot() {
    return true;
  }

  public void main (EntryPointConfiguration config) throws Throwable {
    URL boot = EntryPoint.class.getClassLoader()
      .getResource("META-INF/net/sf/javautil/boot.jar");
   
    ClassContext context = null;
    CompositeClassSource mainSource = new CompositeClassSource();
    ClassSource additional = this.getAdditionalClassSources();
    if (additional != null) mainSource.add(additional);
   
    if (boot != null) {
      mainSource.add( VirtualDirectoryClassSource.createInMemoryJar("boot", "main", boot.openStream()) );
      context = new ClassContext(new StandardClassLoaderHeiarchy(Thread.currentThread().getContextClassLoader()), mainSource);
    } else {
     
      String main = this.getSetting(MAIN_JAR_PROPERTY);
      if (main == null)
        printHelp("No internal uber jar and no main jar specified -D" + MAIN_JAR_PROPERTY + "=''");
     
      File mainFile = new File(main);
      if (!mainFile.exists())
        printHelp("Specified main jar does not exist: " + mainFile);
     
      mainSource.add( new ZipClassSource(mainFile) );
      context = new ClassContext(new StandardClassLoaderHeiarchy(Thread.currentThread().getContextClassLoader()), mainSource);
    }
   
    Thread.currentThread().setContextClassLoader(context);
    this.setupDefaultURLStreamHandlerFactory(context);
   
    String mainClassName = null;
   
    if (mainClassName == null) {
      Manifest manifest = mainSource.getManifest();
      if (manifest == null)
        printHelp("No main jar manifest found in " + mainSource);
     
      mainClassName = manifest.getMainAttributes().getValue("Main-Class");
    }
    Thread.currentThread().setContextClassLoader(context);
   
    if (config.getMainClass() != null)
      this.boot(ClassCache.getFor(context.loadClass(mainClassName)), this);
  }
 
  /**
   * This will by default detect the {@link #LIBDIRS_PROPERTY}
   *
   * @return The class sources to add in addition to the pom.xml and project directory
   * @throws Exception
   */
  public ClassSource getAdditionalClassSources () throws Exception {
    String libdirs = this.getSetting(LIBDIRS_PROPERTY);
    if (libdirs == null) return null;
   
    String[] libs = libdirs.split(";");
    if (libs.length == 1) return new LibDirectoryClassSource(new SystemDirectory(libs[0]), true);
    else {
      CompositeClassSource ccs = new CompositeClassSource();
      for (String lib : libs) ccs.add(new LibDirectoryClassSource(new SystemDirectory(lib), true));
      return ccs;
    }
  }

  public void uncaughtException(Thread t, Throwable e) {
    try {
      e.printStackTrace(originalOut);
      ThrowableManagerRegistry.get().uncaughtException(t, e);
    } catch (Throwable throwable) {
      e.printStackTrace(originalOut);
    }
  }

  /**
   * This will allow for {@link IEntryPointType} exit point handlers to be called related to the use of this framework.
   *
   * @author elponderador
   * @author $Author: ponderator $
   * @version $Id: EntryPoint.java 2709 2010-12-31 00:46:45Z ponderator $
   */
  public static class ExitPoint implements IShutdownHandler {
   
    protected final IShutdownHandler parent;

    public ExitPoint(IShutdownHandler parent) {
      this.parent = parent;
    }

    public void shutdown(Thread thread) {
      getEntryPointType().invokeExitPointHooks();
      parent.shutdown(thread);
    }

    public void register(IShutdownHook hook) {
      getEntryPointType().registerExitPointHook(new ExitPointShutdownHook(hook));
    }

    public void unregister(IShutdownHook hook) {
      for (IExitPointHook ehook : getEntryPointType().getHooks()) {
        if (ehook instanceof ExitPointShutdownHook) {
          if (((ExitPointShutdownHook)ehook).hook == hook) {
            getEntryPointType().unregisterExitPointHook(ehook);
            break;
          }
        }
      }
    }
   
    /**
     * A simple wrapper for {@link IShutdownHook}'s.
     *
     * @author elponderador
     * @author $Author: ponderator $
     * @version $Id: EntryPoint.java 2709 2010-12-31 00:46:45Z ponderator $
     */
    protected class ExitPointShutdownHook implements IExitPointHook {
     
      protected final IShutdownHook hook;

      public ExitPointShutdownHook(IShutdownHook hook) { this.hook = hook; }

      public void exit() { this.hook.shutdown(); }
     
    }
   
  }

}
TOP

Related Classes of net.sourceforge.javautil.classloader.boot.EntryPoint$ExitPoint

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.