From 11562f4402dd29dc5ae7e57721c1b4620f1d9d75 Mon Sep 17 00:00:00 2001
From: Jonathan Hsieh <jon@cloudera.com>
Date: Sat, 18 Jun 2011 12:00:54 -0700
Subject: [PATCH] FLUME-667/FLUME-668: Restored stacks applet to master and node / Add logs webapp to master and node

---
 .../java/com/cloudera/flume/agent/FlumeNode.java   |    9 ++++-
 .../cloudera/flume/conf/FlumeConfiguration.java    |   12 +++++-
 .../com/cloudera/flume/master/FlumeMaster.java     |   23 +++++-----
 .../java/com/cloudera/util/InternalHttpServer.java |   43 +++++++++++++++++++-
 4 files changed, 71 insertions(+), 16 deletions(-)

diff --git a/flume-core/src/main/java/com/cloudera/flume/agent/FlumeNode.java b/flume-core/src/main/java/com/cloudera/flume/agent/FlumeNode.java
index ada8f59..b8f2b67 100644
--- a/flume-core/src/main/java/com/cloudera/flume/agent/FlumeNode.java
+++ b/flume-core/src/main/java/com/cloudera/flume/agent/FlumeNode.java
@@ -63,6 +63,7 @@ import com.cloudera.util.FileUtil;
 import com.cloudera.util.InternalHttpServer;
 import com.cloudera.util.NetUtils;
 import com.cloudera.util.Pair;
+import com.cloudera.util.StatusHttpServer.StackServlet;
 import com.google.common.base.Preconditions;
 
 /**
@@ -260,9 +261,15 @@ public class FlumeNode implements Reportable {
       try {
         http = new InternalHttpServer();
 
+        http.addHandler(InternalHttpServer.createLogAppContext());
+
+        http.addHandler(InternalHttpServer.createServletContext(
+            StackServlet.class, "/stacks", "/*", "stacks"));
+
         http.setBindAddress("0.0.0.0");
         http.setPort(conf.getNodeStatusPort());
-        http.setWebappDir(new File(conf.getNodeWebappRoot()));
+        String webAppRoot = FlumeConfiguration.get().getNodeWebappRoot();
+        http.setWebappDir(new File(webAppRoot));
         http.setScanForApps(true);
 
         http.start();
diff --git a/flume-core/src/main/java/com/cloudera/flume/conf/FlumeConfiguration.java b/flume-core/src/main/java/com/cloudera/flume/conf/FlumeConfiguration.java
index 39ae4fc..9b41401 100644
--- a/flume-core/src/main/java/com/cloudera/flume/conf/FlumeConfiguration.java
+++ b/flume-core/src/main/java/com/cloudera/flume/conf/FlumeConfiguration.java
@@ -1000,14 +1000,22 @@ public class FlumeConfiguration extends Configuration {
    * Returns the webapp root for the master.
    */
   public String getMasterWebappRoot() {
-    return getFlumeHome() + File.separator + get(WEBAPP_ROOT_MASTER, null);
+    String home = getFlumeHome();
+    if (home == null) {
+      home = ".";
+    }
+    return home + File.separator + get(WEBAPP_ROOT_MASTER, null);
   }
 
   /**
    * Returns the webapp root for the node (i.e. agent or collector).
    */
   public String getNodeWebappRoot() {
-    return getFlumeHome() + File.separator + get(WEBAPP_ROOT_NODE, null);
+    String home = getFlumeHome();
+    if (home == null) {
+      home = ".";
+    }
+    return home + File.separator + get(WEBAPP_ROOT_NODE, null);
   }
 
   /**
diff --git a/flume-core/src/main/java/com/cloudera/flume/master/FlumeMaster.java b/flume-core/src/main/java/com/cloudera/flume/master/FlumeMaster.java
index 013283c..5c99c43 100644
--- a/flume-core/src/main/java/com/cloudera/flume/master/FlumeMaster.java
+++ b/flume-core/src/main/java/com/cloudera/flume/master/FlumeMaster.java
@@ -54,6 +54,7 @@ import com.cloudera.flume.util.SystemInfo;
 import com.cloudera.util.CheckJavaVersion;
 import com.cloudera.util.InternalHttpServer;
 import com.cloudera.util.NetUtils;
+import com.cloudera.util.StatusHttpServer.StackServlet;
 
 /**
  * This is a first cut at a server for distributing configurations to different
@@ -248,18 +249,17 @@ public class FlumeMaster implements Reportable {
     ReportManager.get().add(sysInfo);
 
     if (doHttp) {
-      String webPath = FlumeNode.getWebPath(cfg);
-
       http = new InternalHttpServer();
 
-      /*
-      this.http = new StatusHttpServer("flumeconfig", webPath, "0.0.0.0", cfg
-          .getMasterHttpPort(), false);
-      http.addServlet(jerseyMasterServlet(), "/master/*");
-      */
+      http.addHandler(InternalHttpServer.createLogAppContext());
+      http.addHandler(InternalHttpServer.createServletContext(
+          StackServlet.class, "/stacks", "/*", "stacks"));
+
       http.setBindAddress("0.0.0.0");
       http.setPort(cfg.getMasterHttpPort());
