Package edu.berkeley.xtrace.server

Source Code of edu.berkeley.xtrace.server.XTraceServer$GetReportsServlet

/*
* Copyright (c) 2005,2006,2007 The Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in the
*       documentation and/or other materials provided with the distribution.
*     * Neither the name of the University of California, nor the
*       names of its contributors may be used to endorse or promote products
*       derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY OF CALIFORNIA ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/


package edu.berkeley.xtrace.server;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.URLDecoder;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

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

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.servlet.Context;
import org.mortbay.jetty.servlet.DefaultServlet;
import org.mortbay.jetty.servlet.ServletHolder;
import org.mortbay.servlet.CGI;

import edu.berkeley.xtrace.TaskID;
import edu.berkeley.xtrace.XTraceException;
import edu.berkeley.xtrace.reporting.Report;

/**
* @author George Porter
*
*/
public final class XTraceServer {
  private static final Logger LOG = Logger.getLogger(XTraceServer.class);

  private static ReportSource[] sources;
 
  private static BlockingQueue<String> incomingReportQueue, reportsToStorageQueue;

  private static ThreadPerTaskExecutor sourcesExecutor;

  private static ExecutorService storeExecutor;

  private static QueryableReportStore reportstore;
 
  private static final DateFormat JSON_DATE_FORMAT =
    new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  private static final DateFormat HTML_DATE_FORMAT =
    new SimpleDateFormat("MMM dd yyyy, HH:mm:ss");
 
  // Default number of results to show per page for web UI
  private static final int PAGE_LENGTH = 25;
 
  public static void main(String[] args) {
   
    // If they use the default configuration (the FileTree report store),
    // then they have to specify the directory in which to store reports
    if (System.getProperty("xtrace.server.store") == null) {
      if (args.length < 1) {
        System.err.println("Usage: XTraceServer <dataDir>");
        System.exit(1);
      }
      System.setProperty("xtrace.server.storedirectory", args[0]);
    }
   
    setupReportSources();
    setupReportStore();
    setupBackplane();
    setupWebInterface();
  }

  private static void setupReportSources() {
   
    incomingReportQueue = new ArrayBlockingQueue<String>(1024, true);
    sourcesExecutor = new ThreadPerTaskExecutor();
   
    // Default input sources
    String sourcesStr = "edu.berkeley.xtrace.server.UdpReportSource," +
                        "edu.berkeley.xtrace.server.TcpReportSource," +
                        "edu.berkeley.xtrace.server.ThriftReportSource";
   
    if (System.getProperty("xtrace.server.sources") != null) {
      sourcesStr = System.getProperty("xtrace.server.sources");
    } else {
      LOG.warn("No server report sources specified... using defaults (Udp,Tcp,Thrift)");
    }
    String[] sourcesLst = sourcesStr.split(",");
   
    sources = new ReportSource[sourcesLst.length];
    for (int i = 0; i < sourcesLst.length; i++) {
      try {
        LOG.info("Starting report source '" + sourcesLst[i] + "'");
        sources[i] = (ReportSource) Class.forName(sourcesLst[i]).newInstance();
      } catch (InstantiationException e1) {
        LOG.fatal("Could not instantiate report source", e1);
        System.exit(-1);
      } catch (IllegalAccessException e1) {
        LOG.fatal("Could not access report source", e1);
        System.exit(-1);
      } catch (ClassNotFoundException e1) {
        LOG.fatal("Could not find report source class", e1);
        System.exit(-1);
      }
      sources[i].setReportQueue(incomingReportQueue);
      try {
        sources[i].initialize();
      } catch (XTraceException e) {
        LOG.warn("Unable to initialize report source", e);
        // TODO: gracefully shutdown any previously started threads?
        System.exit(-1);
      }
      sourcesExecutor.execute((Runnable) sources[i]);
    }
  }
 
  private static void setupReportStore() {
    reportsToStorageQueue = new ArrayBlockingQueue<String>(1024);
   
    String storeStr = "edu.berkeley.xtrace.server.FileTreeReportStore";
    if (System.getProperty("xtrace.server.store") != null) {
      storeStr = System.getProperty("xtrace.server.store");
    } else {
      LOG.warn("No server report store specified... using default (FileTreeReportStore)");
    }
   
    reportstore = null;
    try {
      reportstore = (QueryableReportStore) Class.forName(storeStr).newInstance();
    } catch (InstantiationException e1) {
      LOG.fatal("Could not instantiate report store", e1);
      System.exit(-1);
    } catch (IllegalAccessException e1) {
      LOG.fatal("Could not access report store class", e1);
      System.exit(-1);
    } catch (ClassNotFoundException e1) {
      LOG.fatal("Could not find report store class", e1);
      System.exit(-1);
    }
   
    reportstore.setReportQueue(reportsToStorageQueue);
    try {
      reportstore.initialize();
    } catch (XTraceException e) {
      LOG.fatal("Unable to start report store", e);
      System.exit(-1);
    }
   
    storeExecutor = Executors.newSingleThreadExecutor();
    storeExecutor.execute(reportstore);
   
    /* Every N seconds we should sync the report store */
    String syncIntervalStr = System.getProperty("xtrace.server.syncinterval", "5");
    long syncInterval = Integer.parseInt(syncIntervalStr);
    Timer timer= new Timer();
    timer.schedule(new SyncTimer(reportstore), syncInterval*1000, syncInterval*1000);
   
    /* Add a shutdown hook to flush and close the report store */
    Runtime.getRuntime().addShutdownHook(new Thread() {
      public void run() {
        reportstore.shutdown();
      }
    });
  }
 
