package org.jboss.invocation.http.servlet;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.security.PrivilegedAction;
import java.security.Principal;
import java.security.AccessController;
import javax.management.MalformedObjectNameException;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jboss.invocation.InvocationException;
import org.jboss.invocation.MarshalledInvocation;
import org.jboss.invocation.MarshalledValue;
import org.jboss.logging.Logger;
import org.jboss.mx.util.MBeanServerLocator;
import org.jboss.mx.util.JMXExceptionDecoder;
import org.jboss.system.Registry;
import org.jboss.security.SecurityAssociation;
public class InvokerServlet extends HttpServlet
{
private static Logger log = Logger.getLogger(InvokerServlet.class);
private static String REQUEST_CONTENT_TYPE =
"application/x-java-serialized-object; class=org.jboss.invocation.MarshalledInvocation";
private static String RESPONSE_CONTENT_TYPE =
"application/x-java-serialized-object; class=org.jboss.invocation.MarshalledValue";
private MBeanServer mbeanServer;
private ObjectName localInvokerName;
public void init(ServletConfig config) throws ServletException
{
super.init(config);
try
{
String name = config.getInitParameter("invokerName");
if( name != null )
{
localInvokerName = new ObjectName(name);
log.debug("localInvokerName="+localInvokerName);
}
}
catch(MalformedObjectNameException e)
{
throw new ServletException("Failed to build invokerName", e);
}
mbeanServer = MBeanServerLocator.locateJBoss();
if( mbeanServer == null )
throw new ServletException("Failed to locate the MBeanServer");
}
public void destroy()
{
}
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
boolean trace = log.isTraceEnabled();
if( trace )
{
log.trace("processRequest, ContentLength: "+request.getContentLength());
log.trace("processRequest, ContentType: "+request.getContentType());
}
Boolean returnValueAsAttribute = (Boolean) request.getAttribute("returnValueAsAttribute");
try
{
response.setContentType(RESPONSE_CONTENT_TYPE);
MarshalledInvocation mi = (MarshalledInvocation) request.getAttribute("MarshalledInvocation");
if( mi == null )
{
ServletInputStream sis = request.getInputStream();
ObjectInputStream ois = new ObjectInputStream(sis);
mi = (MarshalledInvocation) ois.readObject();
ois.close();
}
if (mi.getPrincipal() == null && mi.getCredential() == null)
{
mi.setPrincipal(GetPrincipalAction.getPrincipal());
mi.setCredential(GetCredentialAction.getCredential());
}
Object[] params = {mi};
String[] sig = {"org.jboss.invocation.Invocation"};
ObjectName invokerName = localInvokerName;
if( invokerName == null )
{
Integer nameHash = (Integer) mi.getObjectName();
invokerName = (ObjectName) Registry.lookup(nameHash);
if( invokerName == null )
throw new ServletException("Failed to find invoker name for hash("+nameHash+")");
}
Object value = mbeanServer.invoke(invokerName, "invoke", params, sig);
if( returnValueAsAttribute == null || returnValueAsAttribute.booleanValue() == false )
{
MarshalledValue mv = new MarshalledValue(value);
ServletOutputStream sos = response.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(sos);
oos.writeObject(mv);
oos.close();
}
else
{
request.setAttribute("returnValue", value);
}
}
catch(Throwable t)
{
t = JMXExceptionDecoder.decode(t);
if( t instanceof InvocationTargetException )
{
InvocationTargetException ite = (InvocationTargetException) t;
t = ite.getTargetException();
}
InvocationException appException = new InvocationException(t);
log.debug("Invoke threw exception", t);
if( returnValueAsAttribute == null || returnValueAsAttribute.booleanValue() == false )
{
response.resetBuffer();
MarshalledValue mv = new MarshalledValue(appException);
ServletOutputStream sos = response.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(sos);
oos.writeObject(mv);
oos.close();
}
else
{
request.setAttribute("returnValue", appException);
}
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
processRequest(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
processRequest(request, response);
}
public String getServletInfo()
{
return "An HTTP to JMX invocation servlet";
}
private static class GetPrincipalAction implements PrivilegedAction
{
static PrivilegedAction ACTION = new GetPrincipalAction();
public Object run()
{
Principal principal = SecurityAssociation.getPrincipal();
return principal;
}
static Principal getPrincipal()
{
Principal principal = (Principal) AccessController.doPrivileged(ACTION);
return principal;
}
}
private static class GetCredentialAction implements PrivilegedAction
{
static PrivilegedAction ACTION = new GetCredentialAction();
public Object run()
{
Object credential = SecurityAssociation.getCredential();
return credential;
}
static Object getCredential()
{
Object credential = AccessController.doPrivileged(ACTION);
return credential;
}
}
}