package com.guit.server.guice;
import com.google.gwt.user.client.rpc.SerializationException;
import com.google.gwt.user.server.rpc.RPC;
import com.google.gwt.user.server.rpc.SerializationPolicy;
import com.google.gwt.user.server.rpc.SerializationPolicyLoader;
import com.google.gwt.user.server.rpc.SerializationPolicyProvider;
import com.google.gwt.user.server.rpc.UnexpectedException;
import com.google.gwt.user.server.rpc.impl.ServerSerializationStreamReader;
import com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter;
import com.google.inject.Inject;
import com.guit.client.command.CommandRpc;
import com.guit.client.command.action.Action;
import com.guit.client.command.action.CommandException;
import com.guit.server.command.CommandRpcImpl;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.ParseException;
import java.util.ArrayList;
public class RpcProcessor implements SerializationPolicyProvider {
private final Method execute;
private Method executeBatch;
@Inject
@StaticFilesPath
String staticFilesPath;
public SerializationPolicy serializationPolicyCache;
@Inject
public RpcProcessor() {
try {
this.execute = CommandRpcImpl.class.getMethod("execute", Action.class);
this.executeBatch = CommandRpcImpl.class.getMethod("executeBatch", ArrayList.class);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public String encodeResponse(Object data) {
if (serializationPolicyCache == null) {
throw new RuntimeException("Cannot push on the first request");
}
try {
return (data instanceof Exception ? "//EX" : "//OK")
+ encodeResponse(data.getClass(), data, 1, serializationPolicyCache);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
public String processRequest(String encodedRequest, CommandRpc service) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Method method = execute;
try {
ServerSerializationStreamReader streamReader =
new ServerSerializationStreamReader(classLoader, this);
streamReader.prepareToRead(encodedRequest);
serializationPolicyCache = streamReader.getSerializationPolicy();
// Predecible values
streamReader.readString();
// Method name
String methodName = streamReader.readString();
// Ignore, we know the values
streamReader.readInt();
streamReader.readString();
Object[] parameterValues = new Object[1];
if ("execute".equals(methodName)) {
method = execute;
parameterValues[0] = streamReader.deserializeValue(Action.class);
} else {
method = executeBatch;
parameterValues[0] = streamReader.deserializeValue(ArrayList.class);
}
int flags = streamReader.getFlags();
try {
return "//OK"
+ encodeResponse(method.getReturnType(), method.invoke(service, parameterValues),
flags, serializationPolicyCache);
} catch (InvocationTargetException e) {
Throwable cause = e.getCause();
if (!(cause instanceof CommandException)) {
throw new UnexpectedException("Service method threw an unexpected exception: "
+ cause.toString(), cause);
}
return "//EX" + encodeResponse(cause.getClass(), cause, flags, serializationPolicyCache);
}
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
protected String encodeResponse(Class<?> responseClass, Object object, int flags,
SerializationPolicy serializationPolicy) throws SerializationException {
ServerSerializationStreamWriter stream =
new ServerSerializationStreamWriter(serializationPolicy);
stream.setFlags(flags);
stream.prepareToWrite();
stream.serializeValue(object, responseClass);
return stream.toString();
}
public final SerializationPolicy getSerializationPolicy(String moduleBaseURL, String strongName) {
if (serializationPolicyCache != null) {
return serializationPolicyCache;
}
serializationPolicyCache =
loadSerializationPolicy(this, moduleBaseURL, strongName, staticFilesPath);
if (serializationPolicyCache == null) {
// Failed to get the requested serialization policy; use the default
System.out
.println("WARNING: Failed to get the SerializationPolicy '"
+ strongName
+ "' for module '"
+ moduleBaseURL
+ "'; a legacy, 1.3.3 compatible, serialization policy will be used. You may experience SerializationExceptions as a result.");
serializationPolicyCache = RPC.getDefaultSerializationPolicy();
}
return serializationPolicyCache;
}
static SerializationPolicy loadSerializationPolicy(RpcProcessor servlet, String moduleBaseURL,
String strongName, String staticFilesPath) {
// The request can tell you the path of the web app relative to the
// container root.
String contextPath = ""; // request.getContextPath();
String modulePath = null;
if (moduleBaseURL != null) {
try {
modulePath = new URL(moduleBaseURL).getPath();
} catch (MalformedURLException ex) {
// log the information, we will default
servlet.log("Malformed moduleBaseURL: " + moduleBaseURL, ex);
}
}
SerializationPolicy serializationPolicy = null;
/*
* Check that the module path must be in the same web app as the servlet itself. If you need to
* implement a scheme different than this, override this method.
*/
if (modulePath == null || !modulePath.startsWith(contextPath)) {
String message =
"ERROR: The module path requested, "
+ modulePath
+ ", is not in the same web application as this servlet, "
+ contextPath
+ ". Your module may not be properly configured or your client and server code maybe out of date.";
servlet.log(message);
} else {
// Strip off the context path from the module base URL. It should be a
// strict prefix.
String contextRelativePath = modulePath.substring(contextPath.length());
String serializationPolicyFilePath =
SerializationPolicyLoader
.getSerializationPolicyFileName(contextRelativePath + strongName);
// Open the RPC resource file and read its contents.
InputStream is = null;
try {
is = new FileInputStream(new File(staticFilesPath + serializationPolicyFilePath));
} catch (FileNotFoundException e1) {
}
try {
if (is != null) {
try {
serializationPolicy = SerializationPolicyLoader.loadFromStream(is, null);
} catch (ParseException e) {
servlet.log("ERROR: Failed to parse the policy file '" + serializationPolicyFilePath
+ "'", e);
} catch (IOException e) {
servlet.log("ERROR: Could not read the policy file '" + serializationPolicyFilePath
+ "'", e);
}
} else {
String message =
"ERROR: The serialization policy file '" + serializationPolicyFilePath
+ "' was not found; did you forget to include it in this deployment?";
servlet.log(message);
}
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
// Ignore this error
}
}
}
}
return serializationPolicy;
}
private void log(String message) {
System.out.println(message);
}
private void log(String log, Throwable e) {
System.out.println(log);
}
}