All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ca.jimr.gae.profiler.MiniProfilerServlet Maven / Gradle / Ivy

/**
 * 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:
 * 
    *
  • Returns profile information for a set of requests (in JSON format). *
  • Serves the static resources that make up the profiler UI. *
*/ 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 resourceReplacements = new HashMap(); /** 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 result = new HashMap(); String requestIds = req.getParameter("ids"); if (!isEmpty(requestIds)) { List> requests = new ArrayList>(); for (String requestId : requestIds.split(",")) { requestId = requestId.trim(); @SuppressWarnings("unchecked") Map requestData = (Map) ms.get(String.format(MiniProfilerFilter.MEMCACHE_KEY_FORMAT_STRING, requestId)); if (requestData != null) { Map request = new HashMap(); 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 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; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy