You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lu...@apache.org on 2008/08/28 02:50:09 UTC

svn commit: r689684 - in /myfaces/tomahawk/trunk/sandbox: core/src/main/java/org/apache/myfaces/tomahawk/ core/src/main/java/org/apache/myfaces/tomahawk/util/ core12/src/main/java/org/apache/myfaces/tomahawk/ core12/src/main/java/org/apache/myfaces/tom...

Author: lu4242
Date: Wed Aug 27 17:50:09 2008
New Revision: 689684

URL: http://svn.apache.org/viewvc?rev=689684&view=rev
Log:
TOMAHAWK-1297 Redirect to a JSF page when Throwable exception or error occur

Added:
    myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/tomahawk/
    myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/tomahawk/util/
    myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/tomahawk/util/ErrorPageWriter.java   (with props)
    myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/tomahawk/util/ErrorRedirectJSFPageHandler.java   (with props)
    myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/tomahawk/util/ExceptionContext.java   (with props)
    myfaces/tomahawk/trunk/sandbox/core12/src/main/java/org/apache/myfaces/tomahawk/
    myfaces/tomahawk/trunk/sandbox/core12/src/main/java/org/apache/myfaces/tomahawk/util/
    myfaces/tomahawk/trunk/sandbox/core12/src/main/java/org/apache/myfaces/tomahawk/util/ErrorPageWriter.java   (with props)

