azkaban-aplcache

Details

diff --git a/azkaban-common/build.gradle b/azkaban-common/build.gradle
index 0b60ae4..3f6e3e6 100644
--- a/azkaban-common/build.gradle
+++ b/azkaban-common/build.gradle
@@ -34,9 +34,8 @@ dependencies {
   compile('org.apache.velocity:velocity:1.7')
   compile('org.codehaus.jackson:jackson-core-asl:1.9.5')
   compile('org.codehaus.jackson:jackson-mapper-asl:1.9.5')
-  compile('org.eclipse.jetty:jetty-security:9.3.14+')
-  compile('org.eclipse.jetty:jetty-server:9.3.14+')
-  compile('org.eclipse.jetty:jetty-servlet:9.3.14+')
+  compile('org.mortbay.jetty:jetty:6.1.26')
+  compile('org.mortbay.jetty:jetty-util:6.1.26')
   compile('org.quartz-scheduler:quartz:2.2.1')
   compile('io.dropwizard.metrics:metrics-core:3.1.0')
   compile('io.dropwizard.metrics:metrics-jvm:3.1.0')
diff --git a/azkaban-common/src/main/java/azkaban/jmx/JmxJettyServer.java b/azkaban-common/src/main/java/azkaban/jmx/JmxJettyServer.java
new file mode 100644
index 0000000..fd520f2
--- /dev/null
+++ b/azkaban-common/src/main/java/azkaban/jmx/JmxJettyServer.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2014 LinkedIn Corp.
+ *
+ * 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 azkaban.jmx;
+
+import org.mortbay.jetty.Connector;
+import org.mortbay.jetty.Server;
+
+public class JmxJettyServer implements JmxJettyServerMBean {
+  private Server server;
+  private Connector connector;
+
+  public JmxJettyServer(Server server) {
+    this.server = server;
+    this.connector = server.getConnectors()[0];
+  }
+
+  @Override
+  public boolean isRunning() {
+    return this.server.isRunning();
+  }
+
+  @Override
+  public boolean isFailed() {
+    return this.server.isFailed();
+  }
+
+  @Override
+  public boolean isStopped() {
+    return this.server.isStopped();
+  }
+
+  @Override
+  public int getNumThreads() {
+    return this.server.getThreadPool().getThreads();
+  }
+
+  @Override
+  public int getNumIdleThreads() {
+    return this.server.getThreadPool().getIdleThreads();
+  }
+
+  @Override
+  public String getHost() {
+    return connector.getHost();
+  }
+
+  @Override
+  public int getPort() {
+    return connector.getPort();
+  }
+
+  @Override
+  public int getConfidentialPort() {
+    return connector.getConfidentialPort();
+  }
+
+  @Override
+  public int getConnections() {
+    return connector.getConnections();
+  }
+
+  @Override
+  public int getConnectionsOpen() {
+    return connector.getConnectionsOpen();
+  }
+
+  @Override
+  public int getConnectionsOpenMax() {
+    return connector.getConnectionsOpenMax();
+  }
+
+  @Override
+  public int getConnectionsOpenMin() {
+    return connector.getConnectionsOpenMin();
+  }
+
+  @Override
+  public long getConnectionsDurationAve() {
+    return connector.getConnectionsDurationAve();
+  }
+
+  @Override
+  public long getConnectionsDurationMax() {
+    return connector.getConnectionsDurationMax();
+  }
+
+  @Override
+  public long getConnectionsDurationMin() {
+    return connector.getConnectionsDurationMin();
+  }
+
+  @Override
+  public long getConnectionsDurationTotal() {
+    return connector.getConnectionsDurationTotal();
+  }
+
+  @Override
+  public long getConnectionsRequestAve() {
+    return connector.getConnectionsRequestsAve();
+  }
+
+  @Override
+  public long getConnectionsRequestMax() {
+    return connector.getConnectionsRequestsMax();
+  }
+
+  @Override
+  public long getConnectionsRequestMin() {
+    return connector.getConnectionsRequestsMin();
+  }
+
+  @Override
+  public void turnStatsOn() {
+    connector.setStatsOn(true);
+  }
+
+  @Override
+  public void turnStatsOff() {
+    connector.setStatsOn(false);
+  }
+
+  @Override
+  public void resetStats() {
+    connector.statsReset();
+  }
+
+  @Override
+  public boolean isStatsOn() {
+    return connector.getStatsOn();
+  }
+}
diff --git a/azkaban-exec-server/src/main/java/azkaban/execapp/AzkabanExecutorServer.java b/azkaban-exec-server/src/main/java/azkaban/execapp/AzkabanExecutorServer.java
index 093f809..87925c8 100644
--- a/azkaban-exec-server/src/main/java/azkaban/execapp/AzkabanExecutorServer.java
+++ b/azkaban-exec-server/src/main/java/azkaban/execapp/AzkabanExecutorServer.java
@@ -19,15 +19,12 @@ package azkaban.execapp;
 import com.google.common.base.Throwables;
 
 import org.apache.log4j.Logger;
-import org.eclipse.jetty.server.Connector;
-import org.eclipse.jetty.server.HttpConfiguration;
-import org.eclipse.jetty.server.HttpConnectionFactory;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.ServerConnectionStatistics;
-import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.servlet.ServletContextHandler;
-import org.eclipse.jetty.util.thread.QueuedThreadPool;
 import org.joda.time.DateTimeZone;
+import org.mortbay.jetty.Connector;
+import org.mortbay.jetty.Server;
+import org.mortbay.jetty.servlet.Context;
+import org.mortbay.jetty.servlet.ServletHolder;
+import org.mortbay.thread.QueuedThreadPool;
 
 import java.io.BufferedWriter;
 import java.io.File;
@@ -64,6 +61,7 @@ import azkaban.executor.Executor;
 import azkaban.executor.ExecutorLoader;
 import azkaban.executor.ExecutorManagerException;
 import azkaban.executor.JdbcExecutorLoader;
+import azkaban.jmx.JmxJettyServer;
 import azkaban.metric.IMetricEmitter;
 import azkaban.metric.MetricException;
 import azkaban.metric.MetricReportManager;
@@ -81,14 +79,6 @@ import static azkaban.constants.ServerInternals.AZKABAN_EXECUTOR_PORT_FILENAME;
 import static com.google.common.base.Preconditions.checkState;
 import static java.util.Objects.requireNonNull;
 
-
-/**
- * This class is the entry point for Azkaban Executor
- *
- * TODO This class needs to be refactored and made smaller.
- * TODO Investigate if some components can be extracted into separate classes
- * TODO remove config variables out of this class
- */
 public class AzkabanExecutorServer {
   private static final String CUSTOM_JMX_ATTRIBUTE_PROCESSOR_PROPERTY = "jmx.attribute.processor.class";
   private static final Logger logger = Logger.getLogger(AzkabanExecutorServer.class);
@@ -157,40 +147,39 @@ public class AzkabanExecutorServer {
   private Server createJettyServer(Props props) {
     int maxThreads = props.getInt("executor.maxThreads", DEFAULT_THREAD_NUMBER);
 
-    // HttpConfiguration object is used to configure the HTTP connector
-    final HttpConfiguration httpConfig = new HttpConfiguration();
-    httpConfig.setRequestHeaderSize(props.getInt("jetty.headerBufferSize", DEFAULT_HEADER_BUFFER_SIZE));
-
-    Server server = new Server(new QueuedThreadPool(maxThreads));
-
-    // Creating a connector for HTTP traffic
-    final ServerConnector http = new ServerConnector(server, new HttpConnectionFactory(httpConfig));
-
     /*
      * Default to a port number 0 (zero)
      * The Jetty server automatically finds an unused port when the port number is set to zero
+     * TODO: This is using a highly outdated version of jetty [year 2010]. needs to be updated.
      */
-    http.setPort(props.getInt("executor.port", 0));
+    Server server = new Server(props.getInt("executor.port", 0));
+    QueuedThreadPool httpThreadPool = new QueuedThreadPool(maxThreads);
+    server.setThreadPool(httpThreadPool);
+
+    boolean isStatsOn = props.getBoolean("executor.connector.stats", true);
+    logger.info("Setting up connector with stats on: " + isStatsOn);
 
-    // Add the HTTP connector
-    server.addConnector(http);
+    for (Connector connector : server.getConnectors()) {
+      connector.setStatsOn(isStatsOn);
+      logger.info(String.format(
+          "Jetty connector name: %s, default header buffer size: %d",
+          connector.getName(), connector.getHeaderBufferSize()));
+      connector.setHeaderBufferSize(props.getInt("jetty.headerBufferSize",
+          DEFAULT_HEADER_BUFFER_SIZE));
+      logger.info(String.format(
+          "Jetty connector name: %s, (if) new header buffer size: %d",
+          connector.getName(), connector.getHeaderBufferSize()));
+    }
 
-    ServletContextHandler root = new ServletContextHandler(server, "/", ServletContextHandler.SESSIONS);
+    Context root = new Context(server, "/", Context.SESSIONS);
     root.setMaxFormContentSize(MAX_FORM_CONTENT_SIZE);
 
-    root.addServlet(ExecutorServlet.class, "/executor");
-    root.addServlet(JMXHttpServlet.class, "/jmx");
-    root.addServlet(StatsServlet.class, "/stats");
-    root.addServlet(ServerStatisticsServlet.class, "/serverStatistics");
+    root.addServlet(new ServletHolder(new ExecutorServlet()), "/executor");
+    root.addServlet(new ServletHolder(new JMXHttpServlet()), "/jmx");
+    root.addServlet(new ServletHolder(new StatsServlet()), "/stats");
+    root.addServlet(new ServletHolder(new ServerStatisticsServlet()), "/serverStatistics");
 
     root.setAttribute(ServerInternals.AZKABAN_SERVLET_CONTEXT_KEY, this);
-
-    final boolean isStatsOn = props.getBoolean("executor.connector.stats", true);
-    logger.info("Setting up connector with stats on: " + isStatsOn);
-    if (isStatsOn) {
-      ServerConnectionStatistics.addToAllConnectors(server);
-    }
-
     return server;
   }
 
@@ -497,6 +486,7 @@ public class AzkabanExecutorServer {
     logger.info("Registering MBeans...");
     mbeanServer = ManagementFactory.getPlatformMBeanServer();
 
+    registerMbean("executorJetty", new JmxJettyServer(server));
     registerMbean("flowRunnerManager", new JmxFlowRunnerManager(runnerManager));
     registerMbean("jobJMXMBean", JmxJobMBeanManager.getInstance());
 
@@ -580,11 +570,7 @@ public class AzkabanExecutorServer {
     checkState(connectors.length >= 1, "Server must have at least 1 connector");
 
     // The first connector is created upon initializing the server. That's the one that has the port.
-    final Connector connector = connectors[0];
-
-    checkState(connector instanceof ServerConnector,
-        "Unexpected Connector instance: " + connector.getClass());
-    return ((ServerConnector) connector).getLocalPort();
+    return connectors[0].getLocalPort();
   }
 
   /**
diff --git a/azkaban-exec-server/src/test/java/azkaban/execapp/event/JobCallbackRequestMakerTest.java b/azkaban-exec-server/src/test/java/azkaban/execapp/event/JobCallbackRequestMakerTest.java
index 75ceab9..bd14da4 100644
--- a/azkaban-exec-server/src/test/java/azkaban/execapp/event/JobCallbackRequestMakerTest.java
+++ b/azkaban-exec-server/src/test/java/azkaban/execapp/event/JobCallbackRequestMakerTest.java
@@ -22,18 +22,21 @@ import javax.servlet.http.HttpServletResponse;
 
 import org.apache.http.client.methods.HttpRequestBase;
 import org.apache.log4j.Logger;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.servlet.ServletContextHandler;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.mortbay.jetty.Server;
+import org.mortbay.jetty.servlet.Context;
+import org.mortbay.jetty.servlet.ServletHolder;
 
 import azkaban.jobcallback.JobCallbackConstants;
 import azkaban.jobcallback.JobCallbackStatusEnum;
 import azkaban.utils.Props;
 
 public class JobCallbackRequestMakerTest {
-  private static final Logger logger = Logger.getLogger(JobCallbackRequestMakerTest.class);
+
+  private static final Logger logger = Logger
+      .getLogger(JobCallbackRequestMakerTest.class);
 
   private static final String SLEEP_DURATION_PARAM = "sleepDuration";
   private static final String STATUS_CODE_PARAM = "returnedStatusCode";
@@ -68,8 +71,8 @@ public class JobCallbackRequestMakerTest {
 
       embeddedJettyServer = new Server(PORT_NUMBER);
 
-      ServletContextHandler context = new ServletContextHandler(embeddedJettyServer, "/", ServletContextHandler.SESSIONS);
-      context.addServlet(DelayServlet.class, "/delay");
+      Context context = new Context(embeddedJettyServer, "/", Context.SESSIONS);
+      context.addServlet(new ServletHolder(new DelayServlet()), "/delay");
 
       System.out.println("Start server");
       embeddedJettyServer.start();
diff --git a/azkaban-web-server/src/main/java/azkaban/webapp/AzkabanWebServer.java b/azkaban-web-server/src/main/java/azkaban/webapp/AzkabanWebServer.java
index c6a149d..2053f0b 100644
--- a/azkaban-web-server/src/main/java/azkaban/webapp/AzkabanWebServer.java
+++ b/azkaban-web-server/src/main/java/azkaban/webapp/AzkabanWebServer.java
@@ -18,7 +18,6 @@ package azkaban.webapp;
 
 import com.codahale.metrics.MetricRegistry;
 
-import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -47,19 +46,15 @@ import org.apache.velocity.app.VelocityEngine;
 import org.apache.velocity.runtime.log.Log4JLogChute;
 import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
 import org.apache.velocity.runtime.resource.loader.JarResourceLoader;
-import org.eclipse.jetty.server.HttpConfiguration;
-import org.eclipse.jetty.server.HttpConnectionFactory;
-import org.eclipse.jetty.server.SecureRequestCustomizer;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.ServerConnectionStatistics;
-import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.server.SslConnectionFactory;
-import org.eclipse.jetty.servlet.DefaultServlet;
-import org.eclipse.jetty.servlet.ServletContextHandler;
-import org.eclipse.jetty.servlet.ServletHolder;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-import org.eclipse.jetty.util.thread.QueuedThreadPool;
 import org.joda.time.DateTimeZone;
+import org.mortbay.jetty.Connector;
+import org.mortbay.jetty.Server;
+import org.mortbay.jetty.bio.SocketConnector;
+import org.mortbay.jetty.security.SslSocketConnector;
+import org.mortbay.jetty.servlet.Context;
+import org.mortbay.jetty.servlet.DefaultServlet;
+import org.mortbay.jetty.servlet.ServletHolder;
+import org.mortbay.thread.QueuedThreadPool;
 
 import azkaban.alert.Alerter;
 import azkaban.constants.ServerInternals;
@@ -68,6 +63,7 @@ import azkaban.database.AzkabanDatabaseSetup;
 import azkaban.executor.ExecutorManager;
 import azkaban.executor.JdbcExecutorLoader;
 import azkaban.jmx.JmxExecutorManager;
+import azkaban.jmx.JmxJettyServer;
 import azkaban.jmx.JmxTriggerManager;
 import azkaban.project.JdbcProjectLoader;
 import azkaban.project.ProjectManager;
@@ -131,11 +127,6 @@ import com.linkedin.restli.server.RestliServlet;
  * for sessionizing. jetty.keystore - Jetty keystore . jetty.keypassword - Jetty
  * keystore password jetty.truststore - Jetty truststore jetty.trustpassword -
  * Jetty truststore password
- *
- * TODO This class needs to be refactored and made smaller.
- * TODO Investigate if some components can be extracted into separate classes
- * TODO extract server creation into separate methods
- * TODO remove config variables out of this class
  */
 public class AzkabanWebServer extends AzkabanServer {
   private static final String AZKABAN_ACCESS_LOGGER_NAME =
@@ -150,6 +141,7 @@ public class AzkabanWebServer extends AzkabanServer {
       "azkaban.private.properties";
 
   private static final int MAX_FORM_CONTENT_SIZE = 10 * 1024 * 1024;
+  private static final int MAX_HEADER_BUFFER_SIZE = 10 * 1024 * 1024;
   private static AzkabanWebServer app;
 
   private static final String DEFAULT_TIMEZONE_ID = "default.timezone.id";
@@ -652,10 +644,13 @@ public class AzkabanWebServer extends AzkabanServer {
   private VelocityEngine configureVelocityEngine(final boolean devMode) {
     VelocityEngine engine = new VelocityEngine();
     engine.setProperty("resource.loader", "classpath, jar");
-    engine.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
+    engine.setProperty("classpath.resource.loader.class",
+        ClasspathResourceLoader.class.getName());
     engine.setProperty("classpath.resource.loader.cache", !devMode);
-    engine.setProperty("classpath.resource.loader.modificationCheckInterval", 5L);
-    engine.setProperty("jar.resource.loader.class", JarResourceLoader.class.getName());
+    engine.setProperty("classpath.resource.loader.modificationCheckInterval",
+        5L);
+    engine.setProperty("jar.resource.loader.class",
+        JarResourceLoader.class.getName());
     engine.setProperty("jar.resource.loader.cache", !devMode);
     engine.setProperty("resource.manager.logwhenfound", false);
     engine.setProperty("input.encoding", "UTF-8");
@@ -664,12 +659,15 @@ public class AzkabanWebServer extends AzkabanServer {
     engine.setProperty("resource.manager.logwhenfound", false);
     engine.setProperty("velocimacro.permissions.allow.inline", true);
     engine.setProperty("velocimacro.library.autoreload", devMode);
-    engine.setProperty("velocimacro.library", "/azkaban/webapp/servlet/velocity/macros.vm");
-    engine.setProperty("velocimacro.permissions.allow.inline.to.replace.global", true);
+    engine.setProperty("velocimacro.library",
+        "/azkaban/webapp/servlet/velocity/macros.vm");
+    engine.setProperty(
+        "velocimacro.permissions.allow.inline.to.replace.global", true);
     engine.setProperty("velocimacro.arguments.strict", true);
     engine.setProperty("runtime.log.invalid.references", devMode);
     engine.setProperty("runtime.log.logsystem.class", Log4JLogChute.class);
-    engine.setProperty("runtime.log.logsystem.log4j.logger", Logger.getLogger("org.apache.velocity.Logger"));
+    engine.setProperty("runtime.log.logsystem.log4j.logger",
+        Logger.getLogger("org.apache.velocity.Logger"));
     engine.setProperty("parser.pool.size", 3);
     return engine;
   }
@@ -705,89 +703,67 @@ public class AzkabanWebServer extends AzkabanServer {
       return;
     }
 
-    // Create a Jetty server with custom Thread pool
-    final int maxThreads = azkabanSettings.getInt("jetty.maxThreads", DEFAULT_THREAD_NUMBER);
-    final Server server = new Server(new QueuedThreadPool(maxThreads));
-
-    final int port = azkabanSettings.getInt("jetty.port", DEFAULT_PORT_NUMBER);
-    final int sslPort = azkabanSettings.getInt("jetty.ssl.port", DEFAULT_SSL_PORT_NUMBER);
-    final boolean useSsl = azkabanSettings.getBoolean("jetty.use.ssl", true);
-
-    /*
-     * Configuring HTTP
-     * HttpConfiguration is a configuration holder for http and https.
-     *  - default scheme for http is <code>http</code>,
-     *  - default for secured http is <code>https</code>
-     *
-     * The port for secured communication is set here.
-     */
-    final HttpConfiguration httpConfig = new HttpConfiguration();
-    httpConfig.setSecureScheme("https");
-    httpConfig.setSecurePort(sslPort);
-
-    /*
-     * A Jetty server can have multiple connectors that listens on different ports.
-     * Creating a connector for HTTP traffic
-     */
-    final ServerConnector http = new ServerConnector(server, new HttpConnectionFactory(httpConfig));
-    http.setPort(port);
-    server.addConnector(http);
-
-    if (useSsl) {
-      logger.info("Setting up Jetty Https Server with port:" + sslPort + " and numThreads:" + maxThreads);
-
-      // SslContextFactory is responsible for holding SSL configuration
-      final SslContextFactory sslContextFactory = new SslContextFactory();
-      sslContextFactory.setKeyStorePath(azkabanSettings.getString("jetty.keystore"));
-      sslContextFactory.setKeyStorePassword(azkabanSettings.getString("jetty.password"));
-      sslContextFactory.setKeyManagerPassword(azkabanSettings.getString("jetty.keypassword"));
-      sslContextFactory.setTrustStorePath(azkabanSettings.getString("jetty.truststore"));
-      sslContextFactory.setTrustStorePassword(azkabanSettings.getString("jetty.trustpassword"));
+    int maxThreads =
+        azkabanSettings.getInt("jetty.maxThreads", DEFAULT_THREAD_NUMBER);
+    boolean isStatsOn =
+        azkabanSettings.getBoolean("jetty.connector.stats", true);
+    logger.info("Setting up connector with stats on: " + isStatsOn);
+
+    boolean ssl;
+    int port;
+    final Server server = new Server();
+    if (azkabanSettings.getBoolean("jetty.use.ssl", true)) {
+      int sslPortNumber =
+          azkabanSettings.getInt("jetty.ssl.port", DEFAULT_SSL_PORT_NUMBER);
+      port = sslPortNumber;
+      ssl = true;
+      logger.info("Setting up Jetty Https Server with port:" + sslPortNumber
+          + " and numThreads:" + maxThreads);
+
+      SslSocketConnector secureConnector = new SslSocketConnector();
+      secureConnector.setPort(sslPortNumber);
+      secureConnector.setKeystore(azkabanSettings.getString("jetty.keystore"));
+      secureConnector.setPassword(azkabanSettings.getString("jetty.password"));
+      secureConnector.setKeyPassword(azkabanSettings
+          .getString("jetty.keypassword"));
+      secureConnector.setTruststore(azkabanSettings
+          .getString("jetty.truststore"));
+      secureConnector.setTrustPassword(azkabanSettings
+          .getString("jetty.trustpassword"));
+      secureConnector.setHeaderBufferSize(MAX_HEADER_BUFFER_SIZE);
 
       // set up vulnerable cipher suites to exclude
       List<String> cipherSuitesToExclude = azkabanSettings.getStringList("jetty.excludeCipherSuites");
       logger.info("Excluded Cipher Suites: " + String.valueOf(cipherSuitesToExclude));
       if (cipherSuitesToExclude != null && !cipherSuitesToExclude.isEmpty()) {
-        sslContextFactory.setExcludeCipherSuites(cipherSuitesToExclude.toArray(new String[0]));
+        secureConnector.setExcludeCipherSuites(cipherSuitesToExclude.toArray(new String[0]));
       }
 
-      /*
-       * Configuring HTTPS
-       * A new HttpConfiguration object is required for each connector. Cloning previous configuration here.
-       */
-      final HttpConfiguration httpsConfig = new HttpConfiguration(httpConfig);
-      /*
-       * SecureRequestCustomizer which is how a new connector is able to resolve the https connection before
-       * handing control over to the Jetty Server.
-       */
-      httpsConfig.addCustomizer(new SecureRequestCustomizer());
-
-      // Creating a connector for HTTPS. The SslConnectionFactory is responsible for SSL configuration.
-      final ServerConnector https = new ServerConnector(server,
-          new SslConnectionFactory(sslContextFactory,"http/1.1"),
-          new HttpConnectionFactory(httpsConfig));
-      https.setPort(sslPort);
-      https.setIdleTimeout(500000);
-
-      // Add the HTTPS connector
-      server.addConnector(https);
+      server.addConnector(secureConnector);
+    } else {
+      ssl = false;
+      port = azkabanSettings.getInt("jetty.port", DEFAULT_PORT_NUMBER);
+      SocketConnector connector = new SocketConnector();
+      connector.setPort(port);
+      connector.setHeaderBufferSize(MAX_HEADER_BUFFER_SIZE);
+      server.addConnector(connector);
     }
 
-    final boolean statsEnabled = azkabanSettings.getBoolean("jetty.connector.stats", true);
-    logger.info("Setting up connector with stats on: " + statsEnabled);
-
-    if (statsEnabled) {
-      ServerConnectionStatistics.addToAllConnectors(server);
+    // setting stats configuration for connectors
+    for (Connector connector : server.getConnectors()) {
+      connector.setStatsOn(isStatsOn);
     }
 
     String hostname = azkabanSettings.getString("jetty.hostname", "localhost");
     azkabanSettings.put("server.hostname", hostname);
     azkabanSettings.put("server.port", port);
-    azkabanSettings.put("server.useSSL", String.valueOf(useSsl));
+    azkabanSettings.put("server.useSSL", String.valueOf(ssl));
 
     app = new AzkabanWebServer(server, azkabanSettings);
 
-    final boolean checkDB = azkabanSettings.getBoolean(AzkabanDatabaseSetup.DATABASE_CHECK_VERSION, false);
+    boolean checkDB =
+        azkabanSettings.getBoolean(AzkabanDatabaseSetup.DATABASE_CHECK_VERSION,
+            false);
     if (checkDB) {
       AzkabanDatabaseSetup setup = new AzkabanDatabaseSetup(azkabanSettings);
       setup.loadTableInfo();
@@ -800,34 +776,38 @@ public class AzkabanWebServer extends AzkabanServer {
       }
     }
 
-    String staticDir = azkabanSettings.getString("web.resource.dir", DEFAULT_STATIC_DIR);
-    logger.info("Setting up web resource dir " + staticDir);
-
-    ServletContextHandler root = new ServletContextHandler(server, "/", ServletContextHandler.SESSIONS);
+    QueuedThreadPool httpThreadPool = new QueuedThreadPool(maxThreads);
+    server.setThreadPool(httpThreadPool);
 
-    root.setContextPath("/");
+    String staticDir =
+        azkabanSettings.getString("web.resource.dir", DEFAULT_STATIC_DIR);
+    logger.info("Setting up web resource dir " + staticDir);
+    Context root = new Context(server, "/", Context.SESSIONS);
     root.setMaxFormContentSize(MAX_FORM_CONTENT_SIZE);
 
+    String defaultServletPath =
+        azkabanSettings.getString("azkaban.default.servlet.path", "/index");
     root.setResourceBase(staticDir);
-
-    final String defaultServletPath = azkabanSettings.getString("azkaban.default.servlet.path", "/index");
-    root.addServlet(new ServletHolder(new IndexRedirectServlet(defaultServletPath)), "/");
-    root.addServlet(new ServletHolder(new ProjectServlet()), "/index");
-
-    // TODO static content should be provided by a separate single servlet
-    root.addServlet(DefaultServlet.class, "/css/*");
-    root.addServlet(DefaultServlet.class, "/js/*");
-    root.addServlet(DefaultServlet.class, "/images/*");
-    root.addServlet(DefaultServlet.class, "/fonts/*");
-    root.addServlet(DefaultServlet.class, "/favicon.ico");
-
-    root.addServlet(ProjectManagerServlet.class, "/manager");
-    root.addServlet(ExecutorServlet.class, "/executor");
-    root.addServlet(HistoryServlet.class, "/history");
-    root.addServlet(ScheduleServlet.class, "/schedule");
-    root.addServlet(JMXHttpServlet.class, "/jmx");
-    root.addServlet(TriggerManagerServlet.class, "/triggers");
-    root.addServlet(StatsServlet.class, "/stats");
+    ServletHolder indexRedirect =
+        new ServletHolder(new IndexRedirectServlet(defaultServletPath));
+    root.addServlet(indexRedirect, "/");
+    ServletHolder index = new ServletHolder(new ProjectServlet());
+    root.addServlet(index, "/index");
+
+    ServletHolder staticServlet = new ServletHolder(new DefaultServlet());
+    root.addServlet(staticServlet, "/css/*");
+    root.addServlet(staticServlet, "/js/*");
+    root.addServlet(staticServlet, "/images/*");
+    root.addServlet(staticServlet, "/fonts/*");
+    root.addServlet(staticServlet, "/favicon.ico");
+
+    root.addServlet(new ServletHolder(new ProjectManagerServlet()), "/manager");
+    root.addServlet(new ServletHolder(new ExecutorServlet()), "/executor");
+    root.addServlet(new ServletHolder(new HistoryServlet()), "/history");
+    root.addServlet(new ServletHolder(new ScheduleServlet()), "/schedule");
+    root.addServlet(new ServletHolder(new JMXHttpServlet()), "/jmx");
+    root.addServlet(new ServletHolder(new TriggerManagerServlet()), "/triggers");
+    root.addServlet(new ServletHolder(new StatsServlet()), "/stats");
 
     ServletHolder restliHolder = new ServletHolder(new RestliServlet());
     restliHolder.setInitParameter("resourcePackages", "azkaban.restli");
@@ -838,8 +818,10 @@ public class AzkabanWebServer extends AzkabanServer {
     loadViewerPlugins(root, viewerPluginDir, app.getVelocityEngine());
 
     // triggerplugin
-    String triggerPluginDir = azkabanSettings.getString("trigger.plugin.dir", "plugins/triggers");
-    Map<String, TriggerPlugin> triggerPlugins = loadTriggerPlugins(root, triggerPluginDir, app);
+    String triggerPluginDir =
+        azkabanSettings.getString("trigger.plugin.dir", "plugins/triggers");
+    Map<String, TriggerPlugin> triggerPlugins =
+        loadTriggerPlugins(root, triggerPluginDir, app);
     app.setTriggerPlugins(triggerPlugins);
     // always have basic time trigger
     // TODO: find something else to do the job
@@ -878,13 +860,15 @@ public class AzkabanWebServer extends AzkabanServer {
             && new File("/usr/bin/head").exists()) {
           logger.info("logging top memeory consumer");
 
-          ProcessBuilder processBuilder =
-              new ProcessBuilder("/bin/bash", "-c", "/bin/ps aux --sort -rss | /usr/bin/head");
+          java.lang.ProcessBuilder processBuilder =
+              new java.lang.ProcessBuilder("/bin/bash", "-c",
+                  "/bin/ps aux --sort -rss | /usr/bin/head");
           Process p = processBuilder.start();
           p.waitFor();
 
           InputStream is = p.getInputStream();
-          BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+          java.io.BufferedReader reader =
+              new java.io.BufferedReader(new InputStreamReader(is));
           String line = null;
           while ((line = reader.readLine()) != null) {
             logger.info(line);
@@ -893,10 +877,11 @@ public class AzkabanWebServer extends AzkabanServer {
         }
       }
     });
-    logger.info("Server started. HTTP: " + port + (!useSsl? "": " HTTPS: " + sslPort));
+    logger.info("Server running on " + (ssl ? "ssl" : "") + " port " + port
+        + ".");
   }
 
-  private static Map<String, TriggerPlugin> loadTriggerPlugins(ServletContextHandler root,
+  private static Map<String, TriggerPlugin> loadTriggerPlugins(Context root,
       String pluginPath, AzkabanWebServer azkabanWebApp) {
     File triggerPluginPath = new File(pluginPath);
     if (!triggerPluginPath.exists()) {
@@ -1006,7 +991,7 @@ public class AzkabanWebServer extends AzkabanServer {
       try {
         constructor =
             triggerClass.getConstructor(String.class, Props.class,
-                ServletContextHandler.class, AzkabanWebServer.class);
+                Context.class, AzkabanWebServer.class);
       } catch (NoSuchMethodException e) {
         logger.error("Constructor not found in " + pluginClass);
         continue;
@@ -1043,7 +1028,7 @@ public class AzkabanWebServer extends AzkabanServer {
     return triggerPlugins;
   }
 
-  private static void loadViewerPlugins(ServletContextHandler root, String pluginPath,
+  private static void loadViewerPlugins(Context root, String pluginPath,
       VelocityEngine ve) {
     File viewerPluginPath = new File(pluginPath);
     if (!viewerPluginPath.exists()) {
@@ -1278,6 +1263,7 @@ public class AzkabanWebServer extends AzkabanServer {
     logger.info("Registering MBeans...");
     mbeanServer = ManagementFactory.getPlatformMBeanServer();
 
+    registerMbean("jetty", new JmxJettyServer(server));
     registerMbean("triggerManager", new JmxTriggerManager(triggerManager));
     if (executorManager instanceof ExecutorManager) {
       registerMbean("executorManager", new JmxExecutorManager(
diff --git a/azkaban-web-server/src/test/java/azkaban/fixture/MockLoginAzkabanServlet.java b/azkaban-web-server/src/test/java/azkaban/fixture/MockLoginAzkabanServlet.java
index 84a9967..e266711 100644
--- a/azkaban-web-server/src/test/java/azkaban/fixture/MockLoginAzkabanServlet.java
+++ b/azkaban-web-server/src/test/java/azkaban/fixture/MockLoginAzkabanServlet.java
@@ -16,20 +16,29 @@
 
 package azkaban.fixture;
 
+
+import azkaban.server.AzkabanServer;
 import azkaban.server.session.Session;
 import azkaban.server.session.SessionCache;
+import azkaban.user.UserManager;
 import azkaban.utils.Props;
 import azkaban.webapp.AzkabanWebServer;
 import azkaban.webapp.servlet.LoginAbstractAzkabanServlet;
-import java.io.IOException;
+import azkaban.user.User;
+import org.apache.velocity.app.VelocityEngine;
+import org.mockito.Spy;
+import org.mortbay.jetty.Server;
+
+import javax.servlet.ServletConfig;
 import javax.servlet.ServletException;
+import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-import org.apache.velocity.app.VelocityEngine;
 
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
+import java.io.IOException;
+import java.util.UUID;
+
+import static org.mockito.Mockito.*;
 
 public class MockLoginAzkabanServlet extends LoginAbstractAzkabanServlet {
 
@@ -85,7 +94,10 @@ public class MockLoginAzkabanServlet extends LoginAbstractAzkabanServlet {
             throws Exception{
 
         MockLoginAzkabanServlet servlet = new MockLoginAzkabanServlet();
+
+        Server server = mock(Server.class);
         Props props = new Props();
+        UserManager userManager = mock(UserManager.class);
 
         // Need to mock and inject an application instance into the servlet
         AzkabanWebServer app = mock(AzkabanWebServer.class);