-      http.setWebappDir(new File(FlumeConfiguration.get().getMasterWebappRoot()));
+      String webAppRoot = FlumeConfiguration.get().getMasterWebappRoot();
+      http.setWebappDir(new File(webAppRoot));
+      LOG.info("Webserver root directory: " + webAppRoot);
       http.start();
     }
 
@@ -282,7 +282,7 @@ public class FlumeMaster implements Reportable {
        * Start the Avro/Thrift ReportServer based on the flag set in the
        * configuration file.
        */
-      if (cfg.getReportServerRPC() == cfg.RPC_TYPE_AVRO) {
+      if (cfg.getReportServerRPC() == FlumeConfiguration.RPC_TYPE_AVRO) {
         avroReportServer.serve();
       } else {
         thriftReportServer.serve();
@@ -344,7 +344,7 @@ public class FlumeMaster implements Reportable {
       /*
        * Close the reportserver which started.
        */
-      if (cfg.getReportServerRPC() == cfg.RPC_TYPE_AVRO) {
+      if (cfg.getReportServerRPC() == FlumeConfiguration.RPC_TYPE_AVRO) {
         if (avroReportServer != null) {
           avroReportServer.stop();
           avroReportServer = null;
@@ -481,8 +481,7 @@ public class FlumeMaster implements Reportable {
     FlumeNode.logEnvironment(LOG);
     // Make sure the Java version is not older than 1.6
     if (!CheckJavaVersion.isVersionOk()) {
-      LOG
-          .error("Exiting because of an old Java version or Java version in bad format");
+      LOG.error("Exiting because of an old Java version or Java version in bad format");
       System.exit(-1);
     }
     FlumeConfiguration.hardExitLoadConfig(); // if config file is bad hardexit.
diff --git a/flume-core/src/main/java/com/cloudera/util/InternalHttpServer.java b/flume-core/src/main/java/com/cloudera/util/InternalHttpServer.java
index 63290ca..1f41460 100644
--- a/flume-core/src/main/java/com/cloudera/util/InternalHttpServer.java
+++ b/flume-core/src/main/java/com/cloudera/util/InternalHttpServer.java
@@ -4,11 +4,16 @@ import java.io.File;
 
 import org.mortbay.jetty.Connector;
 import org.mortbay.jetty.Server;
+import org.mortbay.jetty.handler.ContextHandlerCollection;
 import org.mortbay.jetty.nio.SelectChannelConnector;
+import org.mortbay.jetty.servlet.Context;
+import org.mortbay.jetty.servlet.DefaultServlet;
+import org.mortbay.jetty.servlet.ServletHolder;
 import org.mortbay.jetty.webapp.WebAppContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.cloudera.util.StatusHttpServer.StackServlet;
 import com.google.common.base.Preconditions;
 
 /**
@@ -89,11 +94,13 @@ public class InternalHttpServer {
   private int port;
   private String bindAddress;
   private boolean scanForApps;
+  private ContextHandlerCollection handlers;
 
   public InternalHttpServer() {
     port = 0;
     bindAddress = "0.0.0.0";
     scanForApps = true;
+    handlers = new ContextHandlerCollection();
   }
 
   public void initialize() {
@@ -106,6 +113,7 @@ public class InternalHttpServer {
       connector.setHost(bindAddress);
 
       server.addConnector(connector);
+      server.addHandler(handlers);
     }
   }
 
@@ -140,11 +148,12 @@ public class InternalHttpServer {
 
     logger.debug("creating context {} -> {}", name, path);
 
+    // WebAppContext is for loading war files.
     WebAppContext handler = new WebAppContext(path.getPath(), "/" + name);
 
     handler.setParentLoaderPriority(true);
 
-    server.addHandler(handler);
+    handlers.addHandler(handler);
 
     return true;
   }
@@ -278,4 +287,36 @@ public class InternalHttpServer {
 
   }
 
+  public void addHandler(Context ctx) {
+    if (ctx == null) {
+      logger.warn("Attempting to add null webapp context");
+      return;
+    }
+    handlers.addHandler(ctx);
+  }
+
+  public static Context createLogAppContext() {
+    Context ctx = new Context();
+    // logs applet
+    String logDir = System.getProperty("flume.log.dir");
+    if (logDir != null) {
+      ctx.setContextPath("/logs");
+      ctx.setResourceBase(logDir);
+      ctx.addServlet(DefaultServlet.class, "/*");
+      ctx.setDisplayName("logs");
+    }
+    return ctx;
+  }
+
+  public static Context createServletContext(Class<?> sltClz, String contextPath,
+      String pathSpec, String name) {
+    Context ctx = new Context();
+    ServletHolder holder = new ServletHolder(StackServlet.class);
+    ctx.setContextPath("/stacks");
+    ctx.addServlet(holder, "/*");
+    ctx.setDisplayName("stacks");
+
+    return ctx;
+  }
+
 }
-- 
1.7.1

