JettyContainerService.java :  » Google-tech » appscale » com » google » appengine » tools » development » Java Open Source

Java Open Source » Google tech » appscale 
appscale » com » google » appengine » tools » development » JettyContainerService.java
package com.google.appengine.tools.development;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.URL;
import java.security.Permissions;
import java.util.concurrent.Semaphore;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.mortbay.jetty.Server;
import org.mortbay.jetty.handler.HandlerWrapper;
import org.mortbay.jetty.nio.SelectChannelConnector;
import org.mortbay.jetty.webapp.WebAppContext;
import org.mortbay.resource.Resource;
import org.mortbay.util.Scanner;

import com.google.appengine.tools.development.AbstractContainerService;
import com.google.appengine.tools.development.AppContext;
import com.google.appengine.tools.development.ContainerService;
import com.google.appengine.tools.development.ServiceProvider;
import com.google.apphosting.api.ApiProxy;
import com.google.apphosting.utils.config.AppEngineConfigException;
import com.google.apphosting.utils.config.AppEngineWebXml;
import com.google.apphosting.utils.jetty.DevAppEngineWebAppContext;
import com.google.apphosting.utils.jetty.JettyLogger;
import com.google.apphosting.utils.jetty.StubSessionManager;

@ServiceProvider(ContainerService.class)
public class JettyContainerService extends AbstractContainerService
{
  private static final Logger log = Logger.getLogger(JettyContainerService.class.getName());
     
  public static final String WEB_DEFAULTS_XML = "com/google/appengine/tools/development/webdefault.xml";
  private static final int MAX_SIMULTANEOUS_API_CALLS = 10;
  private static final String[] CONFIG_CLASSES = { "org.mortbay.jetty.webapp.WebXmlConfiguration", "org.mortbay.jetty.webapp.TagLibConfiguration" };
  private static final String WEB_XML_ATTR = "com.google.appengine.tools.development.webXml";
  private static final String APPENGINE_WEB_XML_ATTR = "com.google.appengine.tools.development.appEngineWebXml";
  private static final int SCAN_INTERVAL_SECONDS = 5;
  private WebAppContext context;
  private AppContext appContext;
  private Server server;
  private Scanner scanner;

  protected File initContext()
    throws IOException
  {
   
    this.context = new DevAppEngineWebAppContext(this.appDir, this.devAppServerVersion);
    this.appContext = new JettyAppContext();

    this.context.setDescriptor(this.webXmlLocation);

    this.context.setDefaultsDescriptor("com/google/appengine/tools/development/webdefault.xml");

    this.context.setConfigurationClasses(CONFIG_CLASSES);

    File appRoot = determineAppRoot();
    URL[] classPath = getClassPathForApp(appRoot);
    this.context.setClassLoader(new IsolatedAppClassLoader(appRoot, classPath, JettyContainerService.class.getClassLoader()));

    return appRoot;
  }

  protected void startContainer() throws Exception
  {
    this.context.setAttribute("com.google.appengine.tools.development.webXml", this.webXml);
    this.context.setAttribute("com.google.appengine.tools.development.appEngineWebXml", this.appEngineWebXml);

    Thread currentThread = Thread.currentThread();
    ClassLoader previousCcl = currentThread.getContextClassLoader();
    currentThread.setContextClassLoader(null);
    try
    {
      ApiProxyHandler apiHandler = new ApiProxyHandler(this.appEngineWebXml);
      apiHandler.setHandler(this.context);

      SelectChannelConnector connector = new SelectChannelConnector();
      connector.setHost(this.address);
      connector.setPort(this.port);
//      System.out.println("num of acceptors: "+connector.getAcceptors());
//      System.out.println("acceptor size: "+connector.getAcceptQueueSize());
      connector.setSoLingerTime(0);

      this.server = new Server();
      this.server.addConnector(connector);
      this.server.setHandler(apiHandler);

      if (!(isSessionsEnabled())) {
        this.context.getSessionHandler().setSessionManager(new StubSessionManager());
      }
      this.server.start();
      this.port = connector.getLocalPort();
    } finally {
      currentThread.setContextClassLoader(previousCcl);
    }
  }

  protected void stopContainer() throws Exception
  {
    this.server.stop();
  }

  protected void startHotDeployScanner()
    throws Exception
  {
    this.scanner = new Scanner();
    this.scanner.setScanInterval(5);
    this.scanner.setScanDir(getScanTarget());
    this.scanner.setFilenameFilter(new FilenameFilter()
    {
      public boolean accept(File dir, String name) {
        try {
          return (name.equals(JettyContainerService.this.getScanTarget().getName()));
        }
        catch (Exception e)
        {
        }

        return false;
      }
    });
    this.scanner.scan();
    this.scanner.addListener(new ScannerListener());
    this.scanner.start();
  }