Added: myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/tomahawk/util/ErrorPageWriter.java
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/tomahawk/util/ErrorPageWriter.java?rev=689684&view=auto
==============================================================================
--- myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/tomahawk/util/ErrorPageWriter.java (added)
+++ myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/tomahawk/util/ErrorPageWriter.java Wed Aug 27 17:50:09 2008
@@ -0,0 +1,617 @@
+/*
+ * 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.myfaces.tomahawk.util;
+
+import java.beans.BeanInfo;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.lang.reflect.Method;
+import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.faces.component.UIComponent;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+import javax.faces.el.MethodBinding;
+import javax.faces.el.ValueBinding;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * This class is the same as javax.faces.webapp._ErrorPageWriter,
+ * but is cloned here to allow ErrorRedirectJSFPageHandler to provide
+ * an alternative when no navigation rule for a specific exception is
+ * found.
+ * 
+ * @author Jacob Hookom (ICLA with ASF filed)
+ */
+public class ErrorPageWriter {
+
+    private static final Log log = LogFactory.getLog(ErrorPageWriter.class);
+    private static final Class[] NO_ARGS = new Class[0];
+
+    private final static String TS = "<";
+
+    private static final String ERROR_TEMPLATE = "META-INF/rsc/myfaces-dev-error.xml";
+
+    private static final String ERROR_TEMPLATE_RESOURCE = "org.apache.myfaces.ERROR_TEMPLATE_RESOURCE";
+
+    private static String[] ERROR_PARTS;
+
+    private static final String DEBUG_TEMPLATE = "META-INF/rsc/myfaces-dev-debug.xml";
+    
+    private static final String DEBUG_TEMPLATE_RESOURCE = "org.apache.myfaces.DEBUG_TEMPLATE_RESOURCE";    
+
+    private static String[] DEBUG_PARTS;
+
+    public ErrorPageWriter() {
+        super();
+    }
+    
+    private static String getErrorTemplate(FacesContext context)
+    {
+        String errorTemplate = context.getExternalContext().getInitParameter(ERROR_TEMPLATE_RESOURCE);
+        if (errorTemplate != null)
+        {
+            return errorTemplate;
+        }
+        return ERROR_TEMPLATE;
+    }
+    
+    private static String getDebugTemplate(FacesContext context)
+    {
+        String debugTemplate = context.getExternalContext().getInitParameter(DEBUG_TEMPLATE_RESOURCE);
+        if (debugTemplate != null)
+        {
+            return debugTemplate;
+        }        
+        return DEBUG_TEMPLATE;
+    }
+    
+    private static void init(FacesContext context) throws IOException {
+        if (ERROR_PARTS == null) {
+            ERROR_PARTS = splitTemplate(getErrorTemplate(context));
+        }
+
+        if (DEBUG_PARTS == null) {
+            DEBUG_PARTS = splitTemplate(getDebugTemplate(context));
+        }
+    }
+
+    private static String[] splitTemplate(String rsc) throws IOException {
+        InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(rsc);
+        if (is == null) {
+            throw new FileNotFoundException(rsc);
+        }
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        byte[] buff = new byte[512];
+        int read;
+        while ((read = is.read(buff)) != -1) {
+            baos.write(buff, 0, read);
+        }
+        String str = baos.toString();
+        return str.split("@@");
+    }
+
+    static ArrayList getErrorId(Throwable e){
+        String message = e.getMessage();
+
+        if(message==null)
+            return null;
+
+        ArrayList list = new ArrayList();
+        Pattern pattern = Pattern.compile(".*?\\Q,Id:\\E\\s*(\\S+)\\s*\\].*?");
+        Matcher matcher = pattern.matcher(message);
+
+        while (matcher.find()){
+            list.add(matcher.group(1));
+        }
+        if (list.size()>0) return list;
+        return null;
+    }
+
+    public static void writeCause(Writer writer, Throwable ex) throws IOException {
+        String msg = ex.getMessage();
+        for(;;) {
+            Throwable t = getCause(ex);
+            if (t == null)
+                break;
+            
+            ex = t;
+            if (ex.getMessage()!=null) msg = ex.getMessage();
+        }
+
+        if (msg != null) {
+            msg =ex.getClass().getName() + " - " + msg;
+            writer.write(msg.replaceAll("<", TS));
+        } else {
+            writer.write(ex.getClass().getName());
+        }
+    }
+
+    public static void debugHtml(Writer writer, FacesContext faces, Throwable e) throws IOException {
+        init(faces);
+        Date now = new Date();
+        for (int i = 0; i < ERROR_PARTS.length; i++) {
+            if ("message".equals(ERROR_PARTS[i])) {
+                String msg = e.getMessage();
+                if (msg != null) {
+                    writer.write(msg.replaceAll("<", TS));
+                } else {
+                    writer.write(e.getClass().getName());
+                }
+            } else if ("trace".equals(ERROR_PARTS[i])) {
+                writeException(writer, e);
+            } else if ("now".equals(ERROR_PARTS[i])) {
+                writer.write(DateFormat.getDateTimeInstance().format(now));
+            } else if ("tree".equals(ERROR_PARTS[i])) {
+                if (faces.getViewRoot() != null) {
+                    writeComponent(writer, faces.getViewRoot(), getErrorId(e));
+                }
+            } else if ("vars".equals(ERROR_PARTS[i])) {
+                writeVariables(writer, faces);
+            } else if ("cause".equals(ERROR_PARTS[i])) {
+                writeCause(writer, e);
+            } else {
+                writer.write(ERROR_PARTS[i]);
+            }
+        }
+    }
+    
+    public static void debugHtml(Writer writer, FacesContext faces, List exceptionList) throws IOException
+    {
+        init(faces);
+        Date now = new Date();
+        for (int i = 0; i < ERROR_PARTS.length; i++)
+        {
+            if ("message".equals(ERROR_PARTS[i]))
+            {
+                for (int j = 0; j < exceptionList.size(); j++)
+                {
+                    Exception e = (Exception) exceptionList.get(j);
+                    String msg = e.getMessage();
+                    if (msg != null)
+                    {
+                        writer.write(msg.replaceAll("<", TS));
+                    }
+                    else 
+                    {
+                        writer.write(e.getClass().getName());
+                    }
+                    if (!(j+1==exceptionList.size()))
+                    {
+                        writer.write("<br>");
+                    }
+                }
+            }
+            else if ("trace".equals(ERROR_PARTS[i]))
+            {
+                for (int j = 0; j < exceptionList.size(); j++)
+                {
+                    Exception e = (Exception) exceptionList.get(j);
+                    writeException(writer, e);
+                }
+            }
+            else if ("now".equals(ERROR_PARTS[i]))
+            {
+                writer.write(DateFormat.getDateTimeInstance().format(now));
+            }
+            else if ("tree".equals(ERROR_PARTS[i]))
+            {
+                if (faces.getViewRoot() != null)
+                {
+                    List highlightId = null;
+                    for (int j = 0; j < exceptionList.size(); j++)
+                    {
+                        Exception e = (Exception) exceptionList.get(j);
+                        if (highlightId == null)
+                        {
+                            highlightId = getErrorId(e);
+                        }
+                        else
+                        {
+                            highlightId.addAll(getErrorId(e));
+                        }
+                    }
+                    writeComponent(writer, faces.getViewRoot(), highlightId);
+                }
+            }
+            else if ("vars".equals(ERROR_PARTS[i]))
+            {
+                writeVariables(writer, faces);
+            }
+            else if ("cause".equals(ERROR_PARTS[i]))
+            {
+                for (int j = 0; j < exceptionList.size(); j++)
+                {
+                    Exception e = (Exception) exceptionList.get(j);
+                    writeCause(writer, e);
+                    if (!(j+1==exceptionList.size()))
+                    {
+                        writer.write("<br>");
+                    }
+                }
+            }
+            else
+            {
+                writer.write(ERROR_PARTS[i]);
+            }
+        }
+    }    
+
+    private static void writeException(Writer writer, Throwable e) throws IOException {
+        StringWriter str = new StringWriter(256);
+        PrintWriter pstr = new PrintWriter(str);
+        e.printStackTrace(pstr);
+        pstr.close();
+        writer.write(str.toString().replaceAll("<", TS));
+    }
+
+    public static void debugHtml(Writer writer, FacesContext faces) throws IOException {
+        init(faces);
+        Date now = new Date();
+        for (int i = 0; i < DEBUG_PARTS.length; i++) {
+            if ("message".equals(DEBUG_PARTS[i])) {
+                writer.write(faces.getViewRoot().getViewId());
+            } else if ("now".equals(DEBUG_PARTS[i])) {
+                writer.write(DateFormat.getDateTimeInstance().format(now));
+            } else if ("tree".equals(DEBUG_PARTS[i])) {
+                writeComponent(writer, faces.getViewRoot(), null);
+            } else if ("vars".equals(DEBUG_PARTS[i])) {
+                writeVariables(writer, faces);
+            } else {
+                writer.write(DEBUG_PARTS[i]);
+            }
+        }
+    }
+
+    static void writeVariables(Writer writer, FacesContext faces) throws IOException {
+        ExternalContext ctx = faces.getExternalContext();
+        writeVariables(writer, ctx.getRequestParameterMap(), "Request Parameters");
+        writeVariables(writer, ctx.getRequestMap(), "Request Attributes");
+        if (ctx.getSession(false) != null) {
+            writeVariables(writer, ctx.getSessionMap(), "Session Attributes");
+        }
+        writeVariables(writer, ctx.getApplicationMap(), "Application Attributes");
+    }
+
+    private static void writeVariables(Writer writer, Map vars, String caption) throws IOException {
+        writer.write("<table><caption>");
+        writer.write(caption);
+        writer.write("</caption><thead><tr><th style=\"width: 10%; \">Name</th><th style=\"width: 90%; \">Value</th></tr></thead><tbody>");
+        boolean written = false;
+        if (!vars.isEmpty()) {
+            SortedMap map = new TreeMap(vars);
+            Map.Entry entry = null;
+            String key = null;
+            for (Iterator itr = map.entrySet().iterator(); itr.hasNext(); ) {
+                entry = (Map.Entry) itr.next();
+                key = entry.getKey().toString();
+                if (key.indexOf('.') == -1) {
+                    writer.write("<tr><td>");
+                    writer.write(key.replaceAll("<", TS));
+                    writer.write("</td><td>");
+                    writer.write(entry.getValue().toString().replaceAll("<", TS));
+                    writer.write("</td></tr>");
+                    written = true;
+                }
+            }
+        }
+        if (!written) {
+            writer.write("<tr><td colspan=\"2\"><em>None</em></td></tr>");
+        }
+        writer.write("</tbody></table>");
+    }
+
+    static void writeComponent(Writer writer, UIComponent c, List highlightId) throws IOException {
+        writer.write("<dl><dt");
+        if (isText(c)) {
+            writer.write(" class=\"uicText\"");
+        }
+        if (highlightId != null){
+            if ((highlightId.size() > 0) && (highlightId.get(0).equals(c.getId()))){
+                highlightId.remove(0);
+                if (highlightId.size()==0){
+                    writer.write(" class=\"highlightComponent\"");
+                }
+            }
+        }
+        writer.write(">");
+
+        boolean hasChildren = c.getChildCount() > 0 || c.getFacets().size() > 0;
+
+        writeStart(writer, c, hasChildren);
+        writer.write("</dt>");
+        if (hasChildren) {
+            if (c.getFacets().size() > 0) {
+                Map.Entry entry;
+                for (Iterator itr = c.getFacets().entrySet().iterator(); itr.hasNext(); ) {
+                    entry = (Map.Entry) itr.next();
+                    writer.write("<dd class=\"uicFacet\">");
+                    writer.write("<span>");
+                    writer.write((String) entry.getKey());
+                    writer.write("</span>");
+                    writeComponent(writer, (UIComponent) entry.getValue(), highlightId);
+                    writer.write("</dd>");
+                }
+            }
+            if (c.getChildCount() > 0) {
+                for (Iterator itr = c.getChildren().iterator(); itr.hasNext(); ) {
+                    writer.write("<dd>");
+                    writeComponent(writer, (UIComponent) itr.next(), highlightId);
+                    writer.write("</dd>");
+                }
+            }
+            writer.write("<dt>");
+            writeEnd(writer, c);
+            writer.write("</dt>");
+        }
+        writer.write("</dl>");
+    }
+
+    private static void writeEnd(Writer writer, UIComponent c) throws IOException {
+        if (!isText(c)) {
+            writer.write(TS);
+            writer.write('/');
+            writer.write(getName(c));
+            writer.write('>');
+        }
+    }
+
+    private final static String[] IGNORE = new String[] { "parent", "rendererType" };
+
+    private static void writeAttributes(Writer writer, UIComponent c) {
+        try {
+            BeanInfo info = Introspector.getBeanInfo(c.getClass());
+            PropertyDescriptor[] pd = info.getPropertyDescriptors();
+            Method m = null;
+            Object v = null;
+            String str = null;
+            for (int i = 0; i < pd.length; i++) {
+                if (pd[i].getWriteMethod() != null && Arrays.binarySearch(IGNORE, pd[i].getName()) < 0) {
+                    m = pd[i].getReadMethod();
+                    try {
+                        v = m.invoke(c, null);
+                        if (v != null) {
+                            if (v instanceof Collection || v instanceof Map || v instanceof Iterator) {
+                                continue;
+                            }
+                            writer.write(" ");
+                            writer.write(pd[i].getName());
+                            writer.write("=\"");
+                            if (v instanceof ValueBinding) {
+                                str = ((ValueBinding) v).getExpressionString();
+                            } else if (v instanceof MethodBinding) {
+                                str = ((MethodBinding) v).getExpressionString();
+                            } else {
+                                ValueBinding vb = c.getValueBinding(pd[i].getName());
+                                str = vb!=null?(vb.getExpressionString()+"="+v.toString()):v.toString();
+                            }
+                            writer.write(str.replaceAll("<", TS));
+                            writer.write("\"");
+                        }
+                    } catch (Exception e) {
+                        // do nothing
+                    }
+                }
+            }
+
+            ValueBinding binding = c.getValueBinding("binding");
+            if (binding != null) {
+                writer.write(" binding=\"");
+                writer.write(binding.getExpressionString().replaceAll("<", TS));
+                writer.write("\"");
+            }
+        } catch (Exception e) {
+            // do nothing
+        }
+    }
+
+    private static void writeStart(Writer writer, UIComponent c, boolean children) throws IOException {
+        if (isText(c)) {
+            String str = c.toString().trim();
+            writer.write(str.replaceAll("<", TS));
+        } else {
+            writer.write(TS);
+            writer.write(getName(c));
+            writeAttributes(writer, c);
+            if (children) {
+                writer.write('>');
+            } else {
+                writer.write("/>");
+            }
+        }
+    }
+
+    private static String getName(UIComponent c) {
+        String nm = c.getClass().getName();
+        return nm.substring(nm.lastIndexOf('.') + 1);
+    }
+
+    private static boolean isText(UIComponent c) {
+        return (c.getClass().getName().startsWith("com.sun.facelets.compiler"));
+    }
+
+    public static void handleException(FacesContext facesContext, Exception ex) throws ServletException, IOException
+    {
+        handleThrowable(facesContext, ex);
+    }
+    
+    public static void handleThrowable(FacesContext facesContext, Throwable ex) throws ServletException, IOException {
+
+        prepareExceptionStack(ex);
+
+        Object response = facesContext.getExternalContext().getResponse();
+        if(response instanceof HttpServletResponse) {
+            HttpServletResponse httpResp = (HttpServletResponse) response;
+            if (!httpResp.isCommitted()) {
+                httpResp.reset();
+                httpResp.setContentType("text/html; charset=UTF-8");
+                Writer writer = httpResp.getWriter();
+
+                debugHtml(writer, facesContext, ex);
+
+                log.error("An exception occurred", ex);
+            }
+            else {
+                throwException(ex);
+            }
+        }
+        else {
+            throwException(ex);
+        }
+    }
+    
+    public static void handleExceptionList(FacesContext facesContext, List exceptionList) throws ServletException, IOException
+    {
+        for (int i = 0; i < exceptionList.size(); i++)
+        {
+            prepareExceptionStack( (Exception) exceptionList.get(i));
+        }
+
+        Object response = facesContext.getExternalContext().getResponse();
+        if(response instanceof HttpServletResponse)
+        {
+            HttpServletResponse httpResp = (HttpServletResponse) response;
+            if (!httpResp.isCommitted())
+            {
+                httpResp.reset();
+                httpResp.setContentType("text/html; charset=UTF-8");
+                Writer writer = httpResp.getWriter();
+
+                debugHtml(writer, facesContext, exceptionList);
+
+                for (int i = 0; i < exceptionList.size(); i++)
+                {
+                    log.error("An exception occurred", (Exception) exceptionList.get(i));
+                }
+            }
+            else
+            {
+                throwException((Exception)exceptionList.get(0));
+            }
+        }
+        else
+        {
+            throwException((Exception)exceptionList.get(0));
+        }
+    }
+
+    private static void prepareExceptionStack(Throwable ex) {
+
+        if(ex==null)
+            return;
+
+        //check for getRootCause and getCause-methods
+        if(!initCausePerReflection(ex,"getRootCause")) {
+           initCausePerReflection(ex,"getCause");
+        }
+
+        prepareExceptionStack(getCause(ex));
+    }
+
+    /**
+     * Get the cause of an exception, if available. Reflection must be used because
+     * JSF11 supports java1.3 but Throwable.getCause was added in java1.4.
+     */
+    private static Throwable getCause(Throwable ex) {
+        try {
+            Method causeGetter = ex.getClass().getMethod("getCause", NO_ARGS);
+            Throwable cause = (Throwable) causeGetter.invoke(ex, NO_ARGS);
+            return cause;
+        } catch (Exception e1) {
+            return null;
+        }
+    }
+    
+    private static boolean initCausePerReflection(Throwable ex, String methodName) {
+        try {
+            Method causeGetter = ex.getClass().getMethod(methodName, NO_ARGS);
+            Throwable rootCause = (Throwable) causeGetter.invoke(ex, NO_ARGS);
+            return initCauseIfAvailable(ex,rootCause);
+        } catch (Exception e1) {
+            return false;
+        }
+    }
+
+    static void throwException(Throwable e) throws IOException, ServletException {
+
+        prepareExceptionStack(e);
+
+        if (e instanceof IOException)
+        {
+            throw (IOException)e;
+        }
+        else if (e instanceof ServletException)
+        {
+            throw (ServletException)e;
+        }
+        else
+        {
+            ServletException ex;
+
+            if (e.getMessage() != null) {
+                ex=new ServletException(e.getMessage(), e);
+            }
+            else {
+                ex=new ServletException(e);
+            }
+
+            initCauseIfAvailable(ex, e);
+
+            throw ex;
+        }
+    }
+
+    private static boolean initCauseIfAvailable(Throwable th, Throwable cause) {
+
+        if(cause == null)
+            return false;
+
+        try {
+            Method m = Throwable.class.getMethod("initCause",new Class[]{Throwable.class});
+            m.invoke(th,new Object[]{cause});
+            return true;
+        }
+        catch(Exception e) {
+            return false;
+        }
+    }
+}
+

