Package runjettyrun

Source Code of runjettyrun.Bootstrap

/*
* $Id: Bootstrap.java 143 2011-05-19 08:35:17Z tonylovejava@gmail.com $
* $HeadURL: https://run-jetty-run.googlecode.com/svn/trunk/bootstrap/src/runjettyrun/Bootstrap.java $
*
* ==============================================================================
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package runjettyrun;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.management.ManagementFactory;
import java.net.DatagramSocket;
import java.net.ServerSocket;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.management.MBeanServer;

import org.mortbay.jetty.Server;
import org.mortbay.jetty.nio.SelectChannelConnector;
import org.mortbay.jetty.security.SslSocketConnector;
import org.mortbay.jetty.webapp.WebAppContext;
import org.mortbay.management.MBeanContainer;
import org.mortbay.resource.FileResource;
import org.mortbay.resource.Resource;
import org.mortbay.resource.ResourceCollection;
import org.mortbay.util.Scanner;

/**
* Started up by the plugin's runner. Starts Jetty.
*
* @author hillenius, jsynge, jumperchen
*/
public class Bootstrap {

  private static Server server;

  private static WebAppContext web;

  /**
   * Main function, starts the jetty server.
   *
   * @param args
   */
  public static void main(String[] args) throws Exception {

    logArgus(false);
    Bootstrap.Configs configs = new Bootstrap.Configs();


    configs.validation();

    server = new Server();

    initConnnector(server, configs);

    initWebappContext(server,configs);

    initMBeanServer(server);

    // configureScanner
    if (configs.getEnablescanner())
      initScanner(web, configs.getWebAppClassPath(),
          configs.getScanIntervalSeconds());

    try {
      server.start();
      server.join();
    } catch (Exception e) {
      e.printStackTrace();
      System.exit(100);
    }
    return;
  }

  private static void initWebappContext(Server server,Configs configs)
    throws IOException, URISyntaxException {
    web = new WebAppContext();

    if (configs.getParentLoaderPriority()) {
      System.err.println("ParentLoaderPriority enabled");
      web.setParentLoaderPriority(true);
    }

    web.setContextPath(configs.getContext());
    web.setWar(configs.getWebAppDir());


    //TODO add multiple root selection support
    //     ResourceCollection webAppDirResources = new ResourceCollection();
    //
    //       webAppDirResources.setResourcesAsCSV(webAppDir);
    //       web.setBaseResource(webAppDirResources);

    /**
     * open a way to set the configuration classes
     */
    List<String> configurationClasses = configs.getConfigurationClassesList();
    if (configurationClasses.size() != 0) {
      web.setConfigurationClasses(configurationClasses.toArray(new String[0]));

      for (String conf : configurationClasses)
        System.err.println("Enable config class:" + conf);

    }


    // Fix issue 7, File locking on windows/Disable Jetty's locking of
    // static files
    // http://code.google.com/p/run-jetty-run/issues/detail?id=7
    // by disabling the use of the file mapped buffers. The default Jetty
    // behavior is
    // intended to provide a performance boost, but run-jetty-run is focused
    // on
    // development (especially debugging) of web apps, not high-performance
    // production
    // serving of static content. Therefore, I'm not worried about the
    // performance
    // degradation of this change. My only concern is that there might be a
    // need to
    // test this feature that I'm disabling.
    web.setInitParams(Collections.singletonMap(
        "org.mortbay.jetty.servlet.Default.useFileMappedBuffer",
        "false"));

    if (configs.getWebAppClassPath() != null) {
      ProjectClassLoader loader = new ProjectClassLoader(web,
          configs.getWebAppClassPath());
      web.setClassLoader(loader);
    }


    List<Resource> resources = new ArrayList<Resource>();

    URL urlWebapp = new File(configs.getWebAppDir()).toURI().toURL();
    Resource webapp = new FileResource(urlWebapp);
    resources.add(webapp);

    Map<String,String> map = configs.getResourceMap();
    for(String key : map.keySet()){
/*
*       URL url = new File(map.get(key)).toURI().toURL();
      Resource resource;
      try {
        resource = new FileResource(url);
        final ResourceHandler handler = new ResourceHandler();
        handler.setBaseResource(resource);
        handler.setServer(server);
        handler.setContextPath(key);
        web.addHandler(handler);
      } catch (URISyntaxException e) {
        e.printStackTrace();
      }

*/
      resources.add(new VirtualResource(webapp,"/"+key,map.get(key)));
//      final WebAppContext js = new WebAppContext();
//      js.setContextPath(key);
//      js.setResourceBase(map.get(key)); // or whatever the correct path is in your case
//      js.setParentLoaderPriority(true);
//      server.addHandler(js);
    }

    ResourceCollection webAppDirResources = new ResourceCollection();
    webAppDirResources.setResources(resources.toArray(new Resource[0]));
        web.setBaseResource(webAppDirResources);

    server.addHandler(web);
  }