  protected void stopHotDeployScanner() throws Exception
  {
    if (this.scanner != null) {
      this.scanner.stop();
    }
    this.scanner = null;
  }

  private File getScanTarget()
    throws Exception
  {
    if (this.appDir.isFile()) {
      return this.appDir;
    }

    return new File(this.context.getWebInf().getFile().getPath() + File.separator + "appengine-web.xml");
  }

  protected void reloadWebApp()
    throws Exception
  {
    this.server.getHandler().stop();
    restoreSystemProperties();

    Thread currentThread = Thread.currentThread();
    ClassLoader previousCcl = currentThread.getContextClassLoader();
    currentThread.setContextClassLoader(null);
    try
    {
      File webAppDir = initContext();
      loadAppEngineWebXml(webAppDir);

      if (!(isSessionsEnabled())) {
        this.context.getSessionHandler().setSessionManager(new StubSessionManager());
      }
      this.context.setAttribute("com.google.appengine.tools.development.webXml", this.webXml);
      this.context.setAttribute("com.google.appengine.tools.development.appEngineWebXml", this.appEngineWebXml);

      ApiProxyHandler apiHandler = new ApiProxyHandler(this.appEngineWebXml);
      apiHandler.setHandler(this.context);
      this.server.setHandler(apiHandler);
      

      apiHandler.start();
    } finally {
      currentThread.setContextClassLoader(previousCcl);
    }
  }

  public AppContext getAppContext()
  {
    return this.appContext;
  }

  private File determineAppRoot()
    throws IOException
  {
    Resource webInf = this.context.getWebInf();
    if (webInf == null) {
      throw new AppEngineConfigException("Supplied application has to contain WEB-INF directory.");
    }
    return webInf.getFile().getParentFile();
  }

  static
  {
    System.setProperty("org.mortbay.log.class", JettyLogger.class.getName());
  }

  private class ApiProxyHandler extends HandlerWrapper
  {
    private final AppEngineWebXml appEngineWebXml;

    public ApiProxyHandler(AppEngineWebXml paramAppEngineWebXml)
    {
      this.appEngineWebXml = paramAppEngineWebXml;
      
    }

    public void handle(String target, HttpServletRequest request, HttpServletResponse response, int dispatch)
      throws IOException, ServletException
    {
      if (dispatch == 1) {
        Semaphore semaphore = new Semaphore(10);

        LocalEnvironment env = new LocalHttpRequestEnvironment(this.appEngineWebXml, request);
        env.getAttributes().put("com.google.appengine.tools.development.api_call_semaphore", semaphore);
        ApiProxy.setEnvironmentForCurrentThread(env);
        try {
      super.handle(target, request, response, dispatch);
  
          if (request.getRequestURI().startsWith("/_ah/reloadwebapp"))
            try {
              JettyContainerService.this.reloadWebApp();
              JettyContainerService.log.info("Reloaded the webapp context: " + request.getParameter("info"));
            } catch (Exception ex) {
              JettyContainerService.log.log(Level.WARNING, "Failed to reload the current webapp context.", ex);
            }
        }
        finally
        {
          try {
            semaphore.acquire(10);
//            System.out.println("semaphores at hand!");
          } catch (InterruptedException ex) {
            JettyContainerService.log.log(Level.WARNING, "Interrupted while waiting for API calls to complete:", ex);
          }
          ApiProxy.clearEnvironmentForCurrentThread();
        }
      }
      else
      {
      super.handle(target, request, response, dispatch);
    }
      }
    
  }

  private class ScannerListener
    implements Scanner.DiscreteListener
  {
    public void fileAdded(String filename)
      throws Exception
    {
      fileChanged(filename);
    }

    public void fileChanged(String filename) throws Exception
    {
      JettyContainerService.log.info(filename + " updated, reloading the webapp!");
      JettyContainerService.this.reloadWebApp();
    }

    public void fileRemoved(String filename)
      throws Exception
    {
    }
  }

  private class JettyAppContext
    implements AppContext
  {
    public IsolatedAppClassLoader getClassLoader()
    {
      return ((IsolatedAppClassLoader)JettyContainerService.this.context.getClassLoader());
    }

    public Permissions getUserPermissions()
    {
      return JettyContainerService.this.getUserPermissions();
    }

    public Permissions getApplicationPermissions()
    {
      return getClassLoader().getAppPermissions();
    }

    public Object getContainerContext()
    {
      return JettyContainerService.this.context;
    }
  }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.