Package ch.cmbntr.modulizer.bootstrap.impl

Source Code of ch.cmbntr.modulizer.bootstrap.impl.BasicBootstrap

package ch.cmbntr.modulizer.bootstrap.impl;

import static ch.cmbntr.modulizer.bootstrap.util.ModulizerIO.closeQuietly;
import static ch.cmbntr.modulizer.bootstrap.util.ModulizerIO.mkdir;
import static ch.cmbntr.modulizer.bootstrap.util.ModulizerLog.initLogging;
import static java.lang.Boolean.parseBoolean;

import java.awt.GraphicsEnvironment;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.InvalidPropertiesFormatException;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.Future;

import ch.cmbntr.modulizer.bootstrap.Bootstrap;
import ch.cmbntr.modulizer.bootstrap.BootstrapContext;
import ch.cmbntr.modulizer.bootstrap.Launch;
import ch.cmbntr.modulizer.bootstrap.Operations;
import ch.cmbntr.modulizer.bootstrap.Prepare;
import ch.cmbntr.modulizer.bootstrap.util.ModulizerLog;
import ch.cmbntr.modulizer.bootstrap.util.Resources;
import ch.cmbntr.modulizer.bootstrap.util.Resources.Pool;

public class BasicBootstrap extends AbstractOperation implements Bootstrap {

  /**
   * {@inheritDoc}
   */
  @Override
  public void run() {
    final Pool handle = Resources.getPoolHandle();
    try {
      establishContext();
      performSecuritySettings();
      initializeLogging();
      verboseLoading();
      preloading();

      final Future<ClassLoader> prepareLoader = preparePluginLoader(handle);
      final Future<ClassLoader> launchLoader = launchPluginLoader(handle);

      prepare(prepareLoader);
      launch(launchLoader);
      scheduleGC();
    } finally {
      clearContext();
      Resources.dispose(handle);
    }
  }

  private void performSecuritySettings() {
    try {
      if (!parseBoolean(lookupContext(BootstrapContext.CONFIG_KEY_SECURITY_SKIP))) {
        log("applying security settings");
        System.setSecurityManager(null);
      }
    } catch (final SecurityException e) {
      warn("failed to apply security settings: %s", e);
    }
  }

  private void establishContext() {
    final InputStream config = BasicBootstrap.class.getResourceAsStream(BootstrapContext.CONFIG_NAME);
    if (config == null) {
      warn("config not found: %s", BootstrapContext.CONFIG_NAME);
    }
    try {
      final PropertiesContext ctx = PropertiesContext.empty().loadFromXML(config).addSystemProperties();
      ctx.put(BootstrapContext.CONFIG_KEY_APP_ID, sanitizeAppId(ctx));
      ctx.put(BootstrapContext.CONFIG_KEY_APP_DIR, sanitizeAppDir(ctx));
      BootstrapContext.CURRENT.set(ctx);

    } catch (final InvalidPropertiesFormatException e) {
      throw new RuntimeException(e);
    } catch (final IOException e) {
      throw new RuntimeException(e);
    } finally {
      closeQuietly(config);
    }
  }

  private void initializeLogging() {
    String loggingConfig = lookupContext(BootstrapContext.CONFIG_KEY_LOGGING);
    if ("app.dir".equals(loggingConfig)) {
      loggingConfig = "file:" + lookupContext(BootstrapContext.CONFIG_KEY_APP_DIR) + "/bootstrap.log";
    }
    initLogging(loggingConfig);
  }

  private void verboseLoading() {
    final String val = lookupContext(BootstrapContext.CONFIG_KEY_VERBOSE_LOADING_MILLIS);
    final long verboseLoadingMillis = val == null ? -1L : Long.parseLong(val);
    verboseClassloading(verboseLoadingMillis);
  }

  private static void verboseClassloading(final long durationMillis) {
    if (durationMillis > 0L) {
      ManagementFactory.getClassLoadingMXBean().setVerbose(true);
      Resources.delay(durationMillis, new Runnable() {
        @Override
        public void run() {
          ManagementFactory.getClassLoadingMXBean().setVerbose(false);
        }
      });
    }
  }

  private void preloading() {
    final ClassLoader loader = Operations.defaultLoader();
    preload(false, loader, lookupContext(BootstrapContext.CONFIG_KEY_PRELOAD));
    preload(true, loader, lookupContext(BootstrapContext.CONFIG_KEY_PRELOAD_NONHEADLESS));
  }