  private static void initConnnector(Server server, Configs configObj) {
    SelectChannelConnector connector = new SelectChannelConnector();
    connector.setPort(configObj.getPort());

    if (configObj.getEnablessl() && configObj.getSslport() != null)
      connector.setConfidentialPort(configObj.getSslport());

    server.addConnector(connector);

    if (configObj.getEnablessl() && configObj.getSslport() != null)
      initSSL(server, configObj.getSslport(), configObj.getKeystore(),
          configObj.getPassword(), configObj.getKeyPassword(),
          configObj.getNeedClientAuth());

  }

  private static void logArgus(boolean loggerparam) {

    if (loggerparam) {
      String[] propkeys = new String[] { "rjrcontext", "rjrwebapp",
          "rjrport", "rjrsslport", "rjrkeystore", "rjrpassword",
          "rjrclasspath", "rjrkeypassword", "rjrscanintervalseconds",
          "rjrenablescanner", "rjrenablessl", "rjrenbaleJNDI" };
      for (String key : propkeys) {
        System.err.println("-D" + key + "=" + System.getProperty(key));
      }
    }
  }


  private static void initSSL(Server server, int sslport, String keystore,
      String password, String keyPassword, boolean needClientAuth) {
    if (!available(sslport)) {
      throw new IllegalStateException("SSL port :" + sslport
          + " already in use!");
    }
    if (keystore == null) {
      throw new IllegalStateException(
          "you need to provide argument -Drjrkeystore with -Drjrsslport");
    }
    if (password == null) {
      throw new IllegalStateException(
          "you need to provide argument -Drjrpassword with -Drjrsslport");
    }
    if (keyPassword == null) {
      throw new IllegalStateException(
          "you need to provide argument -Drjrkeypassword with -Drjrsslport");
    }

    SslSocketConnector sslConnector = new SslSocketConnector();
    sslConnector.setKeystore(keystore);
    sslConnector.setPassword(password);
    sslConnector.setKeyPassword(keyPassword);

    if (needClientAuth) {
      System.err.println("Enable NeedClientAuth.");
      sslConnector.setNeedClientAuth(needClientAuth);
    }
    sslConnector.setMaxIdleTime(30000);
    sslConnector.setPort(sslport);

    server.addConnector(sslConnector);
  }

  private static void initMBeanServer(Server server) {
    MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
    MBeanContainer mBeanContainer = new MBeanContainer(mBeanServer);
    server.getContainer().addEventListener(mBeanContainer);
    mBeanContainer.start();
  }

