View Javadoc

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.view.facelets;
20  
21  import java.io.IOException;
22  import java.util.Iterator;
23  
24  import javax.el.ExpressionFactory;
25  import javax.faces.FacesException;
26  import javax.faces.application.FacesMessage;
27  import javax.faces.component.ContextCallback;
28  import javax.faces.component.UICommand;
29  import javax.faces.component.UIComponent;
30  import javax.faces.component.UIInput;
31  import javax.faces.component.UIViewRoot;
32  import javax.faces.context.FacesContext;
33  import javax.faces.event.AbortProcessingException;
34  import javax.faces.event.ActionEvent;
35  import javax.faces.event.ExceptionQueuedEvent;
36  import javax.faces.event.ExceptionQueuedEventContext;
37  import javax.faces.event.PhaseId;
38  import javax.faces.event.ValueChangeEvent;
39  import javax.faces.validator.Validator;
40  import javax.faces.validator.ValidatorException;
41  
42  import org.apache.myfaces.config.RuntimeConfig;
43  import org.apache.myfaces.shared.context.ExceptionHandlerImpl;
44  import org.apache.myfaces.test.mock.MockExternalContext;
45  import org.easymock.classextension.EasyMock;
46  import org.junit.Test;
47  import org.testng.Assert;
48  
49  public class ExceptionTestCase extends FaceletTestCase
50  {
51      
52      @Override
53      protected ExpressionFactory createExpressionFactory()
54      {
55          return new org.apache.el.ExpressionFactoryImpl();
56      }
57  
58      @Override
59      protected void setUpFacesContext() throws Exception
60      {
61          super.setUpFacesContext();
62          facesContext.setExceptionHandler(new ExceptionHandlerImpl());
63      }
64      
65      @Test
66      public void testActionException1() throws Exception
67      {
68          UIViewRoot root = facesContext.getViewRoot();
69          vdl.buildView(facesContext, root,"testActionException1.xhtml");
70          
71          request.addParameter("mainForm:button1", "Submit");
72  
73          UICommand button = (UICommand) root.findComponent("mainForm:button1");
74          Assert.assertNotNull(button);
75          
76          ExceptionBean bean = EasyMock.createMock(ExceptionBean.class);
77          EasyMock.expect(bean.doSomeAction()).andThrow(new AbortProcessingException());
78          // Setup is finished need to activate the mock
79          EasyMock.replay(bean);
80                  
81          request.setAttribute("bean", bean);
82                  
83          button.processDecodes(facesContext);
84          
85          try
86          {
87              root.processApplication(facesContext);
88          }
89          catch(FacesException e)
90          {
91              Assert.fail("No exception should be thrown at this point.",e);
92          }
93          
94          int i = 0;
95          for (Iterator<ExceptionQueuedEvent> it = facesContext.getExceptionHandler().getUnhandledExceptionQueuedEvents().iterator(); it.hasNext();)
96          {
97              ExceptionQueuedEvent eqe = it.next();
98              Throwable e = eqe.getContext().getException();
99              if (e instanceof AbortProcessingException && e.getCause() == null)
100             {
101                 //Expected
102                 i++;
103             }
104             else
105             {
106                 Assert.fail("Unexpected exception queued", e);
107             }
108         }
109         Assert.assertEquals(1, i);
110     }
111 
112     /**
113      * A runtime exception thrown must be
114      * 
115      * @throws Exception
116      */
117     @Test
118     public void testActionException1_1() throws Exception
119     {
120         UIViewRoot root = facesContext.getViewRoot();
121         vdl.buildView(facesContext, root,"testActionException1.xhtml");
122         
123         request.addParameter("mainForm:button1", "Submit");
124 
125         UICommand button = (UICommand) root.findComponent("mainForm:button1");
126         Assert.assertNotNull(button);
127         
128         ExceptionBean bean = EasyMock.createMock(ExceptionBean.class);
129         EasyMock.expect(bean.doSomeAction()).andThrow(new RuntimeException());
130         // Setup is finished need to activate the mock
131         EasyMock.replay(bean);
132                 
133         request.setAttribute("bean", bean);
134                 
135         button.processDecodes(facesContext);
136         
137         try
138         {
139             root.processApplication(facesContext);
140         }
141         catch(FacesException e)
142         {
143             return;
144         }
145         Iterable<ExceptionQueuedEvent> unhandledExceptionQueuedEvents = facesContext.getExceptionHandler().getUnhandledExceptionQueuedEvents();
146         ExceptionQueuedEvent exceptionQueuedEvent = unhandledExceptionQueuedEvents.iterator().next();
147          
148         Assert.assertNotNull(exceptionQueuedEvent.getContext().getException(), "Exception should be queued at this point.");
149     }
150     
151     /**
152      * A runtime exception thrown must be
153      * 
154      * @throws Exception
155      */
156     @Test
157     public void testActionException1_2() throws Exception
158     {
159         UIViewRoot root = facesContext.getViewRoot();
160         vdl.buildView(facesContext, root,"testActionException1.xhtml");
161         
162         request.addParameter("mainForm:button1", "Submit");
163 
164         UICommand button = (UICommand) root.findComponent("mainForm:button1");
165         Assert.assertNotNull(button);
166         
167         ExceptionBean bean = EasyMock.createMock(ExceptionBean.class);
168         EasyMock.expect(bean.doSomeAction()).andThrow(new IOException());
169         // Setup is finished need to activate the mock
170         EasyMock.replay(bean);
171                 
172         request.setAttribute("bean", bean);
173                 
174         button.processDecodes(facesContext);
175         
176         try
177         {
178             root.processApplication(facesContext);
179         }
180         catch(FacesException e)
181         {
182             return;
183         }
184         Iterable<ExceptionQueuedEvent> unhandledExceptionQueuedEvents = facesContext.getExceptionHandler().getUnhandledExceptionQueuedEvents();
185         ExceptionQueuedEvent exceptionQueuedEvent = unhandledExceptionQueuedEvents.iterator().next();
186          
187         Assert.assertNotNull(exceptionQueuedEvent.getContext().getException(), "Exception should be queued at this point.");
188     }
189 
190     @Test
191     public void testActionListenerException1() throws Exception
192     {
193         UIViewRoot root = facesContext.getViewRoot();
194         vdl.buildView(facesContext, root,"testActionListenerException1.xhtml");
195         
196         request.addParameter("mainForm:button1", "Submit");
197 
198         UICommand button = (UICommand) root.findComponent("mainForm:button1");
199         Assert.assertNotNull(button);
200         
201         //ActionEvent event = new ActionEvent(button);
202         ExceptionBean bean = EasyMock.createMock(ExceptionBean.class);
203         bean.doSomeActionListener((ActionEvent)EasyMock.anyObject());
204         EasyMock.expectLastCall().andThrow(new AbortProcessingException());
205         // Setup is finished need to activate the mock
206         EasyMock.replay(bean);
207                 
208         request.setAttribute("bean", bean);
209                 
210         button.processDecodes(facesContext);
211         
212         try
213         {
214             root.processApplication(facesContext);
215         }
216         catch(FacesException e)
217         {
218             Assert.fail("No exception should be thrown at this point.");
219         }
220         
221         int i = 0;
222         for (Iterator<ExceptionQueuedEvent> it = facesContext.getExceptionHandler().getUnhandledExceptionQueuedEvents().iterator(); it.hasNext();)
223         {
224             ExceptionQueuedEvent eqe = it.next();
225             Throwable e = eqe.getContext().getException();
226             if (e instanceof AbortProcessingException && e.getCause() == null)
227             {
228                 //Expected
229                 i++;
230             }
231             else
232             {
233                 Assert.fail("Unexpected exception queued", e);
234             }
235         }
236         Assert.assertEquals(1, i);
237 
238     }
239 
240     /**
241      * If a RuntimeException or other is thrown, AbortProcessingException is queued
242      * 
243      * @throws Exception
244      */
245     @Test
246     public void testActionListenerException1_1() throws Exception
247     {
248         UIViewRoot root = facesContext.getViewRoot();
249         vdl.buildView(facesContext, root,"testActionListenerException1.xhtml");
250         
251         request.addParameter("mainForm:button1", "Submit");
252 
253         UICommand button = (UICommand) root.findComponent("mainForm:button1");
254         Assert.assertNotNull(button);
255         
256         //ActionEvent event = new ActionEvent(button);
257         ExceptionBean bean = EasyMock.createMock(ExceptionBean.class);
258         bean.doSomeActionListener((ActionEvent)EasyMock.anyObject());
259         EasyMock.expectLastCall().andThrow(new RuntimeException());
260         // Setup is finished need to activate the mock
261         EasyMock.replay(bean);
262                 
263         request.setAttribute("bean", bean);
264                 
265         button.processDecodes(facesContext);
266         
267         try
268         {
269             root.processApplication(facesContext);
270         }
271         catch (Throwable e)
272         {
273             // JSF 2.0: publish the executor's exception (if any).
274             
275             publishException (e, PhaseId.INVOKE_APPLICATION, facesContext);
276         }
277         //catch(FacesException e)
278         //{
279         //    Assert.fail("No exception should be thrown at this point.");
280         //}
281         
282         int i = 0;
283         for (Iterator<ExceptionQueuedEvent> it = facesContext.getExceptionHandler().getUnhandledExceptionQueuedEvents().iterator(); it.hasNext();)
284         {
285             ExceptionQueuedEvent eqe = it.next();
286             Throwable e = eqe.getContext().getException();
287             if (e instanceof AbortProcessingException)
288             {
289                 Assert.fail("Unexpected exception queued", e);
290             }
291             else
292             {
293                 //Expected
294                 i++;
295             }
296         }
297         Assert.assertEquals(1, i);
298 
299     }
300     
301     private void publishException (Throwable e, PhaseId phaseId, FacesContext facesContext)
302     {
303         ExceptionQueuedEventContext context = new ExceptionQueuedEventContext (facesContext, e, null, phaseId);
304         
305         facesContext.getApplication().publishEvent (facesContext, ExceptionQueuedEvent.class, context);
306     }
307 
308     @Test
309     public void testValidatorException1() throws Exception
310     {
311         UIViewRoot root = facesContext.getViewRoot();
312         vdl.buildView(facesContext, root,"testValidatorException1.xhtml");
313 
314         root.invokeOnComponent(facesContext, "mainForm:input1", new ContextCallback()
315         {
316             public void invokeContextCallback(FacesContext context, UIComponent target)
317             {
318                 Object submittedValue = "Hello!";
319                 ExceptionBean bean = EasyMock.createStrictMock(ExceptionBean.class);
320                 bean.validateMe(facesContext,(UIComponent)target, submittedValue);
321                 EasyMock.expectLastCall().andThrow(new ValidatorException(new FacesMessage(target.getClientId(facesContext),"not valid!")));
322                 // Setup is finished need to activate the mock
323                 EasyMock.replay(bean);
324                 
325                 request.setAttribute("bean", bean);
326                 
327                 UIInput input = (UIInput) target;
328                 input.setSubmittedValue(submittedValue);
329                 try
330                 {
331                     input.processValidators(facesContext);
332                     Assert.assertTrue(facesContext.isValidationFailed());
333                 }
334                 catch(FacesException e)
335                 {
336                     Assert.fail("No exception expected", e);
337                 }
338             }
339         });
340     }
341     
342     @Test
343     public void testValidatorException2() throws Exception
344     {
345         application.addValidator("customValidatorId", CustomValidator.class.getName());
346         UIViewRoot root = facesContext.getViewRoot();
347         vdl.buildView(facesContext, root,"testValidatorException2.xhtml");
348 
349         root.invokeOnComponent(facesContext, "mainForm:input1", new ContextCallback()
350         {
351             public void invokeContextCallback(FacesContext context, UIComponent target)
352             {
353                 Object submittedValue = "Hello!";
354                 
355                 UIInput input = (UIInput) target;
356                 input.setSubmittedValue(submittedValue);
357                 try
358                 {
359                     input.processValidators(facesContext);
360                     Assert.assertTrue(facesContext.isValidationFailed());
361                 }
362                 catch(FacesException e)
363                 {
364                     Assert.fail("No exception expected", e);
365                 }
366             }
367         });
368         
369         Assert.assertEquals("not valid!", facesContext.getMessageList().get(0).getSummary());
370     }
371     
372     @Test
373     public void testValueChangeListenerException1() throws Exception
374     {
375         UIViewRoot root = facesContext.getViewRoot();
376         vdl.buildView(facesContext, root,"testValueChangeListenerException1.xhtml");
377 
378         root.invokeOnComponent(facesContext, "mainForm:input1", new ContextCallback()
379         {
380             public void invokeContextCallback(FacesContext context, UIComponent target)
381             {
382                 Object submittedValue = "Hello!";
383                 ExceptionBean bean = EasyMock.createStrictMock(ExceptionBean.class);
384                 bean.valueChangeListenerMe((ValueChangeEvent)EasyMock.anyObject());
385                 EasyMock.expectLastCall().andThrow(new AbortProcessingException());
386                 // Setup is finished need to activate the mock
387                 EasyMock.replay(bean);
388                 
389                 request.setAttribute("bean", bean);
390                 
391                 UIInput input = (UIInput) target;
392                 input.setSubmittedValue(submittedValue);
393                 try
394                 {
395                     input.processValidators(facesContext);
396                 }
397                 catch(FacesException e)
398                 {
399                     Assert.fail("No exception expected", e);
400                 }
401             }
402         });
403         
404         try
405         {
406             root.processUpdates(facesContext);
407         }
408         catch (Throwable e)
409         {
410             // JSF 2.0: publish the executor's exception (if any).
411             publishException (e, PhaseId.UPDATE_MODEL_VALUES, facesContext);
412         }
413         
414         int i = 0;
415         for (Iterator<ExceptionQueuedEvent> it = facesContext.getExceptionHandler().getUnhandledExceptionQueuedEvents().iterator(); it.hasNext();)
416         {
417             ExceptionQueuedEvent eqe = it.next();
418             Throwable e = eqe.getContext().getException();
419             if (e instanceof AbortProcessingException && e.getCause() == null)
420             {
421                 //Expected
422                 i++;
423             }
424             else
425             {
426                 Assert.fail("Unexpected exception queued", e);
427             }
428         }
429         Assert.assertEquals(1, i);
430     }
431     
432     @Test
433     public void testValueChangeListenerException1_1() throws Exception
434     {
435         UIViewRoot root = facesContext.getViewRoot();
436         vdl.buildView(facesContext, root,"testValueChangeListenerException1.xhtml");
437 
438         root.invokeOnComponent(facesContext, "mainForm:input1", new ContextCallback()
439         {
440             public void invokeContextCallback(FacesContext context, UIComponent target)
441             {
442                 Object submittedValue = "Hello!";
443                 ExceptionBean bean = EasyMock.createStrictMock(ExceptionBean.class);
444                 bean.valueChangeListenerMe((ValueChangeEvent)EasyMock.anyObject());
445                 EasyMock.expectLastCall().andThrow(new RuntimeException());
446                 // Setup is finished need to activate the mock
447                 EasyMock.replay(bean);
448                 
449                 UIInput input = (UIInput) target;
450                 input.setSubmittedValue(submittedValue);
451                 try
452                 {
453                     input.processValidators(facesContext);
454                 }
455                 catch(FacesException e)
456                 {
457                     Assert.fail("No exception expected", e);
458                 }
459                 
460                 request.setAttribute("bean", bean);                
461             }
462         });
463      
464         try
465         {
466             root.processUpdates(facesContext);
467         }
468         catch (Throwable e)
469         {
470             // JSF 2.0: publish the executor's exception (if any).
471             publishException (e, PhaseId.UPDATE_MODEL_VALUES, facesContext);
472         }
473         
474         int i = 0;
475         for (Iterator<ExceptionQueuedEvent> it = facesContext.getExceptionHandler().getUnhandledExceptionQueuedEvents().iterator(); it.hasNext();)
476         {
477             ExceptionQueuedEvent eqe = it.next();
478             Throwable e = eqe.getContext().getException();
479             if (e instanceof AbortProcessingException)
480             {
481                 Assert.fail("Unexpected exception queued", e);
482             }
483             else
484             {
485                 //Expected
486                 i++;
487             }
488         }
489         Assert.assertEquals(1, i);
490     }
491     
492     public static class CustomValidator implements Validator
493     {
494 
495         public void validate(FacesContext context, UIComponent component,
496                 Object value) throws ValidatorException
497         {
498             throw new ValidatorException(new FacesMessage("not valid!"));
499         }
500     }
501 
502     public static interface ExceptionBean
503     {
504         public void validateMe(FacesContext context, UIComponent target, Object value);
505         
506         public void doSomeActionListener(ActionEvent evt);
507         
508         public void valueChangeListenerMe(ValueChangeEvent evt);
509         
510         public Object doSomeAction() throws IOException;
511     }
512 
513 }