  private static void preload(final boolean onlyNonHeadless, final ClassLoader loader, final String preloadSpec) {
    if (preloadSpec == null) {
      return;
    }
    Resources.execute(new Runnable() {
      @Override
      public void run() {
        if (onlyNonHeadless && GraphicsEnvironment.isHeadless()) {
          return;
        }
        for (final List<String> slice : parsePreloadSpec(preloadSpec)) {
          Resources.delay(0L, new Runnable() {
            @Override
            public void run() {
              for (final String clazz : slice) {
                try {
                  Class.forName(clazz, true, loader);
                } catch (final ClassNotFoundException e) {
                  ModulizerLog.warn("preload of %s failed: %s", clazz, e.getMessage());
                }
              }
            }
          });
        }
      }
    });
  }

  private static List<List<String>> parsePreloadSpec(final String barSeparatedClassLists) {
    if (barSeparatedClassLists == null) {
      return Collections.emptyList();
    }

    final String[] slices = barSeparatedClassLists.split("\\|");
    if (slices.length == 1) {
      return Collections.singletonList(classNames(slices[0]));
    } else {
      final List<List<String>> result = new ArrayList<List<String>>(slices.length);
      for (final String slice : slices) {
        final List<String> classes = classNames(slice);
        if (!classes.isEmpty()) {
          result.add(classes);
        }
      }
      return result;
    }
  }

  private static List<String> classNames(final String commaSeparatedClasses) {
    final String[] classes = commaSeparatedClasses.split(",");
    final List<String> result = new ArrayList<String>(classes.length);
    for (final String clazz : classes) {
      final String trimmed = clazz.trim();
      if (trimmed.length() > 0) {
        result.add(trimmed);
      }
    }
    return result;
  }

  private String sanitizeAppId(final PropertiesContext ctx) {
    final String given = ctx.get(BootstrapContext.CONFIG_KEY_APP_ID);
    return given == null ? "unnamed-" + UUID.randomUUID() : given.trim();
  }

  private String sanitizeAppDir(final PropertiesContext ctx) throws IOException {
    final String given = ctx.get(BootstrapContext.CONFIG_KEY_APP_DIR);
    return ensureAppDir(given == null ? determineDefaultAppDir(ctx) : new File(given));
  }

  private File determineBootstrapBaseDir(final PropertiesContext ctx) {
    final String baseDir = ctx.get(BootstrapContext.CONFIG_KEY_BASE_DIR);
    return new File(baseDir == null ? System.getProperty("java.io.tmpdir") : baseDir);
  }

  private File determineDefaultAppDir(final PropertiesContext ctx) {
    final String appId = ctx.get(BootstrapContext.CONFIG_KEY_APP_ID);
    final File appDir = new File(determineBootstrapBaseDir(ctx), appId);
    final String slot = ctx.get(BootstrapContext.CONFIG_KEY_APP_DIR_SLOT);
    return slot == null ? appDir : new File(appDir, slot.trim());
  }

  private String ensureAppDir(final File appDir) throws IOException {
    mkdir(appDir);
    return appDir.getCanonicalFile().getAbsolutePath();
  }

  private Future<ClassLoader> preparePluginLoader(final Pool handle) {
    return pluginLoaderViaSpecKey(handle, BootstrapContext.CONFIG_KEY_PREPARE_PLUGINS);
  }

  private void prepare(final Future<ClassLoader> loader) {
    invokePluginOperations(Prepare.class, loader);
  }

  private Future<ClassLoader> launchPluginLoader(final Pool handle) {
    return pluginLoaderViaSpecKey(handle, BootstrapContext.CONFIG_KEY_LAUNCH_PLUGINS);
  }

  private void launch(final Future<ClassLoader> loader) {
    invokePluginOperations(Launch.class, loader);
  }

  private void scheduleGC() {
    final String val = lookupContext(BootstrapContext.CONFIG_KEY_GC_DELAY);
    final long delay = val == null ? BootstrapContext.DEFAULT_GC_DELAY_MS : Long.parseLong(val);
    delayedGC(delay);
  }

  private static void delayedGC(final long delay) {
    if (delay >= 0L) {
      Resources.delay(delay, new Runnable() {
        @Override
        public void run() {
          ManagementFactory.getMemoryMXBean().gc();
        }
      });
    }
  }

  private void clearContext() {
    final BootstrapContext ctxt = BootstrapContext.CURRENT.getAndSet(null);
    log("final context: %s", ctxt);
  }

}
TOP

Related Classes of ch.cmbntr.modulizer.bootstrap.impl.BasicBootstrap

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.