  /**
   * add source scanner to restart server when source change
   * @param web
   * @param webAppClassPath
   * @param scanIntervalSeconds
   */
  private static void initScanner(final WebAppContext web,
      final String webAppClassPath, int scanIntervalSeconds) {

    final ArrayList<File> scanList = new ArrayList<File>();
    if (webAppClassPath != null) {
      for (URL url : ((ProjectClassLoader) web.getClassLoader())
          .getURLs()) {
        File f = new File(url.getFile());
        if (f.isDirectory()) {
          scanList.add(f);
        }
      }
    }

    // startScanner
    Scanner scanner = new Scanner();
    scanner.setReportExistingFilesOnStartup(false);
    scanner.setScanInterval(scanIntervalSeconds);
    scanner.setScanDirs(scanList);
    scanner.addListener(new Scanner.BulkListener() {

      public void filesChanged(List changes) {
        try {
          // boolean reconfigure = changes.contains(getProject()
          // .getFile().getCanonicalPath());
          System.err.println("Stopping webapp ...");

          web.stop();

          if (webAppClassPath != null) {
            ProjectClassLoader loader = new ProjectClassLoader(web,
                webAppClassPath, false);
            web.setClassLoader(loader);
          }
          System.err.println("Restarting webapp ...");
          web.start();
          System.err.println("Restart completed.");
        } catch (Exception e) {
          System.err
              .println("Error reconfiguring/restarting webapp after change in watched files");
          e.printStackTrace();
        }
      }
    });
    System.err.println("Starting scanner at interval of "
        + scanIntervalSeconds + " seconds.");
    scanner.start();
  }

  private static Boolean getBoolean(String propertiesKey, boolean def) {
    String val = System.getProperty(propertiesKey);

    Boolean ret = def;
    if (val != null) {
      try {
        ret = Boolean.parseBoolean(val);
      } catch (Exception e) {

      }

    }
    return ret;

  }

  /**
   * To get the full list for classpath list,
   * Note:sometimes the classpath will be very longer,
   *     especially when you are working on a Maven project.
   *
   *     Since if classpath too long will cause command line too long issue,
   *     we use file to handle it in this case.
   * @return
   */
  private static String resovleWebappClasspath() {
    String classpath = System.getProperty("rjrclasspath");

    if (classpath != null && classpath.startsWith("file://")) {
      try {
        String filePath = classpath.substring(7);

        BufferedReader br = new BufferedReader(new InputStreamReader(
            new FileInputStream(filePath), "UTF-8"));
        StringBuffer sb = new StringBuffer();
        String str = br.readLine();
        while (str != null) {
          sb.append(str);
          str = br.readLine();
        }
        return sb.toString();

      } catch (IOException e) {
        System.err.println("read classpath failed!");
        throw new RuntimeException(" read classpath failed ", e);
      }
    }

    return classpath;
  }

  private static boolean available(int port) {
    if (port <= 0) {
      throw new IllegalArgumentException("Invalid start port: " + port);
    }

    ServerSocket ss = null;
    DatagramSocket ds = null;
    try {
      ss = new ServerSocket(port);
      ss.setReuseAddress(true);
      ds = new DatagramSocket(port);
      ds.setReuseAddress(true);
      return true;
    } catch (IOException e) {
    } finally {
      if (ds != null) {
        ds.close();
      }

      if (ss != null) {
        try {
          ss.close();
        } catch (IOException e) {
          /* should not be thrown */
        }
      }
    }

    return false;
  }

  /**
   * A configuration object to handle the complicated parse job ,
   * and make thing easier.
   */
  public static class Configs {
    private String context;
    private String webAppDir;
    private Integer port;
    private Integer sslport;
    private String keystore;
    private String password;
    private String webAppClassPath;
    private String keyPassword;
    private Integer scanIntervalSeconds;
    private Boolean enablescanner;
    private Boolean parentLoaderPriority;

    private Boolean enablessl;
    private Boolean needClientAuth;
    private Boolean enableJNDI;
    private String configurationClasses;
    private String resourceMapping;

