Author: craigmcc
Date: Sat Aug 5 22:58:05 2006
New Revision: 429110
URL: http://svn.apache.org/viewvc?rev=429110&view=rev
Log:
Implement a basic exception processing strategy. The default
ExceptionHandler implementation already logs and accumulates any
exceptions thrown by application event handlers, storing them in a
request scope attribute named by symbolic constant
FacesConstants.EXCEPTIONS_LIST for use later in the request processing
lifecycle.
The new functionality is implemented in a phase listener after the
Invoke Application phase has been completed (note that this is *before*
rendering, so it is before any potential call to a prerender() method).
*If* there have been any accumulated exceptions, and *if* the user has
provided a context relative path (starting with '/') to an exception
handler, then an ExternalContext.dispatch() call will be made to this
path (after setting request attributes corresponding to what a servlet
conatiner would report to an error handler, as defined in Section
SRV.9.9.1 of the Servlet Specification). Then, responseComplete() will
be called to prevent the normal Render Response phase from being
executed.
To provide a context relative path to an error handler, the application
developer must specify a context initializaton parameter named
"org.apache.shale.view.EXCEPTION_DISPATCH_PATH". Note that this error
handler will be called *before* the destroy() methods of any relevant
request scoped backing beans have been called, but those methods will
indeed be called as long as the error handler does not itself throw any
exceptions to the container.
SHALE-125
Added:
shale/framework/trunk/shale-core/src/main/java/org/apache/shale/view/ApplicationException.java
Modified:
shale/framework/trunk/shale-core/src/main/java/org/apache/shale/view/Constants.java
shale/framework/trunk/shale-core/src/main/java/org/apache/shale/view/faces/ViewPhaseListener.java
Added:
shale/framework/trunk/shale-core/src/main/java/org/apache/shale/view/ApplicationException.java
URL:
http://svn.apache.org/viewvc/shale/framework/trunk/shale-core/src/main/java/org/apache/shale/view/ApplicationException.java?rev=429110&view=auto
==============================================================================
---
shale/framework/trunk/shale-core/src/main/java/org/apache/shale/view/ApplicationException.java
(added)
+++
shale/framework/trunk/shale-core/src/main/java/org/apache/shale/view/ApplicationException.java
Sat Aug 5 22:58:05 2006
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * <p>Runtime exception encapsulating a <code>List</code> of exceptions that
+ * have occurred during the request processing lifecycle.</p>
+ *
+ * @since 1.0.3
+ */
+public class ApplicationException extends RuntimeException {
+
+
+ // ------------------------------------------------------------
Constructors
+
+
+ /**
+ * <p>Construct an exception with no message.</p>
+ */
+ public ApplicationException() {
+ super();
+ }
+
+
+
+ /**
+ * <p>Construct an exception with the specified message.</p>
+ *
+ * @param message The exception message
+ */
+ public ApplicationException(String message) {
+ super(message);
+ }
+
+
+ /**
+ * <p>Construct an exception with the specified message and cause.</p>
+ *
+ * @param message The exception message
+ * @param cause The root cause
+ */
+ public ApplicationException(String message, Throwable cause) {
+ super(message, cause);
+ this.exceptions = new ArrayList(1);
+ this.exceptions.add(cause);
+ }
+
+
+ /**
+ * <p>Construct an exception with the specified cause.</p>
+ *
+ * @param cause The root cause
+ */
+ public ApplicationException(Throwable cause) {
+ super(cause);
+ this.exceptions = new ArrayList(1);
+ this.exceptions.add(cause);
+ }
+
+
+ /**
+ * <p>Construct an exception with the specified <code>List</code> of
+ * causes. The first exception in the list will be logged as the
+ * formal cause of this exception.</p>
+ *
+ * @param exceptions List of exceptions that have been thrown
+ */
+ public ApplicationException(List exceptions) {
+ super((Exception) exceptions.get(0));
+ this.exceptions = exceptions;
+ }
+
+
+ // ------------------------------------------------------- Public
Properties
+
+
+ /**
+ * <p><code>List</code> of exceptions that are the cumulative cause of
+ * this exception.</p>
+ */
+ private List exceptions;
+
+
+ /**
+ * <p>Return a <code>List</code> of exceptoins that are the cumulative
+ * cause of this exception.</p>
+ */
+ public List getExceptions() {
+ return this.exceptions;
+ }
+
+
+}
Modified:
shale/framework/trunk/shale-core/src/main/java/org/apache/shale/view/Constants.java
URL:
http://svn.apache.org/viewvc/shale/framework/trunk/shale-core/src/main/java/org/apache/shale/view/Constants.java?rev=429110&r1=429109&r2=429110&view=diff
==============================================================================
---
shale/framework/trunk/shale-core/src/main/java/org/apache/shale/view/Constants.java
(original)
+++
shale/framework/trunk/shale-core/src/main/java/org/apache/shale/view/Constants.java
Sat Aug 5 22:58:05 2006
@@ -38,6 +38,27 @@
// ------------------------------------------------------ Manifest
Constants
+
+ /**
+ * <p>Name of the context initialization parameter that defines the
+ * context-relative path we should dispatch to, at the end of
+ * <em>Invoke Application</em> phase of the request processing lifecycle,
+ * if any application exceptions have been cached by the default
+ * [EMAIL PROTECTED] ExceptionHandler} instance. If no value is
specified, the
+ * default behavioer is to proceed to rendering for the view that the
+ * application has navigated to.</p>
+ *
+ * <p><strong>NOTE</strong> - in order to be processed correctly by the
+ * container, the specified path should be a context relative URL
+ * that beings with a '/' character.</p>
+ *
+ * @since 1.0.3
+ */
+ public static final String EXCEPTION_DISPATCH_PATH =
+ "org.apache.shale.view.EXCEPTION_DISPATCH_PATH";
+
+
+
/**
* <p>Name of the context initialization parameter that defines the
* fully qualified class name of the [EMAIL PROTECTED]
ViewControllerMapper} to be
Modified:
shale/framework/trunk/shale-core/src/main/java/org/apache/shale/view/faces/ViewPhaseListener.java
URL:
http://svn.apache.org/viewvc/shale/framework/trunk/shale-core/src/main/java/org/apache/shale/view/faces/ViewPhaseListener.java?rev=429110&r1=429109&r2=429110&view=diff
==============================================================================
---
shale/framework/trunk/shale-core/src/main/java/org/apache/shale/view/faces/ViewPhaseListener.java
(original)
+++
shale/framework/trunk/shale-core/src/main/java/org/apache/shale/view/faces/ViewPhaseListener.java
Sat Aug 5 22:58:05 2006
@@ -16,9 +16,11 @@
package org.apache.shale.view.faces;
+import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;
@@ -28,6 +30,7 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.shale.view.ApplicationException;
import org.apache.shale.view.Constants;
import org.apache.shale.view.ExceptionHandler;
import org.apache.shale.view.ViewController;
@@ -77,6 +80,8 @@
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);
@@ -119,6 +124,61 @@
// --------------------------------------------------------- Private
Methods
+
+
+ /**
+ * <p>If any exceptions have been accumulated, and the user has specified
+ * a forwarding URL, forward to that URL instead of allowing rendering
+ * to proceed.</p>
+ *
+ * @param event <code>PhaseEvent</code> for the current event
+ */
+ private void afterInvokeApplication(PhaseEvent event) {
+
+ // Have we accumulated any exceptions during the current request?
+ FacesContext context = event.getFacesContext();
+ ExternalContext econtext = context.getExternalContext();
+ List list = (List)
+ econtext.getRequestMap().get(FacesConstants.EXCEPTIONS_LIST);
+ if (list == null) {
+ return;
+ }
+
+ // Has the user specified a forwarding URL for handling exceptions?
+ String path =
+ econtext.getInitParameter(Constants.EXCEPTION_DISPATCH_PATH);
+ if (path == null) {
+ return;
+ }
+
+ // Forward control to the specified path instead of allowing
+ // rendering to complete, while simulating container error handling
+ try {
+ // Set up request attributes reflecting the error conditions,
+ // similar to what is passed to an error handler by the servlet
+ // container (see Section 9.9.1 of the Servlet Specification)
+ ApplicationException exception = new ApplicationException(list);
+ Map map = econtext.getRequestMap();
+ map.put("javax.servlet.error.status_code", new Integer(200)); //
Not an HTTP error
+ map.put("javax.servlet.error.exception_type",
ApplicationException.class);
+ map.put("javax.servlet.error.message", exception.getMessage());
+ map.put("javax.servlet.error.exception", exception);
+ StringBuffer sb = new StringBuffer("");
+ if (econtext.getRequestServletPath() != null) {
+ sb.append(econtext.getRequestServletPath());
+ }
+ if (econtext.getRequestPathInfo() != null) {
+ sb.append(econtext.getRequestPathInfo());
+ }
+ map.put("javax.servlet.error.request_uri", sb.toString());
+ map.put("javax.servlet.error.servlet_name",
"javax.faces.webapp.FacesServlet"); // Best we can do ...
+ // Dispatch to the specified error handler
+ econtext.dispatch(path);
+ } catch (IOException e) {
+ handleException(context, e);
+ }
+
+ }
/**