Title: Message
I'll take a look at the changes tonight... sounds like it's minor with no changes visible to the user.
-----Original Message-----
From: John Patterson [mailto:[EMAIL PROTECTED]
Sent: Tuesday, November 18, 2003 11:30 AM
To: [EMAIL PROTECTED]
Subject: Re: [OS-webwork] ExceptionHandlerIntercepter

If the request has not been committed then the ServletDispatcher is clever enough to do a dispatcher.forward() instead of a dispatcher.include().  Therefore any uncommitted content in the buffer is cleared.  However, if the response is already committed then there is no way to handle an exception gracefully.
 
If you want to make sure errors are handled gracefully then you must set a reasonably large response buffer size.  The WW2 IncludeTag also buffers all content, no matter how large, so if you use this then your error pages should be displayed OK (at the expense of higher memory use).
 
As an aside, I use a customised IncludeTag that does not buffer the contents but I will replace this with the ActionTag now that it supports executing a result.
 
My HandleExceptionAction detects if the response has been committed and if so it merely writes "There has been an error while executing the action" using the JspWriter (or the response writer if there is no page context).  It will then return NONE to indicate that no Result is to be executed.
 
However, the normal case is where the response has not been committed and a nice error page specific to the section of the site where the error occurred is shown to the user.
 
I have tested this with both a committed response and a non-committed response and it works fine.
 
John.
 
----- Original Message -----
Sent: Tuesday, November 18, 2003 3:58 PM
Subject: RE: [OS-webwork] ExceptionHandlerIntercepter

How does this handle the issue of content having been written out by the first result? Would you end up with part of the first page, then the error page?
-----Original Message-----
From: John Patterson [mailto:[EMAIL PROTECTED]
Sent: Tuesday, November 18, 2003 10:21 AM
To: Webwork
Subject: [OS-webwork] ExceptionHandlerIntercepter

I just discovered a problem with my ExceptionHandlerInterceptor due to the design of the DefaultActionInvocation class.  I have made some changes to this class which fix the problem and would like to run them past everybody.
 
The ExceptionHandlerInterceptor catches any exceptions that occur during the invoking of the action (and result) and shows the ERROR result instead.  During previous discussions on this list, no alternative approaches were suggested that would allow for:
 
    1 - Catch exceptions occurring in the Action AND Result
    2 - Enable specific error pages to be defined for each package or action
    3 - Use action definitions defined in the xwork.xml (eg ERROR)
    4 - Retain the offending Action on the stack so it can be examined in an error page.
 
Strangely enough, it appeared to be working fine before (but for the wrong reasons).
 
The problem is this: if an exception occurs while processing an Action then the interceptor can return ERROR and the error Result is executed.  However, if an exception occurs while processing the Result and the interceptor returns ERROR, the error Result is NOT executed.  In fact the original result is executed again (which will probably cause the exception again).
 
This is because once a Result has been instantiated it is retained and reused no matter what resultCode is returned from the interceptor.  executeResult() calls getResult() which returns the Result stored in an instance variable.  It seems that the only reason for this is so that other objects can get the result after it has executed.
 
Some may say "Exceptions that happen while executing the result should just be rethrown".  But then how are we to implement the error handling requirements above?
 
Anyway, the changes I made to DefaultActionInvocation are VERY simple and fix the problem by splitting getResult() into two methods (createResult() and getResult()).  executeResult() now calls createResult() instead of recycling the old result.
 
It all seems to work OK and allows an interceptor to return a result code which will not be ignored unless the result has already executed (executed = true)
 
 
 
Index: DefaultActionInvocation.java
===================================================================
RCS file: /cvs/xwork/src/java/com/opensymphony/xwork/DefaultActionInvocation.java,v
retrieving revision 1.10
diff -u -r1.10 DefaultActionInvocation.java
--- DefaultActionInvocation.java 15 Nov 2003 05:50:15 -0000 1.10
+++ DefaultActionInvocation.java 18 Nov 2003 15:18:34 -0000
@@ -93,49 +93,50 @@
 * @throws Exception
 */
     public Result getResult() throws Exception {
-        if (result != null) {
-            Result returnResult = result;
-
-            // If we've chained to other Actions, we need to find the last result
-            while (returnResult instanceof ActionChainResult) {
-                ActionProxy aProxy = ((ActionChainResult) returnResult).getProxy();
-
-                if (aProxy != null) {
-                    Result proxyResult = aProxy.getInvocation().getResult();
-
-                    if ((proxyResult != null) && (aProxy.getExecuteResult())) {
-                        returnResult = proxyResult;
-                    } else {
-                        break;
-                    }
-                } else {
-                    break;
-                }
-            }
-
-            return returnResult;
-        } else {
-            Map results = proxy.getConfig().getResults();
-            ResultConfig resultConfig = (ResultConfig) results.get(resultCode);
-
-            if (resultConfig != null) {
-                Class resultClass = resultConfig.getClazz();
+     Result returnResult = result;

+     // If we've chained to other Actions, we need to find the last result
+     while (returnResult instanceof ActionChainResult) {
+         ActionProxy aProxy = ((ActionChainResult) returnResult).getProxy();

+         if (aProxy != null) {
+             Result proxyResult = aProxy.getInvocation().getResult();

+             if ((proxyResult != null) && (aProxy.getExecuteResult())) {
+                 returnResult = proxyResult;
+             } else {
+                 break;
+             }
+         } else {
+             break;
+         }
+     }

+     return returnResult;
+    }
+   
+    public Result createResult() throws Exception {
+    Map results = proxy.getConfig().getResults();
+    ResultConfig resultConfig = (ResultConfig) results.get(resultCode);
+    Result newResult = null;
+   
+    if (resultConfig != null) {
+      Class resultClass = resultConfig.getClazz();
+
+      if (resultClass != null) {
+        try {
+          newResult = (Result) resultClass.newInstance();
+        } catch (Exception e) {
+          LOG.error("There was an exception while instantiating the result of type " + resultClass, e);
+          throw e;
+        }
+
+        OgnlUtil.setProperties(resultConfig.getParams(), newResult, ActionContext.getContext().getContextMap());
+      }
+    }
 
-                if (resultClass != null) {
-                    try {
-                        result = (Result) resultClass.newInstance();
-                    } catch (Exception e) {
-                        LOG.error("There was an exception while instantiating the result of type " + resultClass, e);
-                        throw e;
-                    }
-
-                    OgnlUtil.setProperties(resultConfig.getParams(), result, ActionContext.getContext().getContextMap());
-                }
-            }
-
-            return result;
-        }
-    }
+    return newResult;
+  }
 
     public String getResultCode() {
         return resultCode;
@@ -260,13 +261,13 @@
     }
 
     /**
-* Uses getResult to get the final Result and executes it
+* Creates a new Result from the resultCode and executes it
 */
     private void executeResult() throws Exception {
-        Result aResult = getResult();
+        result = createResult();
 
-        if (aResult != null) {
-            aResult.execute(this);
+        if (result != null) {
+            result.execute(this);
         } else {
             LOG.warn("No result defined for action " + getAction().getClass().getName() + " and result " + getResultCode());
         }

Reply via email to