Coverage Report - javax.faces.webapp.PreJsf2ExceptionHandlerFactory
 
Classes in this File Line Coverage Branch Coverage Complexity
PreJsf2ExceptionHandlerFactory
0%
0/3
N/A
3.154
PreJsf2ExceptionHandlerFactory$PreJsf2ExceptionHandlerImpl
0%
0/58
0%
0/44
3.154
 
 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 javax.faces.webapp;
 20  
 
 21  
 import java.util.Collections;
 22  
 import java.util.LinkedList;
 23  
 import java.util.Queue;
 24  
 import java.util.logging.Level;
 25  
 import java.util.logging.Logger;
 26  
 
 27  
 import javax.el.ELException;
 28  
 import javax.faces.FacesException;
 29  
 import javax.faces.application.FacesMessage;
 30  
 import javax.faces.component.UIComponent;
 31  
 import javax.faces.component.UpdateModelException;
 32  
 import javax.faces.context.ExceptionHandler;
 33  
 import javax.faces.context.ExceptionHandlerFactory;
 34  
 import javax.faces.event.AbortProcessingException;
 35  
 import javax.faces.event.ExceptionQueuedEvent;
 36  
 import javax.faces.event.ExceptionQueuedEventContext;
 37  
 import javax.faces.event.SystemEvent;
 38  
 
 39  
 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
 40  
 
 41  
 /**
 42  
  * @since 2.0
 43  
  */
 44  
 public class PreJsf2ExceptionHandlerFactory extends ExceptionHandlerFactory
 45  
 {
 46  
     
 47  
     public PreJsf2ExceptionHandlerFactory()
 48  0
     {
 49  0
     }
 50  
 
 51  
     /**
 52  
      * {@inheritDoc}
 53  
      */
 54  
     @Override
 55  
     public ExceptionHandler getExceptionHandler()
 56  
     {
 57  0
         return new PreJsf2ExceptionHandlerImpl();
 58  
     }
 59  
     
 60  
     private static class PreJsf2ExceptionHandlerImpl extends ExceptionHandler
 61  
     {
 62  
         /*
 63  
          * PLEASE NOTE!!!
 64  
          * This is a copy of the ExceptionHandler implementation of myfaces-impl
 65  
          * (org.apache.myfaces.context.ExceptionHandlerImpl), only handle() differs a bit.
 66  
          * Any changes made here should also be applied to ExceptionHandlerImpl in the right way.
 67  
          * 
 68  
          * This is really ugly, but I think we have to do this due to the fact that PreJsf2ExceptionHandlerFactory
 69  
          * can be declared directly as an exception handler factory, so it's not as if we can make the methods
 70  
          * in the factory abstract and have a concrete impl in the impl project (and therefore be able to
 71  
          * extend ExceptionHandlerImpl).  If this is not the case, please change accordingly.
 72  
          */
 73  
         
 74  0
         private static final Logger log = Logger.getLogger(PreJsf2ExceptionHandlerImpl.class.getName());
 75  
         
 76  
         /**
 77  
          * Since JSF 2.0 there is a standard way to deal with unexpected Exceptions: the ExceptionHandler.
 78  
          * Due to backwards compatibility MyFaces 2.0 also supports the init parameter 
 79  
          * org.apache.myfaces.ERROR_HANDLER, introduced in MyFaces 1.2.4. However, the given error handler
 80  
          * now only needs to include the following method:
 81  
          * <ul>
 82  
          * <li>handleException(FacesContext fc, Exception ex)</li>
 83  
          * </ul>
 84  
          * Furthermore, the init parameter only works when using the PreJsf2ExceptionHandlerFactory.
 85  
          * 
 86  
          * @deprecated
 87  
          */
 88  
         @Deprecated
 89  
         @JSFWebConfigParam(since="1.2.4",desc="Deprecated: use JSF 2.0 ExceptionHandler", deprecated=true)
 90  
         private static final String ERROR_HANDLER_PARAMETER = "org.apache.myfaces.ERROR_HANDLER";
 91  
         
 92  
         private Queue<ExceptionQueuedEvent> handled;
 93  
         private Queue<ExceptionQueuedEvent> unhandled;
 94  
         private ExceptionQueuedEvent handledAndThrown;
 95  
 
 96  
         public PreJsf2ExceptionHandlerImpl()
 97  0
         {
 98  0
         }
 99  
         
 100  
         /**
 101  
          * {@inheritDoc}
 102  
          */
 103  
         @Override
 104  
         public ExceptionQueuedEvent getHandledExceptionQueuedEvent()
 105  
         {
 106  0
             return handledAndThrown;
 107  
         }
 108  
 
 109  
         /**
 110  
          * {@inheritDoc}
 111  
          */
 112  
         @Override
 113  
         public Iterable<ExceptionQueuedEvent> getHandledExceptionQueuedEvents()
 114  
         {
 115  0
             return handled == null ? Collections.<ExceptionQueuedEvent>emptyList() : handled;
 116  
         }
 117  
 
 118  
         /**
 119  
          * {@inheritDoc}
 120  
          */
 121  
         @Override
 122  
         public Throwable getRootCause(Throwable t)
 123  
         {
 124  0
             if (t == null)
 125  
             {
 126  0
                 throw new NullPointerException("t");
 127  
             }
 128  
             
 129  0
             while (t != null)
 130  
             {
 131  0
                 Class<?> clazz = t.getClass();
 132  0
                 if (!clazz.equals(FacesException.class) && !clazz.equals(ELException.class))
 133  
                 {
 134  0
                     return t;
 135  
                 }
 136  
                 
 137  0
                 t = t.getCause();
 138  0
             }
 139  
             
 140  0
             return null;
 141  
         }
 142  
 
 143  
         /**
 144  
          * {@inheritDoc}
 145  
          */
 146  
         @Override
 147  
         public Iterable<ExceptionQueuedEvent> getUnhandledExceptionQueuedEvents()
 148  
         {
 149  0
             return unhandled == null ? Collections.<ExceptionQueuedEvent>emptyList() : unhandled;
 150  
         }
 151  
 
 152  
         /**
 153  
          * {@inheritDoc}
 154  
          * 
 155  
          * Differs from ExceptionHandlerImpl.handle() in three points:
 156  
          *  - Any exceptions thrown before or after phase execution will be logged and swallowed.
 157  
          *  - If the Exception is an instance of UpdateModelException, extract the
 158  
          *  FacesMessage from the UpdateModelException.
 159  
          *    Log a SEVERE message to the log and queue the FacesMessage on the
 160  
          *    FacesContext, using the clientId of the source
 161  
          *    component in a call to FacesContext.addMessage(java.lang.String, javax.faces.application.FacesMessage).
 162  
          *  - Checks org.apache.myfaces.ERROR_HANDLER for backwards compatibility to myfaces-1.2's error handling
 163  
          */
 164  
         @Override
 165  
         public void handle() throws FacesException
 166  
         {
 167  0
             if (unhandled != null && !unhandled.isEmpty())
 168  
             {
 169  0
                 if (handled == null)
 170  
                 {
 171  0
                     handled = new LinkedList<ExceptionQueuedEvent>();
 172  
                 }
 173  
                 
 174  0
                 FacesException toThrow = null;
 175  
                 
 176  
                 do
 177  
                 {
 178  
                     // For each ExceptionEvent in the list
 179  
                     
 180  
                     // get the event to handle
 181  0
                     ExceptionQueuedEvent event = unhandled.peek();
 182  
                     try
 183  
                     {
 184  
                         // call its getContext() method
 185  0
                         ExceptionQueuedEventContext context = event.getContext();
 186  
                         
 187  
                         // and call getException() on the returned result
 188  0
                         Throwable exception = context.getException();
 189  
 
 190  
                         // spec described behaviour of PreJsf2ExceptionHandler
 191  
 
 192  
                         // UpdateModelException needs special treatment here
 193  0
                         if (exception instanceof UpdateModelException)
 194  
                         {
 195  0
                             FacesMessage message = ((UpdateModelException) exception).getFacesMessage();
 196  
                             // Log a SEVERE message to the log
 197  0
                             log.log(Level.SEVERE, message.getSummary(), exception.getCause());
 198  
                             // queue the FacesMessage on the FacesContext
 199  0
                             UIComponent component = context.getComponent();
 200  0
                             String clientId = null;
 201  0
                             if (component != null)
 202  
                             {
 203  0
                                 clientId = component.getClientId(context.getContext());
 204  
                             }
 205  0
                             context.getContext().addMessage(clientId, message);
 206  0
                         }
 207  0
                         else if (!shouldSkip(exception) && !context.inBeforePhase() && !context.inAfterPhase())
 208  
                         {
 209  
                             // set handledAndThrown so that getHandledExceptionQueuedEvent() returns this event
 210  0
                             handledAndThrown = event;
 211  
 
 212  
                             // Re-wrap toThrow in a ServletException or
 213  
                             // (PortletException, if in a portlet environment)
 214  
                             // and throw it
 215  
                             // FIXME: The spec says to NOT use a FacesException
 216  
                             // to propagate the exception, but I see
 217  
                             //        no other way as ServletException is not a RuntimeException
 218  0
                             toThrow = wrap(getRethrownException(exception));
 219  
                             break;
 220  
                         }
 221  
                         else
 222  
                         {
 223  
                             // Testing mojarra it logs a message and the exception
 224  
                             // however, this behaviour is not mentioned in the spec
 225  0
                             log.log(Level.SEVERE, exception.getClass().getName() + " occured while processing " +
 226  
                                     (context.inBeforePhase() ? "beforePhase() of " : 
 227  
                                             (context.inAfterPhase() ? "afterPhase() of " : "")) + 
 228  
                                     "phase " + context.getPhaseId() + ": " +
 229  
                                     "UIComponent-ClientId=" + 
 230  
                                     (context.getComponent() != null ? 
 231  
                                             context.getComponent().getClientId(context.getContext()) : "") + ", " +
 232  
                                     "Message=" + exception.getMessage());
 233  
 
 234  0
                             log.log(Level.SEVERE, exception.getMessage(), exception);
 235  
                         }
 236  
                     }
 237  0
                     catch (Throwable t)
 238  
                     {
 239  
                         // A FacesException must be thrown if a problem occurs while performing
 240  
                         // the algorithm to handle the exception
 241  0
                         throw new FacesException("Could not perform the algorithm to handle the Exception", t);
 242  
                     }
 243  
                     finally
 244  
                     {
 245  
                         // if we will throw the Exception or if we just logged it,
 246  
                         // we handled it in either way --> add to handled
 247  0
                         handled.add(event);
 248  0
                         unhandled.remove(event);
 249  0
                     }
 250  0
                 } while (!unhandled.isEmpty());
 251  
                 
 252  
                 // do we have to throw an Exception?
 253  0
                 if (toThrow != null)
 254  
                 {
 255  0
                     throw toThrow;
 256  
                 }
 257  
             }
 258  0
         }
 259  
 
 260  
         /**
 261  
          * {@inheritDoc}
 262  
          */
 263  
         @Override
 264  
         public boolean isListenerForSource(Object source)
 265  
         {
 266  0
             return source instanceof ExceptionQueuedEventContext;
 267  
         }
 268  
 
 269  
         /**
 270  
          * {@inheritDoc}
 271  
          */
 272  
         @Override
 273  
         public void processEvent(SystemEvent exceptionQueuedEvent) throws AbortProcessingException
 274  
         {
 275  0
             if (unhandled == null)
 276  
             {
 277  0
                 unhandled = new LinkedList<ExceptionQueuedEvent>();
 278  
             }
 279  
             
 280  0
             unhandled.add((ExceptionQueuedEvent)exceptionQueuedEvent);
 281  0
         }
 282  
         
 283  
         protected Throwable getRethrownException(Throwable exception)
 284  
         {
 285  
             // Let toRethrow be either the result of calling getRootCause() on the Exception, 
 286  
             // or the Exception itself, whichever is non-null
 287  0
             Throwable toRethrow = getRootCause(exception);
 288  0
             if (toRethrow == null)
 289  
             {
 290  0
                 toRethrow = exception;
 291  
             }
 292  
             
 293  0
             return toRethrow;
 294  
         }
 295  
         
 296  
         protected FacesException wrap(Throwable exception)
 297  
         {
 298  0
             if (exception instanceof FacesException)
 299  
             {
 300  0
                 return (FacesException) exception;
 301  
             }
 302  0
             return new FacesException(exception);
 303  
         }
 304  
         
 305  
         protected boolean shouldSkip(Throwable exception)
 306  
         {
 307  0
             return exception instanceof AbortProcessingException;
 308  
         }
 309  
     }
 310  
 }