Propchange: myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/tomahawk/util/ErrorPageWriter.java
------------------------------------------------------------------------------
    svn:mergeinfo = 

Added: myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/tomahawk/util/ErrorRedirectJSFPageHandler.java
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/tomahawk/util/ErrorRedirectJSFPageHandler.java?rev=689684&view=auto
==============================================================================
--- myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/tomahawk/util/ErrorRedirectJSFPageHandler.java (added)
+++ myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/tomahawk/util/ErrorRedirectJSFPageHandler.java Wed Aug 27 17:50:09 2008
@@ -0,0 +1,370 @@
+/*
+ * 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.myfaces.tomahawk.util;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.faces.FacesException;
+import javax.faces.FactoryFinder;
+import javax.faces.application.NavigationHandler;
+import javax.faces.context.FacesContext;
+import javax.faces.el.ValueBinding;
+import javax.faces.lifecycle.Lifecycle;
+import javax.faces.lifecycle.LifecycleFactory;
+import javax.faces.webapp.FacesServlet;
+import javax.servlet.ServletException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * This handler redirect to a jsf page when an error occurs.
+ * <p>
+ * This class is set as a config-parameter org.apache.myfaces.ERROR_HANDLER
+ * available on myfaces core jsf. (This does not work with RI)
+ * </p>
+ * <p>
+ * The idea is extends myfaces error handling feature, making possible to redirect
+ * to a jsf page when an error occur, using navigation rules.
+ * </p>
+ * <p>
+ * If this handler is not able to handle the error, and alternate error handler
+ * could be set in the config-parameter org.apache.myfaces.ERROR_REDIRECT_ALTERNATE_HANDLER
+ * </p>
+ * <p>
+ * The info of the error in the jsf page can be found using:
+ * </p>
+ * <ul>
+ * <li>#{exceptionContext.cause} : Cause retrieved from the exception</li>
+ * <li>#{exceptionContext.stackTrace} : Stack trace of the exception</li>
+ * <li>#{exceptionContext.exception} : Exception handled by this page </li>
+ * <li>#{exceptionContext.tree} : Print the component tree of the page that cause the error</li>
+ * <li>#{exceptionContext.vars} : Enviroment variables from the request</li>
+ * </ul>
+ * 
+ * @author Leonardo Uribe (latest modification by $Author$)
+ * @version $Revision$ $Date$
+ */
+public class ErrorRedirectJSFPageHandler
+{
+    private static final Log log = LogFactory
+            .getLog(ErrorRedirectJSFPageHandler.class);
+
+    /**
+     * This param tells if ignore java.lang.* superclass names errors
+     * are found. In other words, all java.lang.* exceptions are simply
+     * skipped by this handler (so it could be thrown to an alternate handler
+     * or the jsp handler).
+     */
+    private static final String ERROR_HANDLING_IGNORE_BASE_ERROR_REDIRECT = "org.apache.myfaces.ERROR_HANDLING_IGNORE_BASE_ERROR_REDIRECT";
+       
+    private static final String ERROR_REDIRECT_ALTERNATE_HANDLER_PARAMETER = "org.apache.myfaces.ERROR_REDIRECT_ALTERNATE_HANDLER";
+    
+    private static String getErrorRedirectAlternateHandler(FacesContext context)
+    {
+        String errorHandlerClass = context.getExternalContext().getInitParameter(ERROR_REDIRECT_ALTERNATE_HANDLER_PARAMETER);
+        return errorHandlerClass;
+    }
+    
+    private static boolean isIgnoreBaseErrorRedirect(FacesContext context)
+    {
+        return getBooleanValue(context.getExternalContext().getInitParameter(
+                ERROR_HANDLING_IGNORE_BASE_ERROR_REDIRECT), false);
+    }
+
+    private static boolean getBooleanValue(String initParameter,
+            boolean defaultVal)
+    {
+        if (initParameter == null || initParameter.trim().length() == 0)
+            return defaultVal;
+
+        return (initParameter.equalsIgnoreCase("on")
+                || initParameter.equals("1") || initParameter
+                .equalsIgnoreCase("true"));
+    }
+    
+    public static void handleException(FacesContext facesContext, Exception e)
+            throws ServletException, IOException
+    {
+        boolean oldRenderResponse = facesContext.getRenderResponse();
+        ExceptionContext exceptionContext = new ExceptionContext(e,
+                facesContext.getViewRoot());
+
+        if (!handleCauseOrThrowable(facesContext, exceptionContext, e,
+                oldRenderResponse, isIgnoreBaseErrorRedirect(facesContext)))
+        {
+            //ErrorPageWriter.handleException(facesContext, ex);            
+            String errorHandlerClass = getErrorRedirectAlternateHandler(facesContext);
+            if (errorHandlerClass == null)
+            {
+                //Redirect to another handler if it is available
+                try
+                {
+                    Class clazz = Class.forName(errorHandlerClass);
+
+                    Object errorHandler = clazz.newInstance();
+
+                    Method m = clazz.getMethod("handleException", new Class[]{FacesContext.class,Exception.class});
+                    m.invoke(errorHandler, new Object[]{facesContext, e});
+                }
+                catch(ClassNotFoundException ex)
+                {
+                    throw new ServletException("Error-Handler : " 
+                            +errorHandlerClass
+                            + " was not found. Fix your web.xml-parameter : "+ERROR_REDIRECT_ALTERNATE_HANDLER_PARAMETER,ex);
+                }
+                catch (IllegalAccessException ex)
+                {
+                    throw new ServletException("Constructor of error-Handler : " 
+                            +errorHandlerClass+ " is not accessible. Error-Handler is specified in web.xml-parameter : "
+                            +ERROR_REDIRECT_ALTERNATE_HANDLER_PARAMETER,ex);
+                }
+                catch (InstantiationException ex)
+                {
+                    throw new ServletException("Error-Handler : " 
+                            +errorHandlerClass
+                            + " could not be instantiated. Error-Handler is specified in web.xml-parameter : "
+                            +ERROR_REDIRECT_ALTERNATE_HANDLER_PARAMETER,ex);
+                }
+                catch (NoSuchMethodException ex)
+                {
+                    log.error("Error-Handler : " 
+                            +errorHandlerClass
+                            + " did not have a method with name : handleException and parameters : javax.faces.context.FacesContext, java.lang.Exception. Error-Handler is specified in web.xml-parameter : "
+                            +ERROR_REDIRECT_ALTERNATE_HANDLER_PARAMETER,ex);
+                    //Try to look if it is implemented more general method handleThrowable
+                    handleThrowable(facesContext, ex);
+                }
+                catch (InvocationTargetException ex)
+                {
+                    throw new ServletException("Excecution of method handleException in Error-Handler : " 
+                            +errorHandlerClass
+                            + " caused an exception. Error-Handler is specified in web.xml-parameter : "
+                            +ERROR_REDIRECT_ALTERNATE_HANDLER_PARAMETER,ex);
+                }                
+            }
+            else
+            {
+                //throw exception because this redirect handler
+                //does not have any rule defined.
+                ErrorPageWriter.throwException(e);
+            }
+        }
+    }
+
+    public static void handleThrowable(FacesContext facesContext, Throwable e)
+            throws ServletException, IOException
+    {
+        boolean oldRenderResponse = facesContext.getRenderResponse();
+        ExceptionContext exceptionContext = new ExceptionContext(e,
+                facesContext.getViewRoot());
+
+        if (!handleCauseOrThrowable(facesContext, exceptionContext, e,
+                oldRenderResponse, isIgnoreBaseErrorRedirect(facesContext)))
+        {
+            //ErrorPageWriter.handleThrowable(facesContext, e);
+            String errorHandlerClass = getErrorRedirectAlternateHandler(facesContext);
+            if (errorHandlerClass == null)
+            {
+                try {
+                    Class clazz = Class.forName(errorHandlerClass);
+
+                    Object errorHandler = clazz.newInstance();
+
+                    Method m = clazz.getMethod("handleThrowable", new Class[]{FacesContext.class,Throwable.class});
+                    m.invoke(errorHandler, new Object[]{facesContext, e});
+                }
+                catch(ClassNotFoundException ex) {
+                    throw new ServletException("Error-Handler : " 
+                            +errorHandlerClass
+                            + " was not found. Fix your web.xml-parameter : "+ERROR_REDIRECT_ALTERNATE_HANDLER_PARAMETER,ex);
+                } catch (IllegalAccessException ex) {
+                    throw new ServletException("Constructor of error-Handler : " 
+                            +errorHandlerClass
+                            + " is not accessible. Error-Handler is specified in web.xml-parameter : "
+                            +ERROR_REDIRECT_ALTERNATE_HANDLER_PARAMETER,ex);
+                } catch (InstantiationException ex) {
+                    throw new ServletException("Error-Handler : " 
+                            +errorHandlerClass
+                            + " could not be instantiated. Error-Handler is specified in web.xml-parameter : "
+                            +ERROR_REDIRECT_ALTERNATE_HANDLER_PARAMETER,ex);
+                } catch (NoSuchMethodException ex) {
+                    throw new ServletException("Error-Handler : " 
+                            +errorHandlerClass
+                            + " did not have a method with name : handleException and parameters : javax.faces.context.FacesContext, java.lang.Exception. Error-Handler is specified in web.xml-parameter : "
+                            +ERROR_REDIRECT_ALTERNATE_HANDLER_PARAMETER,ex);
+                } catch (InvocationTargetException ex) {
+                    throw new ServletException("Excecution of method handleException in Error-Handler : " 
+                            +errorHandlerClass
+                            + " threw an exception. Error-Handler is specified in web.xml-parameter : "
+                            +ERROR_REDIRECT_ALTERNATE_HANDLER_PARAMETER,ex);
+                }                
+            }
+            else
+            {
+                //throw exception because this redirect handler
+                //does not have any rule defined.
+                ErrorPageWriter.throwException(e);
+            }
+        }
+    }
+
+    public static void handleExceptionList(FacesContext facesContext,
+            List exceptionList) throws ServletException, IOException
+    {
+        boolean isHandleCauseOrThrowable = false;
+
+        //Try to check if some exception on the list have a applicable
+        //navigation rule.
+        for (Iterator it = exceptionList.iterator(); it.hasNext();)
+        {
+            Exception ex = (Exception) it.next();
+
+            boolean oldRenderResponse = facesContext.getRenderResponse();
+            ExceptionContext exceptionContext = new ExceptionContext(ex,
+                    facesContext.getViewRoot());
+
+            isHandleCauseOrThrowable = handleCauseOrThrowable(facesContext,
+                    exceptionContext, ex, oldRenderResponse,
+                    isIgnoreBaseErrorRedirect(facesContext));
+
+            if (isHandleCauseOrThrowable)
+                break;
+        }
+
+        if (!isHandleCauseOrThrowable)
+        {
+            //If no navigation happened, handle as exception using 
+            //the default ErrorPageWriter
+            //ErrorPageWriter.handleException(facesContext,
+            //        (Exception) exceptionList.get(0));
+            String errorHandlerClass = getErrorRedirectAlternateHandler(facesContext);
+            if(errorHandlerClass != null) {
+                try {
+                    Class clazz = Class.forName(errorHandlerClass);
+
+                    Object errorHandler = clazz.newInstance();
+
+                    Method m = clazz.getMethod("handleExceptionList", new Class[]{FacesContext.class,Exception.class});
+                    m.invoke(errorHandler, new Object[]{facesContext, exceptionList});
+                }
+                catch(ClassNotFoundException ex) {
+                    throw new ServletException("Error-Handler : " 
+                            +errorHandlerClass
+                            + " was not found. Fix your web.xml-parameter : "
+                            +ERROR_REDIRECT_ALTERNATE_HANDLER_PARAMETER,ex);
+                } catch (IllegalAccessException ex) {
+                    throw new ServletException("Constructor of error-Handler : " 
+                            +errorHandlerClass
+                            + " is not accessible. Error-Handler is specified in web.xml-parameter : "
+                            +ERROR_REDIRECT_ALTERNATE_HANDLER_PARAMETER,ex);
+                } catch (InstantiationException ex) {
+                    throw new ServletException("Error-Handler : " 
+                            +errorHandlerClass
+                            + " could not be instantiated. Error-Handler is specified in web.xml-parameter : "
+                            +ERROR_REDIRECT_ALTERNATE_HANDLER_PARAMETER,ex);
+                } catch (NoSuchMethodException ex) {
+                    //Handle in the old way, since no custom method handleExceptionList found,
+                    //throwing the first FacesException on the list.
+                    throw (FacesException) exceptionList.get(0);
+                } catch (InvocationTargetException ex) {
+                    throw new ServletException("Excecution of method handleException in Error-Handler : " 
+                            +errorHandlerClass
+                            + " threw an exception. Error-Handler is specified in web.xml-parameter : "
+                            +ERROR_REDIRECT_ALTERNATE_HANDLER_PARAMETER,ex);
+                }
+            }
+            else
+            {
+                ErrorPageWriter.throwException((Exception) exceptionList.get(0));
+            }
+        }
+    }
+
+    private static String getLifecycleId(FacesContext context)
+    {
+        String lifecycleId = context.getExternalContext().getInitParameter(
+                FacesServlet.LIFECYCLE_ID_ATTR);
+        return lifecycleId != null ? lifecycleId
+                : LifecycleFactory.DEFAULT_LIFECYCLE;
+    }
+
+    private static boolean handleCauseOrThrowable(FacesContext context,
+            ExceptionContext exceptionContext, Throwable th,
+            boolean oldRenderResponse, boolean ignoreBaseException)
+    {
+
+        boolean throwableHandled = false;
+        //First try to find the most inner child in the exception stack
+        if (th.getCause() != null)
+        {
+            throwableHandled = handleCauseOrThrowable(context,
+                    exceptionContext, th.getCause(), oldRenderResponse,
+                    ignoreBaseException);
+        }
+
+        if (throwableHandled == false)
+        {
+            Class thClass = th.getClass();
+            while (thClass != null)
+            {
+                // ignore java.lang.* superclass names
+                if (ignoreBaseException
+                        && thClass.getName().startsWith("java.lang."))
+                {
+                    return false;
+                }
+                log.info("Trying to redirect to jsf page:" + thClass.getName());
+                NavigationHandler nh = context.getApplication()
+                        .getNavigationHandler();
+                nh.handleNavigation(context, null, thClass.getName());
+
+                //Check if the navigation happened.
+                //to call the render response phase
+                if (context.getRenderResponse())//navigationHappened(oldRenderResponse, oldViewId, context)
+                {
+                    //exceptionHandlingContext.setExceptionHandled();
+                    log.error("an error occurred : ", th);
+
+                    ValueBinding vb = context.getApplication()
+                            .createValueBinding("#{exceptionContext}");
+
+                    vb.setValue(context, exceptionContext);
+
+                    LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder
+                            .getFactory(FactoryFinder.LIFECYCLE_FACTORY);
+                    Lifecycle _lifecycle = lifecycleFactory
+                            .getLifecycle(getLifecycleId(context));
+                    _lifecycle.render(context);
+
+                    vb.setValue(context, null);
+
+                    context.responseComplete();
+                    return true;
+                }
+                thClass = thClass.getSuperclass();
+            }
+        }
+        return throwableHandled;
+    }
+}