  private static void setupBackplane() {
    new Thread(new Runnable() {
      public void run() {
        LOG.info("Backplane waiting for packets");
       
        while (true) {
          String msg = null;
          try {
            msg = incomingReportQueue.take();
          } catch (InterruptedException e) {
            LOG.warn("Interrupted", e);
            continue;
          }
          reportsToStorageQueue.offer(msg);
        }
      }
    }).start();
  }
 
  private static class ThreadPerTaskExecutor implements Executor {
       public void execute(Runnable r) {
           new Thread(r).start();
       }
   }
 
  private static void setupWebInterface() {
    String webDir = System.getProperty("xtrace.backend.webui.dir");
    if (webDir == null) {
      LOG.warn("No webui directory specified... using default (./src/webui)");
      webDir = "./src/webui";
    }
   
    int httpPort =
      Integer.parseInt(System.getProperty("xtrace.backend.httpport", "8080"));

    // Initialize Velocity template engine
    try {
      Velocity.setProperty(Velocity.RUNTIME_LOG_LOGSYSTEM_CLASS,
          "org.apache.velocity.runtime.log.Log4JLogChute");
      Velocity.setProperty("runtime.log.logsystem.log4j.logger",
          "edu.berkeley.xtrace.server.XTraceServer");
      Velocity.setProperty("file.resource.loader.path", webDir + "/templates");
      Velocity.setProperty("file.resource.loader.cache", "true");
      Velocity.init();
    } catch (Exception e) {
      LOG.warn("Failed to initialize Velocity", e);
    }
   
    // Create Jetty server
    Server server = new Server(httpPort);
    Context context = new Context(server, "/");
   
    // Create a CGI servlet for scripts in webui/cgi-bin
    ServletHolder cgiHolder = new ServletHolder(new CGI());
    cgiHolder.setInitParameter("cgibinResourceBase", webDir + "/cgi-bin");
    if (System.getenv("PATH") != null) {
      // Pass any special PATH setting on to the execution environment
      cgiHolder.setInitParameter("Path", System.getenv("PATH"));
    }
    context.addServlet(cgiHolder, "*.cgi");
    context.addServlet(cgiHolder, "*.pl");
    context.addServlet(cgiHolder, "*.py");
    context.addServlet(cgiHolder, "*.rb");
    context.addServlet(cgiHolder, "*.tcl");

    context.addServlet(new ServletHolder(
        new GetReportsServlet()), "/reports/*");
    context.addServlet(new ServletHolder(
        new GetLatestTaskServlet()), "/latestTask");
    context.addServlet(new ServletHolder(
        new TagServlet()), "/tag/*");
    context.addServlet(new ServletHolder(
        new TitleServlet()), "/title/*");
    context.addServlet(new ServletHolder(
        new TitleLikeServlet()), "/titleLike/*");
   
    // Add an IndexServlet as the default servlet. This servlet will serve
    // a human-readable (HTML) latest tasks page for "/" and serve static
    // content for any other URL. Being the default servlet, it will get
    // invoked only for URLs that does not match the other patterns where we
    // have registered servlets above.
    context.setResourceBase(webDir + "/html");
    context.addServlet(new ServletHolder(new IndexServlet()), "/");
   
    try {
      server.start();
    } catch (Exception e) {
      LOG.warn("Unable to start web interface", e);
    }
  }
 
