/* * 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); } } }