You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shale.apache.org by gv...@apache.org on 2006/11/20 05:17:41 UTC

svn commit: r477032 - in /shale/framework/trunk: shale-apps/shale-test-view/src/main/java/org/apache/shale/examples/test/view/ shale-apps/shale-test-view/src/main/webapp/ shale-apps/shale-test-view/src/main/webapp/WEB-INF/ shale-view/src/main/java/org/...

Author: gvanmatre
Date: Sun Nov 19 20:17:39 2006
New Revision: 477032

URL: http://svn.apache.org/viewvc?view=rev&rev=477032
Log:
This patch is an attempt to catch exceptions raised in JSF phases allowing the shale view controller to handle them (SHALE-336).  The key extension point is subclassing the UIViewRoot and overriding the methods invoked by the lifecycle.  The overrides catch unchecked exceptions and queue them up to be processed by a global error page.

I've extended the shale-test-view to demonstrate the added exception traps.

Added:
    shale/framework/trunk/shale-apps/shale-test-view/src/main/java/org/apache/shale/examples/test/view/Error.java   (with props)
    shale/framework/trunk/shale-apps/shale-test-view/src/main/java/org/apache/shale/examples/test/view/RaiseException.java   (with props)
    shale/framework/trunk/shale-apps/shale-test-view/src/main/webapp/error.jsp   (with props)
    shale/framework/trunk/shale-apps/shale-test-view/src/main/webapp/raiseException.jsp   (with props)
    shale/framework/trunk/shale-view/src/main/java/org/apache/shale/view/faces/ShaleViewRoot.java
Modified:
    shale/framework/trunk/shale-apps/shale-test-view/src/main/webapp/WEB-INF/faces-config.xml
    shale/framework/trunk/shale-apps/shale-test-view/src/main/webapp/WEB-INF/web.xml
    shale/framework/trunk/shale-apps/shale-test-view/src/main/webapp/menu.jsp
    shale/framework/trunk/shale-view/src/main/java/org/apache/shale/view/faces/ViewPhaseListener.java
    shale/framework/trunk/shale-view/src/main/resources/META-INF/faces-config.xml