    public Configs() {
      context = System.getProperty("rjrcontext");
      webAppDir = System.getProperty("rjrwebapp");
      if(webAppDir != null){
        if(webAppDir.matches("^\".*?\"$")){
          webAppDir = webAppDir.substring(1,webAppDir.length()-1);
        }
      }
      port = Integer.getInteger("rjrport");
      sslport = Integer.getInteger("rjrsslport");
      keystore = System.getProperty("rjrkeystore");
      password = System.getProperty("rjrpassword");
      webAppClassPath = resovleWebappClasspath();
      keyPassword = System.getProperty("rjrkeypassword");
      scanIntervalSeconds = Integer.getInteger("rjrscanintervalseconds");
      enablescanner = Boolean.getBoolean("rjrenablescanner");
      parentLoaderPriority = getBoolean("rjrparentloaderpriority", true);

      enablessl = Boolean.getBoolean("rjrenablessl");
      needClientAuth = Boolean.getBoolean("rjrneedclientauth");
      enableJNDI = Boolean.getBoolean("rjrenbaleJNDI");
      configurationClasses = System
          .getProperty("rjrconfigurationclasses", "");

      resourceMapping = System
      .getProperty("rjrResourceMapping", "");
    }


    public String getContext() {
      return context;
    }

    public String getWebAppDir() {
      return webAppDir;
    }

    public Integer getPort() {
      return port;
    }

    public Integer getSslport() {
      return sslport;
    }

    public String getKeystore() {
      return keystore;
    }

    public String getPassword() {
      return password;
    }

    public String getWebAppClassPath() {
      return webAppClassPath;
    }

    public String getKeyPassword() {
      return keyPassword;
    }

    public Integer getScanIntervalSeconds() {
      return scanIntervalSeconds;
    }

    public Boolean getEnablescanner() {
      return enablescanner;
    }

    public Boolean getParentLoaderPriority() {
      return parentLoaderPriority;
    }

    public Boolean getEnablessl() {
      return enablessl;
    }

    public Boolean getNeedClientAuth() {
      return needClientAuth;
    }

    public Boolean getEnableJNDI() {
      return enableJNDI;
    }

    public String getConfigurationClasses() {
      return configurationClasses;
    }

    public List<String> getConfigurationClassesList(){
      ArrayList<String> configuration = new ArrayList<String>();
      if (getEnableJNDI()) {
        configuration.add("org.mortbay.jetty.webapp.WebInfConfiguration");
        configuration.add("org.mortbay.jetty.plus.webapp.EnvConfiguration");
        configuration.add("org.mortbay.jetty.plus.webapp.Configuration");
        configuration.add("org.mortbay.jetty.webapp.JettyWebXmlConfiguration");
        configuration.add("org.mortbay.jetty.webapp.TagLibConfiguration");
      }
      if (!"".equals(getConfigurationClasses())) {
        String[] configs = getConfigurationClasses().split(";");
        for (String conf : configs) {
          configuration.add(conf);
        }
      }
      return configuration;
    }

    public void validation() {
      if (getContext() == null) {
        throw new IllegalStateException(
            "you need to provide argument -Drjrcontext");
      }
      if (getWebAppDir() == null) {
        throw new IllegalStateException(
            "you need to provide argument -Drjrwebapp");
      }
      if (getPort() == null && getSslport() == null) {
        throw new IllegalStateException(
            "you need to provide argument -Drjrport and/or -Drjrsslport");
      }
      if (!available(port)) {
        throw new IllegalStateException("port :" + port
            + " already in use!");
      }
    }

    public String getResourceMapping() {
      return resourceMapping;
    }

    public Map<String,String> getResourceMap(){

      String[] resources = resourceMapping.split(";");

      HashMap<String,String> map = new HashMap<String,String>();

      for(String resource:resources){
        if( resource == null || "".equals(resource.trim())) continue;
        String[] tokens = resource.split("=");
        map.put(tokens[0],tokens[1]);
      }
      return map;
    }
  }
}
TOP

Related Classes of runjettyrun.Bootstrap

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.