Title: [waffle-scm] [622] trunk: WAFFLE-70: Action method invocation exceptions now handled via ErrorsContext.

Diff

Modified: trunk/.classpath (621 => 622)

--- trunk/.classpath	2008-04-18 12:56:43 UTC (rev 621)
+++ trunk/.classpath	2008-04-18 14:14:23 UTC (rev 622)
@@ -35,6 +35,13 @@
             <attribute name="maven.type" value="test"/>
         </attributes>
     </classpathentry>
+    <classpathentry kind="src" output="target-eclipse/classes" path="examples/simple-example/src/main/java"/>
+    <classpathentry kind="src" output="target-eclipse/classes" path="examples/simple-example/src/main/webapp"/>
+    <classpathentry kind="src" output="target-eclipse/test-classes" path="examples/simple-example/src/test/java">
+        <attributes>
+            <attribute name="maven.type" value="test"/>
+        </attributes>
+    </classpathentry>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
 	<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER/modules/profiles[examples,integration]"/>
 	<classpathentry kind="output" path="target-eclipse/classes"/>

Modified: trunk/examples/simple-example/src/main/java/org/codehaus/waffle/example/simple/action/PersonController.java (621 => 622)

--- trunk/examples/simple-example/src/main/java/org/codehaus/waffle/example/simple/action/PersonController.java	2008-04-18 12:56:43 UTC (rev 621)
+++ trunk/examples/simple-example/src/main/java/org/codehaus/waffle/example/simple/action/PersonController.java	2008-04-18 14:14:23 UTC (rev 622)
@@ -37,6 +37,10 @@
         person = null;
     }
 
+    public void fail(){
+        throw new RuntimeException("I'm a failing method");
+    }
+    
     public Person getPerson() {
         return person;
     }
@@ -44,5 +48,5 @@
     public void setPerson(Person person) {
         this.person = person;
     }
-
+    
 }

Modified: trunk/examples/simple-example/src/main/webapp/person.jspx (621 => 622)

--- trunk/examples/simple-example/src/main/webapp/person.jspx	2008-04-18 12:56:43 UTC (rev 621)
+++ trunk/examples/simple-example/src/main/webapp/person.jspx	2008-04-18 14:14:23 UTC (rev 622)
@@ -27,6 +27,16 @@
 
     <h3>Waffle example: Select Person</h3>
 
+    <c:if test="${errors.errorMessageCount > 0}">
+        <div class="errors">
+            <c:forEach var="error" items="${errors.allErrorMessages}">
+                <div class="error">
+                    ${error.message}
+                </div>
+            </c:forEach>
+        </div>
+    </c:if>
+    
     <table>
         <tr>
             <th>Id</th>
@@ -48,7 +58,8 @@
         </c:forEach>
     </table>
 
-    <a href=""
+    <a href="" or 
+    <a href="" to see a failing call</a>
 
     <!-- Example of partial page -->
     <div id="editArea">

Modified: trunk/waffle-core/src/main/java/org/codehaus/waffle/monitor/AbstractWritingMonitor.java (621 => 622)

--- trunk/waffle-core/src/main/java/org/codehaus/waffle/monitor/AbstractWritingMonitor.java	2008-04-18 12:56:43 UTC (rev 621)
+++ trunk/waffle-core/src/main/java/org/codehaus/waffle/monitor/AbstractWritingMonitor.java	2008-04-18 14:14:23 UTC (rev 622)
@@ -91,7 +91,7 @@
         levels.put("componentRegistered", DEBUG);
         levels.put("instanceRegistered", DEBUG);
         levels.put("nonCachingComponentRegistered", DEBUG);
-        levels.put("servletServiceFailed", WARN);
+        levels.put("actionMethodInvocationFailed", WARN);
         levels.put("servletServiceRequested", DEBUG);
         levels.put("controllerValidatorNotFound", WARN);
         levels.put("methodDefinitionNotFound", WARN);        
@@ -144,7 +144,7 @@
         messages.put("componentRegistered", "Registered component of type ''{1}'' with key ''{0}'' and parameters ''{2}''");
         messages.put("instanceRegistered", "Registered instance ''{1}'' with key ''{0}''");
         messages.put("nonCachingComponentRegistered", "Registered non-caching component of type ''{1}'' with key ''{0}'' and parameters ''{2}''");
