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 javax.faces.component;
20  
21  import static org.easymock.EasyMock.anyObject;
22  import static org.easymock.EasyMock.aryEq;
23  import static org.easymock.EasyMock.eq;
24  import static org.easymock.EasyMock.expect;
25  import static org.easymock.EasyMock.getCurrentArguments;
26  import static org.junit.Assert.assertEquals;
27  import static org.junit.Assert.assertNull;
28  import static org.junit.Assert.fail;
29  
30  import java.lang.reflect.Method;
31  import java.util.Collection;
32  import java.util.HashMap;
33  import java.util.HashSet;
34  import java.util.Iterator;
35  import java.util.Locale;
36  import java.util.Map;
37  
38  import javax.el.ELContext;
39  import javax.el.MethodExpression;
40  import javax.faces.FactoryFinder;
41  import javax.faces.application.Application;
42  import javax.faces.application.ProjectStage;
43  import javax.faces.application.ViewHandler;
44  import javax.faces.context.ExternalContext;
45  import javax.faces.event.AbortProcessingException;
46  import javax.faces.event.ActionEvent;
47  import javax.faces.event.ActionListener;
48  import javax.faces.event.PhaseEvent;
49  import javax.faces.event.PhaseId;
50  import javax.faces.event.PhaseListener;
51  import javax.faces.lifecycle.Lifecycle;
52  import javax.faces.lifecycle.LifecycleFactory;
53  import javax.faces.webapp.FacesServlet;
54  
55  import org.apache.myfaces.TestRunner;
56  import org.apache.myfaces.test.base.junit4.AbstractJsfTestCase;
57  import org.apache.myfaces.test.mock.MockFacesContext12;
58  import org.easymock.IAnswer;
59  import org.easymock.classextension.EasyMock;
60  import org.easymock.classextension.IMocksControl;
61  import org.junit.After;
62  import org.junit.Before;
63  import org.junit.Test;
64  
65  public class UIViewRootTest extends AbstractJsfTestCase
66  {
67      private Map<PhaseId, Class<? extends PhaseListener>> phaseListenerClasses;
68      private IMocksControl _mocksControl;
69      private MockFacesContext12 _facesContext;
70      private UIViewRoot _testimpl;
71      private ExternalContext _externalContext;
72      private Application _application;
73      private Lifecycle _lifecycle;
74      private LifecycleFactory _lifecycleFactory;
75      private ViewHandler _viewHandler;
76      private ELContext _elContext;
77  
78      private static ThreadLocal<LifecycleFactory> LIFECYCLEFACTORY = new ThreadLocal<LifecycleFactory>();
79  
80      @Before
81      public void setUp() throws Exception
82      {
83          super.setUp();
84          phaseListenerClasses = new HashMap<PhaseId, Class<? extends PhaseListener>>();
85          phaseListenerClasses.put(PhaseId.APPLY_REQUEST_VALUES, ApplyRequesValuesPhaseListener.class);
86          phaseListenerClasses.put(PhaseId.PROCESS_VALIDATIONS, ProcessValidationsPhaseListener.class);
87          phaseListenerClasses.put(PhaseId.UPDATE_MODEL_VALUES, UpdateModelValuesPhaseListener.class);
88          phaseListenerClasses.put(PhaseId.INVOKE_APPLICATION, InvokeApplicationPhaseListener.class);
89          phaseListenerClasses.put(PhaseId.RENDER_RESPONSE, RenderResponsePhaseListener.class);
90  
91          _mocksControl = EasyMock.createControl();
92          _externalContext = _mocksControl.createMock(ExternalContext.class);
93          _facesContext = (MockFacesContext12) facesContext;
94          _application = _mocksControl.createMock(Application.class);
95          _lifecycleFactory = _mocksControl.createMock(LifecycleFactory.class);
96          _testimpl = new UIViewRoot();
97          _lifecycle = _mocksControl.createMock(Lifecycle.class);
98          _elContext = _mocksControl.createMock(ELContext.class);
99          _viewHandler = _mocksControl.createMock(ViewHandler.class);
100         _facesContext.setELContext(_elContext);
101 
102         LIFECYCLEFACTORY.set(_lifecycleFactory);
103         FactoryFinder.setFactory(FactoryFinder.LIFECYCLE_FACTORY, MockLifeCycleFactory.class.getName());
104         servletContext.addInitParameter(ProjectStage.PROJECT_STAGE_PARAM_NAME, ProjectStage.UnitTest.name());
105         
106     }
107 
108     @After
109     public void tearDown() throws Exception
110     {
111         super.tearDown();
112         _mocksControl.reset();
113     }
114 
115     @Test
116     public void testSuperClass() throws Exception
117     {
118         assertEquals(UIComponentBase.class, UIViewRoot.class.getSuperclass());
119     }
120 
121     @Test
122     public void testComponentType() throws Exception
123     {
124         assertEquals("javax.faces.ViewRoot", UIViewRoot.COMPONENT_TYPE);
125     }
126 
127     @Test
128     public void testLocale() throws Exception
129     {
130         expect(_application.getViewHandler()).andReturn(_viewHandler).anyTimes();
131         expect(_viewHandler.calculateLocale(_facesContext)).andReturn(null).anyTimes();
132         _mocksControl.replay();
133 
134         _facesContext.setApplication(_application);
135         assertNull(_testimpl.getLocale());
136         _testimpl.setLocale(Locale.JAPANESE);
137         assertEquals(Locale.JAPANESE, _testimpl.getLocale());
138         _mocksControl.verify();
139     }
140 
141     /**
142      * Test method for {@link javax.faces.component.UIViewRoot#createUniqueId()}.
143      */
144     @Test
145     public void testCreateUniqueId()
146     {
147         /*
148         expect(_externalContext.encodeNamespace((String) anyObject())).andAnswer(new IAnswer<String>()
149         {
150             public String answer() throws Throwable
151             {
152                 return (String) getCurrentArguments()[0];
153             }
154         }).anyTimes();*/
155         _mocksControl.replay();
156         Collection<String> createdIds = new HashSet<String>();
157         for (int i = 0; i < 10000; i++)
158         {
159             if (!createdIds.add(_testimpl.createUniqueId()))
160             {
161                 fail("duplicate id created");
162             }
163         }
164         _mocksControl.verify();
165     }
166 
167 // Disabled until Myfaces test issues are resolved..
168 //    /**
169 //     * Test method for {@link javax.faces.component.UIViewRoot#processDecodes(javax.faces.context.FacesContext)}.
170 //     * 
171 //     * @throws Throwable
172 //     */
173 //    @Test
174 //    public void testProcessDecodes() throws Throwable
175 //    {
176 //        testProcessXXX(new TestRunner()
177 //        {
178 //            public void run() throws Throwable
179 //            {
180 //                _testimpl.processDecodes(_facesContext);
181 //            }
182 //        }, PhaseId.APPLY_REQUEST_VALUES, false, true, true);
183 //    }
184 //
185 //    /**
186 //     * Test method for {@link javax.faces.component.UIViewRoot#processValidators(javax.faces.context.FacesContext)}.
187 //     * 
188 //     * @throws Throwable
189 //     */
190 //    @Test
191 //    public void testProcessValidators() throws Throwable
192 //    {
193 //        testProcessXXX(new TestRunner()
194 //        {
195 //            public void run() throws Throwable
196 //            {
197 //                _testimpl.processValidators(_facesContext);
198 //            }
199 //        }, PhaseId.PROCESS_VALIDATIONS, false, true, true);
200 //    }
201 //
202 //    /**
203 //     * Test method for {@link javax.faces.component.UIViewRoot#processUpdates(javax.faces.context.FacesContext)}.
204 //     * 
205 //     * @throws Throwable
206 //     */
207 //    @Test
208 //    public void testProcessUpdates() throws Throwable
209 //    {
210 //        testProcessXXX(new TestRunner()
211 //        {
212 //            public void run() throws Throwable
213 //            {
214 //                _testimpl.processUpdates(_facesContext);
215 //            }
216 //        }, PhaseId.UPDATE_MODEL_VALUES, false, true, true);
217 //    }
218 //
219 //    /**
220 //     * Test method for {@link javax.faces.component.UIViewRoot#processApplication(javax.faces.context.FacesContext)}.
221 //     * 
222 //     * @throws Throwable
223 //     */
224 //    @Test
225 //    public void testProcessApplication() throws Throwable
226 //    {
227 //        testProcessXXX(new TestRunner()
228 //        {
229 //            public void run() throws Throwable
230 //            {
231 //                _testimpl.processApplication(_facesContext);
232 //            }
233 //        }, PhaseId.INVOKE_APPLICATION, false, true, true);
234 //    }
235 //
236 //    /**
237 //     * Test method for {@link javax.faces.component.UIViewRoot#encodeBegin(javax.faces.context.FacesContext)}.
238 //     * 
239 //     * @throws Throwable
240 //     */
241 //    @Test
242 //    public void testEncodeBegin() throws Throwable
243 //    {
244 //        testProcessXXX(new TestRunner()
245 //        {
246 //            public void run() throws Throwable
247 //            {
248 //                _testimpl.encodeBegin(_facesContext);
249 //            }
250 //        }, PhaseId.RENDER_RESPONSE, false, true, false);
251 //    }
252 //
253 //    /**
254 //     * Test method for {@link javax.faces.component.UIViewRoot#encodeEnd(javax.faces.context.FacesContext)}.
255 //     * 
256 //     * @throws Throwable
257 //     */
258 //    @Test
259 //    public void testEncodeEnd() throws Throwable
260 //    {
261 //        testProcessXXX(new TestRunner()
262 //        {
263 //            public void run() throws Throwable
264 //            {
265 //                _testimpl.encodeEnd(_facesContext);
266 //            }
267 //        }, PhaseId.RENDER_RESPONSE, false, false, true);
268 //    }
269 //
270 //    @Test
271 //    public void testEventQueue() throws Exception
272 //    {
273 //        FacesEvent event = _mocksControl.createMock(FacesEvent.class);
274 //        expect(event.getPhaseId()).andReturn(PhaseId.APPLY_REQUEST_VALUES).anyTimes();
275 //        UIComponent component = _mocksControl.createMock(UIComponent.class);
276 //        expect(event.getComponent()).andReturn(component).anyTimes();
277 //        component.broadcast(same(event));
278 //        _testimpl.queueEvent(event);
279 //
280 //        event = _mocksControl.createMock(FacesEvent.class);
281 //        expect(event.getPhaseId()).andReturn(PhaseId.PROCESS_VALIDATIONS).anyTimes();
282 //        _testimpl.queueEvent(event);
283 //
284 //        _mocksControl.replay();
285 //        _testimpl.processDecodes(_facesContext);
286 //        _mocksControl.verify();
287 //    }
288 //
289 //    @Test
290 //    public void testEventQueueWithAbortExcpetion() throws Exception
291 //    {
292 //        FacesEvent event = _mocksControl.createMock(FacesEvent.class);
293 //        expect(event.getPhaseId()).andReturn(PhaseId.INVOKE_APPLICATION).anyTimes();
294 //        UIComponent component = _mocksControl.createMock(UIComponent.class);
295 //        expect(event.getComponent()).andReturn(component).anyTimes();
296 //        component.broadcast(same(event));
297 //        expectLastCall().andThrow(new AbortProcessingException());
298 //        _testimpl.queueEvent(event);
299 //
300 //        event = _mocksControl.createMock(FacesEvent.class);
301 //        expect(event.getPhaseId()).andReturn(PhaseId.INVOKE_APPLICATION).anyTimes();
302 //        _testimpl.queueEvent(event);
303 //
304 //        _mocksControl.replay();
305 //        _testimpl.processApplication(_facesContext);
306 //        _mocksControl.verify();
307 //    }
308 
309     //
310     //
311     //
312     // /**
313     // * Test method for {@link javax.faces.component.UIViewRoot#saveState(javax.faces.context.FacesContext)}.
314     // */
315     // public void testSaveState()
316     // {
317     // fail("Not yet implemented"); // TODO
318     // }
319     //
320     // /**
321     // * Test method for
322     // * {@link javax.faces.component.UIViewRoot#restoreState(javax.faces.context.FacesContext, java.lang.Object)}.
323     // */
324     // public void testRestoreState()
325     // {
326     // fail("Not yet implemented"); // TODO
327     // }
328     //
329     // /**
330     // * Test method for {@link javax.faces.component.UIViewRoot#UIViewRoot()}.
331     // */
332     // public void testUIViewRoot()
333     // {
334     // fail("Not yet implemented"); // TODO
335     // }
336     //
337     //
338     // /**
339     // * Test method for {@link javax.faces.component.UIViewRoot#setLocale(java.util.Locale)}.
340     // */
341     // public void testSetLocale()
342     // {
343     // fail("Not yet implemented"); // TODO
344     // }
345     //
346     // /**
347     // * Test method for {@link javax.faces.component.UIViewRoot#getRenderKitId()}.
348     // */
349     // public void testGetRenderKitId()
350     // {
351     // fail("Not yet implemented"); // TODO
352     // }
353     //
354     // /**
355     // * Test method for {@link javax.faces.component.UIViewRoot#setRenderKitId(java.lang.String)}.
356     // */
357     // public void testSetRenderKitId()
358     // {
359     // fail("Not yet implemented"); // TODO
360     // }
361     //
362     // /**
363     // * Test method for {@link javax.faces.component.UIViewRoot#getViewId()}.
364     // */
365     // public void testGetViewId()
366     // {
367     // fail("Not yet implemented"); // TODO
368     // }
369     //
370     // /**
371     // * Test method for {@link javax.faces.component.UIViewRoot#setViewId(java.lang.String)}.
372     // */
373     // public void testSetViewId()
374     // {
375     // fail("Not yet implemented"); // TODO
376     // }
377     //
378     // /**
379     // * Test method for {@link javax.faces.component.UIViewRoot#addPhaseListener(javax.faces.event.PhaseListener)}.
380     // */
381     // public void testAddPhaseListener()
382     // {
383     // fail("Not yet implemented"); // TODO
384     // }
385     //
386     // /**
387     // * Test method for {@link javax.faces.component.UIViewRoot#removePhaseListener(javax.faces.event.PhaseListener)}.
388     // */
389     // public void testRemovePhaseListener()
390     // {
391     // fail("Not yet implemented"); // TODO
392     // }
393     //
394     // /**
395     // * Test method for {@link javax.faces.component.UIViewRoot#getBeforePhaseListener()}.
396     // */
397     // public void testGetBeforePhaseListener()
398     // {
399     // fail("Not yet implemented"); // TODO
400     // }
401     //
402     // /**
403     // * Test method for {@link javax.faces.component.UIViewRoot#setBeforePhaseListener(javax.el.MethodExpression)}.
404     // */
405     // public void testSetBeforePhaseListener()
406     // {
407     // fail("Not yet implemented"); // TODO
408     // }
409     //
410     // /**
411     // * Test method for {@link javax.faces.component.UIViewRoot#getAfterPhaseListener()}.
412     // */
413     // public void testGetAfterPhaseListener()
414     // {
415     // fail("Not yet implemented"); // TODO
416     // }
417     //
418     // /**
419     // * Test method for {@link javax.faces.component.UIViewRoot#setAfterPhaseListener(javax.el.MethodExpression)}.
420     // */
421     // public void testSetAfterPhaseListener()
422     // {
423     // fail("Not yet implemented"); // TODO
424     // }
425     //
426     // /**
427     // * Test method for {@link javax.faces.component.UIViewRoot#getFamily()}.
428     // */
429     // public void testGetFamily()
430     // {
431     // fail("Not yet implemented"); // TODO
432     // }
433     //
434 
435     private void testProcessXXX(TestRunner runner, PhaseId phaseId, boolean expectSuperCall, boolean checkBefore,
436             boolean checkAfter) throws Throwable
437     {
438         expect(_lifecycleFactory.getLifecycle(eq(LifecycleFactory.DEFAULT_LIFECYCLE))).andReturn(_lifecycle);
439         expect(_externalContext.getInitParameter(eq(FacesServlet.LIFECYCLE_ID_ATTR))).andReturn(null).anyTimes();
440 
441         PhaseEvent event = new PhaseEvent(_facesContext, phaseId, _lifecycle);
442 
443         if (expectSuperCall)
444         {
445             _testimpl = _mocksControl.createMock(UIViewRoot.class, new Method[]{UIViewRoot.class.getMethod(
446                     "isRendered", new Class[0])});
447         }
448 
449         MethodExpression beforeListener = _mocksControl.createMock(MethodExpression.class);
450         _testimpl.setBeforePhaseListener(beforeListener);
451 
452         MethodExpression afterListener = _mocksControl.createMock(MethodExpression.class);
453         _testimpl.setAfterPhaseListener(afterListener);
454 
455         Method[] mockedMethods = new Method[] {
456                 PhaseListener.class.getMethod("beforePhase", new Class[] { PhaseEvent.class }),
457                 PhaseListener.class.getMethod("afterPhase", new Class[] { PhaseEvent.class }) };
458         PhaseListener phaseListener = _mocksControl.createMock(phaseListenerClasses.get(phaseId), mockedMethods);
459         _testimpl.addPhaseListener(phaseListener);
460 
461         PhaseListener anyPhaseListener = _mocksControl.createMock(AnyPhasePhaseListener.class, mockedMethods);
462         _testimpl.addPhaseListener(anyPhaseListener);
463 
464         PhaseListener restoreViewPhaseListener = _mocksControl.createMock(RestoreViewPhasePhaseListener.class,
465                 mockedMethods);
466         _testimpl.addPhaseListener(restoreViewPhaseListener);
467 
468         _mocksControl.checkOrder(true);
469 
470         if (checkBefore)
471         {
472             expect(beforeListener.invoke(eq(_facesContext.getELContext()), aryEq(new Object[] { event }))).andReturn(
473                     null);
474             phaseListener.beforePhase(eq(event));
475             anyPhaseListener.beforePhase(eq(event));
476         }
477 
478         if (expectSuperCall)
479         {
480             expect(_testimpl.isRendered()).andReturn(false);
481         }
482 
483         if (checkAfter)
484         {
485             expect(afterListener.invoke(eq(_facesContext.getELContext()), aryEq(new Object[] { event }))).andReturn(
486                     null);
487             phaseListener.afterPhase(eq(event));
488             anyPhaseListener.afterPhase(eq(event));
489         }
490 
491         _mocksControl.replay();
492         runner.run();
493         _mocksControl.verify();
494     }
495 
496     private final class ActionListenerImplementation implements ActionListener
497     {
498         public int invocationCount = 0;
499         
500         public ActionEvent newActionEventFromListener;
501 
502         public ActionListenerImplementation(UICommand otherUiCommand)
503         {
504             // from spec: Queue one or more additional events, from the same source component
505             // or a DIFFERENT one
506             newActionEventFromListener = new ActionEvent(otherUiCommand);
507         }
508 
509         public void processAction(ActionEvent actionEvent)
510                 throws AbortProcessingException
511         {
512             invocationCount++;
513               
514             newActionEventFromListener.queue();
515             
516             // Simulate infinite recursion,most likely coding error:
517             actionEvent.queue();
518         }
519     }
520 
521     public static class MockLifeCycleFactory extends LifecycleFactory
522     {
523 
524         @Override
525         public void addLifecycle(String lifecycleId, Lifecycle lifecycle)
526         {
527             LIFECYCLEFACTORY.get().addLifecycle(lifecycleId, lifecycle);
528         }
529 
530         @Override
531         public Lifecycle getLifecycle(String lifecycleId)
532         {
533             return LIFECYCLEFACTORY.get().getLifecycle(lifecycleId);
534         }
535 
536         @Override
537         public Iterator<String> getLifecycleIds()
538         {
539             return LIFECYCLEFACTORY.get().getLifecycleIds();
540         }
541 
542     }
543 
544     public static abstract class ApplyRequesValuesPhaseListener implements PhaseListener
545     {
546         public PhaseId getPhaseId()
547         {
548             return PhaseId.APPLY_REQUEST_VALUES;
549         }
550     }
551 
552     public static abstract class ProcessValidationsPhaseListener implements PhaseListener
553     {
554         public PhaseId getPhaseId()
555         {
556             return PhaseId.PROCESS_VALIDATIONS;
557         }
558     }
559 
560     public static abstract class UpdateModelValuesPhaseListener implements PhaseListener
561     {
562         public PhaseId getPhaseId()
563         {
564             return PhaseId.UPDATE_MODEL_VALUES;
565         }
566     }
567 
568     public static abstract class InvokeApplicationPhaseListener implements PhaseListener
569     {
570         public PhaseId getPhaseId()
571         {
572             return PhaseId.INVOKE_APPLICATION;
573         }
574     }
575 
576     public static abstract class AnyPhasePhaseListener implements PhaseListener
577     {
578         public PhaseId getPhaseId()
579         {
580             return PhaseId.ANY_PHASE;
581         }
582     }
583 
584     public static abstract class RestoreViewPhasePhaseListener implements PhaseListener
585     {
586         public PhaseId getPhaseId()
587         {
588             return PhaseId.RESTORE_VIEW;
589         }
590     }
591 
592     public static abstract class RenderResponsePhaseListener implements PhaseListener
593     {
594         public PhaseId getPhaseId()
595         {
596             return PhaseId.RENDER_RESPONSE;
597         }
598     }
599 
600     @Test
601     public void testBroadcastEvents()
602     {
603         
604         UICommand uiCommand = new UICommand();
605         uiCommand.setId("idOfCommandOne");
606         facesContext.getViewRoot().getChildren().add(uiCommand);
607         
608         // Spec 3.4.2.6 Event Broadcasting: During event broadcasting, a listener processing an event may
609         // Queue one or more additional events from the same source component or a different one:
610         // and the DIFFERENT ONE is the next UICommand instance
611         UICommand differentUiCommand = new UICommand();
612         uiCommand.setId("idOfdifferentUiCommand");
613         facesContext.getViewRoot().getChildren().add(differentUiCommand);
614         
615         
616         ActionListenerImplementation actionListener = new ActionListenerImplementation(differentUiCommand);
617         uiCommand.addActionListener(actionListener);
618         
619         ActionListener differentActionListener = org.easymock.EasyMock.createNiceMock(ActionListener.class);
620         differentActionListener.processAction(actionListener.newActionEventFromListener);
621         org.easymock.EasyMock.expectLastCall().times(1);
622         org.easymock.EasyMock.replay(differentActionListener);
623         differentUiCommand.addActionListener(differentActionListener);
624         
625         // Simulates first event, in most cases click in GUI
626         ActionEvent invokeApplicationEvent = new ActionEvent(uiCommand);
627         invokeApplicationEvent.queue();
628         
629         // tested method: In this method is actionListener called and that
630         // listener itself queues new event
631         facesContext.getViewRoot().broadcastEvents(facesContext, PhaseId.INVOKE_APPLICATION);
632         
633         assertEquals(15, actionListener.invocationCount);
634         org.easymock.EasyMock.verify(differentActionListener);
635     }
636 
637 }