blob: 3aa778bd8deb960f84af1efc619c126b01ad940c [file] [log] [blame]
/*
* 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");
// Stop older versions of IE thinking they know best. We set text/plain
// in the line above for a reason. IE's behaviour is unwanted at best
// and dangerous at worst.
response.setHeader("X-Content-Type-Options", "nosniff");
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);
}
}
}