workaround: guvnor repository remote commands using http (bypassing gwt interface)

the commands are passed using serialized java objects.

IN web.xml:

<servlet>
<servlet-name>XptoServlet</servlet-name>
<servlet-class>org.jboss.seam.remoting.gwt.AcecServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>XptoServlet</servlet-name>
<url-pattern>/AcecServlet</url-pattern>
</servlet-mapping>

Servlet code:

package org.jboss.seam.remoting.gwt;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.drools.guvnor.client.rpc.DetailedSerializableException;
import org.drools.guvnor.client.rpc.RepositoryService;
import org.drools.guvnor.client.rpc.SecurityService;
import org.drools.guvnor.client.rpc.SessionExpiredException;
import org.jboss.seam.Component;
import org.jboss.seam.annotations.remoting.WebRemote;
import com.google.gwt.user.client.rpc.SerializationException;
import org.drools.guvnor.server.security.SecurityServiceImpl;
/**
*
* @author Wesley Imamura
*/
public class XptoServlet extends HttpServlet {
private static final String GENERIC_FAILURE_MSG = "An error occurred on the server. Consult server log for details.";
private static final HashMap TYPE_NAMES;
static final Map METHOD_CACHE = new HashMap();
static {
TYPE_NAMES = new HashMap();
TYPE_NAMES.put("Z", boolean.class);
TYPE_NAMES.put("B", byte.class);
TYPE_NAMES.put("C", char.class);
TYPE_NAMES.put("D", double.class);
TYPE_NAMES.put("F", float.class);
TYPE_NAMES.put("I", int.class);
TYPE_NAMES.put("J", long.class);
TYPE_NAMES.put("S", short.class);
}
public final void doPost(HttpServletRequest request, HttpServletResponse response) {
Throwable caught;
try {

System.out.println("Reading map.");
ObjectInputStream ois = new ObjectInputStream(request.getInputStream());
Map map = (Map) ois.readObject();
ois.close();
System.out.println("Map read.");
String methodName = (String) map.get("methodName");
System.out.println("methodName: " + methodName);

Integer paramCount = (Integer) map.get("paramCount");
System.out.println("paramCount: " + paramCount.intValue());

Class[] paramTypes = new Class[paramCount];
for (int i = 0; i < paramCount; i++) {
String paramClassName = (String) map.get("param" + i + "Type");
System.out.println("paramClassName: " + paramClassName);
try {
paramTypes[i] = getClassOrPrimitiveFromName(paramClassName);
} catch (ClassNotFoundException e) {
throw new SerializationException("Unknown parameter " + i + " type '"
+ paramClassName + "'", e);
}
}

Object[] args = new Object[paramCount];
for (int i = 0; i < args.length; i++) {
args[i] = map.get("param" + i + "Value");
if (args[i] != null) {
if (args[i].getClass().getName().equals("java.lang.String"))
System.out.println("GWTRemoteServiceServlet.processCall(). args[" + i + "]: " + ((String) args[i]));
else
System.out.println("GWTRemoteServiceServlet.processCall(). args[" + i + "]: " + args[i].toString());
}
}
System.out.println("args ok.");
RepositoryService repositoryService = (RepositoryService) Component.getInstance("org.drools.guvnor.client.rpc.RepositoryService");
System.out.println("repositoryService ok.");
Method method = getMethod( "org.drools.guvnor.client.rpc.RepositoryService", methodName, repositoryService.getClass(), paramTypes );
System.out.println("method ok.");
try {
SecurityService securityService = new SecurityServiceImpl(); // (SecurityService) Component.getInstance("org.drools.guvnor.client.rpc.SecurityService");
boolean isLogged = securityService.login("admin", "password");
System.out.println("logged in.");

System.out.println("invoking.");
Object result = method.invoke( repositoryService, args );
System.out.println("invoked.");

ReturnedObject returnedObject = new ReturnedObject(method.getReturnType(), result);

System.out.println("writing response.");
ObjectOutputStream oos = new ObjectOutputStream(response.getOutputStream());
oos.writeObject(returnedObject);
oos.close();
System.out.println("response wrote.");

} catch (InvocationTargetException e) {
//now in this case, we log, and then repack it as some sort of a serializable exception
String exName = e.getCause().getClass().getName();
if (exName.endsWith( "NotLoggedInException" )) {
throw new InvocationTargetException(new SessionExpiredException());
} else {
Throwable cause = e.getCause();
StringWriter sw = new StringWriter();
PrintWriter w = new PrintWriter(sw);
cause.printStackTrace( w );
DetailedSerializableException det = new DetailedSerializableException("An error occurred executing the action.", sw.toString());
throw new InvocationTargetException(det);
}
}

response.setContentType("application/binary");
response.setStatus(HttpServletResponse.SC_OK);
return;
} catch (Throwable e) {

e.printStackTrace();

caught = e;
respondWithFailure(response, caught);
}

}
/**
* Called when the machinery of this class itself has a problem, rather than
* the invoked third-party method. It writes a simple 500 message back to the
* client.
*/
private void respondWithFailure(HttpServletResponse response, Throwable caught) {
ServletContext servletContext = getServletContext();
servletContext.log("Exception while dispatching incoming RPC call", caught);
try {
response.setContentType("text/plain");
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
response.getWriter().write(GENERIC_FAILURE_MSG);
} catch (IOException e) {
servletContext.log(
"sendError() failed while sending the previous failure to the client",
caught);
}
}

private Class getClassOrPrimitiveFromName(String name) throws ClassNotFoundException {
Object value = TYPE_NAMES.get(name);
if (value != null) {
return (Class) value;
}
return getClassFromName(name);
}
private Class getClassFromName(String name) throws ClassNotFoundException {
return Class.forName(name, false, this.getClass().getClassLoader());
}

private Method getMethod(String serviceName, String methodName, Class clz, Class[] paramTypes) {
String key = getKey( serviceName, methodName, paramTypes );
if (METHOD_CACHE.containsKey( key )) {
return (Method) METHOD_CACHE.get( key );
} else {
try {
synchronized ( METHOD_CACHE ) {
Method m = findMethod( clz, methodName, paramTypes );
if (m == null) throw new NoSuchMethodException();
METHOD_CACHE.put( key, m );
return m;
}
} catch ( NoSuchMethodException e ) {
throw new SecurityException("Unable to access a service method called [" + methodName + "] on class [" + clz.getName() + "] without the @WebRemote attribute. " +
"This may be a hack attempt, or someone simply neglected to use the @WebRemote attribute to indicate a method as" +
" remotely accessible.");
}
}
}

private String getKey(String serviceName, String methodName, Class[] paramTypes) {
if (paramTypes == null) {
return serviceName + "." + methodName;
} else {
String pTypes = "";
for ( int i = 0; i < paramTypes.length; i++ ) {
pTypes += paramTypes[i].getName();
}
return serviceName + "." + methodName + "(" + pTypes + ")";
}
}
private Method findMethod(Class clz, String methodName, Class[] paramTypes ) throws NoSuchMethodException {
if (clz == Object.class) {
return null;
} else {
Method m = clz.getMethod( methodName, paramTypes );
if (isWebRemoteAnnotated( m )) {
return m;
} else {
return findMethod(clz.getSuperclass(), methodName, paramTypes);
}
}
}
private boolean isWebRemoteAnnotated(Method method) {
if (method == null) return false;
return method.getAnnotation( WebRemote.class ) != null;
}
public static class ReturnedObject implements Serializable {
public ReturnedObject(Class type,
Object result) {
this.returnType = type;
this.returnedObject = result;
}
public Class returnType;
public Object returnedObject;
}
}


--
Wesley Akio Imamura
São Paulo - SP - Brazil