Added: shale/framework/trunk/shale-apps/shale-test-view/src/main/java/org/apache/shale/examples/test/view/Error.java
URL: http://svn.apache.org/viewvc/shale/framework/trunk/shale-apps/shale-test-view/src/main/java/org/apache/shale/examples/test/view/Error.java?view=auto&rev=477032
==============================================================================
--- shale/framework/trunk/shale-apps/shale-test-view/src/main/java/org/apache/shale/examples/test/view/Error.java (added)
+++ shale/framework/trunk/shale-apps/shale-test-view/src/main/java/org/apache/shale/examples/test/view/Error.java Sun Nov 19 20:17:39 2006
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.shale.examples.test.view;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.FacesContext;
+
+import org.apache.shale.view.AbstractViewController;
+import org.apache.shale.view.faces.FacesConstants;
+
+public class Error extends AbstractViewController {
+
+    private String httpErrorCode = null;
+
+    private String exceptionType = null;
+
+    private String message = null;
+
+    private String requestUri = null;
+
+    private String servletName = null;
+    
+    private Recorder recorder = null;
+
+    public void prerender() {
+        System.out.println("Error - Removing exceptions stack");
+
+        Map requestMap = getRequestMap();
+        
+        Exception exception = (Exception) requestMap
+                .get("javax.servlet.error.exception");
+
+        FacesContext facesContext = getFacesContext();
+        if (facesContext == null) return;
+        
+        UIViewRoot root = facesContext.getViewRoot();
+        if (root == null) return;
+        
+        List exceptions = (List) requestMap.get(FacesConstants.EXCEPTIONS_LIST);
+        if (exception != null && exceptions != null) {
+            // save on the view root
+            getFacesContext().getViewRoot().getAttributes().put("errors", exceptions);
+            requestMap.remove(FacesConstants.EXCEPTIONS_LIST);
+
+            
+            Integer errorCode = (Integer) requestMap.get("javax.servlet.error.status_code");
+            if (errorCode != null) {
+            setHttpErrorCode(errorCode.toString());
+            }
+            
+            Object clazz = requestMap.get("javax.servlet.error.exception_type");
+            if (clazz != null) {
+               setExceptionType(clazz.toString());
+            }
+            setMessage((String) requestMap.get("javax.servlet.error.message"));
+            setRequestUri((String) requestMap
+                    .get("javax.servlet.error.request_uri"));
+            setServletName((String) requestMap
+                    .get("javax.servlet.error.servlet_name"));
+
+            setRecorder((Recorder) getBean("recorder"));
+        }
+        
+    }
+
+    public String getExceptionType() {
+        return exceptionType;
+    }
+
+    public void setExceptionType(String exceptionType) {
+        this.exceptionType = exceptionType;
+    }
+
+    public String getHttpErrorCode() {
+        return httpErrorCode;
+    }
+
+    public void setHttpErrorCode(String httpErrorCode) {
+        this.httpErrorCode = httpErrorCode;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    public String getRequestUri() {
+        return requestUri;
+    }
+
+    public void setRequestUri(String requestUri) {
+        this.requestUri = requestUri;
+    }
+
+    public String getServletName() {
+        return servletName;
+    }
+
+    public void setServletName(String servletName) {
+        this.servletName = servletName;
+    }
+
+    public Recorder getRecorder() {
+        return recorder;
+    }
+
+    public void setRecorder(Recorder recorder) {
+        this.recorder = recorder;
+    }
+    
+    public String getStackTrace() {
+       StringBuffer buff = new StringBuffer();
+       Exception e = (Exception) getBean("e");
+       for (int i = 0; i < e.getStackTrace().length; i++) {
+          buff.append(e.getStackTrace()[i].toString())
+              .append("\n");
+       }
+       return buff.toString();
+    }
+}

Propchange: shale/framework/trunk/shale-apps/shale-test-view/src/main/java/org/apache/shale/examples/test/view/Error.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: shale/framework/trunk/shale-apps/shale-test-view/src/main/java/org/apache/shale/examples/test/view/Error.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: shale/framework/trunk/shale-apps/shale-test-view/src/main/java/org/apache/shale/examples/test/view/RaiseException.java
URL: http://svn.apache.org/viewvc/shale/framework/trunk/shale-apps/shale-test-view/src/main/java/org/apache/shale/examples/test/view/RaiseException.java?view=auto&rev=477032
==============================================================================
--- shale/framework/trunk/shale-apps/shale-test-view/src/main/java/org/apache/shale/examples/test/view/RaiseException.java (added)
+++ shale/framework/trunk/shale-apps/shale-test-view/src/main/java/org/apache/shale/examples/test/view/RaiseException.java Sun Nov 19 20:17:39 2006
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Id$
+ */
+
+package org.apache.shale.examples.test.view;
+
+import javax.faces.event.ActionEvent;
+import javax.faces.event.ValueChangeEvent;
+
+import org.apache.shale.view.AbstractViewController;
+
+/**
+ * <p>Tests for handling exceptions.</p>
+ */
+public class RaiseException extends AbstractViewController {
+    
+
+    // -------------------------------------------------------------- Properties
+
+
+    // The "Recorder" object for this request
+    private Recorder recorder = null;
+    public Recorder getRecorder() {
+        return this.recorder;
+    }
+    public void setRecorder(Recorder recorder) {
+        this.recorder = recorder;
+    }
+
+
+    // ------------------------------------------------------- Lifecycle Methods
+
+
+    /**
+     * <p>Record an init event.</p>
+     */
+    public void init() {
+        getRecorder().record("init");
+        System.out.println("RaiseException.init()");
+    }
+
+
+    /**
+     * <p>Record a preprocess event.</p>
+     */
+    public void preprocess() {
+        getRecorder().record("preprocess");
+        System.out.println("RaiseException.preprocess()");
+    }
+
+
+    /**
+     * <p>Record a prerender event.</p>
+     */
+    public void prerender() {
+        getRecorder().record("prerender");
+        System.out.println("RaiseException.prerender()");
+    }
+
+
+    /**
+     * <p>Record a destroy event.</p>
+     */
+    public void destroy() {
+        getRecorder().record("destroy");
+        System.out.println("RaiseException.destroy()");
+    }
+
+    /**
+     * <p>Raises an unchecked exception from an action callback.</p>
+     *
+     * @return null
+     */
+    public String throwActionException() {
+        getRecorder().record("throwActionException");     
+        System.out.println("RaiseException.throwActionException()");
+        throw new NullPointerException("throwActionException");
+    }
+
+    /**
+     * <p>Raises an unchecked exception from an action listener
+     * binding event.</p>
+     *
+     * @param event action event
+     */
+    public void throwActionListenerException(ActionEvent event) {
+        getRecorder().record("throwActionListenerException");
+        System.out.println("RaiseException.throwActionListenerException(ActionEvent)");
+        throw new NullPointerException("throwActionListenerException");
+    }
+
+    /**
+     * <p>Raises an unchecked exception from a value change listener
+     * callback.</p>
+     *
+     * @param event value change listener event
+     */
+    public void throwValueChangeListenerException(ValueChangeEvent event) {
+        getRecorder().record("throwValueChangeListenerException");
+        System.out.println("RaiseException.throwValueChangeListenerException(ValueChangeEvent)");
+        throw new NullPointerException("throwValueChangeListenerException");
+        
+    }
+
+}

Propchange: shale/framework/trunk/shale-apps/shale-test-view/src/main/java/org/apache/shale/examples/test/view/RaiseException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: shale/framework/trunk/shale-apps/shale-test-view/src/main/java/org/apache/shale/examples/test/view/RaiseException.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Modified: shale/framework/trunk/shale-apps/shale-test-view/src/main/webapp/WEB-INF/faces-config.xml
URL: http://svn.apache.org/viewvc/shale/framework/trunk/shale-apps/shale-test-view/src/main/webapp/WEB-INF/faces-config.xml?view=diff&rev=477032&r1=477031&r2=477032
==============================================================================
--- shale/framework/trunk/shale-apps/shale-test-view/src/main/webapp/WEB-INF/faces-config.xml (original)
+++ shale/framework/trunk/shale-apps/shale-test-view/src/main/webapp/WEB-INF/faces-config.xml Sun Nov 19 20:17:39 2006
@@ -47,6 +47,11 @@
             <from-outcome>status</from-outcome>
             <to-view-id>/status.jsp</to-view-id>
         </navigation-case>
+        <navigation-case>
+            <from-outcome>raiseException</from-outcome>
+            <to-view-id>/raiseException.jsp</to-view-id>
+        </navigation-case>
+
     </navigation-rule>
 
     <!-- ========== View Controller Beans ========== -->
@@ -81,6 +86,27 @@
             org.apache.shale.examples.test.view.Standard
         </managed-bean-class>
         <managed-bean-scope>request</managed-bean-scope>
+    </managed-bean>
+
+    <managed-bean>
+        <managed-bean-name>error</managed-bean-name>
+        <managed-bean-class>
+            org.apache.shale.examples.test.view.Error
+        </managed-bean-class>
+        <managed-bean-scope>request</managed-bean-scope>        
+    </managed-bean>
+
+    <managed-bean>
+        <managed-bean-name>raiseException</managed-bean-name>
+        <managed-bean-class>
+            org.apache.shale.examples.test.view.RaiseException
+        </managed-bean-class>
+        <managed-bean-scope>request</managed-bean-scope>
+        <managed-property>
+            <property-name>recorder</property-name>
+            <value>#{recorder}</value>
+        </managed-property>
+        
     </managed-bean>
 
     <managed-bean>

Modified: shale/framework/trunk/shale-apps/shale-test-view/src/main/webapp/WEB-INF/web.xml
URL: http://svn.apache.org/viewvc/shale/framework/trunk/shale-apps/shale-test-view/src/main/webapp/WEB-INF/web.xml?view=diff&rev=477032&r1=477031&r2=477032
==============================================================================
--- shale/framework/trunk/shale-apps/shale-test-view/src/main/webapp/WEB-INF/web.xml (original)
+++ shale/framework/trunk/shale-apps/shale-test-view/src/main/webapp/WEB-INF/web.xml Sun Nov 19 20:17:39 2006
@@ -40,6 +40,11 @@
     <param-value>/WEB-INF/faces-config.xml</param-value>
   </context-param>
 
+  <context-param>
+    <param-name>org.apache.shale.view.EXCEPTION_DISPATCH_PATH</param-name>
+    <param-value>/error.faces</param-value>
+  </context-param>
+
   <!-- JavaServer Faces Servlet Configuration -->
   <servlet>
     <servlet-name>faces</servlet-name>

Added: shale/framework/trunk/shale-apps/shale-test-view/src/main/webapp/error.jsp
URL: http://svn.apache.org/viewvc/shale/framework/trunk/shale-apps/shale-test-view/src/main/webapp/error.jsp?view=auto&rev=477032
==============================================================================
--- shale/framework/trunk/shale-apps/shale-test-view/src/main/webapp/error.jsp (added)
+++ shale/framework/trunk/shale-apps/shale-test-view/src/main/webapp/error.jsp Sun Nov 19 20:17:39 2006
@@ -0,0 +1,92 @@
+<%--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to you under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ $Id$
+
+--%>
+
+<%@ taglib prefix="f" uri="http://java.sun.com/jsf/core" %>
+<%@ taglib prefix="h" uri="http://java.sun.com/jsf/html" %>
+
+<f:view>
+<html>
+<head>
+    <title>Exception Occurred</title>
+</head>
+<body>
+
+<h:form id="error">
+    <table border="0">
+       <tr>
+	     <td>Test Record Events:</td>
+	     <td>
+	         <h:outputText value="#{error.recorder.events}"/>
+	     </td>
+	   </tr>
+	  <tr>
+	     <td>HTTP Error Error Status Code:</td>
+	     <td>
+	         <h:outputText value="#{error.httpErrorCode}"/>
+	         <h:inputHidden value="#{error.httpErrorCode}"/>
+	     </td>
+	   </tr>
+	   <tr>
+	       <td>Exception Type:</td>
+	       <td>
+	         <h:outputText value="#{error.exceptionType}"/>
+	         <h:inputHidden value="#{error.exceptionType}"/>
+	       </td>
+	   </tr>
+	   <tr>
+	       <td>Message:</td>
+	       <td>
+	         <h:outputText value="#{error.message}" />
+	         <h:inputHidden value="#{error.message}"/>
+	       </td>
+	   </tr>
+	   <tr>
+	       <td>Request URI:</td>
+	       <td>
+	         <h:outputText value="#{error.requestUri}"/>
+	         <h:inputHidden value="#{error.requestUri}"/>
+	       </td>
+	   </tr>
+	   <tr>
+	       <td>Servlet Name:</td>
+	       <td>
+	         <h:outputText value="#{error.servletName}" />
+	         <h:inputHidden value="#{error.servletName}"/>
+	       </td>
+	   </tr>
+	</table>   
+	
+	<h:dataTable var="e" value="#{facesContext.viewRoot.attributes.errors}">
+	   <h:column>
+	      <f:verbatim><dl><dt></f:verbatim>
+	      <h:outputText value="#{e.message}"/>
+	      <f:verbatim></dt><dd></f:verbatim>
+	      <h:outputText value="#{error.stackTrace}"/>
+	      <f:verbatim></dd></dl></f:verbatim>
+	   </h:column>
+	</h:dataTable>
+	
+    <p><h:commandLink action="raiseException" value="Back"/> to raise exception.</p>
+
+</h:form>
+</body>
+</html>
+</f:view>

Propchange: shale/framework/trunk/shale-apps/shale-test-view/src/main/webapp/error.jsp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: shale/framework/trunk/shale-apps/shale-test-view/src/main/webapp/error.jsp
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Modified: shale/framework/trunk/shale-apps/shale-test-view/src/main/webapp/menu.jsp
URL: http://svn.apache.org/viewvc/shale/framework/trunk/shale-apps/shale-test-view/src/main/webapp/menu.jsp?view=diff&rev=477032&r1=477031&r2=477032
==============================================================================
--- shale/framework/trunk/shale-apps/shale-test-view/src/main/webapp/menu.jsp (original)
+++ shale/framework/trunk/shale-apps/shale-test-view/src/main/webapp/menu.jsp Sun Nov 19 20:17:39 2006
@@ -46,6 +46,20 @@
     navigation links are included so that the pages may be executed by hand
     as well.</p>
 
+
+    <h3>Test View Controller Exception Handling Strategy</h3>
+    
+    <p>The raise exception page has several links to invoke backing logic that
+    will raise an unchecked exception.  The view controller exception handler 
+    catches these exceptions and forwards on to a error page.  The error page
+    is configured in the web.xml using the "org.apache.shale.view.EXCEPTION_DISPATCH_PATH" 
+    context parameter.  The error page will also show a record of the view controller
+    lifecycle callback events in addition to the other events where the exception is raised. 
+    <br/><br/>
+    <h:form id="f1">
+       <h:commandLink action="raiseException" value="Raise Unchecked Exception"/>
+    </h:form>
+    </p>
 </body>
 </html>
 </f:view>

Added: shale/framework/trunk/shale-apps/shale-test-view/src/main/webapp/raiseException.jsp
URL: http://svn.apache.org/viewvc/shale/framework/trunk/shale-apps/shale-test-view/src/main/webapp/raiseException.jsp?view=auto&rev=477032
==============================================================================
--- shale/framework/trunk/shale-apps/shale-test-view/src/main/webapp/raiseException.jsp (added)
+++ shale/framework/trunk/shale-apps/shale-test-view/src/main/webapp/raiseException.jsp Sun Nov 19 20:17:39 2006
@@ -0,0 +1,73 @@
+<%--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to you under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ $Id$
+
+--%>
+
+<%@ taglib prefix="f" uri="http://java.sun.com/jsf/core" %>
+<%@ taglib prefix="h" uri="http://java.sun.com/jsf/html" %>
+
+<f:view>
+<html>
+<head>
+    <title>Test View Controller Exception handling Strategy</title>
+</head>
+<body>
+
+    <h3>Immediate Action, Action Listeners and Value Change Listeners</h3>
+
+    <h:form id="form1">
+      <ol>
+         <li><h:commandLink immediate="true" id="throwActionException" value="Action Binding" action="#{raiseException.throwActionException}"/></li>
+         <li><h:commandLink immediate="true" id="throwActionListenerException" value="Action Listener Attribute Binding" actionListener="#{raiseException.throwActionListenerException}"/></li>
+         <li>
+             <h:outputLabel for="testvc" value="Value Change Listener Attribute Binding"/>
+             <h:selectOneListbox id="testvc" immediate="true" valueChangeListener="#{raiseException.throwValueChangeListenerException}">
+                 <f:selectItem itemLabel="one" itemValue="1"/>
+                 <f:selectItem itemLabel="two" itemValue="2"/>
+                 <f:selectItem itemLabel="three" itemValue="3"/>                 
+             </h:selectOneListbox>
+             <h:commandLink id="testvcCmd" immediate="true" action="raiseException" value="Apply"/>
+         </li>
+      </ol>
+    </h:form>
+
+
+    <h3>Action, Action Listeners and Value Change Listeners</h3>
+
+    <h:form id="form2">
+      <ol>
+         <li><h:commandLink id="throwActionException" value="Action Binding" action="#{raiseException.throwActionException}"/></li>
+         <li><h:commandLink id="throwActionListenerException" value="Action Listener Attribute Binding" actionListener="#{raiseException.throwActionListenerException}"/></li>
+         <li>
+             <h:outputLabel for="testvc" value="Value Change Listener Attribute Binding"/>
+             <h:selectOneListbox id="testvc" valueChangeListener="#{raiseException.throwValueChangeListenerException}">
+                 <f:selectItem itemLabel="one" itemValue="1"/>
+                 <f:selectItem itemLabel="two" itemValue="2"/>
+                 <f:selectItem itemLabel="three" itemValue="3"/>                 
+             </h:selectOneListbox>
+             <h:commandLink id="testvcCmd" action="raiseException" value="Apply"/>
+         </li>
+      </ol>
+    </h:form>
+
+    <p><a href="menu.faces">Back</a> to main menu</p>
+
+</body>
+</html>
+</f:view>

Propchange: shale/framework/trunk/shale-apps/shale-test-view/src/main/webapp/raiseException.jsp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: shale/framework/trunk/shale-apps/shale-test-view/src/main/webapp/raiseException.jsp
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: shale/framework/trunk/shale-view/src/main/java/org/apache/shale/view/faces/ShaleViewRoot.java
URL: http://svn.apache.org/viewvc/shale/framework/trunk/shale-view/src/main/java/org/apache/shale/view/faces/ShaleViewRoot.java?view=auto&rev=477032
==============================================================================
--- shale/framework/trunk/shale-view/src/main/java/org/apache/shale/view/faces/ShaleViewRoot.java (added)
+++ shale/framework/trunk/shale-view/src/main/java/org/apache/shale/view/faces/ShaleViewRoot.java Sun Nov 19 20:17:39 2006
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.shale.view.faces;
+
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.FacesContext;
+
+import org.apache.shale.view.Constants;
+import org.apache.shale.view.ExceptionHandler;
+
+/**
+ * <p>Extending the UIViewRoot to provide specialized exception
+ * handling needed for the Shale view controller to enforce the contracts
+ * of the callbacks.</p>
+ */
+public class ShaleViewRoot extends UIViewRoot  {
+
+    /**
+     * <p>Override to catch exceptions raised by the action listeners
+     * in the invoke application phase.</p>
+     *
+     * @param context faces context
+     */
+    public void processApplication(FacesContext context) {
+        try {
+            super.processApplication(context);
+        } catch (Exception e) {
+            handleException(context, e);
+            context.responseComplete();
+        }
+    }
+
+    /**
+     * <p>Override to catch and handle exceptions with immediate commands
+     * and value change listeners in the apply request values phase.</p>
+     *
+     * @param context faces context
+     */
+    public void processDecodes(FacesContext context) {
+        try {
+            super.processDecodes(context);
+        } catch (Exception e) {
+            handleException(context, e);
+            context.responseComplete();
+        }
+    }
+
+    /**
+     * <p>Override to catch and handle exceptions raised in the 
+     * update model phase.</p>
+     *
+     * @param context faces context
+     */
+    public void processUpdates(FacesContext context) {
+        try {
+            super.processUpdates(context);
+        } catch (Exception e) {
+            handleException(context, e);
+            context.responseComplete();
+        }
+    }
+
+    /**
+     * <p>Override to catch and handle exceptions in value change
+     * listeners that might have occured in the process validations
+     * phase.</p>
+     *
+     * @param context faces context
+     */
+    public void processValidators(FacesContext context) {
+        try {
+            super.processValidators(context);
+        } catch (Exception e) {
+            handleException(context, e);
+            context.responseComplete();           
+        }
+    }
+
+
+    /**
+     * <p>Handle the specified exception according to the strategy
+     * defined by our current {@link ExceptionHandler}.</p>
+     *
+     * @param context FacesContext for the current request
+     * @param exception Exception to be handled
+     */
+    private void handleException(FacesContext context, Exception exception) {
+
+        if (context == null) {
+            exception.printStackTrace(System.out);
+            return;
+        }
+        ExceptionHandler handler = (ExceptionHandler)
+          context.getApplication().getVariableResolver().resolveVariable
+                (context, Constants.EXCEPTION_HANDLER);
+        handler.handleException(exception);
+
+    }
+}

Modified: shale/framework/trunk/shale-view/src/main/java/org/apache/shale/view/faces/ViewPhaseListener.java
URL: http://svn.apache.org/viewvc/shale/framework/trunk/shale-view/src/main/java/org/apache/shale/view/faces/ViewPhaseListener.java?view=diff&rev=477032&r1=477031&r2=477032
==============================================================================
--- shale/framework/trunk/shale-view/src/main/java/org/apache/shale/view/faces/ViewPhaseListener.java (original)
+++ shale/framework/trunk/shale-view/src/main/java/org/apache/shale/view/faces/ViewPhaseListener.java Sun Nov 19 20:17:39 2006
@@ -90,11 +90,15 @@
             log.trace("afterPhase(" + event.getFacesContext()
                       + "," + event.getPhaseId() + ")");
         }