Propchange: myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/tomahawk/util/ErrorRedirectJSFPageHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/tomahawk/util/ErrorRedirectJSFPageHandler.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/tomahawk/util/ExceptionContext.java
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/tomahawk/util/ExceptionContext.java?rev=689684&view=auto
==============================================================================
--- myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/tomahawk/util/ExceptionContext.java (added)
+++ myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/tomahawk/util/ExceptionContext.java Wed Aug 27 17:50:09 2008
@@ -0,0 +1,190 @@
+/*
+ * 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.myfaces.tomahawk.util;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.text.DateFormat;
+import java.util.Date;
+
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+
+/**
+ * The ExceptionContext class holds all information related to an error
+ * ocurred in a jsf environment, handled by a redirection using
+ * ErrorRedirectJSFPageHandler.
+ * 
+ * @author Leonardo Uribe (latest modification by $Author$)
+ * @version $Revision$ $Date$
+ */
+public class ExceptionContext
+{
+
+    private Throwable _exception;
+
+    private UIComponent _viewRoot;
+
+    private String _cause;
+
+    private String _tree;
+    
+    private String _vars;
+
+    public ExceptionContext(Throwable _exception, UIComponent viewRoot)
+    {
+        super();
+        this._exception = _exception;
+        this._viewRoot = viewRoot;
+    }
+
+    public void setException(Throwable exception)
+    {
+        this._exception = exception;
+    }
+
+    public Throwable getException()
+    {
+        return _exception;
+    }
+
+    public String getCause()
+    {
+        if (_cause == null)
+        {
+            StringWriter writer = null;
+            try
+            {
+                writer = new StringWriter(256);
+                ErrorPageWriter.writeCause(writer, _exception);
+            }
+            catch (IOException e)
+            {
+                //do nothing
+            }
+            finally
+            {
+                try
+                {
+                    if (writer != null)
+                        writer.close();
+                }
+                catch (IOException e)
+                {
+                    //do nothing
+                }
+            }
+            _cause = writer.toString();
+        }
+        return _cause;
+    }
+
+    public String getStackTrace()
+    {
+        StringWriter str = new StringWriter(256);
+        PrintWriter pstr = new PrintWriter(str);
+        _exception.printStackTrace(pstr);
+        pstr.close();
+        return str.toString();
+    }
+
+    public String getNow()
+    {
+        Date now = new Date();
+        return DateFormat.getDateTimeInstance().format(now);
+    }
+
+    public UIComponent getViewRoot()
+    {
+        return _viewRoot;
+    }
+
+    public void setViewRoot(UIComponent viewRoot)
+    {
+        this._viewRoot = viewRoot;
+    }
+
+    public String getVars()
+    {
+        if (_vars == null)
+        {
+            StringWriter writer = null;
+            try
+            {
+                writer = new StringWriter(256);
+                ErrorPageWriter.writeVariables(writer, FacesContext.getCurrentInstance());
+                _vars = writer.toString();
+            }
+            catch (IOException e)
+            {
+                //do nothing
+            }
+            finally
+            {
+                try
+                {
+                    if (writer != null)
+                        writer.close();
+                }
+                catch (IOException e)
+                {
+                    //do nothing
+                }
+            }
+        }
+        return _vars;
+    }
+    
+    public String getTree()
+    {
+        if (_tree == null)
+        {
+            if (_viewRoot != null)
+            {
+                StringWriter writer = null;
+                try
+                {
+                    writer = new StringWriter(256);
+                    ErrorPageWriter.writeComponent(writer, _viewRoot,
+                            ErrorPageWriter.getErrorId(_exception));
+                    _tree = writer.toString();
+                }
+                catch (IOException e)
+                {
+                    //do nothing
+                }
+                finally
+                {
+                    try
+                    {
+                        if (writer != null)
+                            writer.close();
+                    }
+                    catch (IOException e)
+                    {
+                        //do nothing
+                    }
+                }
+            }
+        }
+        return _tree;
+    }
+    
+}

Propchange: myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/tomahawk/util/ExceptionContext.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/tomahawk/util/ExceptionContext.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: myfaces/tomahawk/trunk/sandbox/core12/src/main/java/org/apache/myfaces/tomahawk/util/ErrorPageWriter.java
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/sandbox/core12/src/main/java/org/apache/myfaces/tomahawk/util/ErrorPageWriter.java?rev=689684&view=auto
==============================================================================
--- myfaces/tomahawk/trunk/sandbox/core12/src/main/java/org/apache/myfaces/tomahawk/util/ErrorPageWriter.java (added)
+++ myfaces/tomahawk/trunk/sandbox/core12/src/main/java/org/apache/myfaces/tomahawk/util/ErrorPageWriter.java Wed Aug 27 17:50:09 2008
@@ -0,0 +1,578 @@
+/*
+ * 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.myfaces.tomahawk.util;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import javax.faces.context.FacesContext;
+import javax.faces.context.ExternalContext;
+import javax.faces.component.UIComponent;
+import javax.el.Expression;
+import javax.el.ValueExpression;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletResponse;
+import java.beans.BeanInfo;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.io.*;
+import java.lang.reflect.Method;
+import java.text.DateFormat;
+import java.util.*;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+/**
+ * This class is the same as javax.faces.webapp._ErrorPageWriter,
+ * but is cloned here to allow ErrorRedirectJSFPageHandler to provide
+ * an alternative when no navigation rule for a specific exception is
+ * found.
+ * 
+ * @author Jacob Hookom (ICLA with ASF filed)
+ */
+public class ErrorPageWriter {
+
+    private static final Log log = LogFactory.getLog(ErrorPageWriter.class);
+
+    private final static String TS = "&lt;";
+
+    private static final String ERROR_TEMPLATE = "META-INF/rsc/myfaces-dev-error.xml";
+
+    private static final String ERROR_TEMPLATE_RESOURCE = "org.apache.myfaces.ERROR_TEMPLATE_RESOURCE";
+
+    private static String[] ERROR_PARTS;
+
+    private static final String DEBUG_TEMPLATE = "META-INF/rsc/myfaces-dev-debug.xml";
+    
+    private static final String DEBUG_TEMPLATE_RESOURCE = "org.apache.myfaces.DEBUG_TEMPLATE_RESOURCE";    
+
+    private static String[] DEBUG_PARTS;
+
+    public ErrorPageWriter() {
+        super();
+    }
+    
+    private static String getErrorTemplate(FacesContext context)
+    {
+        String errorTemplate = context.getExternalContext().getInitParameter(ERROR_TEMPLATE_RESOURCE);
+        if (errorTemplate != null)
+        {
+            return errorTemplate;
+        }
+        return ERROR_TEMPLATE;
+    }
+    
+    private static String getDebugTemplate(FacesContext context)
+    {
+        String debugTemplate = context.getExternalContext().getInitParameter(DEBUG_TEMPLATE_RESOURCE);
+        if (debugTemplate != null)
+        {
+            return debugTemplate;
+        }        
+        return DEBUG_TEMPLATE;
+    }
+    
+    private static void init(FacesContext context) throws IOException {
+        if (ERROR_PARTS == null) {
+            ERROR_PARTS = splitTemplate(getErrorTemplate(context));
+        }
+
+        if (DEBUG_PARTS == null) {
+            DEBUG_PARTS = splitTemplate(getDebugTemplate(context));
+        }
+    }
+
+    private static String[] splitTemplate(String rsc) throws IOException {
+        InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(rsc);
+        if (is == null) {
+            throw new FileNotFoundException(rsc);
+        }
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        byte[] buff = new byte[512];
+        int read;
+        while ((read = is.read(buff)) != -1) {
+            baos.write(buff, 0, read);
+        }
+        String str = baos.toString();
+        return str.split("@@");
+    }
+
+    public static ArrayList getErrorId(Throwable e){
+        String message = e.getMessage();
+
+        if(message==null)
+            return null;
+
+        ArrayList list = new ArrayList();
+        Pattern pattern = Pattern.compile(".*?\\Q,Id:\\E\\s*(\\S+)\\s*\\].*?");
+        Matcher matcher = pattern.matcher(message);
+
+        while (matcher.find()){
+            list.add(matcher.group(1));
+        }
+        if (list.size()>0) return list;
+        return null;
+    }
+
+    public static void writeCause(Writer writer, Throwable ex) throws IOException {
+        String msg = ex.getMessage();
+        while (ex.getCause()!=null){
+            ex=ex.getCause();
+            if (ex.getMessage()!=null) msg = ex.getMessage();
+        }
+
+        if (msg != null) {
+            msg =ex.getClass().getName() + " - " + msg;
+            writer.write(msg.replaceAll("<", TS));
+        } else {
+            writer.write(ex.getClass().getName());
+        }
+    }
+
+    public static void debugHtml(Writer writer, FacesContext faces, Throwable e) throws IOException {
+        init(faces);
+        Date now = new Date();
+        for (int i = 0; i < ERROR_PARTS.length; i++) {
+            if ("message".equals(ERROR_PARTS[i])) {
+                String msg = e.getMessage();
+                if (msg != null) {
+                    writer.write(msg.replaceAll("<", TS));
+                } else {
+                    writer.write(e.getClass().getName());
+                }
+            } else if ("trace".equals(ERROR_PARTS[i])) {
+                writeException(writer, e);
+            } else if ("now".equals(ERROR_PARTS[i])) {
+                writer.write(DateFormat.getDateTimeInstance().format(now));
+            } else if ("tree".equals(ERROR_PARTS[i])) {
+                if (faces.getViewRoot() != null) {
+                    writeComponent(writer, faces.getViewRoot(), getErrorId(e));
+                }
+            } else if ("vars".equals(ERROR_PARTS[i])) {
+                writeVariables(writer, faces);
+            } else if ("cause".equals(ERROR_PARTS[i])) {
+                writeCause(writer, e);
+            } else {
+                writer.write(ERROR_PARTS[i]);
+            }
+        }
+    }
+    
+    public static void debugHtml(Writer writer, FacesContext faces, List exceptionList) throws IOException
+    {
+        init(faces);
+        Date now = new Date();
+        for (int i = 0; i < ERROR_PARTS.length; i++)
+        {
+            if ("message".equals(ERROR_PARTS[i]))
+            {
+                for (int j = 0; j < exceptionList.size(); j++)
+                {
+                    Exception e = (Exception) exceptionList.get(j);
+                    String msg = e.getMessage();
+                    if (msg != null)
+                    {
+                        writer.write(msg.replaceAll("<", TS));
+                    }
+                    else 
+                    {
+                        writer.write(e.getClass().getName());
+                    }
+                    if (!(j+1==exceptionList.size()))
+                    {
+                        writer.write("<br>");
+                    }
+                }
+            }
+            else if ("trace".equals(ERROR_PARTS[i]))
+            {
+                for (int j = 0; j < exceptionList.size(); j++)
+                {
+                    Exception e = (Exception) exceptionList.get(j);
+                    writeException(writer, e);
+                }
+            }
+            else if ("now".equals(ERROR_PARTS[i]))
+            {
+                writer.write(DateFormat.getDateTimeInstance().format(now));
+            }
+            else if ("tree".equals(ERROR_PARTS[i]))
+            {
+                if (faces.getViewRoot() != null)
+                {
+                    List highlightId = null;
+                    for (int j = 0; j < exceptionList.size(); j++)
+                    {
+                        Exception e = (Exception) exceptionList.get(j);
+                        if (highlightId == null)
+                        {
+                            highlightId = getErrorId(e);
+                        }
+                        else
+                        {
+                            highlightId.addAll(getErrorId(e));
+                        }
+                    }
+                    writeComponent(writer, faces.getViewRoot(), highlightId);
+                }
+            }
+            else if ("vars".equals(ERROR_PARTS[i]))
+            {
+                writeVariables(writer, faces);
+            }
+            else if ("cause".equals(ERROR_PARTS[i]))
+            {
+                for (int j = 0; j < exceptionList.size(); j++)
+                {
+                    Exception e = (Exception) exceptionList.get(j);
+                    writeCause(writer, e);
+                    if (!(j+1==exceptionList.size()))
+                    {
+                        writer.write("<br>");
+                    }
+                }
+            }
+            else
+            {
+                writer.write(ERROR_PARTS[i]);
+            }
+        }
+    }    
+
+    private static void writeException(Writer writer, Throwable e) throws IOException {
+        StringWriter str = new StringWriter(256);
+        PrintWriter pstr = new PrintWriter(str);
+        e.printStackTrace(pstr);
+        pstr.close();
+        writer.write(str.toString().replaceAll("<", TS));
+    }
+
+    public static void debugHtml(Writer writer, FacesContext faces) throws IOException {
+        init(faces);
+        Date now = new Date();
+        for (int i = 0; i < DEBUG_PARTS.length; i++) {
+            if ("message".equals(DEBUG_PARTS[i])) {
+                writer.write(faces.getViewRoot().getViewId());
+            } else if ("now".equals(DEBUG_PARTS[i])) {
+                writer.write(DateFormat.getDateTimeInstance().format(now));
+            } else if ("tree".equals(DEBUG_PARTS[i])) {
+                writeComponent(writer, faces.getViewRoot(), null);
+            } else if ("vars".equals(DEBUG_PARTS[i])) {
+                writeVariables(writer, faces);
+            } else {
+                writer.write(DEBUG_PARTS[i]);
+            }
+        }
+    }
+
+    public static void writeVariables(Writer writer, FacesContext faces) throws IOException {
+        ExternalContext ctx = faces.getExternalContext();
+        writeVariables(writer, ctx.getRequestParameterMap(), "Request Parameters");
+        writeVariables(writer, ctx.getRequestMap(), "Request Attributes");
+        if (ctx.getSession(false) != null) {
+            writeVariables(writer, ctx.getSessionMap(), "Session Attributes");
+        }
+        writeVariables(writer, ctx.getApplicationMap(), "Application Attributes");
+    }
+
+    private static void writeVariables(Writer writer, Map vars, String caption) throws IOException {
+        writer.write("<table><caption>");
+        writer.write(caption);
+        writer.write("</caption><thead><tr><th style=\"width: 10%; \">Name</th><th style=\"width: 90%; \">Value</th></tr></thead><tbody>");
+        boolean written = false;
+        if (!vars.isEmpty()) {
+            SortedMap map = new TreeMap(vars);
+            Map.Entry entry = null;
+            String key = null;
+            for (Iterator itr = map.entrySet().iterator(); itr.hasNext(); ) {
+                entry = (Map.Entry) itr.next();
+                key = entry.getKey().toString();
+                if (key.indexOf('.') == -1) {
+                    writer.write("<tr><td>");
+                    writer.write(key.replaceAll("<", TS));
+                    writer.write("</td><td>");
+                    writer.write(entry.getValue().toString().replaceAll("<", TS));
+                    writer.write("</td></tr>");
+                    written = true;
+                }
+            }
+        }
+        if (!written) {
+            writer.write("<tr><td colspan=\"2\"><em>None</em></td></tr>");
+        }
+        writer.write("</tbody></table>");
+    }
+
+    public static void writeComponent(Writer writer, UIComponent c, List highlightId) throws IOException {
+        writer.write("<dl><dt");
+        if (isText(c)) {
+            writer.write(" class=\"uicText\"");
+        }
+        if (highlightId != null){
+            if ((highlightId.size() > 0) && (highlightId.get(0).equals(c.getId()))){
+                highlightId.remove(0);
+                if (highlightId.size()==0){
+                    writer.write(" class=\"highlightComponent\"");
+                }
+            }
+        }
+        writer.write(">");
+
+        boolean hasChildren = c.getChildCount() > 0 || c.getFacets().size() > 0;
+
+        writeStart(writer, c, hasChildren);
+        writer.write("</dt>");
+        if (hasChildren) {
+            if (c.getFacets().size() > 0) {
+                Map.Entry entry;
+                for (Iterator itr = c.getFacets().entrySet().iterator(); itr.hasNext(); ) {
+                    entry = (Map.Entry) itr.next();
+                    writer.write("<dd class=\"uicFacet\">");
+                    writer.write("<span>");
+                    writer.write((String) entry.getKey());
+                    writer.write("</span>");
+                    writeComponent(writer, (UIComponent) entry.getValue(), highlightId);
+                    writer.write("</dd>");
+                }
+            }
+            if (c.getChildCount() > 0) {
+                for (Iterator itr = c.getChildren().iterator(); itr.hasNext(); ) {
+                    writer.write("<dd>");
+                    writeComponent(writer, (UIComponent) itr.next(), highlightId);
+                    writer.write("</dd>");
+                }
+            }
+            writer.write("<dt>");
+            writeEnd(writer, c);
+            writer.write("</dt>");
+        }
+        writer.write("</dl>");
+    }
+
+    private static void writeEnd(Writer writer, UIComponent c) throws IOException {
+        if (!isText(c)) {
+            writer.write(TS);
+            writer.write('/');
+            writer.write(getName(c));
+            writer.write('>');
+        }
+    }
+
+    private final static String[] IGNORE = new String[] { "parent", "rendererType" };
+
+    private static void writeAttributes(Writer writer, UIComponent c) {
+        try {
+            BeanInfo info = Introspector.getBeanInfo(c.getClass());
+            PropertyDescriptor[] pd = info.getPropertyDescriptors();
+            Method m = null;
+            Object v = null;
+            String str = null;
+            for (int i = 0; i < pd.length; i++) {
+                if (pd[i].getWriteMethod() != null && Arrays.binarySearch(IGNORE, pd[i].getName()) < 0) {
+                    m = pd[i].getReadMethod();
+                    try {
+                        v = m.invoke(c, null);
+                        if (v != null) {
+                            if (v instanceof Collection || v instanceof Map || v instanceof Iterator) {
+                                continue;
+                            }
+                            writer.write(" ");
+                            writer.write(pd[i].getName());
+                            writer.write("=\"");
+                            if (v instanceof Expression) {
+                                str = ((Expression) v).getExpressionString();
+                            }
+                            writer.write(str.replaceAll("<", TS));
+                            writer.write("\"");
+                        }
+                    } catch (Exception e) {
+                        // do nothing
+                    }
+                }
+            }
+
+            ValueExpression binding = c.getValueExpression("binding");
+            if (binding != null) {
+                writer.write(" binding=\"");
+                writer.write(binding.getExpressionString().replaceAll("<", TS));
+                writer.write("\"");
+            }
+        } catch (Exception e) {
+            // do nothing
+        }
+    }
+
+    private static void writeStart(Writer writer, UIComponent c, boolean children) throws IOException {
+        if (isText(c)) {
+            String str = c.toString().trim();
+            writer.write(str.replaceAll("<", TS));
+        } else {
+            writer.write(TS);
+            writer.write(getName(c));
+            writeAttributes(writer, c);
+            if (children) {
+                writer.write('>');
+            } else {
+                writer.write("/>");
+            }
+        }
+    }
+
+    private static String getName(UIComponent c) {
+        String nm = c.getClass().getName();
+        return nm.substring(nm.lastIndexOf('.') + 1);
+    }
+
+    private static boolean isText(UIComponent c) {
+        return (c.getClass().getName().startsWith("com.sun.facelets.compiler"));
+    }
+
+    public static void handleException(FacesContext facesContext, Exception ex) throws ServletException, IOException
+    {
+        handleThrowable(facesContext, ex);
+    }
+    
+    public static void handleThrowable(FacesContext facesContext, Throwable ex) throws ServletException, IOException {
+
+        prepareExceptionStack(ex);
+
+        Object response = facesContext.getExternalContext().getResponse();
+        if(response instanceof HttpServletResponse) {
+            HttpServletResponse httpResp = (HttpServletResponse) response;
+            if (!httpResp.isCommitted()) {
+                httpResp.reset();
+                httpResp.setContentType("text/html; charset=UTF-8");
+                Writer writer = httpResp.getWriter();
+
+                debugHtml(writer, facesContext, ex);
+
+                log.error("An exception occurred", ex);
+            }
+            else {
+                throwException(ex);
+            }
+        }
+        else {
+            throwException(ex);
+        }
+    }
+    
+    public static void handleExceptionList(FacesContext facesContext, List exceptionList) throws ServletException, IOException
+    {
+        for (int i = 0; i < exceptionList.size(); i++)
+        {
+            prepareExceptionStack( (Exception) exceptionList.get(i));
+        }
+
+        Object response = facesContext.getExternalContext().getResponse();
+        if(response instanceof HttpServletResponse)
+        {
+            HttpServletResponse httpResp = (HttpServletResponse) response;
+            if (!httpResp.isCommitted())
+            {
+                httpResp.reset();
+                httpResp.setContentType("text/html; charset=UTF-8");
+                Writer writer = httpResp.getWriter();
+
+                debugHtml(writer, facesContext, exceptionList);
+
+                for (int i = 0; i < exceptionList.size(); i++)
+                {
+                    log.error("An exception occurred", (Exception) exceptionList.get(i));
+                }
+            }
+            else
+            {
+                throwException((Exception)exceptionList.get(0));
+            }
+        }
+        else
+        {
+            throwException((Exception)exceptionList.get(0));
+        }
+    }
+
+    private static void prepareExceptionStack(Throwable ex) {
+
+        if(ex==null)
+            return;
+
+        //check for getRootCause and getCause-methods
+        if(!initCausePerReflection(ex,"getRootCause")) {
+           initCausePerReflection(ex,"getCause");
+        }
+
+        prepareExceptionStack(ex.getCause());
+    }
+
+    private static boolean initCausePerReflection(Throwable ex, String methodName) {
+        try {
+            Method causeGetter = ex.getClass().getMethod(methodName,new Class[]{});
+            Throwable rootCause = (Throwable) causeGetter.invoke(ex,new Class[]{});
+            return initCauseIfAvailable(ex,rootCause);
+        } catch (Exception e1) {
+            return false;
+        }
+    }
+
+    static void throwException(Throwable e) throws IOException, ServletException {
+
+        prepareExceptionStack(e);
+
+        if (e instanceof IOException)
+        {
+            throw (IOException)e;
+        }
+        else if (e instanceof ServletException)
+        {
+            throw (ServletException)e;
+        }
+        else
+        {
+            ServletException ex;
+
+            if (e.getMessage() != null) {
+                ex=new ServletException(e.getMessage(), e);
+            }
+            else {
+                ex=new ServletException(e);
+            }
+
+            initCauseIfAvailable(ex, e);
+
+            throw ex;
+        }
+    }
+
+    private static boolean initCauseIfAvailable(Throwable th, Throwable cause) {
+
+        if(cause == null)
+            return false;
+
+        try {
+            Method m = Throwable.class.getMethod("initCause",new Class[]{Throwable.class});
+            m.invoke(th,new Object[]{cause});
+            return true;
+        }
+        catch(Exception e) {
+            return false;
+        }
+    }
+}
+

Propchange: myfaces/tomahawk/trunk/sandbox/core12/src/main/java/org/apache/myfaces/tomahawk/util/ErrorPageWriter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/tomahawk/trunk/sandbox/core12/src/main/java/org/apache/myfaces/tomahawk/util/ErrorPageWriter.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL