Package ca.jimr.gae.profiler

Source Code of ca.jimr.gae.profiler.MiniProfilerServlet

/**
* Copyright (C) 2011 by Jim Riecken
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package ca.jimr.gae.profiler;

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.*;

import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;

import ca.jimr.gae.profiler.resources.MiniProfilerResourceLoader;

import com.google.appengine.api.memcache.MemcacheService;
import com.google.appengine.api.memcache.MemcacheServiceFactory;
import com.google.appengine.tools.appstats.MiniProfilerAppstats;

/**
* Servlet that:
* <ul>
* <li>Returns profile information for a set of requests (in JSON format).
* <li>Serves the static resources that make up the profiler UI.
* </ul>
*/
public class MiniProfilerServlet extends HttpServlet
{
  private static final long serialVersionUID = 7906645907029238585L;

  private static final String MAX_STACK_FRAMES_KEY = "maxStackFrames";
  private static final String HTML_ID_PREFIX_KEY = "htmlIdPrefix";
  private static final String RESOURCE_CACHE_HOURS_KEY = "resourceCacheHours";

  /**
   * The maximum number of stack frames that should show up in Appstats RPC
   * details. If this is null the whole stack trace will be shown.
   */
  private Integer maxStackFrames;
  /**
   * The prefix for all HTML element ids/classes used in the profiler UI. This
   * must be the same value as the {@code htmlIdPrefix} field in
   * {@link MiniProfilerFilter}.
   */
  private String htmlIdPrefix = "mp";
  /**
   * The number of hours that the static resources should be cached in the
   * browser for.
   */
  private int resourceCacheHours = 0;

  /**
   * The loader that will load the static resources for the profiler UI from
   * files in the classpath.
   */
  private MiniProfilerResourceLoader resourceLoader;
  /** Map of string replacements that will be done on loaded resources. */
  private Map<String, String> resourceReplacements = new HashMap<String, String>();
  /** The Appengine Memcache Service */
  private MemcacheService ms;

  @Override
  public void init(ServletConfig config) throws ServletException
  {
    String configMaxStackFrames = config.getInitParameter(MAX_STACK_FRAMES_KEY);
    if (!isEmpty(configMaxStackFrames))
    {
      maxStackFrames = Integer.valueOf(configMaxStackFrames);
    }
    String configHtmlIdPrefix = config.getInitParameter(HTML_ID_PREFIX_KEY);
    if (!isEmpty(configHtmlIdPrefix))
    {
      htmlIdPrefix = configHtmlIdPrefix.trim();
    }
    String configResourceCacheHours = config.getInitParameter(RESOURCE_CACHE_HOURS_KEY);
    if (!isEmpty(configResourceCacheHours))
    {
      resourceCacheHours = Integer.parseInt(configResourceCacheHours);
    }

    ms = MemcacheServiceFactory.getMemcacheService(MiniProfilerFilter.MEMCACHE_NAMESPACE);
    resourceLoader = new MiniProfilerResourceLoader();
    resourceReplacements.put("@@prefix@@", htmlIdPrefix);
  }

  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
  {
    String requestURI = req.getRequestURI();
    if (requestURI.endsWith("results"))
    {
      doResults(req, resp);
    } else if (requestURI.endsWith("resource"))
    {
      doResource(req, resp);
    }
  }

  /**
   * Serve one of the static resources for the profiler UI.
   */
  private void doResource(HttpServletRequest req, HttpServletResponse resp) throws IOException
  {
    boolean success = true;
    String resource = (String) req.getParameter("id");
    if (!isEmpty(resource))
    {
      if (resource.endsWith(".js"))
      {
        resp.setContentType("text/javascript");
      } else if (resource.endsWith(".css"))
      {
        resp.setContentType("text/css");
      } else if (resource.endsWith(".html"))
      {
        resp.setContentType("text/html");
      } else
      {
        resp.setContentType("text/plain");
      }

      String contents = resourceLoader.getResource(resource, resourceReplacements);
      if (contents != null)
      {
        if (resourceCacheHours > 0)
        {
          Calendar c = Calendar.getInstance();
          c.add(Calendar.HOUR, resourceCacheHours);
          resp.setHeader("Cache-Control", "public, must-revalidate");
          resp.setHeader("Expires", new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz").format(c.getTime()));
        } else
        {
          resp.setHeader("Cache-Control", "no-cache");
        }

        PrintWriter w = resp.getWriter();
        w.print(contents);
      } else
      {
        success = false;
      }
    }
    if (!success)
    {
      resp.sendError(404);
    }
  }

  /**
   * Generate the results for a set of requests in JSON format.
   */
  private void doResults(HttpServletRequest req, HttpServletResponse resp) throws IOException, JsonGenerationException, JsonMappingException
  {
    Map<String, Object> result = new HashMap<String, Object>();

    String requestIds = req.getParameter("ids");
    if (!isEmpty(requestIds))
    {
      List<Map<String, Object>> requests = new ArrayList<Map<String, Object>>();
      for (String requestId : requestIds.split(","))
      {
        requestId = requestId.trim();
        @SuppressWarnings("unchecked")
        Map<String, Object> requestData = (Map<String, Object>) ms.get(String.format(MiniProfilerFilter.MEMCACHE_KEY_FORMAT_STRING, requestId));
        if (requestData != null)
        {
          Map<String, Object> request = new HashMap<String, Object>();
          request.put("id", requestId);
          request.put("redirect", requestData.get("redirect"));
          request.put("requestURL", requestData.get("requestURL"));
          request.put("timestamp", requestData.get("timestamp"));
          request.put("profile", requestData.get("profile"));
          if (requestData.containsKey("appstatsId"))
          {
            Map<String, Object> appstatsMap = MiniProfilerAppstats.getAppstatsDataFor((String) requestData.get("appstatsId"), maxStackFrames);
            request.put("appstats", appstatsMap != null ? appstatsMap : null);
          } else
          {
            request.put("appstats", null);
          }
          requests.add(request);
        }
      }
      result.put("ok", true);
      result.put("requests", requests);
    } else
    {
      result.put("ok", false);
    }

    resp.setContentType("application/json");
    resp.setHeader("Cache-Control", "no-cache");

    ObjectMapper jsonMapper = new ObjectMapper();
    jsonMapper.writeValue(resp.getOutputStream(), result);
  }

  /**
   * Get whether the specified string is null or empty.
   *
   * @param str
   *          The string to test.
   * @return Whether the string is empty.
   */
  private static boolean isEmpty(String str)
  {
    return str == null || str.trim().length() == 0;
  }
}
TOP

Related Classes of ca.jimr.gae.profiler.MiniProfilerServlet

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.