-        messages.put("servletServiceFailed", "Servlet service failed: {0}");
+        messages.put("actionMethodInvocationFailed", "ActionMethod invocation failed: {0}");
         messages.put("servletServiceRequested", "Servlet service requested with parameters: {0}");
         messages.put("controllerValidatorNotFound", "Controller validator ''{0}'' not found: defaulting to controller ''{1}''");
         messages.put("methodDefinitionNotFound", "Method definition not found in controller definition ''{0}''");        
@@ -323,8 +323,8 @@
         write("nonCachingComponentRegistered", key, type, asList(parameters));
     }
 
-    public void servletServiceFailed(Exception cause){
-        write("servletServiceFailed", cause);        
+    public void actionMethodInvocationFailed(Exception cause){
+        write("actionMethodInvocationFailed", cause);        
     }
     
     public void servletServiceRequested(Map<String, List<String>> parameters){

Modified: trunk/waffle-core/src/main/java/org/codehaus/waffle/monitor/ServletMonitor.java (621 => 622)

--- trunk/waffle-core/src/main/java/org/codehaus/waffle/monitor/ServletMonitor.java	2008-04-18 12:56:43 UTC (rev 621)
+++ trunk/waffle-core/src/main/java/org/codehaus/waffle/monitor/ServletMonitor.java	2008-04-18 14:14:23 UTC (rev 622)
@@ -21,7 +21,7 @@
  */
 public interface ServletMonitor extends Monitor {
 
-    void servletServiceFailed(Exception cause);
+    void actionMethodInvocationFailed(Exception cause);
     
     void servletServiceRequested(Map<String, List<String>> parameters);
 

Modified: trunk/waffle-core/src/main/java/org/codehaus/waffle/servlet/WaffleServlet.java (621 => 622)

--- trunk/waffle-core/src/main/java/org/codehaus/waffle/servlet/WaffleServlet.java	2008-04-18 12:56:43 UTC (rev 621)
+++ trunk/waffle-core/src/main/java/org/codehaus/waffle/servlet/WaffleServlet.java	2008-04-18 14:14:23 UTC (rev 622)
@@ -41,6 +41,7 @@
 import org.codehaus.waffle.controller.ControllerDefinitionFactory;
 import org.codehaus.waffle.monitor.ServletMonitor;
 import org.codehaus.waffle.validation.ErrorsContext;
+import org.codehaus.waffle.validation.GlobalErrorMessage;
 import org.codehaus.waffle.validation.Validator;
 import org.codehaus.waffle.view.RedirectView;
 import org.codehaus.waffle.view.View;
@@ -57,7 +58,6 @@
     private static final String DEFAULT_VIEW_SUFFIX = ".jspx";
     private static final String DEFAULT_VIEW_PREFIX = "/";
     private static final String EMPTY = "";
-    private static final String ERROR = "ERROR: ";
     private static final String POST = "POST";
     private ActionMethodExecutor actionMethodExecutor;
     private ActionMethodResponseHandler actionMethodResponseHandler;
@@ -169,12 +169,12 @@
         dataBinder.bind(request, response, errorsContext, controllerDefinition.getController());
         validator.validate(controllerDefinition, errorsContext);
 
+        ActionMethodResponse actionMethodResponse = new ActionMethodResponse();
+        View view = null;
+        
         try {
-            ActionMethodResponse actionMethodResponse = new ActionMethodResponse();
-            MethodDefinition methodDefinition = controllerDefinition.getMethodDefinition();
-            View view = null;
 
-            if (errorsContext.hasErrorMessages() || methodDefinition == null) {
+            if (errorsContext.hasErrorMessages() || noMethodDefinition(controllerDefinition)) {
                 view = buildReferringView(controllerDefinition);
             } else {
                 actionMethodExecutor.execute(actionMethodResponse, controllerDefinition);
@@ -185,7 +185,7 @@
                     // Null or VOID indicate a Waffle convention (return to referring page)
                     // unless PRG is disabled 
                     if (request.getMethod().equalsIgnoreCase(POST)) {
-                        if ( usePRG(methodDefinition) ){
+                        if ( usePRG(controllerDefinition.getMethodDefinition()) ){
                             // PRG (Post/Redirect/Get): see http://en.wikipedia.org/wiki/Post/Redirect/Get
                             view = buildRedirectingView(request, controllerDefinition);                            
                         } else {
@@ -198,20 +198,25 @@
                 }
             }
 
-            if (view != null) {
-                actionMethodResponse.setReturnValue(view);
-            }
+        } catch (ActionMethodInvocationException e) {
+            errorsContext.addErrorMessage(new GlobalErrorMessage("Action method invocation failed: "+e.getMessage(), e));
+            view = buildReferringView(controllerDefinition);
+            servletMonitor.actionMethodInvocationFailed(e);
+        }
+        
+        if (view != null) {
+            actionMethodResponse.setReturnValue(view);
+        }
 
-            requestAttributeBinder.bind(request, controllerDefinition.getController());
-            actionMethodResponseHandler.handle(request, response, actionMethodResponse);
+        requestAttributeBinder.bind(request, controllerDefinition.getController());
+        actionMethodResponseHandler.handle(request, response, actionMethodResponse);
 
-        } catch (ActionMethodInvocationException e) {
-            servletMonitor.servletServiceFailed(e);
-            log(ERROR + e.getMessage());
-            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
-        }
     }
 
+    private boolean noMethodDefinition(ControllerDefinition controllerDefinition) {
+        return controllerDefinition.getMethodDefinition() == null;
+    }
+
     @SuppressWarnings("unchecked")
     private Map<String, List<String>> parametersOf(HttpServletRequest request) {
         Map<String, List<String>> parameters = new HashMap<String, List<String>>();

Modified: trunk/waffle-core/src/main/java/org/codehaus/waffle/validation/GlobalErrorMessage.java (621 => 622)

--- trunk/waffle-core/src/main/java/org/codehaus/waffle/validation/GlobalErrorMessage.java	2008-04-18 12:56:43 UTC (rev 621)
+++ trunk/waffle-core/src/main/java/org/codehaus/waffle/validation/GlobalErrorMessage.java	2008-04-18 14:14:23 UTC (rev 622)
@@ -10,6 +10,7 @@
  *****************************************************************************/
 package org.codehaus.waffle.validation;
 
+
 /**
  * ErrorMessage associated to global validations.
  *
@@ -17,9 +18,15 @@
  */
 public class GlobalErrorMessage implements ErrorMessage {
     private String message;
+    private Throwable cause;
 
     public GlobalErrorMessage(String message) {
+        this(message, null);
+    }
+
+    public GlobalErrorMessage(String message, Throwable cause) {
         this.message = message;
+        this.cause = cause;
     }
 
     public Type getType() {
@@ -29,5 +36,9 @@
     public String getMessage() {
         return message;
     }
+    
+    public Throwable getCause(){
+        return cause;
+    }
 
 }

Modified: trunk/waffle-core/src/test/java/org/codehaus/waffle/servlet/WaffleServletTest.java (621 => 622)

--- trunk/waffle-core/src/test/java/org/codehaus/waffle/servlet/WaffleServletTest.java	2008-04-18 12:56:43 UTC (rev 621)
+++ trunk/waffle-core/src/test/java/org/codehaus/waffle/servlet/WaffleServletTest.java	2008-04-18 14:14:23 UTC (rev 622)
@@ -49,6 +49,7 @@
 import org.codehaus.waffle.i18n.MessagesContext;
 import org.codehaus.waffle.monitor.ServletMonitor;
 import org.codehaus.waffle.monitor.SilentMonitor;
+import org.codehaus.waffle.validation.ErrorMessage;
 import org.codehaus.waffle.validation.ErrorsContext;
 import org.codehaus.waffle.validation.Validator;
 import org.codehaus.waffle.view.View;
@@ -390,7 +391,7 @@
             one(validator).validate(with(any(ControllerDefinition.class)), with(any(ErrorsContext.class)));
         }});
 
-        // Mock
+        // Mock RequestAttributeBinder
         final RequestAttributeBinder requestAttributeBinder = mockery.mock(RequestAttributeBinder.class);
         mockery.checking(new Expectations() {{
             one(requestAttributeBinder).bind(with(same(request)), with(any(NonDispatchingController.class)));
@@ -422,7 +423,7 @@
 
     @SuppressWarnings({"serial", "unchecked"})
     @Test
-    public void canThrowExceptionInMethodInvocation() throws Exception {
+    public void canHandleExceptionsInMethodInvocation() throws Exception {
         // Mock ErrorsContext
         final ErrorsContext errorsContext = mockery.mock(ErrorsContext.class);
         final ContextContainer contextContainer = mockery.mock(ContextContainer.class);
@@ -432,6 +433,7 @@
                 will(returnValue(errorsContext));
                 one(errorsContext).hasErrorMessages();
                 will(returnValue(false));
+                one(errorsContext).addErrorMessage(with(any(ErrorMessage.class)));
             }
         });
 
@@ -450,23 +452,47 @@
             atLeast(1).of(request).getParameterNames();
             will(returnValue(enumeration));
         }});
-
+        
         // Mock HttpServletResponse
         final HttpServletResponse response = mockery.mock(HttpServletResponse.class);
+
+        // MethodDefinition
+        Method method = NonDispatchingController.class.getMethod("increment");
+        final MethodDefinition methodDefinition = new MethodDefinition(method);
+        
+        // Mock ActionMethodResponseHandler
+        final ActionMethodResponseHandler actionMethodResponseHandler = mockery.mock(ActionMethodResponseHandler.class);
         mockery.checking(new Expectations() {{
-            one(response).sendError(with(equal(HttpServletResponse.SC_INTERNAL_SERVER_ERROR)), with(any(String.class)));
+            one(actionMethodResponseHandler).handle(with(same(request)), with(same(response)), with(any(ActionMethodResponse.class)));
         }});
 
+        // Mock Validator
+        final Validator validator = mockery.mock(Validator.class);
+        mockery.checking(new Expectations() {{
+            allowing(validator).validate(with(any(ControllerDefinition.class)), with(any(ErrorsContext.class)));
+        }});
+
+        // Mock RequestAttributeBinder
+        final RequestAttributeBinder requestAttributeBinder = mockery.mock(RequestAttributeBinder.class);
+        mockery.checking(new Expectations() {{
+            one(requestAttributeBinder).bind(with(same(request)), with(any(NonDispatchingController.class)));
+        }});
+        
         // stub out what we don't want called ... execute it
-        WaffleServlet servlet = new WaffleServlet() {
+        WaffleServlet servlet = new WaffleServlet(null,
+                actionMethodResponseHandler,
+                new SilentMonitor(),
+                new OgnlDataBinder(new OgnlValueConverterFinder(), null, new SilentMonitor()),
+                requestAttributeBinder,
+                null, validator) {
             @Override
             protected ControllerDefinition getControllerDefinition(HttpServletRequest request, HttpServletResponse response) {
-                return new ControllerDefinition("no name", nonDispatchingController, new MethodDefinition(null));
-            }            
+                return new ControllerDefinition("no name", nonDispatchingController, methodDefinition);
+            }
             @Override
             public ServletConfig getServletConfig() {
                 return servletConfig;
-            }
+            }            
             @Override
             public void log(String string) {
                 // ignore
@@ -485,15 +511,9 @@
         final ServletMonitor servletMonitor = mockery.mock(ServletMonitor.class);
         mockery.checking(new Expectations() {{
             allowing(servletMonitor).servletServiceRequested(with(any(Map.class)));
-            allowing(servletMonitor).servletServiceFailed(actionMethodInvocationException);
+            allowing(servletMonitor).actionMethodInvocationFailed(actionMethodInvocationException);
         }});
 
-        // Mock Validator
-        final Validator validator = mockery.mock(Validator.class);
-        mockery.checking(new Expectations() {{
-            one(validator).validate(with(any(ControllerDefinition.class)), with(any(ErrorsContext.class)));
-        }});
-
         // Set up what normally would happen via "init()"
         Field dataBinderField = WaffleServlet.class.getDeclaredField("dataBinder");
         dataBinderField.setAccessible(true);
@@ -507,10 +527,6 @@
         servletMonitorField.setAccessible(true);
         servletMonitorField.set(servlet, servletMonitor);
 
-        Field validatorFactoryField = WaffleServlet.class.getDeclaredField("validator");
-        validatorFactoryField.setAccessible(true);
-        validatorFactoryField.set(servlet, validator);
-
         servlet.service(request, response);
     }
 

Modified: trunk/waffle-core/src/test/java/org/codehaus/waffle/testmodel/StubMonitor.java (621 => 622)

--- trunk/waffle-core/src/test/java/org/codehaus/waffle/testmodel/StubMonitor.java	2008-04-18 12:56:43 UTC (rev 621)
+++ trunk/waffle-core/src/test/java/org/codehaus/waffle/testmodel/StubMonitor.java	2008-04-18 14:14:23 UTC (rev 622)
@@ -119,7 +119,7 @@
     public void nonCachingComponentRegistered(Object key, Class<?> clazz, Object[] parameters) {
     }
 
-    public void servletServiceFailed(Exception cause) {
+    public void actionMethodInvocationFailed(Exception cause) {
     }
     
     public void servletServiceRequested(Map<String, List<String>> parameters) {


To unsubscribe from this list please visit:

http://xircles.codehaus.org/manage_email

Reply via email to