/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.catalina.manager; import java.io.IOException; import java.io.PrintWriter; import java.util.Set; import javax.management.Attribute; import javax.management.MBeanException; import javax.management.MBeanOperationInfo; import javax.management.MBeanParameterInfo; import javax.management.MBeanServer; import javax.management.ObjectName; import javax.management.OperationsException; import javax.management.ReflectionException; import javax.management.openmbean.CompositeData; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.mbeans.MBeanDumper; import org.apache.tomcat.util.modeler.Registry; /** * This servlet will dump JMX attributes in a simple format and implement proxy * services for modeler. * * @author Costin Manolache */ public class JMXProxyServlet extends HttpServlet { private static final long serialVersionUID = 1L; // Constant for "no parameters" when invoking a JMX operation // without any parameters. private static final String[] NO_PARAMETERS = new String[0]; // ----------------------------------------------------- Instance Variables /** * MBean server. */ protected transient MBeanServer mBeanServer = null; protected transient Registry registry; // --------------------------------------------------------- Public Methods /** * Initialize this servlet. */ @Override public void init() throws ServletException { // Retrieve the MBean server registry = Registry.getRegistry(null, null); mBeanServer = Registry.getRegistry(null, null).getMBeanServer(); } /** * Process a GET request for the specified resource. * * @param request The servlet request we are processing * @param response The servlet response we are creating * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet-specified error occurs */ @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/plain"); PrintWriter writer = response.getWriter(); if (mBeanServer == null) { writer.println("Error - No mbean server"); return; } String qry = request.getParameter("set"); if (qry != null) { String name = request.getParameter("att"); String val = request.getParameter("val"); setAttribute(writer, qry, name, val); return; } qry = request.getParameter("get"); if (qry != null) { String name = request.getParameter("att"); getAttribute(writer, qry, name, request.getParameter("key")); return; } qry = request.getParameter("invoke"); if (qry != null) { String opName = request.getParameter("op"); String[] params = getInvokeParameters(request.getParameter("ps")); invokeOperation(writer, qry, opName, params); return; } qry = request.getParameter("qry"); if (qry == null) { qry = "*:*"; } listBeans(writer, qry); } public void getAttribute(PrintWriter writer, String onameStr, String att, String key) { try { ObjectName oname = new ObjectName(onameStr); Object value = mBeanServer.getAttribute(oname, att); if (null != key && value instanceof CompositeData) value = ((CompositeData) value).get(key); String valueStr; if (value != null) { valueStr = value.toString(); } else { valueStr = "<null>"; } writer.print("OK - Attribute get '"); writer.print(onameStr); writer.print("' - "); writer.print(att); if (null != key) { writer.print(" - key '"); writer.print(key); writer.print("'"); } writer.print(" = "); writer.println(MBeanDumper.escape(valueStr)); } catch (Exception ex) { writer.println("Error - " + ex.toString()); ex.printStackTrace(writer); } } public void setAttribute(PrintWriter writer, String onameStr, String att, String val) { try { setAttributeInternal(onameStr, att, val); writer.println("OK - Attribute set"); } catch (Exception ex) { writer.println("Error - " + ex.toString()); ex.printStackTrace(writer); } } public void listBeans(PrintWriter writer, String qry) { Set<ObjectName> names = null; try { names = mBeanServer.queryNames(new ObjectName(qry), null); writer.println("OK - Number of results: " + names.size()); writer.println(); } catch (Exception ex) { writer.println("Error - " + ex.toString()); ex.printStackTrace(writer); return; } String dump = MBeanDumper.dumpBeans(mBeanServer, names); writer.print(dump); } /** * Determines if a type is supported by the {@link JMXProxyServlet}. * * @param type The type to check * @return Always returns <code>true</code> */ public boolean isSupported(String type) { return true; } private void invokeOperation(PrintWriter writer, String onameStr, String op, String[] valuesStr) { try { Object retVal = invokeOperationInternal(onameStr, op, valuesStr); if (retVal != null) { writer.println("OK - Operation " + op + " returned:"); output("", writer, retVal); } else { writer.println("OK - Operation " + op + " without return value"); } } catch (Exception ex) { writer.println("Error - " + ex.toString()); ex.printStackTrace(writer); } } /** * Parses parameter values from a parameter string. * * @param paramString The string containing comma-separated * operation-invocation parameters, or <code>null</code> if there * are no parameters. * @return An array of String parameters (empty array if * <code>paramString</code> was <code>null</code>). */ private String[] getInvokeParameters(String paramString) { if (paramString == null) return NO_PARAMETERS; else return paramString.split(","); } /** * Sets an MBean attribute's value. */ private void setAttributeInternal(String onameStr, String attributeName, String value) throws OperationsException, MBeanException, ReflectionException { ObjectName oname = new ObjectName(onameStr); String type = registry.getType(oname, attributeName); Object valueObj = registry.convertValue(type, value); mBeanServer.setAttribute(oname, new Attribute(attributeName, valueObj)); } /** * Invokes an operation on an MBean. * * @param onameStr The name of the MBean. * @param operation The name of the operation to invoke. * @param parameters An array of Strings containing the parameters to the * operation. They will be converted to the appropriate types to * call the requested operation. * @return The value returned by the requested operation. */ private Object invokeOperationInternal(String onameStr, String operation, String[] parameters) throws OperationsException, MBeanException, ReflectionException { ObjectName oname = new ObjectName(onameStr); MBeanOperationInfo methodInfo = registry.getMethodInfo(oname, operation); MBeanParameterInfo[] signature = methodInfo.getSignature(); String[] signatureTypes = new String[signature.length]; Object[] values = new Object[signature.length]; for (int i = 0; i < signature.length; i++) { MBeanParameterInfo pi = signature[i]; signatureTypes[i] = pi.getType(); values[i] = registry.convertValue(pi.getType(), parameters[i]); } return mBeanServer.invoke(oname, operation, values, signatureTypes); } private void output(String indent, PrintWriter writer, Object result) { if (result instanceof Object[]) { for (Object obj : (Object[]) result) { output(" " + indent, writer, obj); } } else { String strValue; if (result != null) { strValue = result.toString(); } else { strValue = "<null>"; } writer.println(indent + strValue); } } }