+        
+        if (afterPhaseExceptionCheck(event)) {
+            // dispatched to the target error page, stop further processing
+            return;
+        }
+
         PhaseId phaseId = event.getPhaseId();
         if (PhaseId.RESTORE_VIEW.equals(phaseId)) {
             afterRestoreView(event);
-        } else if (PhaseId.INVOKE_APPLICATION.equals(phaseId)) {
-            afterInvokeApplication(event);
         } else if (PhaseId.RENDER_RESPONSE.equals(phaseId)
                    || event.getFacesContext().getResponseComplete()) {
             afterRenderResponse(event);
@@ -145,23 +149,27 @@
      * to proceed.</p>
      *
      * @param event <code>PhaseEvent</code> for the current event
+     * @return <code>true</code> if exceptions have been handled
+     * and dispatched to the specified path
      */
-    private void afterInvokeApplication(PhaseEvent event) {
+    private boolean afterPhaseExceptionCheck(PhaseEvent event) {
 
         // Have we accumulated any exceptions during the current request?
+        // Have we already logged the exception?
         FacesContext context = event.getFacesContext();
         ExternalContext econtext = context.getExternalContext();
         List list = (List)
           econtext.getRequestMap().get(FacesConstants.EXCEPTIONS_LIST);
-        if (list == null) {
-            return;
+        if (list == null
+         || econtext.getRequestMap().get("javax.servlet.error.exception") != null) {
+            return false;
         }
 
         // Has the user specified a forwarding URL for handling exceptions?
         String path =
           econtext.getInitParameter(Constants.EXCEPTION_DISPATCH_PATH);
         if (path == null) {
-            return;
+            return false;
         }
 
         // Forward control to the specified path instead of allowing
@@ -187,11 +195,15 @@
             map.put("javax.servlet.error.servlet_name", "javax.faces.webapp.FacesServlet"); // Best we can do ...
             // Dispatch to the specified error handler
             context.responseComplete();
+            // force a destroy before dispatching to the error page
+            econtext.getRequestMap().remove(FacesConstants.VIEWS_INITIALIZED);
             econtext.dispatch(path);
+
         } catch (IOException e) {
             handleException(context, e);
         }
 
+        return true;
     }
 
 
@@ -208,11 +220,12 @@
         if (list == null) {
             return;
         }
-        Iterator vcs = list.iterator();
-        while (vcs.hasNext()) {
-            Object vc = vcs.next();
-//            viewControllerCallbacks(event.getFacesContext()).destroy(vc);
-        }
+        //Iterator vcs = list.iterator();
+        //while (vcs.hasNext()) {
+        //    Object vc = vcs.next();
+        //     viewControllerCallbacks(event.getFacesContext()).destroy(vc);
+        //}
+
         map.remove(FacesConstants.VIEWS_INITIALIZED);
 
     }

Modified: shale/framework/trunk/shale-view/src/main/resources/META-INF/faces-config.xml
URL: http://svn.apache.org/viewvc/shale/framework/trunk/shale-view/src/main/resources/META-INF/faces-config.xml?view=diff&rev=477032&r1=477031&r2=477032
==============================================================================
--- shale/framework/trunk/shale-view/src/main/resources/META-INF/faces-config.xml (original)
+++ shale/framework/trunk/shale-view/src/main/resources/META-INF/faces-config.xml Sun Nov 19 20:17:39 2006
@@ -48,6 +48,16 @@
     <phase-listener>org.apache.shale.view.faces.ViewPhaseListener</phase-listener>
   </lifecycle>
 
+  <component>
+      <description>
+        Extending the UIViewRoot to provide specialized exception
+        handling needed for the Shale view controller to enforce the contracts
+        of the callbacks.
+      </description>
+      <component-type>javax.faces.ViewRoot</component-type>
+      <component-class>org.apache.shale.view.faces.ShaleViewRoot</component-class>
+  </component>
+
   <!-- Custom JSF Components -->
   <component>
     <description>