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

com.purej.vminspect.http.servlet.VmInspectionServlet Maven / Gradle / Ivy

// Copyright (c), 2013, adopus consulting GmbH Switzerland, all rights reserved.
package com.purej.vminspect.http.servlet;

import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.purej.vminspect.data.statistics.StatisticsCollector;
import com.purej.vminspect.http.DefaultMBeanAccessControl;
import com.purej.vminspect.http.HttpRequest;
import com.purej.vminspect.http.HttpResponse;
import com.purej.vminspect.http.MBeanAccessControl;
import com.purej.vminspect.http.RequestController;
import com.purej.vminspect.http.RequestParams;
import com.purej.vminspect.util.Utils;

/**
 * This servlet allows PureJ VM Inspection to be used in servlet-containers / JEE containers. This servlet is implemented
 * against servlet-spec version 2.5 but should also run with newer versions.
 * 

* The following servlet init parameters are supported (all optional): *

    *
  • vminspect.mbeans.readonly: true/false, specifies if VmInspect is allowed to edit MBean values or invoke non-info operations (default: false)
  • *
  • vminspect.mbeans.writeConfirmation: true/false, specifies if a confirmation screen is displayed before edit MBean attributes or invoke MBean operations
  • *
  • vminspect.mbeans.accessControlFactory: fully qualified class name of an implementation of the {@link MBeanAccessControlFactory} interface
  • *
  • vminspect.statistics.collection.frequencyMs: Number of milliseconds for the statistics collection timer (default: 60'000ms)
  • *
  • vminspect.statistics.storage.dir: Optional Path where to store the statistics files (default: no storage directory). If no storage * directory is configured, the statistics will be kept in-memory and thus will be lost after a VM restart.
  • *
* * @author Stefan Mueller */ public final class VmInspectionServlet extends HttpServlet { private static final Logger LOGGER = LoggerFactory.getLogger(VmInspectionServlet.class); private static final long serialVersionUID = 1L; // Members that get set in the init method: private StatisticsCollector _collector; private RequestController _controller; private MBeanAccessControlFactory _mbeanAccessControlFactory; @Override public void init() throws ServletException { // Load configuration from init parameters: boolean mbeansReadonly = Boolean.parseBoolean(getServletConfig().getInitParameter("vminspect.mbeans.readonly")); boolean mbeansWriteConfirmation = Boolean.parseBoolean(getServletConfig().getInitParameter("vminspect.mbeans.writeConfirmation")); String accessControlFactoryClz = getServletConfig().getInitParameter("vminspect.mbeans.accessControlFactory"); String collectionFrequency = getServletConfig().getInitParameter("vminspect.statistics.collection.frequencyMs"); String storageDir = getServletConfig().getInitParameter("vminspect.statistics.storage.dir"); // Create the correct MBeanAccessControlFactory instance (custom or default): MBeanAccessControlFactory accessControlFactory; if (accessControlFactoryClz != null) { try { accessControlFactory = (MBeanAccessControlFactory) Class.forName(accessControlFactoryClz).newInstance(); } catch (Exception e) { throw new ServletException("Could not load configured MBeanAccessControlFactory class '" + accessControlFactoryClz + "'!"); } } else { // Create a default static MBeanAccessControlFactory instance using the boolean attributes: final MBeanAccessControl accessControl = new DefaultMBeanAccessControl(mbeansReadonly, mbeansWriteConfirmation); accessControlFactory = new MBeanAccessControlFactory() { @Override public MBeanAccessControl create(HttpServletRequest request) { return accessControl; } }; } // Call the init: init(accessControlFactory, collectionFrequency != null ? Integer.parseInt(collectionFrequency) : 60000, storageDir); } /** * Initializes this servlet instance or does nothing if already initialized. * This method can be used to programmatically initialize the servlet. * * @param mbeanAccessControlFactory the factory to create {@link MBeanAccessControl} instances for fine-grained MBeans access control * @param statisticsCollectionFrequencyMs the statistics collection frequency in milliseconds (60'000 recommended) * @param statisticsStorageDir the optional statistics storage directory */ public void init(MBeanAccessControlFactory mbeanAccessControlFactory, int statisticsCollectionFrequencyMs, String statisticsStorageDir) { if (_collector == null) { if (mbeanAccessControlFactory == null) { throw new IllegalArgumentException("MBeanAccessControlFactory is null!"); } // Get or create collector, create controller: _collector = StatisticsCollector.init(statisticsStorageDir, statisticsCollectionFrequencyMs, this); _controller = new RequestController(_collector); _mbeanAccessControlFactory = mbeanAccessControlFactory; } } @Override public void destroy() { StatisticsCollector.destroy(this); // Makes sure the collector is destroyed if this was the last reference... _collector = null; _controller = null; } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Same logic as for HTTP get... doGet(request, response); } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { // Create the request, process it and write the response: HttpRequest httpRequest = createHttpRequest(request); MBeanAccessControl mbeanAccessControl = null; if (httpRequest.getParameter(RequestParams.MBEAN_NAME) != null) { // Only create an instance of the MBeanAccessControl if a single MBean is targeted: mbeanAccessControl = _mbeanAccessControlFactory.create(request); } HttpResponse httpResponse = _controller.process(httpRequest, mbeanAccessControl); writeHttpResponse(httpResponse, request.getRequestURI(), response); } catch (Exception e) { LOGGER.warn("An error occurred processing request!", e); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, Utils.getExceptionInfo(e)); } finally { response.flushBuffer(); } } private static HttpRequest createHttpRequest(HttpServletRequest req) { HttpRequest request = new HttpRequest(); // Add all parameters: for (Enumeration e = req.getParameterNames(); e.hasMoreElements();) { String name = (String) e.nextElement(); request.getParameters().put(name, req.getParameter(name)); } // Add all cookies: if (req.getCookies() != null) { for (Cookie cookie : req.getCookies()) { request.getCookies().put(cookie.getName(), Utils.urlDecode(cookie.getValue())); } } return request; } private static void writeHttpResponse(HttpResponse httpResponse, String requestURI, HttpServletResponse response) throws IOException { // Sanity check first: byte[] data = httpResponse.getContentBytes(); if (data == null || data.length == 0) { response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } // a) Cookies: for (Map.Entry entry : httpResponse.getCookies().entrySet()) { Cookie cookie = new Cookie(entry.getKey(), Utils.urlEncode(entry.getValue())); cookie.setMaxAge(30 * 24 * 60 * 60); // 30 days cookie.setPath(requestURI); response.addCookie(cookie); } // b) Caching: if (httpResponse.getCacheSeconds() > 0) { response.addHeader("Cache-Control", "max-age=" + httpResponse.getCacheSeconds()); } else { response.addHeader("Cache-Control", "no-cache"); response.addHeader("Pragma", "no-cache"); response.addHeader("Expires", "-1"); } // c) content type and length: response.setContentType(httpResponse.getContentType()); response.setContentLength(data.length); // d) binary content: response.getOutputStream().write(data); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy