]
Norman Richards reassigned JBSEAM-3924:
---------------------------------------
Assignee: Norman Richards
This patch adds full integration of seam with gwt 1.5.
------------------------------------------------------
Key: JBSEAM-3924
URL:
https://jira.jboss.org/jira/browse/JBSEAM-3924
Project: Seam
Issue Type: Patch
Components: GWT
Affects Versions: 2.1.1.GA
Environment: Any
Reporter: Nicolae Tabusca
Assignee: Norman Richards
Priority: Critical
Fix For: 2.1.2.GA
Attachments: GWTService.java
### Eclipse Workspace Patch 1.0
#P jboss-seam
Index: src/remoting/org/jboss/seam/remoting/gwt/GWTService.java
===================================================================
--- src/remoting/org/jboss/seam/remoting/gwt/GWTService.java (revision 9989)
+++ src/remoting/org/jboss/seam/remoting/gwt/GWTService.java (working copy)
@@ -1,976 +1,178 @@
package org.jboss.seam.remoting.gwt;
+import static org.jboss.seam.ScopeType.APPLICATION;
+import static org.jboss.seam.annotations.Install.BUILT_IN;
+
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.Arrays;
-import java.util.HashMap;
-import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.jboss.seam.core.ConversationPropagation;
+import org.jboss.seam.Component;
+import org.jboss.seam.annotations.Install;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+import org.jboss.seam.annotations.remoting.WebRemote;
+import org.jboss.seam.contexts.ServletLifecycle;
import org.jboss.seam.log.LogProvider;
import org.jboss.seam.log.Logging;
import org.jboss.seam.servlet.ContextualHttpServletRequest;
+import org.jboss.seam.util.EJB;
import org.jboss.seam.web.AbstractResource;
import com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException;
-import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.SerializationException;
import com.google.gwt.user.server.rpc.RPC;
import com.google.gwt.user.server.rpc.RPCRequest;
-import com.google.gwt.user.server.rpc.RPCServletUtils;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
-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;
/**
- * Abstract base class for GWT 1.5 integration.
+ * GWT integration.
*
- * @author Shane Bryzak
+ * @author Nicolae Tabusca
*/
-public abstract class GWTService extends AbstractResource implements
SerializationPolicyProvider
-{
- protected static final LogProvider log = Logging.getLogProvider(GWTService.class);
+@Scope(APPLICATION)
+(a)Name("org.jboss.seam.remoting.gwt.gwtRemoteService")
+@Install(precedence = BUILT_IN, classDependencies =
{"com.google.gwt.user.client.rpc.RemoteService"})
+@BypassInterceptors
+public class GWTService extends AbstractResource {
+
+ protected static final LogProvider log
+ = Logging.getLogProvider(GWTService.class);
- private static final HashMap<String, Class<?>> TYPE_NAMES;
+ public GWTService() {
+ }
- static
- {
- TYPE_NAMES = new HashMap<String, Class<?>>();
- 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);
+ @Override
+ public String getResourcePath() {
+ return "/gwt";
+ }
- }
-
- /**
- * A cache of moduleBaseURL and serialization policy strong name to
- * {@link SerializationPolicy}.
- */
- private final Map<String, SerializationPolicy> serializationPolicyCache = new
HashMap<String, SerializationPolicy>();
+ /**
+ * This is called internally.
+ *
+ * @see RemoteServiceServlet#doPost
+ */
+ @Override
+ public final void getResource(final HttpServletRequest request,
+ final HttpServletResponse response)
+ throws ServletException, IOException {
- @Override
- public String getResourcePath()
- {
- return "/gwt";
- }
+ ContextualHttpServletRequest contextualRequest
+ = new ContextualHttpServletRequest(request) {
- protected abstract ServerSerializationStreamReader getStreamReader();
+ private GWTController controller = new GWTController();
- protected abstract ServerSerializationStreamWriter getStreamWriter();
-
- protected abstract String createResponse(
- ServerSerializationStreamWriter stream, Class responseType,
- Object responseObj, boolean isException);
-
- // private final Set knownImplementedInterfaces = new HashSet();
- private final ThreadLocal<HttpServletRequest> perThreadRequest = new
ThreadLocal<HttpServletRequest>();
-
- private final ThreadLocal<HttpServletResponse> perThreadResponse = new
ThreadLocal<HttpServletResponse>();
-
- /**
- * This is called internally.
- *
- * @see RemoteServiceServlet#doPost
- */
- @Override
- public final void getResource(final HttpServletRequest request,
- final HttpServletResponse response) throws ServletException,
- IOException
- {
- try
- {
- // Store the request & response objects in thread-local storage.
- perThreadRequest.set(request);
- perThreadResponse.set(response);
-
- new ContextualHttpServletRequest(request) {
@Override
- public void process() throws Exception
- {
-
- try
- {
- // Read the request fully.
- //
- String requestPayload = RemoteServiceServlet_readContent(request);
-
- RemoteServiceServlet_onBeforeRequestDeserialized(requestPayload);
-
- // Invoke the core dispatching logic, which returns the
- // serialized result
- String responsePayload = processCall(requestPayload);
-
- RemoteServiceServlet_onAfterResponseSerialized(responsePayload);
-
- // Write the response.
- //
- RemoteServiceServlet_writeResponse(request, response,
- responsePayload);
-
- } catch (Throwable e)
- {
- RemoteServiceServlet_doUnexpectedFailure(e);
- }
-
+ public void process() throws Exception {
+
+ controller.service(request, response);
}
+ };
- @Override
- protected void restoreConversationId()
- {
- ConversationPropagation.instance().setConversationId(
- GWTService.this.perThreadRequest.get().getParameter(
- "conversationId"));
- }
+ contextualRequest.run();
- @Override
- protected void handleConversationPropagation()
- {
- }
- }.run();
- } finally
- {
- perThreadRequest.remove();
- perThreadResponse.remove();
- }
- }
+ }
- /**
- * This is public so that it can be unit tested easily without HTTP.
- */
- public String processCall(String payload) throws SerializationException
- {
- // Create a stream to deserialize the request.
- //
- // ServerSerializationStreamReader streamReader = getStreamReader();
- // streamReader.prepareToRead(payload);
- //
- // // Read the service interface
- // //
- // String serviceIntfName = streamReader.readString();
- //
- // // Read the method name.
- // //
- // String methodName = streamReader.readString();
- //
- // // Read the number and names of the parameter classes from the stream.
- // // We have to do this so that we can find the correct overload of the
- // // method.
- // //
- // int paramCount = streamReader.readInt();
- // Class[] paramTypes = new Class[paramCount];
- // for (int i = 0; i < paramTypes.length; i++)
- // {
- // String paramClassName = streamReader.readString();
- // try
- // {
- // paramTypes[i] = getClassOrPrimitiveFromName(paramClassName);
- // } catch (ClassNotFoundException e)
- // {
- // throw new SerializationException("Unknown parameter " + i
- // + " type '" + paramClassName + "'", e);
- // }
- // }
- //
- // // Deserialize the parameters.
- // //
- // Object[] args = new Object[paramCount];
- // for (int i = 0; i < args.length; i++)
- // {
- // args[i] = streamReader.deserializeValue(paramTypes[i]);
- // }
+ @SuppressWarnings("serial")
+ private class GWTController extends RemoteServiceServlet {
- try
- {
- SeamRPCRequest rpcRequest = RPC_decodeRequest(payload,
- this.getClass(), this);
+ @Override
+ public ServletContext getServletContext() {
+ return ServletLifecycle.getServletContext();
+ }
+
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public String processCall(String payload) throws SerializationException {
+ try {
+ Component remoteService = getRemoteServiceComponent(payload);
+
+ Class beanClass = remoteService.getBeanClass();
+ RPCRequest rpcRequest = RPC.decodeRequest(payload, beanClass, this);
- return RPC_invokeAndEncodeResponse(this, rpcRequest.getMethod(),
- rpcRequest.getParameterTypes(), rpcRequest.getParameters(),
- rpcRequest.getSerializationPolicy());
- } catch (IncompatibleRemoteServiceException ex)
- {
- getServletContext()
- .log(
- "An IncompatibleRemoteServiceException was thrown while
processing this call.",
- ex);
- return RPC.encodeResponseForFailure(null, ex);
- }
+ Method serviceDef = rpcRequest.getMethod();
+ Method serviceImpl = beanClass.getMethod(serviceDef.getName(),
+ serviceDef.getParameterTypes());
+ if (isWebRemoteAnnotated(serviceImpl) == false) {
+ throw new RuntimeException(
+ "Unable to access a service method called ["
+ + serviceImpl.getName() + "] on class
["
+ + beanClass.getName()
+ + "] without the @WebRemote attribute.
");
+ }
- // Make the call via reflection.
- //
- // String responsePayload = GENERIC_FAILURE_MSG;
- // ServerSerializationStreamWriter streamWriter = getStreamWriter();
- // Throwable caught = null;
- // try
- // {
- // GWTToSeamAdapter.ReturnedObject returnedObject =
- // adapter.callWebRemoteMethod(
- // serviceIntfName, methodName, paramTypes, args);
- // Class returnType = returnedObject.returnType;
- // Object returnVal = returnedObject.returnedObject;
- // // Class returnType = serviceIntfMethod.getReturnType();
- // // Object returnVal = serviceIntfMethod.invoke(this, args);
- // responsePayload = createResponse(streamWriter, returnType, returnVal,
- // false);
- // } catch (IllegalArgumentException e)
- // {
- // caught = e;
- // } catch (IllegalAccessException e)
- // {
- // caught = e;
- // } catch (InvocationTargetException e)
- // {
- // // Try to serialize the caught exception if the client is expecting it,
- // // otherwise log the exception server-side.
- // caught = e;
- // Throwable cause = e.getCause();
- // if (cause != null)
- // {
- // // Update the caught exception to the underlying cause
- // caught = cause;
- // // Serialize the exception back to the client if it's a declared
- // // exception
- // if (cause instanceof SerializableException)
- // {
- // Class thrownClass = cause.getClass();
- // responsePayload = createResponse(streamWriter, thrownClass,
- // cause, true);
- // // Don't log the exception on the server
- // caught = null;
- // }
- // }
- // }
- //
- // if (caught != null)
- // {
- // responsePayload = GENERIC_FAILURE_MSG;
- // ServletContext servletContext = getServletContext();
- // // servletContext may be null (for example, when unit testing)
- // if (servletContext != null)
- // {
- // // Log the exception server side
- // servletContext.log("Exception while dispatching incoming RPC call",
- // caught);
- // }
- // }
- }
+ return RPC.invokeAndEncodeResponse(
+ Component.getInstance(remoteService.getName()),
+ rpcRequest.getMethod(), rpcRequest.getParameters(),
+ rpcRequest.getSerializationPolicy());
- /**
- * Gets the <code>HttpServletRequest</code> object for the current call.
It
- * is stored thread-locally so that simultaneous invocations can have
- * different request objects.
- */
- protected final HttpServletRequest getThreadLocalRequest()
- {
- return perThreadRequest.get();
- }
-
- /**
- * Gets the <code>HttpServletResponse</code> object for the current call.
It
- * is stored thread-locally so that simultaneous invocations can have
- * different response objects.
- */
- protected final HttpServletResponse getThreadLocalResponse()
- {
- return perThreadResponse.get();
- }
-
- /**
- * Returns an {@link RPCRequest} that is built by decoding the contents of an
- * encoded RPC request and optionally validating that type can handle the
- * request. If the type parameter is not <code>null</code>, the
- * implementation checks that the type is assignable to the
- * {@link com.google.gwt.user.client.rpc.RemoteService} interface requested
- * in the encoded request string.
- *
- * <p>
- * If the serializationPolicyProvider parameter is not <code>null</code>,
it
- * is asked for a {@link SerializationPolicy} to use to restrict the set of
- * types that can be decoded from the request. If this parameter is
- * <code>null</code>, then only subtypes of
- * {@link com.google.gwt.user.client.rpc.IsSerializable IsSerializable} or
- * types which have custom field serializers can be decoded.
- * </p>
- *
- * <p>
- * Invoking this method with <code>null</code> for the type parameter,
- * <code>decodeRequest(encodedRequest, null)</code>, is equivalent to
calling
- * <code>decodeRequest(encodedRequest)</code>.
- * </p>
- *
- * @param encodedRequest
- * a string that encodes the
- * {@link com.google.gwt.user.client.rpc.RemoteService} interface,
- * the service method, and the arguments to pass to the service
- * method
- * @param type
- * if not <code>null</code>, the implementation checks that
the
- * type is assignable to the
- * {@link com.google.gwt.user.client.rpc.RemoteService} interface
- * encoded in the encoded request string.
- * @param serializationPolicyProvider
- * if not <code>null</code>, the implementation asks this
provider
- * for a {@link SerializationPolicy} which will be used to restrict
- * the set of types that can be decoded from this request
- * @return an {@link RPCRequest} instance
- *
- * @throws NullPointerException
- * if the encodedRequest is <code>null</code>
- * @throws IllegalArgumentException
- * if the encodedRequest is an empty string
- * @throws IncompatibleRemoteServiceException
- * if any of the following conditions apply:
- * <ul>
- * <li>if the types in the encoded request cannot be
deserialized</li>
- * <li>if the {@link ClassLoader} acquired from
- *
<code>Thread.currentThread().getContextClassLoader()</code>
- * cannot load the service interface or any of the types specified
- * in the encodedRequest</li>
- * <li>the requested interface is not assignable to
- * {@link com.google.gwt.user.client.rpc.RemoteService}</li>
- * <li>the service method requested in the encodedRequest is not a
- * member of the requested service interface</li>
- * <li>the type parameter is not <code>null</code> and
is not
- * assignable to the requested
- * {@link com.google.gwt.user.client.rpc.RemoteService} interface
- * </ul>
- */
- public static SeamRPCRequest RPC_decodeRequest(String encodedRequest,
- Class<?> type, SerializationPolicyProvider serializationPolicyProvider)
- {
- if (encodedRequest == null)
- {
- throw new NullPointerException("encodedRequest cannot be null");
- }
-
- if (encodedRequest.length() == 0)
- {
- throw new IllegalArgumentException("encodedRequest cannot be
empty");
- }
-
- ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
-
- try
- {
- ServerSerializationStreamReader streamReader = new
ServerSerializationStreamReader(
- classLoader, serializationPolicyProvider);
- streamReader.prepareToRead(encodedRequest);
-
- // Read the name of the RemoteService interface
- String serviceIntfName = streamReader.readString();
-
- /*
- * todo?? if (type != null) { if (!implementsInterface(type,
- * serviceIntfName)) { // The service does not implement the requested
- * interface throw new IncompatibleRemoteServiceException(
- * "Blocked attempt to access interface '" + serviceIntfName +
- * "', which is not implemented by '" + printTypeName(type)
+
- * "'; this is either misconfiguration or a hack attempt"); } }
- */
-
- SerializationPolicy serializationPolicy = streamReader
- .getSerializationPolicy();
- Class<?> serviceIntf;
- try
- {
- serviceIntf = RPC_getClassFromSerializedName(serviceIntfName,
- classLoader);
- if (!RemoteService.class.isAssignableFrom(serviceIntf))
- {
- // The requested interface is not a RemoteService interface
- throw new IncompatibleRemoteServiceException(
- "Blocked attempt to access interface '"
- + printTypeName(serviceIntf)
- + "', which doesn't extend RemoteService; this
is either misconfiguration or a hack attempt");
+ } catch (IncompatibleRemoteServiceException ex) {
+ log.error(ex.getMessage(), ex);
+ return RPC.encodeResponseForFailure(null, ex);
+ } catch (SecurityException e) {
+ log.error(e.getMessage(), e);
+ return RPC.encodeResponseForFailure(null, e);
+ } catch (NoSuchMethodException e) {
+ log.error(e.getMessage(), e);
+ return RPC.encodeResponseForFailure(null, e);
}
- } catch (ClassNotFoundException e)
- {
- throw new IncompatibleRemoteServiceException(
- "Could not locate requested interface '" +
serviceIntfName
- + "' in default classloader", e);
- }
+ }
- String serviceMethodName = streamReader.readString();
+ @SuppressWarnings("unchecked")
+ private Component getRemoteServiceComponent(String payload)
+ throws SerializationException {
- int paramCount = streamReader.readInt();
- Class<?>[] parameterTypes = new Class[paramCount];
+ ClassLoader classLoader = Thread.currentThread()
+ .getContextClassLoader();
+ ServerSerializationStreamReader streamReader
+ = new ServerSerializationStreamReader(classLoader, this);
- for (int i = 0; i < parameterTypes.length; i++)
- {
- String paramClassName = streamReader.readString();
- try
- {
- parameterTypes[i] = RPC_getClassFromSerializedName(
- paramClassName, classLoader);
- } catch (ClassNotFoundException e)
- {
- throw new IncompatibleRemoteServiceException("Parameter " + i
- + " of is of an unknown type '" + paramClassName +
"'", e);
- }
- }
+ streamReader.prepareToRead(payload);
- try
- {
- Method method = serviceIntf.getMethod(serviceMethodName,
- parameterTypes);
+ // Read the name of the RemoteService interface
+ String serviceIntfName = streamReader.readString();
- Object[] parameterValues = new Object[parameterTypes.length];
- for (int i = 0; i < parameterValues.length; i++)
- {
- parameterValues[i] = streamReader
- .deserializeValue(parameterTypes[i]);
+ Component component = Component.forName(serviceIntfName);
+ if (null == component) {
+ throw new RuntimeException("No such component: "
+ + serviceIntfName);
}
- return new SeamRPCRequest(method, parameterValues, parameterTypes,
- serializationPolicy);
+ if (component.getType().isSessionBean()
+ && component.getBusinessInterfaces().size() > 0) {
- } catch (NoSuchMethodException e)
- {
- throw new IncompatibleRemoteServiceException(
- formatMethodNotFoundErrorMessage(serviceIntf,
- serviceMethodName, parameterTypes));
- }
- } catch (SerializationException ex)
- {
- throw new IncompatibleRemoteServiceException(ex.getMessage(), ex);
- }
- }
+ boolean localDefined = false;
+ for (Class c : component.getBusinessInterfaces()) {
+ if (c.isAnnotationPresent(EJB.LOCAL)) {
+ localDefined = true;
+ break;
+ }
+ }
- /**
- * Returns the {@link Class} instance for the named class or primitive type.
- *
- * @param serializedName
- * the serialized name of a class or primitive type
- * @param classLoader
- * the classLoader used to load {@link Class}es
- * @return Class instance for the given type name
- * @throws ClassNotFoundException
- * if the named type was not found
- */
- private static Class<?> RPC_getClassFromSerializedName(
- String serializedName, ClassLoader classLoader)
- throws ClassNotFoundException
- {
- Class<?> value = TYPE_NAMES.get(serializedName);
- if (value != null)
- {
- return value;
- }
-
- return Class.forName(serializedName, false, classLoader);
- }
-
- /**
- * Returns a string that encodes the result of calling a service method,
- * which could be the value returned by the method or an exception thrown by
- * it.
- *
- * <p>
- * If the serializationPolicy parameter is not <code>null</code>, it is
used
- * to determine what types can be encoded as part of this response. If this
- * parameter is <code>null</code>, then only subtypes of
- * {@link com.google.gwt.user.client.rpc.IsSerializable IsSerializable} or
- * types which have custom field serializers may be encoded.
- * </p>
- *
- * <p>
- * This method does no security checking; security checking must be done on
- * the method prior to this invocation.
- * </p>
- *
- * @param target
- * instance on which to invoke the serviceMethod
- * @param serviceMethod
- * the method to invoke
- * @param args
- * arguments used for the method invocation
- * @param serializationPolicy
- * determines the serialization policy to be used
- * @return a string which encodes either the method's return or a checked
- * exception thrown by the method
- *
- * @throws NullPointerException
- * if the serviceMethod or the serializationPolicy are
- * <code>null</code>
- * @throws SecurityException
- * if the method cannot be accessed or if the number or type of
- * actual and formal arguments differ
- * @throws SerializationException
- * if an object could not be serialized by the stream
- * @throws UnexpectedException
- * if the serviceMethod throws a checked exception that is not
- * declared in its signature
- */
- public static String RPC_invokeAndEncodeResponse(Object target,
- Method serviceMethod, Class[] paramTypes, Object[] args,
- SerializationPolicy serializationPolicy) throws SerializationException
- {
- if (serviceMethod == null)
- {
- throw new NullPointerException("serviceMethod");
- }
-
- if (serializationPolicy == null)
- {
- throw new NullPointerException("serializationPolicy");
- }
-
- String responsePayload;
- try
- {
- GWTToSeamAdapter adapter = GWTToSeamAdapter.instance();
-
- String serviceIntfName = serviceMethod.getDeclaringClass().getName();
-
- GWTToSeamAdapter.ReturnedObject returnedObject = adapter
- .callWebRemoteMethod(serviceIntfName, serviceMethod.getName(),
- paramTypes, args);
-
- // Object result = serviceMethod.invoke(target, args);
-
- responsePayload = RPC.encodeResponseForSuccess(serviceMethod,
- returnedObject.returnedObject, serializationPolicy);
- } catch (IllegalAccessException e)
- {
- SecurityException securityException = new SecurityException(
- formatIllegalAccessErrorMessage(target, serviceMethod));
- securityException.initCause(e);
- throw securityException;
- } catch (IllegalArgumentException e)
- {
- SecurityException securityException = new SecurityException(
- formatIllegalArgumentErrorMessage(target, serviceMethod, args));
- securityException.initCause(e);
- throw securityException;
- } catch (InvocationTargetException e)
- {
- // Try to encode the caught exception
- //
- Throwable cause = e.getCause();
-
- responsePayload = RPC.encodeResponseForFailure(serviceMethod, cause,
- serializationPolicy);
- }
-
- return responsePayload;
- }
-
- /**
- * Override this method to examine the serialized response that will be
- * returned to the client. The default implementation does nothing and need
- * not be called by subclasses.
- */
- protected void RemoteServiceServlet_onAfterResponseSerialized(
- String serializedResponse)
- {
- }
-
- /**
- * Override this method to examine the serialized version of the request
- * payload before it is deserialized into objects. The default implementation
- * does nothing and need not be called by subclasses.
- */
- protected void RemoteServiceServlet_onBeforeRequestDeserialized(
- String serializedRequest)
- {
- }
-
- /**
- * Override this method in order to control the parsing of the incoming
- * request. For example, you may want to bypass the check of the Content-Type
- * and character encoding headers in the request, as some proxies re-write
- * the request headers. Note that bypassing these checks may expose the
- * servlet to some cross-site vulnerabilities.
- *
- * @param request
- * the incoming request
- * @return the content of the incoming request encoded as a string.
- */
- protected String RemoteServiceServlet_readContent(HttpServletRequest request)
- throws ServletException, IOException
- {
- return RPCServletUtils.readContentAsUtf8(request, true);
- }
-
- public final SerializationPolicy getSerializationPolicy(
- String moduleBaseURL, String strongName)
- {
-
- SerializationPolicy serializationPolicy = getCachedSerializationPolicy(
- moduleBaseURL, strongName);
- if (serializationPolicy != null)
- {
- return serializationPolicy;
- }
-
- serializationPolicy = doGetSerializationPolicy(getThreadLocalRequest(),
- moduleBaseURL, strongName);
-
- if (serializationPolicy == null)
- {
- // Failed to get the requested serialization policy; use the default
- getServletContext()
- .log(
- "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.");
- serializationPolicy = RPC.getDefaultSerializationPolicy();
- }
-
- // This could cache null or an actual instance. Either way we will not
- // attempt to lookup the policy again.
- putCachedSerializationPolicy(moduleBaseURL, strongName,
- serializationPolicy);
-
- return serializationPolicy;
- }
-
- private SerializationPolicy getCachedSerializationPolicy(
- String moduleBaseURL, String strongName)
- {
- synchronized (serializationPolicyCache)
- {
- return serializationPolicyCache.get(moduleBaseURL + strongName);
- }
- }
-
- private void putCachedSerializationPolicy(String moduleBaseURL,
- String strongName, SerializationPolicy serializationPolicy)
- {
- synchronized (serializationPolicyCache)
- {
- serializationPolicyCache.put(moduleBaseURL + strongName,
- serializationPolicy);
- }
- }
-
- /**
- * Gets the {@link SerializationPolicy} for given module base URL and strong
- * name if there is one.
- *
- * Override this method to provide a {@link SerializationPolicy} using an
- * alternative approach.
- *
- * @param request
- * the HTTP request being serviced
- * @param moduleBaseURL
- * as specified in the incoming payload
- * @param strongName
- * a strong name that uniquely identifies a serialization policy
- * file
- * @return a {@link SerializationPolicy} for the given module base URL and
- * strong name, or <code>null</code> if there is none
- */
- protected SerializationPolicy doGetSerializationPolicy(
- HttpServletRequest request, String moduleBaseURL, String strongName)
- {
- // 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
- getServletContext().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.";
- getServletContext().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 read its contents.
- InputStream is = getServletContext().getResourceAsStream(
- serializationPolicyFilePath);
- try
- {
- if (is != null)
- {
- try
- {
- serializationPolicy = SerializationPolicyLoader
- .loadFromStream(is, null);
- } catch (ParseException e)
- {
- getServletContext().log(
- "ERROR: Failed to parse the policy file '"
- + serializationPolicyFilePath + "'", e);
- } catch (IOException e)
- {
- getServletContext().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?";
- getServletContext().log(message);
+ if (localDefined == false) {
+ throw new RuntimeException(
+ String.format("Type cannot be determined for component
[%s]. Please ensure that it has a local interface.",
+ component));
+ }
}
- } finally
- {
- if (is != null)
- {
- try
- {
- is.close();
- } catch (IOException e)
- {
- // Ignore this error
- }
- }
- }
- }
+
+ return component;
+ }
- return serializationPolicy;
- }
-
- private void RemoteServiceServlet_writeResponse(HttpServletRequest request,
- HttpServletResponse response, String responsePayload)
- throws IOException
- {
- boolean gzipEncode = RPCServletUtils.acceptsGzipEncoding(request)
- && shouldCompressResponse(request, response, responsePayload);
-
- RPCServletUtils.writeResponse(getServletContext(), response,
- responsePayload, gzipEncode);
- }
-
- /**
- * Override this method to control what should happen when an exception
- * escapes the {@link #processCall(String)} method. The default
- * implementation will log the failure and send a generic failure response to
- * the client.
- * <p/>
- *
- * An "expected failure" is an exception thrown by a service method that
is
- * declared in the signature of the service method. These exceptions are
- * serialized back to the client, and are not passed to this method. This
- * method is called only for exceptions or errors that are not part of the
- * service method's signature, or that result from SecurityExceptions,
- * SerializationExceptions, or other failures within the RPC framework.
- * <p/>
- *
- * Note that if the desired behavior is to both send the GENERIC_FAILURE_MSG
- * response AND to rethrow the exception, then this method should first send
- * the GENERIC_FAILURE_MSG response itself (using getThreadLocalResponse),
- * and then rethrow the exception. Rethrowing the exception will cause it to
- * escape into the servlet container.
- *
- * @param e
- * the exception which was thrown
- */
- protected void RemoteServiceServlet_doUnexpectedFailure(Throwable e)
- {
- ServletContext servletContext = getServletContext();
- RPCServletUtils.writeResponseForUnexpectedFailure(servletContext,
- getThreadLocalResponse(), e);
- }
-
- /**
- * Determines whether the response to a given servlet request should or
- * should not be GZIP compressed. This method is only called in cases where
- * the requester accepts GZIP encoding.
- * <p>
- * This implementation currently returns <code>true</code> if the
response
- * string's estimated byte length is longer than 256 bytes. Subclasses can
- * override this logic.
- * </p>
- *
- * @param request
- * the request being served
- * @param response
- * the response that will be written into
- * @param responsePayload
- * the payload that is about to be sent to the client
- * @return <code>true</code> if responsePayload should be GZIP
compressed,
- * otherwise <code>false</code>.
- */
- protected boolean shouldCompressResponse(HttpServletRequest request,
- HttpServletResponse response, String responsePayload)
- {
- return RPCServletUtils
- .exceedsUncompressedContentLengthLimit(responsePayload);
- }
-
- private static String formatMethodNotFoundErrorMessage(Class<?> serviceIntf,
- String serviceMethodName, Class<?>[] parameterTypes)
- {
- StringBuffer sb = new StringBuffer();
-
- sb.append("Could not locate requested method '");
- sb.append(serviceMethodName);
- sb.append("(");
- for (int i = 0; i < parameterTypes.length; ++i)
- {
- if (i > 0)
- {
- sb.append(", ");
- }
- sb.append(printTypeName(parameterTypes[i]));
- }
- sb.append(")'");
-
- sb.append(" in interface '");
- sb.append(printTypeName(serviceIntf));
- sb.append("'");
-
- return sb.toString();
- }
-
- private static String formatIllegalAccessErrorMessage(Object target,
- Method serviceMethod)
- {
- StringBuffer sb = new StringBuffer();
- sb.append("Blocked attempt to access inaccessible method '");
- sb.append(getSourceRepresentation(serviceMethod));
- sb.append("'");
-
- if (target != null)
- {
- sb.append(" on target '");
- sb.append(printTypeName(target.getClass()));
- sb.append("'");
- }
-
- sb.append("; this is either misconfiguration or a hack attempt");
-
- return sb.toString();
- }
-
- private static String formatIllegalArgumentErrorMessage(Object target,
- Method serviceMethod, Object[] args)
- {
- StringBuffer sb = new StringBuffer();
- sb.append("Blocked attempt to invoke method '");
- sb.append(getSourceRepresentation(serviceMethod));
- sb.append("'");
-
- if (target != null)
- {
- sb.append(" on target '");
- sb.append(printTypeName(target.getClass()));
- sb.append("'");
- }
-
- sb.append(" with invalid arguments");
-
- if (args != null && args.length > 0)
- {
- sb.append(Arrays.asList(args));
- }
-
- return sb.toString();
- }
-
- /**
- * Returns the source representation for a method signature.
- *
- * @param method
- * method to get the source signature for
- * @return source representation for a method signature
- */
- private static String getSourceRepresentation(Method method)
- {
- return method.toString().replace('$', '.');
- }
-
- /**
- * Straight copy from
- * {@link com.google.gwt.dev.util.TypeInfo#getSourceRepresentation(Class)} to
- * avoid runtime dependency on gwt-dev.
- */
- private static String printTypeName(Class<?> type)
- {
- // Primitives
- //
- if (type.equals(Integer.TYPE))
- {
- return "int";
- } else if (type.equals(Long.TYPE))
- {
- return "long";
- } else if (type.equals(Short.TYPE))
- {
- return "short";
- } else if (type.equals(Byte.TYPE))
- {
- return "byte";
- } else if (type.equals(Character.TYPE))
- {
- return "char";
- } else if (type.equals(Boolean.TYPE))
- {
- return "boolean";
- } else if (type.equals(Float.TYPE))
- {
- return "float";
- } else if (type.equals(Double.TYPE))
- {
- return "double";
- }
-
- // Arrays
- //
- if (type.isArray())
- {
- Class<?> componentType = type.getComponentType();
- return printTypeName(componentType) + "[]";
- }
-
- // Everything else
- //
- return type.getName().replace('$', '.');
- }
-
-}
+ /**
+ * Only allow methods annotated with @WebRemote for security reasons.
+ */
+ private boolean isWebRemoteAnnotated(Method method) {
+ if (method == null)
+ return false;
+ return method.getAnnotation(WebRemote.class) != null;
+ }
+ }
+}
\ No newline at end of file
Index: src/remoting/org/jboss/seam/remoting/gwt/GWTToSeamAdapter.java
===================================================================
--- src/remoting/org/jboss/seam/remoting/gwt/GWTToSeamAdapter.java (revision 9989)
+++ src/remoting/org/jboss/seam/remoting/gwt/GWTToSeamAdapter.java (working copy)
@@ -1,210 +0,0 @@
-package org.jboss.seam.remoting.gwt;
-
-import static org.jboss.seam.ScopeType.APPLICATION;
-import static org.jboss.seam.annotations.Install.BUILT_IN;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.jboss.seam.Component;
-import org.jboss.seam.annotations.Install;
-import org.jboss.seam.annotations.Name;
-import org.jboss.seam.annotations.Scope;
-import org.jboss.seam.annotations.intercept.BypassInterceptors;
-import org.jboss.seam.annotations.remoting.WebRemote;
-import org.jboss.seam.util.EJB;
-
-/**
- * This class adapts GWT RPC mechanism to Seam actions.
- *
- * @author Michael Neale
- */
-@Scope(APPLICATION)
-(a)Name("org.jboss.seam.remoting.gwt.gwtToSeamAdapter")
-@BypassInterceptors
-@Install(precedence=BUILT_IN)
-public class GWTToSeamAdapter {
-
- /** A very simple cache of previously looked up methods */
- private final Map METHOD_CACHE = new HashMap();
-
- public static GWTToSeamAdapter instance()
- {
- GWTToSeamAdapter adapter = (GWTToSeamAdapter)
Component.getInstance(GWTToSeamAdapter.class);
-
- if (adapter == null)
- {
- throw new IllegalStateException("No GWTToSeamAdapter exists");
- }
-
- return adapter;
- }
-
- /**
- * Call the service.
- *
- * @param serviceIntfName
- * The interface name - this will be the fully qualified name of
- * the remote service interface as understood by GWT. This
- * correlates to a component name in seam.
- * @param methodName
- * The method name of the service being invoked.
- * @param paramTypes
- * The types of parameters - needed for method lookup for
- * polymorphism.
- * @param args
- * The values to be passed to the service method.
- * @return A populated ReturnedObject - the returned object payload may be
- * null, but the type will not be.
- * @throws InvocationTargetException
- * @throws IllegalAccessException
- */
- public ReturnedObject callWebRemoteMethod(String serviceIntfName,
- String methodName, Class[] paramTypes, Object[] args)
- throws InvocationTargetException, IllegalAccessException,
- SecurityException {
-
- // Find the component we're calling
- Component component = Component.forName(serviceIntfName);
-
- if (component == null)
- throw new RuntimeException("No such component: " + serviceIntfName);
-
- Object instance = getServiceComponent(serviceIntfName);
- Class clz = null;
-
- if (component.getType().isSessionBean()
- && component.getBusinessInterfaces().size() > 0) {
- for (Class c : component.getBusinessInterfaces()) {
- if (c.isAnnotationPresent(EJB.LOCAL)) {
- clz = c;
- break;
- }
- }
-
- if (clz == null)
- throw new RuntimeException(
- String
- .format(
- "Type cannot be determined for component [%s]. Please
ensure that it has a local interface.",
- component));
- }
-
- if (clz == null)
- clz = component.getBeanClass();
-
- Method method = getMethod(serviceIntfName, methodName, clz, paramTypes);
-
- Object result = method.invoke(instance, args);
- return new ReturnedObject(method.getReturnType(), result);
- }
-
- /**
- * Get the method on the class, including walking up the class heirarchy if
- * needed. Methods have to be marked as "@WebRemote" to be allowed.
- *
- * @param methodName
- * @param clz
- * @param paramTypes
- */
- 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 +
")";
- }
-
- }
-
- /**
- * Recurse up the class hierarchy, looking for a compatable method that is
- * marked as "@WebRemote". If one is not found (or we hit Object.class)
then
- * we barf - basically trust nothing from the client other then what we want
- * to allow them to call.
- */
- 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);
- }
- }
- }
-
- /**
- * Only allow methods annotated with
- *
- * @WebRemote for security reasons.
- */
- private boolean isWebRemoteAnnotated(Method method) {
- if (method == null)
- return false;
- return method.getAnnotation(WebRemote.class) != null;
- }
-
- /**
- * Return the service component that has been bound to the given name.
- */
- protected Object getServiceComponent(String serviceIntfName) {
- return Component.getInstance(serviceIntfName);
- }
-
- /**
- * This is used for returning results to the GWT service endpoint. The class
- * is needed even if the result is null. a void.class responseType is
- * perfectly acceptable.
- *
- * @author Michael Neale
- */
- static class ReturnedObject {
- public ReturnedObject(Class type, Object result) {
- this.returnType = type;
- this.returnedObject = result;
- }
-
- public Class returnType;
-
- public Object returnedObject;
- }
-
-}
Index: src/remoting/org/jboss/seam/remoting/gwt/SeamRPCRequest.java
===================================================================
--- src/remoting/org/jboss/seam/remoting/gwt/SeamRPCRequest.java (revision 9989)
+++ src/remoting/org/jboss/seam/remoting/gwt/SeamRPCRequest.java (working copy)
@@ -1,47 +0,0 @@
-package org.jboss.seam.remoting.gwt;
-
-import com.google.gwt.user.server.rpc.SerializationPolicy;
-
-import java.lang.reflect.Method;
-
-/**
- * @author Tomaz Cerar
- * @version $Revision$
- * @modifiedBy $Author$
- * @modified $Date$
- */
-public class SeamRPCRequest
-{
- private final java.lang.reflect.Method method;
- private final java.lang.Object[] parameters;
- private final Class[] parameterTypes;
- private final com.google.gwt.user.server.rpc.SerializationPolicy
serializationPolicy;
-
- public SeamRPCRequest(Method method, Object[] parameters,
- Class[] parameterTypes, SerializationPolicy serializationPolicy) {
- this.method = method;
- this.parameters = parameters;
- this.parameterTypes = parameterTypes;
- this.serializationPolicy = serializationPolicy;
- }
-
- public Method getMethod()
- {
- return method;
- }
-
- public Object[] getParameters()
- {
- return parameters;
- }
-
- public Class[] getParameterTypes()
- {
- return parameterTypes;
- }
-
- public SerializationPolicy getSerializationPolicy()
- {
- return serializationPolicy;
- }
-}
Index: src/remoting/org/jboss/seam/remoting/gwt/GWT14Service.java
===================================================================
--- src/remoting/org/jboss/seam/remoting/gwt/GWT14Service.java (revision 9989)
+++ src/remoting/org/jboss/seam/remoting/gwt/GWT14Service.java (working copy)
@@ -1,113 +0,0 @@
-package org.jboss.seam.remoting.gwt;
-
-import static org.jboss.seam.ScopeType.APPLICATION;
-import static org.jboss.seam.annotations.Install.BUILT_IN;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-
-import org.jboss.seam.annotations.Create;
-import org.jboss.seam.annotations.Install;
-import org.jboss.seam.annotations.Name;
-import org.jboss.seam.annotations.Scope;
-import org.jboss.seam.annotations.intercept.BypassInterceptors;
-
-import com.google.gwt.user.client.rpc.SerializationException;
-import com.google.gwt.user.server.rpc.impl.ServerSerializationStreamReader;
-import com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter;
-
-/**
- *
- * @author Shane Bryzak
- */
-@Scope(APPLICATION)
-(a)Name("org.jboss.seam.remoting.gwt.gwtRemoteService")
-@Install(precedence = BUILT_IN, classDependencies =
{"com.google.gwt.user.client.rpc.RemoteService"})
-@BypassInterceptors
-public class GWT14Service extends GWTService
-{
- private static final String SERIALIZATION_POLICY_PROVIDER_CLASS =
"com.google.gwt.user.server.rpc.SerializationPolicyProvider";
-
- private static final String SERIALIZATION_POLICY_CLASS =
"com.google.gwt.user.server.rpc.SerializationPolicy";
- private static final String LEGACY_SERIALIZATION_POLICY_CLASS =
"com.google.gwt.user.server.rpc.impl.LegacySerializationPolicy";
-
-
- private Constructor streamReaderConstructor;
- private Constructor streamWriterConstructor;
-
- private Object legacySerializationPolicy;
-
- @Create
- public void startup() throws Exception
- {
- try
- {
- log.trace("GWT14Service starting up");
-
- Class policyProviderClass =
Class.forName(SERIALIZATION_POLICY_PROVIDER_CLASS);
- Class serializationPolicyClass = Class.forName(SERIALIZATION_POLICY_CLASS);
-
- streamReaderConstructor =
ServerSerializationStreamReader.class.getConstructor(
- new Class[] { ClassLoader.class, policyProviderClass } );
- streamWriterConstructor =
ServerSerializationStreamWriter.class.getConstructor(
- new Class[] { serializationPolicyClass } );
-
- Class legacySerializationPolicyClass =
Class.forName(LEGACY_SERIALIZATION_POLICY_CLASS);
- Method m =
legacySerializationPolicyClass.getDeclaredMethod("getInstance");
- legacySerializationPolicy = m.invoke(null);
- }
- catch (Exception ex)
- {
- log.error("Error initializing GWT14Service. Please ensure " +
- "the GWT 1.4 libraries are in the classpath.");
- throw ex;
- }
- }
-
- @Override
- protected String createResponse(ServerSerializationStreamWriter stream,
- Class responseType, Object responseObj, boolean isException)
- {
- stream.prepareToWrite();
- if (responseType != void.class)
- {
- try
- {
- stream.serializeValue(responseObj, responseType);
- } catch (SerializationException e)
- {
- responseObj = e;
- isException = true;
- }
- }
-
- return (isException ? "//EX" : "//OK") + stream.toString();
- }
-
- @Override
- public ServerSerializationStreamReader getStreamReader()
- {
- try
- {
- return (ServerSerializationStreamReader) streamReaderConstructor.newInstance(
- Thread.currentThread().getContextClassLoader(), null);
- }
- catch (Exception ex)
- {
- throw new RuntimeException("Unable to create stream reader", ex);
- }
- }
-
- @Override
- public ServerSerializationStreamWriter getStreamWriter()
- {
- try
- {
- return (ServerSerializationStreamWriter)
streamWriterConstructor.newInstance(legacySerializationPolicy);
- }
- catch (Exception ex)
- {
- throw new RuntimeException("Unable to create stream writer", ex);
- }
- }
-}
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: