Coverage Report - org.apache.myfaces.renderkit.ErrorPageWriter
 
Classes in this File Line Coverage Branch Coverage Complexity
ErrorPageWriter
0%
0/436
0%
0/256
6.722
ErrorPageWriter$ErrorPageBean
0%
0/34
0%
0/2
6.722
ErrorPageWriter$ExtendedComponentTreeVisitCallback
0%
0/131
0%
0/80
6.722
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one
 3  
  * or more contributor license agreements.  See the NOTICE file
 4  
  * distributed with this work for additional information
 5  
  * regarding copyright ownership.  The ASF licenses this file
 6  
  * to you under the Apache License, Version 2.0 (the
 7  
  * "License"); you may not use this file except in compliance
 8  
  * with the License.  You may obtain a copy of the License at
 9  
  *
 10  
  *   http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing,
 13  
  * software distributed under the License is distributed on an
 14  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15  
  * KIND, either express or implied.  See the License for the
 16  
  * specific language governing permissions and limitations
 17  
  * under the License.
 18  
  */
 19  
 package org.apache.myfaces.renderkit;
 20  
 
 21  
 import java.beans.BeanInfo;
 22  
 import java.beans.Introspector;
 23  
 import java.beans.PropertyDescriptor;
 24  
 import java.io.ByteArrayOutputStream;
 25  
 import java.io.IOException;
 26  
 import java.io.InputStream;
 27  
 import java.io.PrintWriter;
 28  
 import java.io.Serializable;
 29  
 import java.io.StringWriter;
 30  
 import java.io.Writer;
 31  
 import java.lang.reflect.Method;
 32  
 import java.text.DateFormat;
 33  
 import java.util.ArrayList;
 34  
 import java.util.Arrays;
 35  
 import java.util.Collection;
 36  
 import java.util.Date;
 37  
 import java.util.EnumSet;
 38  
 import java.util.HashMap;
 39  
 import java.util.Iterator;
 40  
 import java.util.List;
 41  
 import java.util.Map;
 42  
 import java.util.SortedMap;
 43  
 import java.util.TreeMap;
 44  
 import java.util.logging.Level;
 45  
 import java.util.logging.Logger;
 46  
 import java.util.regex.Matcher;
 47  
 import java.util.regex.Pattern;
 48  
 
 49  
 import javax.el.Expression;
 50  
 import javax.el.ValueExpression;
 51  
 import javax.faces.FacesException;
 52  
 import javax.faces.component.EditableValueHolder;
 53  
 import javax.faces.component.UIColumn;
 54  
 import javax.faces.component.UIComponent;
 55  
 import javax.faces.component.UIData;
 56  
 import javax.faces.component.UIViewRoot;
 57  
 import javax.faces.component.visit.VisitCallback;
 58  
 import javax.faces.component.visit.VisitContext;
 59  
 import javax.faces.component.visit.VisitHint;
 60  
 import javax.faces.component.visit.VisitResult;
 61  
 import javax.faces.context.ExternalContext;
 62  
 import javax.faces.context.FacesContext;
 63  
 import javax.faces.context.PartialResponseWriter;
 64  
 import javax.faces.context.ResponseWriter;
 65  
 import javax.faces.el.MethodBinding;
 66  
 import javax.faces.el.ValueBinding;
 67  
 import javax.faces.render.Renderer;
 68  
 import javax.faces.view.Location;
 69  
 import javax.servlet.http.HttpServletResponse;
 70  
 
 71  
 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
 72  
 import org.apache.myfaces.lifecycle.ViewNotFoundException;
 73  
 import org.apache.myfaces.shared.config.MyfacesConfig;
 74  
 import org.apache.myfaces.shared.renderkit.html.HtmlResponseWriterImpl;
 75  
 import org.apache.myfaces.shared.util.ClassUtils;
 76  
 import org.apache.myfaces.shared.util.StateUtils;
 77  
 import org.apache.myfaces.spi.WebConfigProvider;
 78  
 import org.apache.myfaces.spi.WebConfigProviderFactory;
 79  
 import org.apache.myfaces.view.facelets.component.UIRepeat;
 80  
 import org.apache.myfaces.view.facelets.el.ContextAware;
 81  
 
 82  
 /**
 83  
  * This class provides utility methods to generate the
 84  
  * MyFaces error and debug pages. 
 85  
  *
 86  
  * @author Jacob Hookom (ICLA with ASF filed)
 87  
  * @author Jakob Korherr (refactored and moved here from javax.faces.webapp._ErrorPageWriter)
 88  
  */
 89  0
 public final class ErrorPageWriter
 90  
 {
 91  
 
 92  
     /**
 93  
      * This bean aims to generate the error page html for inclusion on a facelet error page via
 94  
      * <ui:include src="javax.faces.error.xhtml" />. When performing this include the facelet
 95  
      * "myfaces-dev-error-include.xhtml" will be included. This facelet references to the ErrorPageBean.
 96  
      * This also works for custom error page templates.
 97  
      * The bean is added to the ViewMap of the UIViewRoot, which is 
 98  
      * displaying the error page, in RestoreViewExecutor.execute().
 99  
      * @author Jakob Korherr
 100  
      */
 101  0
     public static class ErrorPageBean implements Serializable
 102  
     {
 103  
 
 104  
         private static final long serialVersionUID = -79513324193326616L;
 105  
 
 106  
         public String getErrorPageHtml() throws IOException
 107  
         {
 108  0
             FacesContext facesContext = FacesContext.getCurrentInstance();
 109  0
             Map<String, Object> requestMap = facesContext.getExternalContext().getRequestMap();
 110  
 
 111  0
             Throwable t = (Throwable) requestMap.get(EXCEPTION_KEY);
 112  0
             if (t == null)
 113  
             {
 114  0
                 throw new IllegalStateException("No Exception to handle");
 115  
             }
 116  
 
 117  0
             UIViewRoot view = (UIViewRoot) requestMap.get(VIEW_KEY);
 118  
 
 119  0
             StringWriter writer = new StringWriter();
 120  0
             ErrorPageWriter.debugHtml(writer, facesContext, view, null, t);
 121  0
             String html = writer.toString();
 122  
 
 123  
             // change the HTML in the buffer to be included in an existing html page
 124  
             String body;
 125  
             try
 126  
             {
 127  0
                 body = html.substring(html.indexOf("<body>") + "<body>".length(), html.indexOf("</body>"));
 128  
             }
 129  0
             catch (Exception e)
 130  
             {
 131  
                 // no body found - return the entire html
 132  0
                 return html;
 133  0
             }
 134  
 
 135  
             String head;
 136  
             try
 137  
             {
 138  0
                 head = html.substring(html.indexOf("<head>") + "<head>".length(), html.indexOf("</head>"));
 139  
             }
 140  0
             catch (Exception e)
 141  
             {
 142  
                 // no head found - return entire body
 143  0
                 return body;
 144  0
             }
 145  
 
 146  
             // extract style and script information from head and add it to body
 147  0
             StringBuilder builder = new StringBuilder(body);
 148  
             // extract <style>
 149  0
             int startIndex = 0;
 150  
             while (true)
 151  
             {
 152  
                 try
 153  
                 {
 154  0
                     int endIndex = head.indexOf("</style>", startIndex) + "</style>".length();
 155  0
                     builder.append(head.substring(head.indexOf("<style", startIndex), endIndex));
 156  0
                     startIndex = endIndex;
 157  
                 }
 158  0
                 catch (Exception e)
 159  
                 {
 160  
                     // no style found - break extraction
 161  0
                     break;
 162  0
                 }
 163  
             }
 164  
             // extract <script>
 165  0
             startIndex = 0;
 166  
             while (true)
 167  
             {
 168  
                 try
 169  
                 {
 170  0
                     int endIndex = head.indexOf("</script>", startIndex) + "</script>".length();
 171  0
                     builder.append(head.substring(head.indexOf("<script", startIndex), endIndex));
 172  0
                     startIndex = endIndex;
 173  
                 }
 174  0
                 catch (Exception e)
 175  
                 {
 176  
                     // no script found - break extraction
 177  0
                     break;
 178  0
                 }
 179  
             }
 180  
 
 181  0
             return builder.toString();
 182  
         }
 183  
 
 184  
     }
 185  
 
 186  
     /**
 187  
      * The key which is used to store the ErrorPageBean in the view map of a facelet error page.
 188  
      */
 189  
     public static final String ERROR_PAGE_BEAN_KEY = "__myFacesErrorPageBean";
 190  
 
 191  
     private static final String EXCEPTION_KEY = "javax.servlet.error.exception";
 192  
     public static final String VIEW_KEY = "org.apache.myfaces.error.UIViewRoot";
 193  
 
 194  0
     private static final Logger log = Logger.getLogger(ErrorPageWriter.class.getName());
 195  
 
 196  
     private final static String TS = "&lt;";
 197  
 
 198  
     private static final String ERROR_TEMPLATE = "META-INF/rsc/myfaces-dev-error.xml";
 199  
 
 200  
     /**
 201  
      * Indicate the template name used to render the default error page used by MyFaces specific 
 202  
      * error handler implementation. 
 203  
      *
 204  
      * <p>See org.apache.myfaces.ERROR_HANDLING for details about
 205  
      * how to enable/disable it.</p>
 206  
      */
 207  
     @JSFWebConfigParam(defaultValue="META-INF/rsc/myfaces-dev-error.xml", since="1.2.4")
 208  
     private static final String ERROR_TEMPLATE_RESOURCE = "org.apache.myfaces.ERROR_TEMPLATE_RESOURCE";
 209  
 
 210  
     private static String[] errorParts;
 211  
 
 212  
     private static final String DEBUG_TEMPLATE = "META-INF/rsc/myfaces-dev-debug.xml";
 213  
 
 214  
     /**
 215  
      * Indicate the template name used to render the default debug page (see ui:debug tag).
 216  
      */
 217  
     @JSFWebConfigParam(defaultValue="META-INF/rsc/myfaces-dev-debug.xml", since="1.2.4")
 218  
     private static final String DEBUG_TEMPLATE_RESOURCE = "org.apache.myfaces.DEBUG_TEMPLATE_RESOURCE";
 219  
 
 220  
     private static String[] debugParts;
 221  
 
 222  
     private static final String REGEX_PATTERN = ".*?\\Q,Id:\\E\\s*(\\S+)\\s*\\].*?";
 223  
 
 224  0
     private final static String[] IGNORE = new String[] { "parent", "rendererType" };
 225  
 
 226  0
     private final static String[] ALWAYS_WRITE = new String[] { "class", "clientId" };
 227  
 
 228  
     /**
 229  
      * Extended debug info is stored under this key in the request
 230  
      * map for every UIInput component when in Development mode.
 231  
      * ATTENTION: this constant is duplicate in javax.faces.component.UIInput
 232  
      */
 233  
     public static final String DEBUG_INFO_KEY = "org.apache.myfaces.debug.DEBUG_INFO";
 234  
 
 235  
     /**
 236  
      * The number of facets of this component which have already been visited while
 237  
      * creating the extended component tree is saved under this key in the component's
 238  
      * attribute map.
 239  
      */
 240  
     private static final String VISITED_FACET_COUNT_KEY = "org.apache.myfaces.debug.VISITED_FACET_COUNT";
 241  
     //private static Map<UIComponent, Integer> visitedFacetCount = new HashMap<UIComponent, Integer>();
 242  
 
 243  
     /**
 244  
      * Indicate if myfaces is responsible to handle errors. 
 245  
      * See http://wiki.apache.org/myfaces/Handling_Server_Errors for details.
 246  
      */
 247  
     @JSFWebConfigParam(defaultValue="false, on Development Project stage: true",
 248  
                        expectedValues="true,false", since="1.2.4")
 249  
     public static final String ERROR_HANDLING_PARAMETER = "org.apache.myfaces.ERROR_HANDLING";
 250  
 
 251  
     public ErrorPageWriter()
 252  
     {
 253  0
         super();
 254  0
     }
 255  
 
 256  
     /**
 257  
      * Generates the HTML error page for the given Throwable 
 258  
      * and writes it to the given writer.
 259  
      * @param writer
 260  
      * @param faces
 261  
      * @param e
 262  
      * @throws IOException
 263  
      */
 264  
     public static void debugHtml(Writer writer, FacesContext faces, Throwable e) throws IOException
 265  
     {
 266  0
         debugHtml(writer, faces, faces.getViewRoot(), null,  e);
 267  0
     }
 268  
 
 269  
     private static void debugHtml(Writer writer, FacesContext faces, UIViewRoot view,
 270  
                                   Collection<UIComponent> components, Throwable... exs) throws IOException
 271  
     {
 272  0
         _init(faces);
 273  0
         Date now = new Date();
 274  
 
 275  0
         for (int i = 0; i < errorParts.length; i++)
 276  
         {
 277  0
             if ("view".equals((errorParts[i])))
 278  
             {
 279  0
                 if (faces.getViewRoot() != null)
 280  
                 {
 281  0
                     String viewId = faces.getViewRoot().getViewId();
 282  0
                     writer.write("viewId=" + viewId);
 283  0
                     writer.write("<br/>");
 284  0
                     String realPath = null;
 285  
                     try
 286  
                     {
 287  
                         //Could not work on tomcat 7 running by cargo
 288  0
                         realPath = faces.getExternalContext().getRealPath(viewId);
 289  
                     }
 290  0
                     catch(Throwable e)
 291  
                     {
 292  
                         //swallow it
 293  0
                     }
 294  0
                     if (realPath != null)
 295  
                     {
 296  0
                         writer.write("location=" + realPath);
 297  0
                         writer.write("<br/>");
 298  
                     }
 299  0
                     writer.write("phaseId=" + faces.getCurrentPhaseId());
 300  0
                     writer.write("<br/>");
 301  0
                     writer.write("<br/>");
 302  0
                 }
 303  
             }
 304  0
             else if ("message".equals(errorParts[i]))
 305  
             {
 306  0
                 boolean printed = false;
 307  
                 //Iterator<UIComponent> iterator = null;
 308  
                 //if (components != null)
 309  
                 //{ 
 310  
                 //    iterator = components.iterator();
 311  
                 //}
 312  0
                 for (Throwable e : exs)
 313  
                 {
 314  0
                     String msg = e.getMessage();
 315  0
                     if (printed)
 316  
                     {
 317  0
                         writer.write("<br/>");
 318  
                     }
 319  0
                     if (msg != null)
 320  
                     {
 321  0
                         writer.write(msg.replaceAll("<", TS));
 322  
                     }
 323  
                     else
 324  
                     {
 325  0
                         writer.write(e.getClass().getName());
 326  
                     }
 327  0
                     printed = true;
 328  
                 }
 329  0
             }
 330  0
             else if ("trace".equals(errorParts[i]))
 331  
             {
 332  0
                 boolean printed = false;
 333  0
                 for (Throwable e : exs)
 334  
                 {
 335  0
                     if (printed)
 336  
                     {
 337  0
                         writer.write("\n");
 338  
                     }
 339  0
                     _writeException(writer, e);
 340  0
                     printed = true;
 341  
                 }
 342  0
             }
 343  0
             else if ("now".equals(errorParts[i]))
 344  
             {
 345  0
                 writer.write(DateFormat.getDateTimeInstance().format(now));
 346  
             }
 347  0
             else if ("tree".equals(errorParts[i]))
 348  
             {
 349  0
                 if (view != null)
 350  
                 {
 351  0
                     List<String> errorIds = _getErrorId(components, exs);
 352  0
                     _writeComponent(faces, writer, view, errorIds, true);
 353  0
                 }
 354  
             }
 355  0
             else if ("vars".equals(errorParts[i]))
 356  
             {
 357  0
                 _writeVariables(writer, faces, view);
 358  
             }
 359  0
             else if ("cause".equals(errorParts[i]))
 360  
             {
 361  0
                 boolean printed = false;
 362  0
                 Iterator<UIComponent> iterator = null;
 363  0
                 if (components != null)
 364  
                 {
 365  0
                     iterator = components.iterator();
 366  
                 }
 367  0
                 for (Throwable e : exs)
 368  
                 {
 369  0
                     if (printed)
 370  
                     {
 371  0
                         writer.write("<br/>");
 372  
                     }
 373  0
                     _writeCause(writer, e);
 374  0
                     if (iterator != null)
 375  
                     {
 376  0
                         UIComponent uiComponent = iterator.next();
 377  0
                         if (uiComponent != null)
 378  
                         {
 379  0
                             _writeComponent(faces, writer, uiComponent, null, /* writeChildren */false);
 380  
                         }
 381  
                     }
 382  0
                     printed = true;
 383  
                 }
 384  0
             }
 385  
             else
 386  
             {
 387  0
                 writer.write(errorParts[i]);
 388  
             }
 389  
         }
 390  0
     }
 391  
 
 392  
     /**
 393  
      * Generates the HTML debug page for the current view
 394  
      * and writes it to the given writer.
 395  
      * @param writer
 396  
      * @param faces
 397  
      * @throws IOException
 398  
      */
 399  
     public static void debugHtml(Writer writer, FacesContext faces) throws IOException
 400  
     {
 401  0
         _init(faces);
 402  0
         Date now = new Date();
 403  0
         for (int i = 0; i < debugParts.length; i++)
 404  
         {
 405  0
             if ("message".equals(debugParts[i]))
 406  
             {
 407  0
                 writer.write(faces.getViewRoot().getViewId());
 408  
             }
 409  0
             else if ("now".equals(debugParts[i]))
 410  
             {
 411  0
                 writer.write(DateFormat.getDateTimeInstance().format(now));
 412  
             }
 413  0
             else if ("tree".equals(debugParts[i]))
 414  
             {
 415  0
                 _writeComponent(faces, writer, faces.getViewRoot(), null, true);
 416  
             }
 417  0
             else if ("extendedtree".equals(debugParts[i]))
 418  
             {
 419  0
                 _writeExtendedComponentTree(writer, faces);
 420  
             }
 421  0
             else if ("vars".equals(debugParts[i]))
 422  
             {
 423  0
                 _writeVariables(writer, faces, faces.getViewRoot());
 424  
             }
 425  
             else
 426  
             {
 427  0
                 writer.write(debugParts[i]);
 428  
             }
 429  
         }
 430  0
     }
 431  
 
 432  
     public static void handle(FacesContext facesContext, Collection<UIComponent> components,
 433  
                               Throwable... exs) throws FacesException
 434  
     {
 435  0
         for (Throwable ex : exs)
 436  
         {
 437  0
             _prepareExceptionStack(ex);
 438  
         }
 439  
 
 440  0
         if (!facesContext.getExternalContext().isResponseCommitted())
 441  
         {
 442  0
             facesContext.getExternalContext().responseReset();
 443  
         }
 444  
 
 445  0
         int responseStatus = -1;
 446  0
         for (Throwable ex : exs)
 447  
         {
 448  0
             if (ex instanceof ViewNotFoundException)
 449  
             {
 450  0
                 responseStatus = HttpServletResponse.SC_NOT_FOUND;
 451  0
                 break;
 452  
             }
 453  
             else
 454  
             {
 455  0
                 responseStatus = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
 456  
             }
 457  
         }
 458  0
         if (responseStatus != -1)
 459  
         {
 460  0
             facesContext.getExternalContext().setResponseStatus(responseStatus);
 461  
         }
 462  
 
 463  
         // normal request --> html error page
 464  0
         facesContext.getExternalContext().setResponseContentType("text/html");
 465  0
         facesContext.getExternalContext().setResponseCharacterEncoding("UTF-8");
 466  
         try
 467  
         {
 468  
             // We need the real one, because the one returned from FacesContext.getResponseWriter()
 469  
             // is configured with the encoding of the view.
 470  0
             Writer writer = facesContext.getExternalContext().getResponseOutputWriter();
 471  0
             debugHtml(writer, facesContext, facesContext.getViewRoot(), components, exs);
 472  
         }
 473  0
         catch(IOException ioe)
 474  
         {
 475  0
             throw new FacesException("Could not write the error page", ioe);
 476  0
         }
 477  
 
 478  
         // mark the response as complete
 479  0
         facesContext.responseComplete();
 480  0
     }
 481  
 
 482  
     /**
 483  
      * Handles the given Throwbale in the following way:
 484  
      * If there is no <error-page> entry in web.xml, try to reset the current HttpServletResponse,
 485  
      * generate the error page and call responseComplete(). If this fails, rethrow the Exception.
 486  
      * If there is an <error-page> entry in web.xml, save the current UIViewRoot in the RequestMap
 487  
      * with the key "org.apache.myfaces.error.UIViewRoot" to access it on the error page and
 488  
      * rethrow the Exception to let it flow up to FacesServlet.service() and thus be handled by the container.
 489  
      * @param facesContext
 490  
      * @param ex
 491  
      * @throws FacesException
 492  
      * @deprecated Use MyFacesExceptionHandlerWrapperImpl and handle() method
 493  
      */
 494  
     @Deprecated
 495  
     public static void handleThrowable(FacesContext facesContext, Throwable ex) throws FacesException
 496  
     {
 497  0
         _prepareExceptionStack(ex);
 498  
 
 499  0
         boolean errorPageWritten = false;
 500  
 
 501  
         // check if an error page is present in web.xml
 502  
         // if so, do not generate an error page
 503  
         //WebXml webXml = WebXml.getWebXml(facesContext.getExternalContext());
 504  
         //if (webXml.isErrorPagePresent())
 505  0
         WebConfigProvider webConfigProvider = WebConfigProviderFactory.getWebConfigProviderFactory(
 506  
                 facesContext.getExternalContext()).getWebConfigProvider(facesContext.getExternalContext());
 507  
 
 508  0
         if(webConfigProvider.isErrorPagePresent(facesContext.getExternalContext()))
 509  
         {
 510  
             // save current view in the request map to access it on the error page
 511  0
             facesContext.getExternalContext().getRequestMap().put(VIEW_KEY, facesContext.getViewRoot());
 512  
         }
 513  
         else
 514  
         {
 515  
             // check for org.apache.myfaces.ERROR_HANDLING
 516  
             // do not generate an error page if it is false
 517  0
             String errorHandling = facesContext.getExternalContext().getInitParameter(ERROR_HANDLING_PARAMETER);
 518  0
             boolean errorHandlingDisabled = (errorHandling != null && errorHandling.equalsIgnoreCase("false"));
 519  0
             if (!errorHandlingDisabled)
 520  
             {
 521  
                 // write the error page
 522  0
                 Object response = facesContext.getExternalContext().getResponse();
 523  0
                 if (response instanceof HttpServletResponse)
 524  
                 {
 525  0
                     HttpServletResponse httpResp = (HttpServletResponse) response;
 526  0
                     if (!httpResp.isCommitted())
 527  
                     {
 528  0
                         httpResp.reset();
 529  0
                         if (facesContext.getPartialViewContext().isAjaxRequest())
 530  
                         {
 531  
                             // ajax request --> xml error page 
 532  0
                             httpResp.setContentType("text/xml; charset=UTF-8");
 533  
                             try
 534  
                             {
 535  0
                                 Writer writer = httpResp.getWriter();
 536  
                                 // can't use facesContext.getResponseWriter(), because it might not have been set
 537  0
                                 ResponseWriter responseWriter = new HtmlResponseWriterImpl(writer, "text/xml", "utf-8");
 538  0
                                 PartialResponseWriter partialWriter = new PartialResponseWriter(responseWriter);
 539  0
                                 partialWriter.startDocument();
 540  0
                                 partialWriter.startError(ex.getClass().getName());
 541  0
                                 if (ex.getCause() != null)
 542  
                                 {
 543  0
                                     partialWriter.write(ex.getCause().toString());
 544  
                                 }
 545  0
                                 else if (ex.getMessage() != null)
 546  
                                 {
 547  0
                                     partialWriter.write(ex.getMessage());
 548  
                                 }
 549  0
                                 partialWriter.endError();
 550  0
                                 partialWriter.endDocument();
 551  
                             }
 552  0
                             catch(IOException ioe)
 553  
                             {
 554  0
                                 throw new FacesException("Could not write the error page", ioe);
 555  0
                             }
 556  
                         }
 557  
                         else
 558  
                         {
 559  
                             // normal request --> html error page
 560  0
                             httpResp.setContentType("text/html; charset=UTF-8");
 561  
                             try
 562  
                             {
 563  0
                                 Writer writer = httpResp.getWriter();
 564  0
                                 debugHtml(writer, facesContext, ex);
 565  
                             }
 566  0
                             catch(IOException ioe)
 567  
                             {
 568  0
                                 throw new FacesException("Could not write the error page", ioe);
 569  0
                             }
 570  
                         }
 571  0
                         log.log(Level.SEVERE, "An exception occurred", ex);
 572  
 
 573  
                         // mark the response as complete
 574  0
                         facesContext.responseComplete();
 575  
 
 576  0
                         errorPageWritten = true;
 577  
                     }
 578  
                 }
 579  
             }
 580  
         }
 581  
 
 582  
         // rethrow the throwable, if we did not write the error page
 583  0
         if (!errorPageWritten)
 584  
         {
 585  0
             if (ex instanceof FacesException)
 586  
             {
 587  0
                 throw (FacesException) ex;
 588  
             }
 589  0
             if (ex instanceof RuntimeException)
 590  
             {
 591  0
                 throw (RuntimeException) ex;
 592  
             }
 593  0
             throw new FacesException(ex);
 594  
         }
 595  
 
 596  0
     }
 597  
 
 598  
     private static String _getErrorTemplate(FacesContext context)
 599  
     {
 600  0
         String errorTemplate = context.getExternalContext().getInitParameter(ERROR_TEMPLATE_RESOURCE);
 601  0
         if (errorTemplate != null)
 602  
         {
 603  0
             return errorTemplate;
 604  
         }
 605  0
         return ERROR_TEMPLATE;
 606  
     }
 607  
 
 608  
     private static String _getDebugTemplate(FacesContext context)
 609  
     {
 610  0
         String debugTemplate = context.getExternalContext().getInitParameter(DEBUG_TEMPLATE_RESOURCE);
 611  0
         if (debugTemplate != null)
 612  
         {
 613  0
             return debugTemplate;
 614  
         }
 615  0
         return DEBUG_TEMPLATE;
 616  
     }
 617  
 
 618  
     private static void _init(FacesContext context) throws IOException
 619  
     {
 620  0
         if (errorParts == null)
 621  
         {
 622  0
             errorParts = _splitTemplate(_getErrorTemplate(context));
 623  
         }
 624  
 
 625  0
         if (debugParts == null)
 626  
         {
 627  0
             debugParts = _splitTemplate(_getDebugTemplate(context));
 628  
         }
 629  0
     }
 630  
 
 631  
     private static String[] _splitTemplate(String rsc) throws IOException
 632  
     {
 633  0
         InputStream is = ClassUtils.getContextClassLoader().getResourceAsStream(rsc);
 634  0
         if (is == null)
 635  
         {
 636  
             // try to get the resource from ExternalContext
 637  0
             is = FacesContext.getCurrentInstance().getExternalContext().getResourceAsStream(rsc);
 638  0
             if (is == null)
 639  
             {
 640  
                 // fallback
 641  0
                 is = ErrorPageWriter.class.getClassLoader().getResourceAsStream(rsc);
 642  
             }
 643  
         }
 644  
 
 645  0
         if (is == null)
 646  
         {
 647  
             // throw an IllegalArgumentException instead of a FileNotFoundException,
 648  
             // because when using <ui:debug /> this error is hard to trace,
 649  
             // because the Exception is thrown in the Renderer and so it seems like
 650  
             // the facelet (or jsp) does not exist.
 651  0
             throw new IllegalArgumentException("Could not find resource " + rsc);
 652  
         }
 653  0
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
 654  0
         byte[] buff = new byte[512];
 655  
         int read;
 656  0
         while ((read = is.read(buff)) != -1)
 657  
         {
 658  0
             baos.write(buff, 0, read);
 659  
         }
 660  0
         String str = baos.toString();
 661  0
         return str.split("@@");
 662  
     }
 663  
 
 664  
     private static List<String> _getErrorId(Collection<UIComponent> components, Throwable... exs)
 665  
     {
 666  0
         List<String> list = null;
 667  0
         for (Throwable e : exs)
 668  
         {
 669  0
             String message = e.getMessage();
 670  
 
 671  0
             if (message == null)
 672  
             {
 673  0
                 continue;
 674  
             }
 675  
 
 676  0
             Pattern pattern = Pattern.compile(REGEX_PATTERN);
 677  0
             Matcher matcher = pattern.matcher(message);
 678  
 
 679  0
             while (matcher.find())
 680  
             {
 681  0
                 if (list == null)
 682  
                 {
 683  0
                     list = new ArrayList<String>();
 684  
                 }
 685  0
                 list.add(matcher.group(1));
 686  
             }
 687  
         }
 688  0
         if (list != null && list.size() > 0)
 689  
         {
 690  0
             return list;
 691  
         }
 692  0
         else if (components != null)
 693  
         {
 694  0
             list = new ArrayList<String>();
 695  0
             for (UIComponent uiComponent : components)
 696  
             {
 697  0
                 if (uiComponent  != null)
 698  
                 {
 699  0
                     list.add(uiComponent.getId());
 700  
                 }
 701  0
             }
 702  0
             return list;
 703  
         }
 704  0
         return null;
 705  
     }
 706  
 
 707  
     private static void _writeException(Writer writer, Throwable e) throws IOException
 708  
     {
 709  0
         StringWriter str = new StringWriter(256);
 710  0
         PrintWriter pstr = new PrintWriter(str);
 711  0
         e.printStackTrace(pstr);
 712  0
         pstr.close();
 713  0
         writer.write(str.toString().replaceAll("<", TS));
 714  0
     }
 715  
 
 716  
     private static void _writeCause(Writer writer, Throwable ex) throws IOException
 717  
     {
 718  0
         String msg = ex.getMessage();
 719  0
         String contextAwareLocation = null;
 720  0
         if (ex instanceof ContextAware)
 721  
         {
 722  0
             ContextAware caex = (ContextAware) ex;
 723  0
             contextAwareLocation = caex.getLocation().toString() + "    " +
 724  
                                    caex.getQName() + "=\"" +
 725  
                                    caex.getExpressionString() + "\"";
 726  
         }
 727  0
         while (ex.getCause() != null)
 728  
         {
 729  0
             ex = ex.getCause();
 730  0
             if (ex instanceof ContextAware)
 731  
             {
 732  0
                 ContextAware caex = (ContextAware) ex;
 733  0
                 contextAwareLocation = caex.getLocation().toString() + "    " +
 734  
                                        caex.getQName() + "=\"" +
 735  
                                        caex.getExpressionString() + "\"";
 736  
             }
 737  0
             if (ex.getMessage() != null)
 738  
             {
 739  0
                 msg = ex.getMessage();
 740  
             }
 741  
         }
 742  
 
 743  0
         if (msg != null)
 744  
         {
 745  0
             msg = ex.getClass().getName() + " - " + msg;
 746  0
             writer.write(msg.replaceAll("<", TS));
 747  
         }
 748  
         else
 749  
         {
 750  0
             writer.write(ex.getClass().getName());
 751  
         }
 752  0
         StackTraceElement stackTraceElement = ex.getStackTrace()[0];
 753  0
         writer.write("<br/> at " + stackTraceElement.toString());
 754  
 
 755  0
         if (contextAwareLocation != null)
 756  
         {
 757  0
             writer.write("<br/> <br/>");
 758  0
             writer.write(contextAwareLocation);
 759  0
             writer.write("<br/>");
 760  
         }
 761  0
     }
 762  
 
 763  
     private static void _writeVariables(Writer writer, FacesContext faces, UIViewRoot view) throws IOException
 764  
     {
 765  0
         ExternalContext ctx = faces.getExternalContext();
 766  0
         _writeVariables(writer, ctx.getRequestParameterMap(), "Request Parameters");
 767  0
         _writeVariables(writer, ctx.getRequestMap(), "Request Attributes");
 768  0
         if (view != null)
 769  
         {
 770  0
           _writeVariables(writer, view.getViewMap(), "View Attributes");
 771  
         }
 772  0
         if (ctx.getSession(false) != null)
 773  
         {
 774  0
             _writeVariables(writer, ctx.getSessionMap(), "Session Attributes");
 775  
         }
 776  0
         MyfacesConfig config = MyfacesConfig.getCurrentInstance(ctx);
 777  0
         if(config!=null && !config.isFlashScopeDisabled() && ctx.getFlash() != null)
 778  
         {
 779  0
             _writeVariables(writer, ctx.getFlash(), "Flash Attributes");
 780  
         }
 781  0
         _writeVariables(writer, ctx.getApplicationMap(), "Application Attributes");
 782  0
     }
 783  
 
 784  
     private static void _writeVariables(Writer writer, Map<String, ? extends Object> vars, String caption)
 785  
             throws IOException
 786  
     {
 787  0
         writer.write("<table><caption>");
 788  0
         writer.write(caption);
 789  0
         writer.write("</caption><thead><tr><th style=\"width: 10%; \">Name</th>"
 790  
                      + "<th style=\"width: 90%; \">Value</th></tr></thead><tbody>");
 791  0
         boolean written = false;
 792  0
         if (!vars.isEmpty())
 793  
         {
 794  0
             SortedMap<String, Object> sortedMap = new TreeMap<String, Object>(vars);
 795  0
             for (Map.Entry<String, Object> entry : sortedMap.entrySet())
 796  
             {
 797  0
                 String key = entry.getKey();
 798  0
                 if (key.indexOf('.') == -1)
 799  
                 {
 800  0
                     writer.write("<tr><td>");
 801  0
                     writer.write(key.replaceAll("<", TS));
 802  0
                     writer.write("</td><td>");
 803  0
                     Object value = entry.getValue();
 804  
                     // in some (very rare) situations value can be null or not null
 805  
                     // but with null toString() representation
 806  0
                     if (value != null && value.toString() != null)
 807  
                     {
 808  0
                         writer.write(value.toString().replaceAll("<", TS));
 809  
                     }
 810  
                     else
 811  
                     {
 812  0
                         writer.write("null");
 813  
                     }
 814  0
                     writer.write("</td></tr>");
 815  0
                     written = true;
 816  
                 }
 817  0
             }
 818  
         }
 819  0
         if (!written)
 820  
         {
 821  0
             writer.write("<tr><td colspan=\"2\"><em>None</em></td></tr>");
 822  
         }
 823  0
         writer.write("</tbody></table>");
 824  0
     }
 825  
 
 826  
     private static void _writeComponent(FacesContext faces, Writer writer, UIComponent c, List<String> highlightId,
 827  
                                         boolean writeChildren) throws IOException
 828  
     {
 829  0
         writer.write("<dl><dt");
 830  0
         if (_isText(c))
 831  
         {
 832  0
             writer.write(" class=\"uicText\"");
 833  
         }
 834  0
         if (highlightId != null)
 835  
         {
 836  0
             if ((highlightId.size() > 0))
 837  
             {
 838  0
                 String id = c.getId();
 839  0
                 if (highlightId.contains(id))
 840  
                 {
 841  0
                     writer.write(" class=\"highlightComponent\"");
 842  
                 }
 843  
             }
 844  
         }
 845  0
         writer.write(">");
 846  
 
 847  0
         boolean hasChildren = (c.getChildCount() > 0 || c.getFacetCount() > 0) && writeChildren;
 848  
 
 849  0
         int stateSize = 0;
 850  
 
 851  0
         Object state = c.saveState(faces);
 852  0
         if (state != null)
 853  
         {
 854  
             try
 855  
             {
 856  0
                 byte[] stateBytes = StateUtils.getAsByteArray(state, faces.getExternalContext());
 857  0
                 stateSize = stateBytes.length;
 858  
             }
 859  0
             catch (Exception e)
 860  
             {
 861  0
                 stateSize = -1;
 862  0
                 if (log.isLoggable(Level.FINEST))
 863  
                 {
 864  0
                     log.fine("Could not determine state size: " + e.getMessage());
 865  
                 }
 866  0
             }
 867  
         }
 868  0
         _writeStart(writer, c, hasChildren, true);
 869  0
         writer.write(" - State size:" + stateSize + " bytes");
 870  0
         writer.write("</dt>");
 871  0
         if (hasChildren)
 872  
         {
 873  0
             if (c.getFacetCount() > 0)
 874  
             {
 875  0
                 for (Map.Entry<String, UIComponent> entry : c.getFacets().entrySet())
 876  
                 {
 877  0
                     writer.write("<dd class=\"uicFacet\">");
 878  0
                     writer.write("<span>");
 879  0
                     writer.write(entry.getKey());
 880  0
                     writer.write("</span>");
 881  0
                     _writeComponent(faces, writer, entry.getValue(), highlightId, true);
 882  0
                     writer.write("</dd>");
 883  0
                 }
 884  
             }
 885  0
             if (c.getChildCount() > 0)
 886  
             {
 887  0
                 for (int i = 0, childCount = c.getChildCount(); i < childCount; i++)
 888  
                 {
 889  0
                     UIComponent child = c.getChildren().get(i);
 890  0
                     writer.write("<dd>");
 891  0
                     _writeComponent(faces, writer, child, highlightId, writeChildren);
 892  0
                     writer.write("</dd>");
 893  
                 }
 894  
             }
 895  0
             writer.write("<dt>");
 896  0
             _writeEnd(writer, c);
 897  0
             writer.write("</dt>");
 898  
         }
 899  0
         writer.write("</dl>");
 900  0
     }
 901  
 
 902  
     /**
 903  
      * Creates the Extended Component Tree via UIViewRoot.visitTree()
 904  
      * and ExtendedComponentTreeVisitCallback as VisitCallback.
 905  
      *
 906  
      * @param writer
 907  
      * @param facesContext
 908  
      * @throws IOException
 909  
      */
 910  
     private static void _writeExtendedComponentTree(Writer writer,
 911  
             FacesContext facesContext) throws IOException
 912  
     {
 913  0
         VisitContext visitContext = VisitContext.createVisitContext(
 914  
                 facesContext, null, EnumSet.of(VisitHint.SKIP_UNRENDERED));
 915  0
         facesContext.getViewRoot().visitTree(visitContext, new ExtendedComponentTreeVisitCallback(writer));
 916  0
         _clearVisitedFacetCountMap(facesContext);
 917  0
     }
 918  
 
 919  
     /**
 920  
      * The VisitCallback that is used to create the Extended Component Tree.
 921  
      *
 922  
      * @author Jakob Korherr
 923  
      */
 924  
     private static class ExtendedComponentTreeVisitCallback implements VisitCallback
 925  
     {
 926  
 
 927  
         private Writer _writer;
 928  
 
 929  
         public ExtendedComponentTreeVisitCallback(Writer writer)
 930  0
         {
 931  0
             _writer = writer;
 932  0
         }
 933  
 
 934  
         @SuppressWarnings("unchecked")
 935  
         public VisitResult visit(VisitContext context, UIComponent target)
 936  
         {
 937  0
             final Map<String, Object> requestMap = context.getFacesContext()
 938  
                     .getExternalContext().getRequestMap();
 939  
 
 940  
             try
 941  
             {
 942  0
                 if (!(target instanceof UIViewRoot))
 943  
                 {
 944  0
                     _writer.write("<dd>");
 945  
                 }
 946  
 
 947  0
                 UIComponent parent = target.getParent();
 948  0
                 boolean hasChildren = (target.getChildCount() > 0 || target.getFacetCount() > 0);
 949  0
                 String facetName = _getFacetName(target);
 950  
 
 951  0
                 if (!(target instanceof UIColumn))
 952  
                 {
 953  0
                     if (parent instanceof UIColumn
 954  
                             && ((parent.getChildCount() > 0 && parent.getChildren().get(0) == target)
 955  
                                     ||  (facetName != null &&
 956  
                                             _getVisitedFacetCount(context.getFacesContext(), parent) == 0)))
 957  
                     {
 958  0
                         if (parent.getParent() instanceof UIData
 959  
                                 && _isFirstUIColumn(parent.getParent(), (UIColumn) parent))
 960  
                         {
 961  0
                             _writer.write("<span>Row: ");
 962  0
                             int rowIndex = ((UIData) parent.getParent()).getRowIndex();
 963  0
                             _writer.write("" + rowIndex);
 964  0
                             if (rowIndex == -1)
 965  
                             {
 966  
                                 // tell the user that rowIndex == -1 stands for visiting column-facets
 967  0
                                 _writer.write(" (all column facets)");
 968  
                             }
 969  0
                             _writer.write("</span>");
 970  
                         }
 971  0
                         _writer.write("<dl><dt>");
 972  0
                         _writeStart(_writer, parent, true, false);
 973  0
                         _writer.write("</dt><dd>");
 974  
                     }
 975  
 
 976  0
                     if (facetName != null)
 977  
                     {
 978  0
                         _writer.write("<span>" + facetName + "</span>");
 979  0
                         _incrementVisitedFacetCount(context.getFacesContext(), parent);
 980  
                     }
 981  0
                     _writer.write("<dl><dt");
 982  0
                     if (_isText(target))
 983  
                     {
 984  0
                         _writer.write(" class=\"uicText\"");
 985  
                     }
 986  0
                     _writer.write(">");
 987  
 
 988  0
                     Map<String, List<Object[]>> debugInfos = null;
 989  
                     // is the target a EditableValueHolder component?
 990  
                     // If so, debug infos from DebugPhaseListener should be available
 991  0
                     if (target instanceof EditableValueHolder)
 992  
                     {
 993  
                         // get the debug info
 994  0
                         debugInfos = (Map<String, List<Object[]>>) requestMap
 995  
                                 .get(DEBUG_INFO_KEY + target.getClientId());
 996  
                     }
 997  
 
 998  
                     // Get the component's renderer.
 999  
                     // Note that getRenderer(FacesContext context) is definded in UIComponent,
 1000  
                     // but it is protected, so we have to use reflection!
 1001  0
                     Renderer renderer = null;
 1002  
                     try
 1003  
                     {
 1004  0
                         Method getRenderer = UIComponent.class.getDeclaredMethod(
 1005  
                                 "getRenderer", FacesContext.class);
 1006  
                         // make it accessible for us!
 1007  0
                         getRenderer.setAccessible(true);
 1008  0
                         renderer = (Renderer) getRenderer.invoke(target, context.getFacesContext());
 1009  
                     }
 1010  0
                     catch (Exception e)
 1011  
                     {
 1012  
                         // nothing - do not output renderer information
 1013  0
                     }
 1014  
 
 1015  
                     // write the component start
 1016  0
                     _writeStart(_writer, target, (hasChildren || debugInfos != null || renderer != null), false);
 1017  0
                     _writer.write("</dt>");
 1018  
 
 1019  0
                     if (renderer != null)
 1020  
                     {
 1021  
                         // write renderer info
 1022  0
                         _writer.write("<div class=\"renderer\">Rendered by ");
 1023  0
                         _writer.write(renderer.getClass().getCanonicalName());
 1024  0
                         _writer.write("</div>");
 1025  
 
 1026  0
                         if (!hasChildren && debugInfos == null)
 1027  
                         {
 1028  
                             // close the component
 1029  0
                             _writer.write("<dt>");
 1030  0
                             _writeEnd(_writer, target);
 1031  0
                             _writer.write("</dt>");
 1032  
                         }
 1033  
                     }
 1034  
 
 1035  0
                     if (debugInfos != null)
 1036  
                     {
 1037  0
                         final String fieldid = target.getClientId() + "_lifecycle";
 1038  0
                         _writer.write("<div class=\"lifecycle_values_wrapper\">");
 1039  0
                         _writer.write("<a href=\"#\" onclick=\"toggle('");
 1040  0
                         _writer.write(fieldid);
 1041  0
                         _writer.write("'); return false;\"><span id=\"");
 1042  0
                         _writer.write(fieldid);
 1043  0
                         _writer.write("Off\">+</span><span id=\"");
 1044  0
                         _writer.write(fieldid);
 1045  0
                         _writer.write("On\" style=\"display: none;\">-</span> Value Lifecycle</a>");
 1046  0
                         _writer.write("<div id=\"");
 1047  0
                         _writer.write(fieldid);
 1048  0
                         _writer.write("\" class=\"lifecycle_values\">");
 1049  
 
 1050  
                         // process any available debug info
 1051  0
                         for (Map.Entry<String, List<Object[]>> entry : debugInfos.entrySet())
 1052  
                         {
 1053  0
                             _writer.write("<span>");
 1054  0
                             _writer.write(entry.getKey());
 1055  0
                             _writer.write("</span><ol>");
 1056  0
                             int i = 0;
 1057  0
                             for (Object[] debugInfo : entry.getValue())
 1058  
                             {
 1059  
                                 // structure of the debug-info array:
 1060  
                                 //     - 0: phase
 1061  
                                 //     - 1: old value
 1062  
                                 //     - 2: new value
 1063  
                                 //     - 3: StackTraceElement List
 1064  
 
 1065  
                                 // oldValue and newValue could be null
 1066  0
                                 String oldValue = debugInfo[1] == null ? "null" : debugInfo[1].toString();
 1067  0
                                 String newValue = debugInfo[2] == null ? "null" : debugInfo[2].toString();
 1068  0
                                 _writer.write("<li><b>");
 1069  0
                                 _writer.write(entry.getKey());
 1070  0
                                 _writer.write("</b> set from <b>");
 1071  0
                                 _writer.write(oldValue);
 1072  0
                                 _writer.write("</b> to <b>");
 1073  0
                                 _writer.write(newValue);
 1074  0
                                 _writer.write("</b> in Phase ");
 1075  0
                                 _writer.write(debugInfo[0].toString());
 1076  
 
 1077  
                                 // check if a call stack is available
 1078  0
                                 if (debugInfo[3] != null)
 1079  
                                 {
 1080  0
                                     final String stackTraceId = fieldid + "_" + entry.getKey() + "_" + i;
 1081  0
                                     _writer.write("<div class=\"stacktrace_wrapper\">");
 1082  0
                                     _writer.write("<a href=\"#\" onclick=\"toggle('");
 1083  0
                                     _writer.write(stackTraceId);
 1084  0
                                     _writer.write("'); return false;\"><span id=\"");
 1085  0
                                     _writer.write(stackTraceId);
 1086  0
                                     _writer.write("Off\">+</span><span id=\"");
 1087  0
                                     _writer.write(stackTraceId);
 1088  0
                                     _writer.write("On\" style=\"display: none;\">-</span> Call Stack</a>");
 1089  0
                                     _writer.write("<div id=\"");
 1090  0
                                     _writer.write(stackTraceId);
 1091  0
                                     _writer.write("\" class=\"stacktrace_values\">");
 1092  0
                                     _writer.write("<ul>");
 1093  
                                     for (StackTraceElement stackTraceElement
 1094  0
                                             : (List<StackTraceElement>) debugInfo[3])
 1095  
                                     {
 1096  0
                                         _writer.write("<li>");
 1097  0
                                         _writer.write(stackTraceElement.toString());
 1098  0
                                         _writer.write("</li>");
 1099  0
                                     }
 1100  0
                                     _writer.write("</ul></div></div>");
 1101  
                                 }
 1102  
 
 1103  0
                                 _writer.write("</li>");
 1104  
 
 1105  0
                                 i++;
 1106  0
                             }
 1107  0
                             _writer.write("</ol>");
 1108  0
                         }
 1109  
 
 1110  0
                         _writer.write("</div></div>");
 1111  
 
 1112  
                         // now remove the debug info from the request map, 
 1113  
                         // so that it does not appear in the scope values of the debug page 
 1114  0
                         requestMap.remove(DEBUG_INFO_KEY + target.getClientId());
 1115  
 
 1116  0
                         if (!hasChildren)
 1117  
                         {
 1118  
                             // close the component
 1119  0
                             _writer.write("<dt>");
 1120  0
                             _writeEnd(_writer, target);
 1121  0
                             _writer.write("</dt>");
 1122  
                         }
 1123  
                     }
 1124  
                 }
 1125  
 
 1126  0
                 if (!hasChildren)
 1127  
                 {
 1128  0
                     _writer.write("</dl>");
 1129  
 
 1130  0
                     while (parent != null &&
 1131  
                            ((parent.getChildCount()>0 && parent.getChildren().get(parent.getChildCount()-1) == target)
 1132  
                                     || (parent.getFacetCount() != 0
 1133  
                                             && _getVisitedFacetCount(context.getFacesContext(), parent) == 
 1134  
                                                     parent.getFacetCount())))
 1135  
                     {
 1136  
                         // target is last child of parent or the "last" facet
 1137  
 
 1138  
                         // remove the visited facet count from the attribute map
 1139  0
                         _removeVisitedFacetCount(context.getFacesContext(), parent);
 1140  
 
 1141  
                         // check for componentes that visit their children multiple times
 1142  0
                         if (parent instanceof UIData)
 1143  
                         {
 1144  0
                             UIData uidata = (UIData) parent;
 1145  0
                             if (uidata.getRowIndex() != uidata.getRowCount() - 1)
 1146  
                             {
 1147  
                                 // only continue if we're in the last row
 1148  0
                                 break;
 1149  
                             }
 1150  0
                         }
 1151  0
                         else if (parent instanceof UIRepeat)
 1152  
                         {
 1153  0
                             UIRepeat uirepeat = (UIRepeat) parent;
 1154  0
                             if (uirepeat.getIndex() + uirepeat.getStep() < uirepeat.getRowCount())
 1155  
                             {
 1156  
                                 // only continue if we're in the last row
 1157  0
                                 break;
 1158  
                             }
 1159  
                         }
 1160  
 
 1161  0
                         _writer.write("</dd><dt>");
 1162  0
                         _writeEnd(_writer, parent);
 1163  0
                         _writer.write("</dt></dl>");
 1164  
 
 1165  0
                         if (!(parent instanceof UIViewRoot))
 1166  
                         {
 1167  0
                             _writer.write("</dd>");
 1168  
                         }
 1169  
 
 1170  0
                         target = parent;
 1171  0
                         parent = target.getParent();
 1172  
                     }
 1173  
                 }
 1174  
             }
 1175  0
             catch (IOException ioe)
 1176  
             {
 1177  0
                 throw new FacesException(ioe);
 1178  0
             }
 1179  
 
 1180  0
             return VisitResult.ACCEPT;
 1181  
         }
 1182  
 
 1183  
     }
 1184  
 
 1185  
     private static boolean _isFirstUIColumn(UIComponent uidata, UIColumn uicolumn)
 1186  
     {
 1187  0
         for (int i = 0, childCount = uidata.getChildCount(); i < childCount; i++)
 1188  
         {
 1189  0
             UIComponent child = uidata.getChildren().get(i);
 1190  0
             if (child instanceof UIColumn)
 1191  
             {
 1192  0
                 return (child == uicolumn);
 1193  
             }
 1194  
         }
 1195  0
         return false;
 1196  
     }
 1197  
 
 1198  
     private static String _getFacetName(UIComponent component)
 1199  
     {
 1200  0
         UIComponent parent = component.getParent();
 1201  0
         if (parent != null)
 1202  
         {
 1203  0
             if (parent.getFacetCount() > 0)
 1204  
             {
 1205  0
                 for (Map.Entry<String, UIComponent> entry : parent.getFacets().entrySet())
 1206  
                 {
 1207  0
                     if (entry.getValue() == component)
 1208  
                     {
 1209  0
                         return entry.getKey();
 1210  
                     }
 1211  0
                 }
 1212  
             }
 1213  
         }
 1214  0
         return null;
 1215  
     }
 1216  
 
 1217  
     private static int _getVisitedFacetCount(FacesContext facesContext, UIComponent component)
 1218  
     {
 1219  0
         Map<UIComponent, Integer> visitedFacetCount = (Map<UIComponent, Integer>)
 1220  
             facesContext.getAttributes().get(VISITED_FACET_COUNT_KEY);
 1221  0
         if (visitedFacetCount == null)
 1222  
         {
 1223  0
             return 0;
 1224  
         }
 1225  0
         Integer count = visitedFacetCount.get(component);
 1226  0
         if (count != null)
 1227  
         {
 1228  0
             return count;
 1229  
         }
 1230  0
         return 0;
 1231  
     }
 1232  
 
 1233  
     private static void _incrementVisitedFacetCount(FacesContext facesContext, UIComponent component)
 1234  
     {
 1235  0
         Map<UIComponent, Integer> visitedFacetCount = (Map<UIComponent, Integer>)
 1236  
             facesContext.getAttributes().get(VISITED_FACET_COUNT_KEY);
 1237  0
         if (visitedFacetCount == null)
 1238  
         {
 1239  0
             visitedFacetCount = new HashMap<UIComponent, Integer>();
 1240  0
             facesContext.getAttributes().put(VISITED_FACET_COUNT_KEY, visitedFacetCount);
 1241  
         }
 1242  0
         visitedFacetCount.put(component, _getVisitedFacetCount(facesContext, component) + 1);
 1243  0
     }
 1244  
 
 1245  
     private static void _removeVisitedFacetCount(FacesContext facesContext, UIComponent component)
 1246  
     {
 1247  0
         Map<UIComponent, Integer> visitedFacetCount = (Map<UIComponent, Integer>)
 1248  
             facesContext.getAttributes().get(VISITED_FACET_COUNT_KEY);
 1249  0
         if (visitedFacetCount == null)
 1250  
         {
 1251  0
             return;
 1252  
         }
 1253  0
         visitedFacetCount.remove(component);
 1254  0
     }
 1255  
     
 1256  
     private static void _clearVisitedFacetCountMap(FacesContext facesContext)
 1257  
     {
 1258  0
         Map<UIComponent, Integer> visitedFacetCount = (Map<UIComponent, Integer>)
 1259  
             facesContext.getAttributes().get(VISITED_FACET_COUNT_KEY);
 1260  0
         if (visitedFacetCount != null)
 1261  
         {
 1262  0
             visitedFacetCount.clear();
 1263  0
             facesContext.getAttributes().remove(VISITED_FACET_COUNT_KEY);
 1264  
         }
 1265  0
     }
 1266  
 
 1267  
     private static void _writeEnd(Writer writer, UIComponent c) throws IOException
 1268  
     {
 1269  0
         if (!_isText(c))
 1270  
         {
 1271  0
             writer.write(TS);
 1272  0
             writer.write('/');
 1273  0
             writer.write(_getName(c));
 1274  0
             writer.write('>');
 1275  
         }
 1276  0
     }
 1277  
 
 1278  
     private static void _writeAttributes(Writer writer, UIComponent c, boolean valueExpressionValues)
 1279  
     {
 1280  
         try
 1281  
         {
 1282  0
             BeanInfo info = Introspector.getBeanInfo(c.getClass());
 1283  0
             PropertyDescriptor[] pd = info.getPropertyDescriptors();
 1284  0
             Method m = null;
 1285  0
             Object v = null;
 1286  0
             ValueExpression valueExpression = null;
 1287  0
             String str = null;
 1288  0
             for (int i = 0; i < pd.length; i++)
 1289  
             {
 1290  0
                 if ((pd[i].getWriteMethod() != null || Arrays.binarySearch(ALWAYS_WRITE, pd[i].getName()) > -1)
 1291  
                     && Arrays.binarySearch(IGNORE, pd[i].getName()) < 0)
 1292  
                 {
 1293  0
                     m = pd[i].getReadMethod();
 1294  0
                     if (m != null)
 1295  
                     {
 1296  
                         try
 1297  
                         {
 1298  
                             // first check if the property is a ValueExpression
 1299  0
                             valueExpression = c.getValueExpression(pd[i].getName());
 1300  0
                             if (valueExpressionValues && valueExpression != null)
 1301  
                             {
 1302  0
                                 String expressionString = valueExpression.getExpressionString();
 1303  0
                                 if (null == expressionString)
 1304  
                                 {
 1305  0
                                     expressionString = "";
 1306  
                                 }
 1307  0
                                 _writeAttribute(writer, pd[i].getName(), expressionString);
 1308  0
                             }
 1309  
                             else
 1310  
                             {
 1311  0
                                 v = m.invoke(c, null);
 1312  0
                                 if (v != null)
 1313  
                                 {
 1314  0
                                     if (v instanceof Collection || v instanceof Map || v instanceof Iterator)
 1315  
                                     {
 1316  0
                                         continue;
 1317  
                                     }
 1318  0
                                     if (v instanceof Expression)
 1319  
                                     {
 1320  0
                                         str = ((Expression)v).getExpressionString();
 1321  
                                     }
 1322  0
                                     else if (v instanceof ValueBinding)
 1323  
                                     {
 1324  0
                                         str = ((ValueBinding) v).getExpressionString();
 1325  
                                     }
 1326  0
                                     else if (v instanceof MethodBinding)
 1327  
                                     {
 1328  0
                                         str = ((MethodBinding) v).getExpressionString();
 1329  
                                     }
 1330  
                                     else
 1331  
                                     {
 1332  0
                                         str = v.toString();
 1333  
                                     }
 1334  
 
 1335  0
                                     _writeAttribute(writer, pd[i].getName(), str);
 1336  
                                 }
 1337  
                             }
 1338  
                         }
 1339  0
                         catch (Exception e)
 1340  
                         {
 1341  
                             // do nothing
 1342  0
                         }
 1343  
                     }
 1344  
                 }
 1345  
             }
 1346  
 
 1347  0
             ValueExpression binding = c.getValueExpression("binding");
 1348  0
             if (binding != null)
 1349  
             {
 1350  0
                 _writeAttribute(writer, "binding", binding.getExpressionString());
 1351  
             }
 1352  
 
 1353  
             // write the location
 1354  0
             String location = _getComponentLocation(c);
 1355  0
             if (location != null)
 1356  
             {
 1357  0
                 _writeAttribute(writer, "location", location);
 1358  
             }
 1359  
         }
 1360  0
         catch (Exception e)
 1361  
         {
 1362  
             // do nothing
 1363  0
         }
 1364  0
     }
 1365  
 
 1366  
     private static void _writeAttribute(Writer writer, String name, String value) throws IOException
 1367  
     {
 1368  0
         writer.write(" ");
 1369  0
         writer.write(name);
 1370  0
         writer.write("=\"");
 1371  0
         writer.write(value.replaceAll("<", TS));
 1372  0
         writer.write("\"");
 1373  0
     }
 1374  
 
 1375  
     private static void _writeStart(Writer writer, UIComponent c,
 1376  
             boolean children, boolean valueExpressionValues) throws IOException
 1377  
     {
 1378  0
         if (_isText(c))
 1379  
         {
 1380  0
             String str = c.toString().trim();
 1381  0
             writer.write(str.replaceAll("<", TS));
 1382  0
         }
 1383  
         else
 1384  
         {
 1385  0
             writer.write(TS);
 1386  0
             writer.write(_getName(c));
 1387  0
             _writeAttributes(writer, c, valueExpressionValues);
 1388  0
             if (children)
 1389  
             {
 1390  0
                 writer.write('>');
 1391  
             }
 1392  
             else
 1393  
             {
 1394  0
                 writer.write("/>");
 1395  
             }
 1396  
         }
 1397  0
     }
 1398  
 
 1399  
     private static String _getName(UIComponent c)
 1400  
     {
 1401  0
         String nm = c.getClass().getName();
 1402  0
         return nm.substring(nm.lastIndexOf('.') + 1);
 1403  
     }
 1404  
 
 1405  
     private static boolean _isText(UIComponent c)
 1406  
     {
 1407  0
         return (c.getClass().getName().startsWith("org.apache.myfaces.view.facelets.compiler"));
 1408  
     }
 1409  
 
 1410  
     private static void _prepareExceptionStack(Throwable ex)
 1411  
     {
 1412  
 
 1413  0
         if (ex == null)
 1414  
         {
 1415  0
             return;
 1416  
         }
 1417  
 
 1418  
         // check for getRootCause and getCause-methods
 1419  0
         if (!_initCausePerReflection(ex, "getRootCause"))
 1420  
         {
 1421  0
             _initCausePerReflection(ex, "getCause");
 1422  
         }
 1423  
 
 1424  0
         _prepareExceptionStack(ex.getCause());
 1425  0
     }
 1426  
 
 1427  
     private static boolean _initCausePerReflection(Throwable ex, String methodName)
 1428  
     {
 1429  
         try
 1430  
         {
 1431  0
             Method causeGetter = ex.getClass().getMethod(methodName, (Class[])null);
 1432  0
             Throwable rootCause = (Throwable)causeGetter.invoke(ex, (Object[])null);
 1433  0
             return _initCauseIfAvailable(ex, rootCause);
 1434  
         }
 1435  0
         catch (Exception e1)
 1436  
         {
 1437  0
             return false;
 1438  
         }
 1439  
     }
 1440  
 
 1441  
     private static boolean _initCauseIfAvailable(Throwable th, Throwable cause)
 1442  
     {
 1443  0
         if (cause == null)
 1444  
         {
 1445  0
             return false;
 1446  
         }
 1447  
 
 1448  
         try
 1449  
         {
 1450  0
             Method m = Throwable.class.getMethod("initCause", new Class[] { Throwable.class });
 1451  0
             m.invoke(th, new Object[] { cause });
 1452  0
             return true;
 1453  
         }
 1454  0
         catch (Exception e)
 1455  
         {
 1456  0
             return false;
 1457  
         }
 1458  
     }
 1459  
 
 1460  
     /**
 1461  
      * Gets the Location of the given UIComponent from its attribute map.
 1462  
      * @param component
 1463  
      * @return
 1464  
      */
 1465  
     private static String _getComponentLocation(UIComponent component)
 1466  
     {
 1467  0
         Location location = (Location) component.getAttributes()
 1468  
                 .get(UIComponent.VIEW_LOCATION_KEY);
 1469  0
         if (location != null)
 1470  
         {
 1471  0
             return location.toString();
 1472  
         }
 1473  0
         return null;
 1474  
     }
 1475  
 }