Author: shane.bryzak(a)jboss.com
Date: 2008-11-10 04:54:23 -0500 (Mon, 10 Nov 2008)
New Revision: 9536
Modified:
trunk/src/remoting/org/jboss/seam/remoting/Call.java
trunk/src/remoting/org/jboss/seam/remoting/ExecutionHandler.java
trunk/src/remoting/org/jboss/seam/remoting/InterfaceGenerator.java
trunk/src/remoting/org/jboss/seam/remoting/MarshalUtils.java
trunk/src/remoting/org/jboss/seam/remoting/remote.js
Log:
JBSEAM-633
Modified: trunk/src/remoting/org/jboss/seam/remoting/Call.java
===================================================================
--- trunk/src/remoting/org/jboss/seam/remoting/Call.java 2008-11-10 06:24:00 UTC (rev
9535)
+++ trunk/src/remoting/org/jboss/seam/remoting/Call.java 2008-11-10 09:54:23 UTC (rev
9536)
@@ -1,5 +1,6 @@
package org.jboss.seam.remoting;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
@@ -16,214 +17,250 @@
import org.jboss.seam.util.EJB;
/**
- *
+ *
* @author Shane Bryzak
*/
public class Call
{
- private String id;
- private String componentName;
- private String methodName;
- //private String expression;
+ private String id;
+ private String componentName;
+ private String methodName;
+ // private String expression;
+ private Throwable exception;
- private List<Wrapper> params = new ArrayList<Wrapper> ();
+ private List<Wrapper> params = new ArrayList<Wrapper>();
- private Object result;
+ private Object result;
- private CallContext context;
+ private CallContext context;
- private List<String> constraints = null;
+ private List<String> constraints = null;
- /**
- * Constructor.
- *
- * @param componentName String
- * @param methodName String
- */
- public Call(String id, String componentName, String methodName)
- {
- this.id = id;
- this.componentName = componentName;
- this.methodName = methodName;
- this.context = new CallContext();
- }
+ /**
+ * Constructor.
+ *
+ * @param componentName
+ * String
+ * @param methodName
+ * String
+ */
+ public Call(String id, String componentName, String methodName) {
+ this.id = id;
+ this.componentName = componentName;
+ this.methodName = methodName;
+ this.context = new CallContext();
+ }
- /**
- * Return the call context.
- *
- * @return CallContext
- */
- public CallContext getContext()
- {
- return context;
- }
+ /**
+ * Return the call context.
+ *
+ * @return CallContext
+ */
+ public CallContext getContext()
+ {
+ return context;
+ }
+
+ /**
+ * Returns the exception thrown by the invoked method. If no exception was thrown,
+ * will return null.
+ */
+ public Throwable getException()
+ {
+ return exception;
+ }
- /**
- * Add a parameter to this call.
- *
- * @param param BaseWrapper
- */
- public void addParameter(Wrapper param)
- {
- params.add(param);
- }
+ /**
+ * Add a parameter to this call.
+ *
+ * @param param
+ */
+ public void addParameter(Wrapper param)
+ {
+ params.add(param);
+ }
- /**
- * Returns the result of this call.
- *
- * @return Wrapper
- */
- public Object getResult()
- {
- return result;
- }
+ /**
+ * Returns the result of this call.
+ *
+ * @return Wrapper
+ */
+ public Object getResult()
+ {
+ return result;
+ }
- /**
- * Returns the id of this call.
- *
- * @return String
- */
- public String getId()
- {
- return id;
- }
+ /**
+ * Returns the id of this call.
+ *
+ * @return String
+ */
+ public String getId()
+ {
+ return id;
+ }
- /**
- * Returns the object graph constraints annotated on the method that is called.
- *
- * @return List The constraints
- */
- public List<String> getConstraints()
- {
- return constraints;
- }
+ /**
+ * Returns the object graph constraints annotated on the method that is
+ * called.
+ *
+ * @return List The constraints
+ */
+ public List<String> getConstraints()
+ {
+ return constraints;
+ }
- /**
- * Execute this call
- *
- * @throws Exception
- */
- public void execute()
- throws Exception
- {
- if (componentName != null)
- {
- processInvocation();
- }
- }
-
- private void processInvocation()
- throws Exception
- {
- // Find the component we're calling
- Component component = Component.forName(componentName);
+ /**
+ * Execute this call
+ *
+ * @throws Exception
+ */
+ public void execute() throws Exception
+ {
+ if (componentName != null)
+ {
+ processInvocation();
+ }
+ }
- if (component == null)
- throw new RuntimeException("No such component: " + componentName);
+ private void processInvocation() throws Exception
+ {
+ // Find the component we're calling
+ Component component = Component.forName(componentName);
- // Create an instance of the component
- Object instance = Component.getInstance(componentName, true);
-
- if (instance == null)
- {
- throw new RuntimeException(String.format(
- "Could not create instance of component %s", componentName));
- }
+ if (component == null)
+ {
+ throw new RuntimeException("No such component: " + componentName);
+ }
- Class type = null;
+ // Create an instance of the component
+ Object instance = Component.getInstance(componentName, true);
- if (component.getType().isSessionBean() &&
- component.getBusinessInterfaces().size() > 0)
- {
- for (Class c : component.getBusinessInterfaces())
- {
- if (c.isAnnotationPresent(EJB.LOCAL))
+ if (instance == null)
+ {
+ throw new RuntimeException(String.format(
+ "Could not create instance of component %s", componentName));
+ }
+
+ Class type = null;
+
+ if (component.getType().isSessionBean()
+ && component.getBusinessInterfaces().size() > 0)
+ {
+ for (Class c : component.getBusinessInterfaces())
{
- type = c;
- break;
+ if (c.isAnnotationPresent(EJB.LOCAL))
+ {
+ type = c;
+ break;
+ }
}
- }
- if (type == null)
- throw new RuntimeException(String.format(
- "Type cannot be determined for component [%s]. Please ensure that it has a
local interface.", component));
- }
+ if (type == null)
+ {
+ throw new RuntimeException(String.format(
+ "Type cannot be determined for component [%s]. Please ensure that it
has a local interface.",
+ component));
+ }
+ }
- if (type == null)
- type = component.getBeanClass();
+ if (type == null)
+ {
+ type = component.getBeanClass();
+ }
- // Find the method according to the method name and the parameter classes
- Method m = findMethod(methodName, type);
- if (m == null)
- throw new RuntimeException("No compatible method found.");
+ // Find the method according to the method name and the parameter classes
+ Method m = findMethod(methodName, type);
+ if (m == null)
+ throw new RuntimeException("No compatible method found.");
- if (m.getAnnotation(WebRemote.class).exclude().length > 0)
- constraints = Arrays.asList(m.getAnnotation(WebRemote.class).exclude());
+ if (m.getAnnotation(WebRemote.class).exclude().length > 0)
+ constraints = Arrays
+ .asList(m.getAnnotation(WebRemote.class).exclude());
- // Invoke!
- result = m.invoke(instance, convertParams(m.getGenericParameterTypes()));
- }
+ Object[] params = convertParams(m.getGenericParameterTypes());
- /**
- * Convert our parameter values to an Object array of the specified target
- * types.
- *
- * @param targetTypes Class[] An array containing the target class types.
- * @return Object[] The converted parameter values.
- */
- private Object[] convertParams(Type[] targetTypes)
- throws ConversionException
- {
- Object[] paramValues = new Object[targetTypes.length];
+ // Invoke!
+ try
+ {
+ result = m.invoke(instance, params);
+ }
+ catch (InvocationTargetException e)
+ {
+ this.exception = e.getCause();
+ }
+ }
- for (int i = 0; i < targetTypes.length; i++)
- paramValues[i] = params.get(i).convert(targetTypes[i]);
+ /**
+ * Convert our parameter values to an Object array of the specified target
+ * types.
+ *
+ * @param targetTypes
+ * Class[] An array containing the target class types.
+ * @return Object[] The converted parameter values.
+ */
+ private Object[] convertParams(Type[] targetTypes)
+ throws ConversionException
+ {
+ Object[] paramValues = new Object[targetTypes.length];
- return paramValues;
- }
+ for (int i = 0; i < targetTypes.length; i++)
+ {
+ paramValues[i] = params.get(i).convert(targetTypes[i]);
+ }
- /**
- * Find the best matching method within the specified class according to
- * the parameter types that were provided to the Call.
- *
- * @param name String The name of the method.
- * @param cls Class The Class to search in.
- * @return Method The best matching method.
- */
- private Method findMethod(String name, Class cls)
- {
- Map<Method, Integer> candidates = new HashMap<Method, Integer> ();
+ return paramValues;
+ }
- for (Method m : cls.getDeclaredMethods()) {
- if (m.getAnnotation(WebRemote.class) == null)
- continue;
+ /**
+ * Find the best matching method within the specified class according to the
+ * parameter types that were provided to the Call.
+ *
+ * @param name
+ * String The name of the method.
+ * @param cls
+ * Class The Class to search in.
+ * @return Method The best matching method.
+ */
+ private Method findMethod(String name, Class cls)
+ {
+ Map<Method, Integer> candidates = new HashMap<Method, Integer>();
- if (name.equals(m.getName()) &&
- m.getParameterTypes().length == params.size()) {
- int score = 0;
+ for (Method m : cls.getDeclaredMethods())
+ {
+ if (m.getAnnotation(WebRemote.class) == null) continue;
- for (int i = 0; i < m.getParameterTypes().length; i++) {
- ConversionScore convScore =
params.get(i).conversionScore(m.getParameterTypes()[
- i]);
- if (convScore == ConversionScore.nomatch)
- continue;
- score += convScore.getScore();
- }
- candidates.put(m, score);
+ if (name.equals(m.getName())
+ && m.getParameterTypes().length == params.size())
+ {
+ int score = 0;
+
+ for (int i = 0; i < m.getParameterTypes().length; i++)
+ {
+ ConversionScore convScore = params.get(i).conversionScore(
+ m.getParameterTypes()[i]);
+ if (convScore == ConversionScore.nomatch)
+ continue;
+ score += convScore.getScore();
+ }
+ candidates.put(m, score);
+ }
}
- }
- Method bestMethod = null;
- int bestScore = 0;
+ Method bestMethod = null;
+ int bestScore = 0;
- for (Method m : candidates.keySet()) {
- int thisScore = candidates.get(m).intValue();
- if (bestMethod == null || thisScore > bestScore) {
- bestMethod = m;
- bestScore = thisScore;
+ for (Method m : candidates.keySet())
+ {
+ int thisScore = candidates.get(m).intValue();
+ if (bestMethod == null || thisScore > bestScore)
+ {
+ bestMethod = m;
+ bestScore = thisScore;
+ }
}
- }
- return bestMethod;
- }
+ return bestMethod;
+ }
}
Modified: trunk/src/remoting/org/jboss/seam/remoting/ExecutionHandler.java
===================================================================
--- trunk/src/remoting/org/jboss/seam/remoting/ExecutionHandler.java 2008-11-10 06:24:00
UTC (rev 9535)
+++ trunk/src/remoting/org/jboss/seam/remoting/ExecutionHandler.java 2008-11-10 09:54:23
UTC (rev 9536)
@@ -223,8 +223,7 @@
for (Call call : calls)
{
- MarshalUtils.marshalResult(call.getId(), call.getContext(), out,
- call.getResult(), call.getConstraints());
+ MarshalUtils.marshalResult(call, out);
}
out.write(BODY_TAG_CLOSE);
Modified: trunk/src/remoting/org/jboss/seam/remoting/InterfaceGenerator.java
===================================================================
--- trunk/src/remoting/org/jboss/seam/remoting/InterfaceGenerator.java 2008-11-10 06:24:00
UTC (rev 9535)
+++ trunk/src/remoting/org/jboss/seam/remoting/InterfaceGenerator.java 2008-11-10 09:54:23
UTC (rev 9536)
@@ -361,7 +361,7 @@
}
if (m.getGenericParameterTypes().length > 0) componentSrc.append(",
");
- componentSrc.append("callback) {\n");
+ componentSrc.append("callback, exceptionHandler) {\n");
componentSrc.append(" return Seam.Remoting.execute(this, \"");
componentSrc.append(m.getName());
@@ -374,7 +374,7 @@
componentSrc.append(i);
}
- componentSrc.append("], callback);\n");
+ componentSrc.append("], callback, exceptionHandler);\n");
componentSrc.append(" }\n");
}
Modified: trunk/src/remoting/org/jboss/seam/remoting/MarshalUtils.java
===================================================================
--- trunk/src/remoting/org/jboss/seam/remoting/MarshalUtils.java 2008-11-10 06:24:00 UTC
(rev 9535)
+++ trunk/src/remoting/org/jboss/seam/remoting/MarshalUtils.java 2008-11-10 09:54:23 UTC
(rev 9536)
@@ -20,46 +20,63 @@
private static final byte[] VALUE_TAG_OPEN = "<value>".getBytes();
private static final byte[] VALUE_TAG_CLOSE = "</value>".getBytes();
+
+ private static final byte[] EXCEPTION_TAG_OPEN =
"<exception>".getBytes();
+ private static final byte[] EXCEPTION_TAG_CLOSE =
"</exception>".getBytes();
+
+ private static final byte[] MESSAGE_TAG_OPEN = "<message>".getBytes();
+ private static final byte[] MESSAGE_TAG_CLOSE =
"</message>".getBytes();
- public static void marshalResult(String callId, CallContext ctx, OutputStream out,
- Object result, List<String> constraints)
+ public static void marshalResult(Call call, OutputStream out)
throws IOException
{
- if (callId != null)
+ if (call.getId() != null)
{
out.write(RESULT_TAG_OPEN_START);
- out.write(callId.getBytes());
+ out.write(call.getId().getBytes());
out.write(RESULT_TAG_OPEN_END);
}
else
out.write(RESULT_TAG_OPEN);
- out.write(VALUE_TAG_OPEN);
-
- ctx.createWrapperFromObject(result, "").marshal(out);
-
- out.write(VALUE_TAG_CLOSE);
-
- out.write(RequestHandler.REFS_TAG_OPEN);
-
- // Using a for-loop, because stuff can get added to outRefs as we recurse the object
graph
- for (int i = 0; i < ctx.getOutRefs().size(); i++)
+ if (call.getException() != null)
{
- Wrapper wrapper = ctx.getOutRefs().get(i);
-
- out.write(RequestHandler.REF_TAG_OPEN_START);
- out.write(Integer.toString(i).getBytes());
- out.write(RequestHandler.REF_TAG_OPEN_END);
-
- if (wrapper instanceof BeanWrapper && constraints != null)
- ((BeanWrapper) wrapper).serialize(out, constraints);
- else
- wrapper.serialize(out);
-
- out.write(RequestHandler.REF_TAG_CLOSE);
+ out.write(EXCEPTION_TAG_OPEN);
+ out.write(MESSAGE_TAG_OPEN);
+ call.getContext().createWrapperFromObject(call.getException().getMessage(),
"").marshal(out);
+ out.write(MESSAGE_TAG_CLOSE);
+ out.write(EXCEPTION_TAG_CLOSE);
}
-
- out.write(RequestHandler.REFS_TAG_CLOSE);
+ else
+ {
+ out.write(VALUE_TAG_OPEN);
+
+ call.getContext().createWrapperFromObject(call.getResult(),
"").marshal(out);
+
+ out.write(VALUE_TAG_CLOSE);
+
+ out.write(RequestHandler.REFS_TAG_OPEN);
+
+ // Using a for-loop, because stuff can get added to outRefs as we recurse the
object graph
+ for (int i = 0; i < call.getContext().getOutRefs().size(); i++)
+ {
+ Wrapper wrapper = call.getContext().getOutRefs().get(i);
+
+ out.write(RequestHandler.REF_TAG_OPEN_START);
+ out.write(Integer.toString(i).getBytes());
+ out.write(RequestHandler.REF_TAG_OPEN_END);
+
+ if (wrapper instanceof BeanWrapper && call.getConstraints() != null)
+ ((BeanWrapper) wrapper).serialize(out, call.getConstraints());
+ else
+ wrapper.serialize(out);
+
+ out.write(RequestHandler.REF_TAG_CLOSE);
+ }
+
+ out.write(RequestHandler.REFS_TAG_CLOSE);
+ }
+
out.write(RESULT_TAG_CLOSE);
}
}
Modified: trunk/src/remoting/org/jboss/seam/remoting/remote.js
===================================================================
--- trunk/src/remoting/org/jboss/seam/remoting/remote.js 2008-11-10 06:24:00 UTC (rev
9535)
+++ trunk/src/remoting/org/jboss/seam/remoting/remote.js 2008-11-10 09:54:23 UTC (rev
9536)
@@ -152,7 +152,8 @@
}
}
-Seam.Remoting.__Context = function() {
+Seam.Remoting.__Context = function()
+{
this.conversationId = null;
Seam.Remoting.__Context.prototype.setConversationId = function(conversationId)
@@ -166,6 +167,16 @@
}
}
+Seam.Remoting.Exception = function(msg)
+{
+ this.message = msg;
+
+ Seam.Remoting.Exception.prototype.getMessage = function()
+ {
+ return this.message;
+ }
+}
+
Seam.Remoting.context = new Seam.Remoting.__Context();
Seam.Remoting.getContext = function()
@@ -466,7 +477,7 @@
// call.asyncReq = Seam.Remoting.sendAjaxRequest(envelope, Seam.Remoting.PATH_EXECUTE,
Seam.Remoting.processResponse, false);
//}
-Seam.Remoting.createCall = function(component, methodName, params, callback)
+Seam.Remoting.createCall = function(component, methodName, params, callback,
exceptionHandler)
{
var callId = "" + Seam.Remoting.__callId++;
if (!callback)
@@ -506,7 +517,7 @@
data += "</call>";
- return {data: data, id: callId, callback: callback};
+ return {data: data, id: callId, callback: callback, exceptionHandler:
exceptionHandler};
}
Seam.Remoting.createHeader = function()
@@ -597,9 +608,9 @@
}
}
-Seam.Remoting.execute = function(component, methodName, params, callback)
+Seam.Remoting.execute = function(component, methodName, params, callback,
exceptionHandler)
{
- var call = Seam.Remoting.createCall(component, methodName, params, callback);
+ var call = Seam.Remoting.createCall(component, methodName, params, callback,
exceptionHandler);
if (Seam.Remoting.inBatch)
{
@@ -765,10 +776,11 @@
var call = Seam.Remoting.pendingCalls.get(callId);
Seam.Remoting.pendingCalls.remove(callId);
- if (call && call.callback)
+ if (call && (call.callback || call.exceptionHandler))
{
var valueNode = null;
var refsNode = null;
+ var exceptionNode = null;
var children = result.childNodes;
for (var i = 0; i < children.length; i++)
@@ -778,15 +790,35 @@
valueNode = children.item(i);
else if (tag == "refs")
refsNode = children.item(i);
+ else if (tag == "exception")
+ exceptionNode = children.item(i);
}
- var refs = new Array();
- if (refsNode)
- Seam.Remoting.unmarshalRefs(refsNode, refs);
-
- var value = Seam.Remoting.unmarshalValue(valueNode.firstChild, refs);
-
- call.callback(value, context, callId);
+ if (exceptionNode != null)
+ {
+ var msgNode = null;
+ var children = exceptionNode.childNodes;
+ for (var i = 0; i < children.length; i++)
+ {
+ var tag = children.item(i).tagName;
+ if (tag == "message")
+ msgNode = children.item(i);
+ }
+
+ var msg = Seam.Remoting.unmarshalValue(msgNode.firstChild);
+ var ex = new Seam.Remoting.Exception(msg);
+ call.exceptionHandler(ex);
+ }
+ else
+ {
+ var refs = new Array();
+ if (refsNode)
+ Seam.Remoting.unmarshalRefs(refsNode, refs);
+
+ var value = Seam.Remoting.unmarshalValue(valueNode.firstChild, refs);
+
+ call.callback(value, context, callId);
+ }
}
}