  private static class GetReportsServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
      response.setContentType("text/plain");
      response.setStatus(HttpServletResponse.SC_OK);
      String uri = request.getRequestURI();
      int pathLen = request.getServletPath().length() + 1;
      String taskId = uri.length() > pathLen ? uri.substring(pathLen) : null;
      Writer out = response.getWriter();
      if (taskId != null) {
        Iterator<Report> iter;
        try {
          iter = reportstore.getReportsByTask(TaskID.createFromString(taskId));
        } catch (XTraceException e) {
          throw new ServletException(e);
        }
        while (iter.hasNext()) {
          out.write(iter.next().toString());
          out.write("\n");
        }
      }
    }
  }
 
  private static class GetLatestTaskServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
      response.setContentType("text/plain");
      response.setStatus(HttpServletResponse.SC_OK);
      Writer out = response.getWriter();
     
      List<TaskRecord> task = reportstore.getLatestTasks(0, 1);
      if (task.size() != 1) {
        LOG.warn("getLatestTasks(1) returned " + task.size() + " entries");
        return;
      }
      try {
        Iterator<Report> iter = reportstore.getReportsByTask(task.get(0).getTaskId());
        while (iter.hasNext()) {
          Report r = iter.next();
          out.write(r.toString());
          out.write("\n");
        }
      } catch (XTraceException e) {
        LOG.warn("Internal error", e);
        out.write("Internal error: " + e);
      }
    }
  }
 
  private static class TagServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request,
        HttpServletResponse response) throws ServletException, IOException {
      String tag = getUriPastServletName(request);
      if (tag == null || tag.equalsIgnoreCase("")) {
        response.sendError(505, "No tag given");
      } else {
        Collection<TaskRecord> taskInfos = reportstore.getTasksByTag(
            tag, getOffset(request), getLength(request));
        showTasks(request, response, taskInfos, "Tasks with tag: " + tag, false);
      }
    }
  }
 
  private static class TitleServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request,
        HttpServletResponse response) throws ServletException, IOException {
      String title = getUriPastServletName(request);
      if (title == null || title.equalsIgnoreCase("")) {
        response.sendError(505, "No title given");
      } else {
        Collection<TaskRecord> taskInfos = reportstore.getTasksByTitle(
            title, getOffset(request), getLength(request));
        showTasks(request, response, taskInfos, "Tasks with title: " + title, false);
      }
    }
  }
 
  private static class TitleLikeServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request,
        HttpServletResponse response) throws ServletException, IOException {
      String title = getUriPastServletName(request);
      if (title == null || title.equalsIgnoreCase("")) {
        response.sendError(505, "No title given");
      } else {
        Collection<TaskRecord> taskInfos = reportstore.getTasksByTitleSubstring(
            title, getOffset(request), getLength(request));
        showTasks(request, response, taskInfos, "Tasks with title like: " + title, false);
      }
    }
  }
 
  private static class IndexServlet extends DefaultServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
      if(request.getRequestURI().equals("/")) {
        Collection<TaskRecord> tasks = reportstore.getLatestTasks(getOffset(request), getLength(request));
        showTasks(request, response, tasks, "X-Trace Latest Tasks", true);
      } else {
        super.doGet(request, response);
      }
    }
  }

  private static String getUriPastServletName(HttpServletRequest request) {
    String uri = request.getRequestURI();
    int pathLen = request.getServletPath().length() + 1;
    String text = uri.length() > pathLen ? uri.substring(pathLen) : null;
    if (text != null) {
      try {
        text = URLDecoder.decode(text, "UTF-8");
      } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
        return null;
      }
    }
    return text;
  }

  private static void showTasks(HttpServletRequest request,
      HttpServletResponse response, Collection<TaskRecord> tasks, String title, boolean showDbStats) throws IOException {
    if ("json".equals(request.getParameter("format"))) {
      response.setContentType("text/plain");
    }
    else {
      response.setContentType("text/html");
    }
    int offset = getOffset(request);
    int length = getLength(request);
    // Create Velocity context
    VelocityContext context = new VelocityContext();
    context.put("tasks", tasks);
    context.put("title", title);
    context.put("reportStore", reportstore);
    context.put("request", request);
    context.put("offset", offset);
    context.put("length", length);
    context.put("lastResultNum", offset + length - 1);
    context.put("prevOffset", Math.max(0, offset - length));
    context.put("nextOffset", offset + length);
    context.put("showStats", showDbStats);
    context.put("JSON_DATE_FORMAT", JSON_DATE_FORMAT);
    context.put("HTML_DATE_FORMAT", HTML_DATE_FORMAT);
    context.put("PAGE_LENGTH", PAGE_LENGTH);
    // Return Velocity results
    try {
      Velocity.mergeTemplate("tasks.vm", "UTF-8", context, response.getWriter());
      response.setStatus(HttpServletResponse.SC_OK);
    } catch (Exception e) {
      LOG.warn("Failed to display tasks.vm", e);
      response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
          "Failed to display tasks.vm");
    }
  }

  /**
   * Get the length GET parameter from a HTTP request, or return the default
   * (of PAGE_LENGTH) when it is not specified or invalid.
   * @param request
   * @return
   */
  private static int getLength(HttpServletRequest request) {
    int length = getIntParam(request, "length", PAGE_LENGTH);
    return Math.max(length, 0); // Don't allow negative
  }

  /**
   * Get the offset HTTP parameter from a request, or return the default
   * (of 0) when it is not specified.
   * @param request
   * @return
   */
  private static int getOffset(HttpServletRequest request) {
    int offset = getIntParam(request, "offset", 0);
    return Math.max(offset, 0); // Don't allow negative
  }
 
  /**
   * Read an integer parameter from a HTTP request, or return a default value
   * if the parameter is not specified.
   * @param request
   * @param name
   * @param defaultValue
   * @return
   */
  private static final int getIntParam(
      HttpServletRequest request, String name, int defaultValue) {
    int value;
    try {
      return Integer.parseInt(request.getParameter(name));
    } catch(Exception ex) {
      return defaultValue;
    }
  }
 
  private static final class SyncTimer extends TimerTask {
    private QueryableReportStore reportstore;

    public SyncTimer(QueryableReportStore reportstore) {
      this.reportstore = reportstore;
    }

    public void run() {
      reportstore.sync();
    }
  }
}
TOP

Related Classes of edu.berkeley.xtrace.server.XTraceServer$GetReportsServlet

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.
ew');