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.mc.test.core;
20  
21  import org.apache.myfaces.mc.test.core.mock.MockMyFacesViewDeclarationLanguageFactory;
22  import java.io.FileNotFoundException;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.lang.reflect.Constructor;
26  import java.lang.reflect.Field;
27  import java.lang.reflect.InvocationTargetException;
28  import java.lang.reflect.Method;
29  import java.net.URI;
30  import java.net.URL;
31  import java.net.URLClassLoader;
32  import java.util.List;
33  import java.util.Map;
34  import java.util.concurrent.ConcurrentHashMap;
35  import java.util.logging.Level;
36  import java.util.logging.Logger;
37  
38  import javax.el.ExpressionFactory;
39  import javax.faces.FacesException;
40  import javax.faces.FactoryFinder;
41  import javax.faces.application.Application;
42  import javax.faces.application.FacesMessage;
43  import javax.faces.application.ProjectStage;
44  import javax.faces.application.ViewHandler;
45  import javax.faces.component.UIViewRoot;
46  import javax.faces.context.ExternalContext;
47  import javax.faces.context.FacesContext;
48  import javax.faces.context.FacesContextFactory;
49  import javax.faces.context.Flash;
50  import javax.faces.event.ExceptionQueuedEvent;
51  import javax.faces.event.ExceptionQueuedEventContext;
52  import javax.faces.event.PhaseId;
53  import javax.faces.event.PhaseListener;
54  import javax.faces.event.PreRenderViewEvent;
55  import javax.faces.lifecycle.Lifecycle;
56  import javax.faces.lifecycle.LifecycleFactory;
57  import javax.faces.view.ViewDeclarationLanguage;
58  import javax.faces.webapp.FacesServlet;
59  import javax.naming.Context;
60  import javax.servlet.ServletContext;
61  import javax.servlet.ServletContextEvent;
62  import javax.servlet.http.HttpServletResponse;
63  
64  import org.apache.myfaces.config.ConfigFilesXmlValidationUtils;
65  import org.apache.myfaces.config.DefaultFacesConfigurationProvider;
66  import org.apache.myfaces.config.RuntimeConfig;
67  import org.apache.myfaces.config.annotation.NoInjectionAnnotationLifecycleProvider;
68  import org.apache.myfaces.config.element.FacesConfig;
69  import org.apache.myfaces.config.impl.digester.elements.FactoryImpl;
70  import org.apache.myfaces.lifecycle.LifecycleImpl;
71  import org.apache.myfaces.lifecycle.ViewNotFoundException;
72  import org.apache.myfaces.mc.test.core.annotation.DeclareFacesConfig;
73  import org.apache.myfaces.mc.test.core.annotation.ManagedBeans;
74  import org.apache.myfaces.mc.test.core.annotation.PageBean;
75  import org.apache.myfaces.mc.test.core.annotation.TestConfig;
76  import org.apache.myfaces.mc.test.core.mock.DefaultContext;
77  import org.apache.myfaces.mc.test.core.mock.MockInitialContextFactory;
78  import org.apache.myfaces.shared.config.MyfacesConfig;
79  import org.apache.myfaces.shared.util.ClassUtils;
80  import org.apache.myfaces.spi.FacesConfigurationProvider;
81  import org.apache.myfaces.spi.impl.DefaultFacesConfigurationProviderFactory;
82  import org.apache.myfaces.spi.impl.NoInjectionAnnotationInjectionProvider;
83  import org.apache.myfaces.test.el.MockExpressionFactory;
84  import org.apache.myfaces.test.mock.MockPrintWriter;
85  import org.apache.myfaces.test.mock.MockServletConfig;
86  import org.apache.myfaces.test.mock.MockServletContext;
87  import org.apache.myfaces.test.mock.MockWebContainer;
88  import org.apache.myfaces.webapp.AbstractFacesInitializer;
89  import org.apache.myfaces.webapp.StartupServletContextListener;
90  import org.junit.After;
91  import org.junit.AfterClass;
92  import org.junit.Before;
93  import org.xml.sax.SAXException;
94  
95  /**
96   * <p>Abstract JUnit test case base class, which sets up MyFaces Core environment
97   * using mock object for the outer servlet environment.</p>
98   * <p>Since jsp engine is not bundled with MyFaces, this configuration is able to 
99   * handle facelet pages only.</p>
100  * 
101  * @author Leonardo Uribe
102  *
103  */
104 public abstract class AbstractMyFacesTestCase
105 {
106     private static final Class<?> PHASE_EXECUTOR_CLASS;
107     private static final Class<?> PHASE_MANAGER_CLASS;
108     
109     static 
110     {
111         Class<?> phaseExecutorClass = null;
112         Class<?> phaseManagerClass = null;
113         try
114         {
115             phaseExecutorClass = Class.forName("org.apache.myfaces.lifecycle.PhaseExecutor");
116             phaseManagerClass = Class.forName("org.apache.myfaces.lifecycle.PhaseListenerManager");
117         }
118         catch (ClassNotFoundException e)
119         {
120             //No op
121         }
122         PHASE_EXECUTOR_CLASS = phaseExecutorClass;
123         PHASE_MANAGER_CLASS = phaseManagerClass;
124     }
125     
126     public static final String PHASE_MANAGER_INSTANCE = "org.apache.myfaces.test.PHASE_MANAGER_INSTANCE";
127     
128     public static final String LAST_PHASE_PROCESSED = "oam.LAST_PHASE_PROCESSED";
129     
130     public static final String LAST_RENDER_PHASE_STEP = "oam.LAST_RENDER_PHASE_STEP";
131     
132     public static final int BEFORE_RENDER_STEP = 1;
133     public static final int BUILD_VIEW_CYCLE_STEP = 2;
134     public static final int VIEWHANDLER_RENDER_STEP = 3;
135     public static final int AFTER_RENDER_STEP = 4;
136     
137     // ------------------------------------------------------------ Constructors
138 
139     /**
140      * <p>Construct a new instance of this test case.</p>
141      *
142      */    
143     public AbstractMyFacesTestCase()
144     {
145     }
146 
147     // ---------------------------------------------------- Overall Test Methods
148 
149     /**
150      * <p>Set up instance variables required by this test case.</p>
151      */
152     @Before
153     public void setUp() throws Exception
154     {
155         // Set up a new thread context class loader
156         setUpClassloader();
157         
158         jsfConfiguration = sharedConfiguration.get(getTestJavaClass().getName());
159         if (jsfConfiguration == null)
160         {
161             jsfConfiguration = new SharedFacesConfiguration();
162         }
163         
164         TestConfig testConfig = getTestJavaClass().getAnnotation(TestConfig.class);
165         boolean enableJNDI = (testConfig != null) ? testConfig.enableJNDI() : true;
166         if (enableJNDI)
167         {
168             System.setProperty(Context.INITIAL_CONTEXT_FACTORY, MockInitialContextFactory.class.getName());
169             jndiContext = new DefaultContext();
170             MockInitialContextFactory.setCurrentContext(jndiContext);
171         }
172 
173         // Set up Servlet API Objects
174         setUpServletObjects();
175 
176         // Set up JSF API Objects
177         FactoryFinder.releaseFactories();
178 
179         setUpServletListeners();
180         
181         webContainer.contextInitialized(new ServletContextEvent(servletContext));
182         
183         setUpFacesServlet();
184         
185         sharedConfiguration.put(getTestJavaClass().getName(), jsfConfiguration);
186     }
187     
188     /**
189      * Set up the thread context classloader. JSF uses the this classloader
190      * in order to find related factory classes and other resources, but in
191      * some selected cases, the default classloader cannot be properly set.
192      * 
193      * @throws Exception 
194      */
195     protected void setUpClassloader() throws Exception
196     {
197         // Set up a new thread context class loader
198         threadContextClassLoader = Thread.currentThread()
199                 .getContextClassLoader();
200         Thread.currentThread()
201                 .setContextClassLoader(
202                         new URLClassLoader(new URL[0], this.getClass()
203                                 .getClassLoader()));
204         classLoaderSet = true;
205     }
206     
207     /**
208      * <p>Setup servlet objects that will be used for the test:</p>
209      * 
210      * <ul>
211      * <li><code>servletConfig</code> (<code>MockServletConfig</code>)</li>
212      * <li><code>servletContext</code> (<code>MockServletContext</code>)</li>
213      * </ul>
214      * 
215      * @throws Exception
216      */
217     protected void setUpServletObjects() throws Exception
218     {
219         servletContext = new MockServletContext();
220         servletConfig = new MockServletConfig(servletContext);
221         servletContext.setDocumentRoot(getWebappContextURI());
222         webContainer = new MockWebContainer();
223         servletContext.setWebContainer(webContainer);
224         setUpWebConfigParams();
225     }
226     
227     /**
228      * <p>Setup web config params. By default it sets the following params</p>
229      * 
230      * <ul>
231      * <li>"org.apache.myfaces.INITIALIZE_ALWAYS_STANDALONE", "true"</li>
232      * <li>"javax.faces.PROJECT_STAGE", "UnitTest"</li>
233      * <li>"javax.faces.PARTIAL_STATE_SAVING", "true"</li>
234      * <li>"javax.faces.FACELETS_REFRESH_PERIOD", "-1"</li>
235      * </ul>
236      * 
237      * @throws Exception
238      */
239     protected void setUpWebConfigParams() throws Exception
240     {
241         servletContext.addInitParameter("org.apache.myfaces.INITIALIZE_ALWAYS_STANDALONE", "true");
242         servletContext.addInitParameter("javax.faces.PROJECT_STAGE", "UnitTest");
243         servletContext.addInitParameter("javax.faces.PARTIAL_STATE_SAVING", "true");
244         servletContext.addInitParameter(ViewHandler.FACELETS_REFRESH_PERIOD_PARAM_NAME,"-1");
245         servletContext.addInitParameter("org.apache.myfaces.spi.InjectionProvider", 
246             NoInjectionAnnotationInjectionProvider.class.getName());
247         servletContext.addInitParameter("org.apache.myfaces.config.annotation.LifecycleProvider",
248             NoInjectionAnnotationLifecycleProvider.class.getName());
249     }
250     
251     /**
252      * <p>Return an URI that identifies the base path that will be used by servletContext
253      * to load resources like facelet files an others. By default it points to the directory
254      * path calculated from the package name of the child test class.</p>
255      * 
256      * @return
257      */
258     protected URI getWebappContextURI()
259     {
260         try
261         {
262             ClassLoader cl = Thread.currentThread().getContextClassLoader();
263             URL url = cl.getResource(getWebappResourcePath());
264             if (url == null)
265             {
266                 throw new FileNotFoundException(cl.getResource("").getFile()
267                         + getWebappResourcePath() + " was not found");
268             }
269             else
270             {
271                 return new URI(url.toString());
272             }
273         }
274         catch (Exception e)
275         {
276             throw new RuntimeException("Error Initializing Context", e);
277         }
278     }
279     
280     /**
281      * Return a path that is used to load resources like facelet files an others.
282      * By default it points to the directory path calculated from the package 
283      * name of the child test class.
284      * 
285      * @return
286      */
287     protected String getWebappResourcePath()
288     {
289         TestConfig testConfig = getTestJavaClass().getAnnotation(TestConfig.class);
290         if (testConfig != null && testConfig.webappResourcePath() != null &&
291             !"testClassResourcePackage".equals(testConfig.webappResourcePath()))
292         {
293             return testConfig.webappResourcePath();
294         }
295         return this.getClass().getName().substring(0,
296                 this.getClass().getName().lastIndexOf('.')).replace('.', '/')
297                 + "/";
298     }
299     
300     /**
301      * Create the ExpressionFactory instance that will be used to initialize the test
302      * environment. By default it uses MockExpressionFactory. 
303      * 
304      * @return
305      */
306     protected ExpressionFactory createExpressionFactory()
307     {
308         TestConfig testConfig = getTestJavaClass().getAnnotation(TestConfig.class);
309         if (testConfig != null && testConfig.expressionFactory() != null &&
310             testConfig.expressionFactory().length() > 0)
311         {
312             return (ExpressionFactory) ClassUtils.newInstance(
313                 testConfig.expressionFactory(), ExpressionFactory.class);
314         }
315         return new MockExpressionFactory();
316     }
317     
318     /**
319      * setup servlets avaliable in the test environment
320      * 
321      * @throws Exception
322      */
323     protected void setUpServlets() throws Exception
324     {
325         setUpFacesServlet();
326     }
327     
328     /**
329      * setup listeners avaliable in the test environment
330      * 
331      * @throws Exception
332      */
333     protected void setUpServletListeners() throws Exception
334     {
335         setUpMyFaces();
336     }
337     
338     /**
339      * 
340      * @return
341      */
342     protected FacesConfigurationProvider createFacesConfigurationProvider()
343     {
344         return new MyFacesMockFacesConfigurationProvider(this); 
345     }
346     
347     protected AbstractFacesInitializer createFacesInitializer()
348     {
349         return new JUnitNoCDIFacesInitializer(this);
350     }
351     
352     protected void setUpMyFaces() throws Exception
353     {
354         if (facesConfigurationProvider == null)
355         {
356             facesConfigurationProvider = createFacesConfigurationProvider();
357         }
358         servletContext.setAttribute(
359                 DefaultFacesConfigurationProviderFactory.FACES_CONFIGURATION_PROVIDER_INSTANCE_KEY, 
360                 facesConfigurationProvider);
361         listener = new StartupServletContextListener();
362         listener.setFacesInitializer(createFacesInitializer());
363         webContainer.subscribeListener(listener);
364         //listener.contextInitialized(new ServletContextEvent(servletContext));
365     }
366 
367     protected void tearDownMyFaces()
368     {
369         //Don't tear down FacesConfigurationProvider, because that is shared by all tests.
370         //This helps to reduce the time each test takes 
371         //facesConfigurationProvider = null
372         
373         //listener.contextDestroyed(new ServletContextEvent(servletContext));
374     }
375 
376     protected void setUpFacesServlet() throws Exception
377     {
378         lifecycleFactory = (LifecycleFactory)FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
379         facesContextFactory = (FacesContextFactory)FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
380         lifecycle = lifecycleFactory.getLifecycle(getLifecycleId());
381     }
382     
383     protected void tearDownFacesServlet() throws Exception
384     {
385         lifecycleFactory = null;
386         facesContextFactory = null;
387     }
388     
389     protected void tearDownServlets() throws Exception
390     {
391         tearDownFacesServlet();
392     }
393     
394     protected void tearDownServletListeners() throws Exception
395     {
396         tearDownMyFaces();
397     }
398 
399     @After
400     public void tearDown() throws Exception
401     {
402         tearDownServlets();
403 
404         webContainer.contextDestroyed(new ServletContextEvent(servletContext));
405         
406         tearDownServletListeners();
407         
408         listener = null;
409         
410         servletConfig = null;
411         servletContext = null;
412         
413         FactoryFinder.releaseFactories();
414         
415         if (jndiContext != null)
416         {
417             MockInitialContextFactory.clearCurrentContext();
418         }
419         
420         tearDownClassloader();
421     }
422     
423     protected void tearDownClassloader() throws Exception
424     {
425         if (classLoaderSet)
426         {
427             Thread.currentThread().setContextClassLoader(threadContextClassLoader);
428             threadContextClassLoader = null;
429             classLoaderSet = false;
430         }
431     }    
432     
433     @AfterClass
434     public static void tearDownClass()
435     {
436         standardFacesConfig = null;
437         sharedConfiguration.clear();
438     }
439     
440     private String getLifecycleId()
441     {
442         // 1. check for Servlet's init-param
443         // 2. check for global context parameter
444         // 3. use default Lifecycle Id, if none of them was provided
445         String serLifecycleId = servletConfig.getInitParameter(FacesServlet.LIFECYCLE_ID_ATTR);
446         String appLifecycleId = servletConfig.getServletContext().getInitParameter(FacesServlet.LIFECYCLE_ID_ATTR);
447         appLifecycleId = serLifecycleId == null ? appLifecycleId : serLifecycleId;
448         return appLifecycleId != null ? appLifecycleId : LifecycleFactory.DEFAULT_LIFECYCLE;
449     }
450 
451     /**
452      * Call lifecycle.execute(facesContext)
453      * 
454      * @param facesContext
455      */
456     public void processLifecycleExecute(FacesContext facesContext)
457     {
458         lifecycle.attachWindow(facesContext);
459         lifecycle.execute(facesContext);
460         facesContext.getAttributes().put(LAST_PHASE_PROCESSED, PhaseId.INVOKE_APPLICATION);
461     }
462 
463     /**
464      * Execute restore view phase.
465      * 
466      * @param facesContext
467      */
468     public void restoreView(FacesContext facesContext)
469     {
470         lifecycle.attachWindow(facesContext);
471         executePhase(facesContext, PhaseId.RESTORE_VIEW);
472         facesContext.getAttributes().put(LAST_PHASE_PROCESSED, PhaseId.RESTORE_VIEW);
473     }
474     
475     /**
476      * Execute apply request values phase. If the responseComplete or renderResponse
477      * flags are set, it returns without do any action.
478      * 
479      * @param facesContext
480      */
481     public void applyRequestValues(FacesContext facesContext)
482     {
483         if (facesContext.getRenderResponse() || facesContext.getResponseComplete())
484         {
485             return;
486         }
487         processRemainingPhasesBefore(facesContext, PhaseId.APPLY_REQUEST_VALUES);
488         executePhase(facesContext, PhaseId.APPLY_REQUEST_VALUES);
489         facesContext.getAttributes().put(LAST_PHASE_PROCESSED, PhaseId.APPLY_REQUEST_VALUES);
490     }
491 
492     /**
493      * Execute process validations phase. If the responseComplete or renderResponse
494      * flags are set, it returns without do any action.
495      * 
496      * @param facesContext
497      */
498     public void processValidations(FacesContext facesContext)
499     {
500         if (facesContext.getRenderResponse() || facesContext.getResponseComplete())
501         {
502             return;
503         }
504         processRemainingPhasesBefore(facesContext, PhaseId.PROCESS_VALIDATIONS);
505         executePhase(facesContext, PhaseId.PROCESS_VALIDATIONS);
506         facesContext.getAttributes().put(LAST_PHASE_PROCESSED, PhaseId.PROCESS_VALIDATIONS);
507     }
508 
509     /**
510      * Execute update model phase. If the responseComplete or renderResponse
511      * flags are set, it returns without do any action.
512      * 
513      * @param facesContext
514      */
515     public void updateModelValues(FacesContext facesContext)
516     {
517         if (facesContext.getRenderResponse() || facesContext.getResponseComplete())
518         {
519             return;
520         }
521         processRemainingPhasesBefore(facesContext, PhaseId.UPDATE_MODEL_VALUES);
522         executePhase(facesContext, PhaseId.UPDATE_MODEL_VALUES);
523         facesContext.getAttributes().put(LAST_PHASE_PROCESSED, PhaseId.UPDATE_MODEL_VALUES);
524 
525     }
526     
527     /**
528      * Execute invoke application phase. If the responseComplete or renderResponse
529      * flags are set, it returns without do any action.
530      * 
531      * @param facesContext
532      */
533     public void invokeApplication(FacesContext facesContext)
534     {
535         if (facesContext.getRenderResponse() || facesContext.getResponseComplete())
536         {
537             return;
538         }
539         processRemainingPhasesBefore(facesContext, PhaseId.INVOKE_APPLICATION);
540         executePhase(facesContext, PhaseId.INVOKE_APPLICATION);
541         facesContext.getAttributes().put(LAST_PHASE_PROCESSED, PhaseId.INVOKE_APPLICATION);
542     }
543 
544     public void processLifecycleRender(FacesContext facesContext)
545     {
546         renderResponse(facesContext);
547     }
548 
549     /**
550      * Call lifecycle.render(facesContext)
551      * 
552      * @param facesContext
553      */
554     public void renderResponse(FacesContext facesContext)
555     {
556         processRemainingExecutePhases(facesContext);
557         lifecycle.render(facesContext);
558         facesContext.getAttributes().put(LAST_PHASE_PROCESSED, PhaseId.RENDER_RESPONSE);
559         facesContext.getAttributes().put(LAST_RENDER_PHASE_STEP, AFTER_RENDER_STEP);
560     }
561     
562     protected void processRemainingPhasesBefore(FacesContext facesContext, PhaseId phaseId)
563     {
564         PhaseId lastPhaseId = (PhaseId) facesContext.getAttributes().get(LAST_PHASE_PROCESSED);
565         if (lastPhaseId == null)
566         {
567             if (!phaseId.equals(PhaseId.RESTORE_VIEW))
568             {
569                 restoreView(facesContext);
570                 lastPhaseId = (PhaseId) facesContext.getAttributes().get(LAST_PHASE_PROCESSED);
571             }
572             else
573             {
574                 // There are no phases before restore view
575                 return;
576             }
577         }
578         if (PhaseId.APPLY_REQUEST_VALUES.equals(phaseId))
579         {
580             return;
581         }
582         boolean continueProcess = false;
583         if (continueProcess || PhaseId.RESTORE_VIEW.equals(lastPhaseId))
584         {
585             applyRequestValues(facesContext);
586             lastPhaseId = (PhaseId) facesContext.getAttributes().get(LAST_PHASE_PROCESSED);
587             continueProcess = true;
588         }
589         if (PhaseId.PROCESS_VALIDATIONS.equals(phaseId))
590         {
591             return;
592         }
593         if (continueProcess || PhaseId.APPLY_REQUEST_VALUES.equals(lastPhaseId))
594         {
595             processValidations(facesContext);
596             lastPhaseId = (PhaseId) facesContext.getAttributes().get(LAST_PHASE_PROCESSED);
597             continueProcess = true;
598         }
599         if (PhaseId.UPDATE_MODEL_VALUES.equals(phaseId))
600         {
601             return;
602         }
603         if (continueProcess || PhaseId.PROCESS_VALIDATIONS.equals(lastPhaseId))
604         {
605             updateModelValues(facesContext);
606             lastPhaseId = (PhaseId) facesContext.getAttributes().get(LAST_PHASE_PROCESSED);
607             continueProcess = true;
608         }
609         if (PhaseId.INVOKE_APPLICATION.equals(phaseId))
610         {
611             return;
612         }
613         if (continueProcess || PhaseId.UPDATE_MODEL_VALUES.equals(lastPhaseId))
614         {
615             invokeApplication(facesContext);
616             lastPhaseId = (PhaseId) facesContext.getAttributes().get(LAST_PHASE_PROCESSED);
617             continueProcess = true;
618         }        
619         if (PhaseId.RENDER_RESPONSE.equals(phaseId))
620         {
621             return;
622         }
623         if (continueProcess || PhaseId.INVOKE_APPLICATION.equals(lastPhaseId))
624         {
625             renderResponse(facesContext);
626             lastPhaseId = (PhaseId) facesContext.getAttributes().get(LAST_PHASE_PROCESSED);
627             continueProcess = true;
628         }
629     }
630     
631     public void processRemainingExecutePhases(FacesContext facesContext)
632     {
633         PhaseId lastPhaseId = (PhaseId) facesContext.getAttributes().get(LAST_PHASE_PROCESSED);
634         if (lastPhaseId == null)
635         {
636             processLifecycleExecute(facesContext);
637             return;
638         }
639         else
640         {
641             boolean continueProcess = false;
642             if (PhaseId.RESTORE_VIEW.equals(lastPhaseId))
643             {
644                 applyRequestValues(facesContext);
645                 continueProcess = true;
646             }
647             if (continueProcess || PhaseId.APPLY_REQUEST_VALUES.equals(lastPhaseId))
648             {
649                 processValidations(facesContext);
650                 continueProcess = true;
651             }
652             if (continueProcess || PhaseId.PROCESS_VALIDATIONS.equals(lastPhaseId))
653             {
654                 updateModelValues(facesContext);
655                 continueProcess = true;
656             }
657             if (continueProcess || PhaseId.UPDATE_MODEL_VALUES.equals(lastPhaseId))
658             {
659                 invokeApplication(facesContext);
660                 continueProcess = true;
661             }
662         }
663     }
664 
665     public void processRemainingPhases(FacesContext facesContext)
666     {
667         PhaseId lastPhaseId = (PhaseId) facesContext.getAttributes().get(LAST_PHASE_PROCESSED);
668         if (lastPhaseId == null)
669         {
670             processLifecycleExecute(facesContext);
671             renderResponse(facesContext);
672             return;
673         }
674         else
675         {
676             boolean continueProcess = false;
677             if (PhaseId.RESTORE_VIEW.equals(lastPhaseId))
678             {
679                 applyRequestValues(facesContext);
680                 continueProcess = true;
681             }
682             if (continueProcess || PhaseId.APPLY_REQUEST_VALUES.equals(lastPhaseId))
683             {
684                 processValidations(facesContext);
685                 continueProcess = true;
686             }
687             if (continueProcess || PhaseId.PROCESS_VALIDATIONS.equals(lastPhaseId))
688             {
689                 updateModelValues(facesContext);
690                 continueProcess = true;
691             }
692             if (continueProcess || PhaseId.UPDATE_MODEL_VALUES.equals(lastPhaseId))
693             {
694                 invokeApplication(facesContext);
695                 continueProcess = true;
696             }
697             if (continueProcess || PhaseId.INVOKE_APPLICATION.equals(lastPhaseId))
698             {
699                 Integer step = (Integer) facesContext.getAttributes().get(LAST_RENDER_PHASE_STEP);
700                 if (step == null)
701                 {
702                     renderResponse(facesContext);
703                 }
704                 else
705                 {
706                     if (BEFORE_RENDER_STEP == step.intValue())
707                     {
708                         executeBuildViewCycle(facesContext);
709                         executeViewHandlerRender(facesContext);
710                         executeAfterRender(facesContext);
711                     }
712                     else if (BUILD_VIEW_CYCLE_STEP == step.intValue())
713                     {
714                         executeViewHandlerRender(facesContext);
715                         executeAfterRender(facesContext);
716                     }
717                     else if (VIEWHANDLER_RENDER_STEP == step.intValue())
718                     {
719                         executeAfterRender(facesContext);
720                     }
721                 }
722             }
723         }
724     }
725     
726     /**
727      * Indicate if annotation scanning should be done over the classpath. 
728      * By default it is set to false.
729      * 
730      * @return
731      */
732     protected boolean isScanAnnotations()
733     {
734         TestConfig testConfig = getTestJavaClass().getAnnotation(TestConfig.class);
735         if (testConfig != null)
736         {
737             return testConfig.scanAnnotations();
738         }
739         return false;
740     }
741     
742     public void executeBeforeRender(FacesContext facesContext)
743     {
744         if (lifecycle instanceof LifecycleImpl)
745         {
746             LifecycleImpl lifecycleImpl = (LifecycleImpl) lifecycle;
747             
748             Object phaseExecutor = null;
749             Object phaseManager = null;
750             try
751             {
752                 Field renderExecutorField = lifecycleImpl.getClass().getDeclaredField("renderExecutor");
753                 if (!renderExecutorField.isAccessible())
754                 {
755                     renderExecutorField.setAccessible(true);
756                 }
757                 phaseExecutor = renderExecutorField.get(lifecycleImpl);
758 
759                 if (facesContext.getResponseComplete())
760                 {
761                     return;
762                 }
763 
764                 phaseManager = facesContext.getAttributes().get(PHASE_MANAGER_INSTANCE);
765                 if (phaseManager == null)
766                 {
767                     Method getPhaseListenersMethod = lifecycleImpl.getClass().getDeclaredMethod("getPhaseListeners");
768                     if (!getPhaseListenersMethod.isAccessible())
769                     {
770                         getPhaseListenersMethod.setAccessible(true);
771                     }
772 
773                     Constructor<?> plmc = PHASE_MANAGER_CLASS.getDeclaredConstructor(
774                         new Class[]{Lifecycle.class, FacesContext.class, PhaseListener[].class});
775                     if (!plmc.isAccessible())
776                     {
777                         plmc.setAccessible(true);
778                     }
779                     phaseManager = plmc.newInstance(lifecycle, facesContext, getPhaseListenersMethod.invoke(
780                         lifecycleImpl, null));
781                     facesContext.getAttributes().put(PHASE_MANAGER_INSTANCE, phaseManager);
782                 }
783             }
784             catch (NoSuchFieldException ex)
785             {
786                 throw new IllegalStateException("Cannot get executors from LifecycleImpl", ex);
787             }
788             catch (SecurityException ex)
789             {
790                 throw new UnsupportedOperationException("Cannot get executors from LifecycleImpl", ex);
791             }
792             catch (IllegalArgumentException ex)
793             {
794                 throw new UnsupportedOperationException("Cannot get executors from LifecycleImpl", ex);
795             }
796             catch (IllegalAccessException ex)
797             {
798                 throw new UnsupportedOperationException("Cannot get executors from LifecycleImpl", ex);
799             }
800             catch (NoSuchMethodException ex)
801             {
802                 throw new UnsupportedOperationException("Cannot get executors from LifecycleImpl", ex);
803             }
804             catch (InvocationTargetException ex)
805             {
806                 throw new UnsupportedOperationException("Cannot get executors from LifecycleImpl", ex);
807             }
808             catch (InstantiationException ex)
809             {
810                 throw new UnsupportedOperationException("Cannot get executors from LifecycleImpl", ex);
811             }
812             
813             Flash flash = facesContext.getExternalContext().getFlash();
814             
815             try
816             {
817                 facesContext.setCurrentPhaseId(PhaseId.RENDER_RESPONSE);
818                 
819                 flash.doPrePhaseActions(facesContext);
820                 
821                 // let the PhaseExecutor do some pre-phase actions
822                 
823                 //renderExecutor.doPrePhaseActions(facesContext);
824                 Method doPrePhaseActionsMethod = phaseExecutor.getClass().getMethod("doPrePhaseActions", 
825                     FacesContext.class);
826                 if(!(doPrePhaseActionsMethod.isAccessible()))
827                 {
828                     doPrePhaseActionsMethod.setAccessible(true);
829                 }
830                 doPrePhaseActionsMethod.invoke(phaseExecutor, facesContext);
831                 
832                 //phaseListenerMgr.informPhaseListenersBefore(PhaseId.RENDER_RESPONSE);
833                 Method informPhaseListenersBeforeMethod = phaseManager.getClass().getDeclaredMethod(
834                     "informPhaseListenersBefore", PhaseId.class);
835                 if(!(informPhaseListenersBeforeMethod.isAccessible()))
836                 {
837                     informPhaseListenersBeforeMethod.setAccessible(true);
838                 }
839                 informPhaseListenersBeforeMethod.invoke(phaseManager, PhaseId.RENDER_RESPONSE);
840                 
841                 // also possible that one of the listeners completed the response
842                 if (facesContext.getResponseComplete())
843                 {
844                     return;
845                 }
846                 
847                 //renderExecutor.execute(facesContext);
848             }
849             
850             catch (Throwable e)
851             {
852                 // JSF 2.0: publish the executor's exception (if any).
853                 ExceptionQueuedEventContext context = new ExceptionQueuedEventContext (
854                     facesContext, e, null, PhaseId.RENDER_RESPONSE);
855                 facesContext.getApplication().publishEvent (facesContext, ExceptionQueuedEvent.class, context);
856             }
857             
858             finally
859             {
860                 /*
861                 phaseListenerMgr.informPhaseListenersAfter(renderExecutor.getPhase());
862                 flash.doPostPhaseActions(facesContext);
863                 
864                 // publish a field in the application map to indicate
865                 // that the first request has been processed
866                 requestProcessed(facesContext);
867                 */
868             }
869             
870             facesContext.getExceptionHandler().handle();
871             
872 
873             facesContext.getAttributes().remove(PHASE_MANAGER_INSTANCE);
874             
875             facesContext.getAttributes().put(LAST_RENDER_PHASE_STEP, BEFORE_RENDER_STEP);
876         }
877         else
878         {
879             throw new UnsupportedOperationException("Cannot execute phase on custom lifecycle instances");
880         }
881     }
882     
883     public void executeBuildViewCycle(FacesContext facesContext)
884     {
885         Application application = facesContext.getApplication();
886         ViewHandler viewHandler = application.getViewHandler();
887         UIViewRoot root;
888         UIViewRoot previousRoot;
889         String viewId;
890         String newViewId;
891         boolean isNotSameRoot;
892         int loops = 0;
893         int maxLoops = 15;
894         
895         if (facesContext.getViewRoot() == null)
896         {
897             throw new ViewNotFoundException("A view is required to execute "+facesContext.getCurrentPhaseId());
898         }
899         
900         try
901         {
902             // do-while, because the view might change in PreRenderViewEvent-listeners
903             do
904             {
905                 root = facesContext.getViewRoot();
906                 previousRoot = root;
907                 viewId = root.getViewId();
908                 
909                 ViewDeclarationLanguage vdl = viewHandler.getViewDeclarationLanguage(
910                         facesContext, viewId);
911                 if (vdl != null)
912                 {
913                     vdl.buildView(facesContext, root);
914                 }
915                 
916                 // publish a PreRenderViewEvent: note that the event listeners
917                 // of this event can change the view, so we have to perform the algorithm 
918                 // until the viewId does not change when publishing this event.
919                 application.publishEvent(facesContext, PreRenderViewEvent.class, root);
920                 
921                 // was the response marked as complete by an event listener?
922                 if (facesContext.getResponseComplete())
923                 {
924                     return;
925                 }
926 
927                 root = facesContext.getViewRoot();
928                 
929                 newViewId = root.getViewId();
930                 
931                 isNotSameRoot = !( (newViewId == null ? newViewId == viewId : newViewId.equals(viewId) ) && 
932                         previousRoot.equals(root) ); 
933                 
934                 loops++;
935             }
936             while ((newViewId == null && viewId != null) 
937                     || (newViewId != null && (!newViewId.equals(viewId) || isNotSameRoot ) ) && loops < maxLoops);
938             
939             if (loops == maxLoops)
940             {
941                 // PreRenderView reach maxLoops - probably a infinitive recursion:
942                 boolean production = facesContext.isProjectStage(ProjectStage.Production);
943                 /*
944                 Level level = production ? Level.FINE : Level.WARNING;
945                 if (log.isLoggable(level))
946                 {
947                     log.log(level, "Cicle over buildView-PreRenderViewEvent on RENDER_RESPONSE phase "
948                                    + "reaches maximal limit, please check listeners for infinite recursion.");
949                 }*/
950             }
951             
952             facesContext.getAttributes().put(LAST_RENDER_PHASE_STEP, BUILD_VIEW_CYCLE_STEP);
953         }
954         catch (IOException e)
955         {
956             throw new FacesException(e.getMessage(), e);
957         }
958     }
959     
960     public void executeViewHandlerRender(FacesContext facesContext)
961     {
962         Application application = facesContext.getApplication();
963         ViewHandler viewHandler = application.getViewHandler();
964 
965         try
966         {
967             viewHandler.renderView(facesContext, facesContext.getViewRoot());
968             
969             // log all unhandled FacesMessages, don't swallow them
970             // perf: org.apache.myfaces.context.servlet.FacesContextImpl.getMessageList() creates
971             // new Collections.unmodifiableList with every invocation->  call it only once
972             // and messageList is RandomAccess -> use index based loop
973             List<FacesMessage> messageList = facesContext.getMessageList();
974             if (!messageList.isEmpty())
975             {
976                 StringBuilder builder = new StringBuilder();
977                 //boolean shouldLog = false;
978                 for (int i = 0, size = messageList.size(); i < size; i++)
979                 {
980                     FacesMessage message = messageList.get(i);
981                     if (!message.isRendered())
982                     {
983                         builder.append("\n- ");
984                         builder.append(message.getDetail());
985                         
986                         //shouldLog = true;
987                     }
988                 }
989                 /*
990                 if (shouldLog)
991                 {
992                     log.log(Level.WARNING, "There are some unhandled FacesMessages, " +
993                             "this means not every FacesMessage had a chance to be rendered.\n" +
994                             "These unhandled FacesMessages are: " + builder.toString());
995                 }*/
996             }
997             facesContext.getAttributes().put(LAST_RENDER_PHASE_STEP, VIEWHANDLER_RENDER_STEP);
998         }
999         catch (IOException e)
1000         {
1001             throw new FacesException(e.getMessage(), e);
1002         }
1003     }
1004     
1005     public void executeAfterRender(FacesContext facesContext)
1006     {
1007         if (lifecycle instanceof LifecycleImpl)
1008         {
1009             LifecycleImpl lifecycleImpl = (LifecycleImpl) lifecycle;
1010             
1011             Object phaseExecutor = null;
1012             Object phaseManager = null;
1013             Method informPhaseListenersAfterMethod = null;
1014             try
1015             {
1016                 Field renderExecutorField = lifecycleImpl.getClass().getDeclaredField("renderExecutor");
1017                 if (!renderExecutorField.isAccessible())
1018                 {
1019                     renderExecutorField.setAccessible(true);
1020                 }
1021                 phaseExecutor = renderExecutorField.get(lifecycleImpl);
1022             
1023                 phaseManager = facesContext.getAttributes().get(PHASE_MANAGER_INSTANCE);
1024                 if (phaseManager == null)
1025                 {
1026                     Method getPhaseListenersMethod = lifecycleImpl.getClass().getDeclaredMethod("getPhaseListeners");
1027                     if (!getPhaseListenersMethod.isAccessible())
1028                     {
1029                         getPhaseListenersMethod.setAccessible(true);
1030                     }
1031 
1032                     Constructor<?> plmc = PHASE_MANAGER_CLASS.getDeclaredConstructor(
1033                         new Class[]{Lifecycle.class, FacesContext.class, PhaseListener[].class});
1034                     if (!plmc.isAccessible())
1035                     {
1036                         plmc.setAccessible(true);
1037                     }
1038                     phaseManager = plmc.newInstance(lifecycle, facesContext, getPhaseListenersMethod.invoke(
1039                         lifecycleImpl, null));
1040                     facesContext.getAttributes().put(PHASE_MANAGER_INSTANCE, phaseManager);
1041                 }
1042 
1043                 //phaseListenerMgr.informPhaseListenersAfter(renderExecutor.getPhase());
1044                 informPhaseListenersAfterMethod = phaseManager.getClass().getDeclaredMethod(
1045                     "informPhaseListenersAfter", PhaseId.class);
1046                 if(!(informPhaseListenersAfterMethod.isAccessible()))
1047                 {
1048                     informPhaseListenersAfterMethod.setAccessible(true);
1049                 }
1050                 
1051                 informPhaseListenersAfterMethod.invoke(phaseManager, PhaseId.RENDER_RESPONSE);
1052             }
1053             catch (NoSuchFieldException ex)
1054             {
1055                 throw new IllegalStateException("Cannot get executors from LifecycleImpl", ex);
1056             }
1057             catch (SecurityException ex)
1058             {
1059                 throw new UnsupportedOperationException("Cannot get executors from LifecycleImpl", ex);
1060             }
1061             catch (IllegalArgumentException ex)
1062             {
1063                 throw new UnsupportedOperationException("Cannot get executors from LifecycleImpl", ex);
1064             }
1065             catch (IllegalAccessException ex)
1066             {
1067                 throw new UnsupportedOperationException("Cannot get executors from LifecycleImpl", ex);
1068             }
1069             catch (NoSuchMethodException ex)
1070             {
1071                 throw new UnsupportedOperationException("Cannot get executors from LifecycleImpl", ex);
1072             }
1073             catch (InvocationTargetException ex)
1074             {
1075                 throw new UnsupportedOperationException("Cannot get executors from LifecycleImpl", ex);
1076             }
1077             catch (InstantiationException ex)
1078             {
1079                 throw new UnsupportedOperationException("Cannot get executors from LifecycleImpl", ex);
1080             }
1081             
1082             Flash flash = facesContext.getExternalContext().getFlash();
1083             
1084             flash.doPostPhaseActions(facesContext);
1085             
1086             facesContext.getExceptionHandler().handle();
1087 
1088             facesContext.getAttributes().remove(PHASE_MANAGER_INSTANCE);
1089             
1090             facesContext.getAttributes().put(LAST_RENDER_PHASE_STEP, AFTER_RENDER_STEP);
1091             //End render response phase
1092             facesContext.getAttributes().put(LAST_PHASE_PROCESSED, PhaseId.RENDER_RESPONSE);
1093         }
1094         else
1095         {
1096             throw new UnsupportedOperationException("Cannot execute phase on custom lifecycle instances");
1097         }
1098     }
1099     
1100     /**
1101      * Execute an specified phase, doing some reflection over LifecycleImpl.
1102      * 
1103      * @param facesContext
1104      * @param phase
1105      */
1106     protected void executePhase(FacesContext facesContext, PhaseId phase)
1107     {
1108         if (lifecycle instanceof LifecycleImpl)
1109         {
1110             LifecycleImpl lifecycleImpl = (LifecycleImpl) lifecycle;
1111             
1112             int phaseId = phase.equals(PhaseId.RESTORE_VIEW) ? 0 :
1113                           phase.equals(PhaseId.APPLY_REQUEST_VALUES) ? 1 : 
1114                           phase.equals(PhaseId.PROCESS_VALIDATIONS) ? 2 :
1115                           phase.equals(PhaseId.UPDATE_MODEL_VALUES) ? 3 : 
1116                           phase.equals(PhaseId.INVOKE_APPLICATION) ? 4 : 5 ;
1117             
1118             Method executePhaseMethod = null;
1119             Object phaseManager = null;
1120             Object phaseExecutor = null;
1121             try
1122             {
1123                 if (phaseId < 5)
1124                 {
1125                     Field lifecycleExecutorsField;
1126                         lifecycleExecutorsField = lifecycleImpl.getClass().getDeclaredField("lifecycleExecutors");
1127                         if (!lifecycleExecutorsField.isAccessible())
1128                         {
1129                             lifecycleExecutorsField.setAccessible(true);
1130                         }
1131                         phaseExecutor = ((Object[])lifecycleExecutorsField.get(lifecycleImpl))[phaseId];
1132                 }
1133                 else
1134                 {
1135                     Field renderExecutorField = lifecycleImpl.getClass().getDeclaredField("renderExecutor");
1136                     if (!renderExecutorField.isAccessible())
1137                     {
1138                         renderExecutorField.setAccessible(true);
1139                     }
1140                     phaseExecutor = renderExecutorField.get(lifecycleImpl);
1141                 }
1142 
1143                 phaseManager = facesContext.getAttributes().get(PHASE_MANAGER_INSTANCE);
1144                 if (phaseManager == null)
1145                 {
1146                     Method getPhaseListenersMethod = lifecycleImpl.getClass().getDeclaredMethod("getPhaseListeners");
1147                     if (!getPhaseListenersMethod.isAccessible())
1148                     {
1149                         getPhaseListenersMethod.setAccessible(true);
1150                     }
1151 
1152                     Constructor<?> plmc = PHASE_MANAGER_CLASS.getDeclaredConstructor(
1153                         new Class[]{Lifecycle.class, FacesContext.class, PhaseListener[].class});
1154                     if (!plmc.isAccessible())
1155                     {
1156                         plmc.setAccessible(true);
1157                     }
1158                     phaseManager = plmc.newInstance(lifecycle, facesContext, 
1159                         getPhaseListenersMethod.invoke(lifecycleImpl, null));
1160                     facesContext.getAttributes().put(PHASE_MANAGER_INSTANCE, phaseManager);
1161                 }
1162 
1163                 executePhaseMethod = lifecycleImpl.getClass().getDeclaredMethod("executePhase", new Class[]{
1164                         FacesContext.class, PHASE_EXECUTOR_CLASS, PHASE_MANAGER_CLASS});
1165                 if (!executePhaseMethod.isAccessible())
1166                 {
1167                     executePhaseMethod.setAccessible(true);
1168                 }
1169                 
1170                 executePhaseMethod.invoke(lifecycleImpl, facesContext, phaseExecutor, phaseManager);
1171             }
1172             catch (NoSuchFieldException ex)
1173             {
1174                 throw new IllegalStateException("Cannot get executors from LifecycleImpl", ex);
1175             }
1176             catch (SecurityException ex)
1177             {
1178                 throw new UnsupportedOperationException("Cannot get executors from LifecycleImpl", ex);
1179             }
1180             catch (IllegalArgumentException ex)
1181             {
1182                 throw new UnsupportedOperationException("Cannot get executors from LifecycleImpl", ex);
1183             }
1184             catch (IllegalAccessException ex)
1185             {
1186                 throw new UnsupportedOperationException("Cannot get executors from LifecycleImpl", ex);
1187             }
1188             catch (NoSuchMethodException ex)
1189             {
1190                 throw new UnsupportedOperationException("Cannot get executors from LifecycleImpl", ex);
1191             }
1192             catch (InvocationTargetException ex)
1193             {
1194                 throw new UnsupportedOperationException("Cannot get executors from LifecycleImpl", ex);
1195             }
1196             catch (InstantiationException ex)
1197             {
1198                 throw new UnsupportedOperationException("Cannot get executors from LifecycleImpl", ex);
1199             }            
1200             
1201             if (phase.equals(PhaseId.RENDER_RESPONSE))
1202             {
1203                 facesContext.getAttributes().remove(PHASE_MANAGER_INSTANCE);
1204             }
1205         }
1206         else
1207         {
1208             throw new UnsupportedOperationException("Cannot execute phase on custom lifecycle instances");
1209         }
1210     }
1211     
1212     protected String getRenderedContent(FacesContext facesContext) throws IOException
1213     {
1214         MockPrintWriter writer1 = (MockPrintWriter) 
1215             (((HttpServletResponse) facesContext.getExternalContext().getResponse()).getWriter());
1216         return String.valueOf(writer1.content());
1217     }
1218 
1219     // ------------------------------------------------------ Instance Variables
1220 
1221 
1222     // Thread context class loader saved and restored after each test
1223     private ClassLoader threadContextClassLoader = null;
1224     private boolean classLoaderSet = false;
1225     private Context jndiContext = null;
1226 
1227     // Servlet objects 
1228     protected MockServletConfig servletConfig = null;
1229     protected MockServletContext servletContext = null;
1230     protected MockWebContainer webContainer = null;
1231 
1232     // MyFaces specific objects created by the servlet environment
1233     protected StartupServletContextListener listener = null;
1234     protected FacesConfigurationProvider facesConfigurationProvider = null;
1235     
1236     protected FacesContextFactory facesContextFactory = null;
1237     protected LifecycleFactory lifecycleFactory = null;
1238     protected Lifecycle lifecycle;
1239 
1240     private static FacesConfig standardFacesConfig;
1241     private static Map<String, SharedFacesConfiguration> sharedConfiguration =
1242         new ConcurrentHashMap<String, SharedFacesConfiguration>();
1243     private SharedFacesConfiguration jsfConfiguration;
1244     
1245     protected Class<?> getTestJavaClass()
1246     {
1247         return this.getClass();
1248     }
1249     
1250 
1251     // ------------------------------------------------------ Subclasses
1252 
1253     /**
1254      * Mock FacesConfigurationProvider that replace the original ViewDeclarationLanguageFactory 
1255      * with a customized one that contains only facelets vdl and cache some FacesConfig that 
1256      * does not change to reduce the time required to process each test.
1257      * 
1258      * @author Leonardo Uribe
1259      *
1260      */
1261     protected class MyFacesMockFacesConfigurationProvider extends DefaultFacesConfigurationProvider
1262     {
1263         private AbstractMyFacesTestCase testCase;
1264         
1265         public MyFacesMockFacesConfigurationProvider(AbstractMyFacesTestCase testCase)
1266         {
1267             this.testCase = testCase;
1268         }
1269         
1270         @Override
1271         public FacesConfig getStandardFacesConfig(ExternalContext ectx)
1272         {
1273             if (standardFacesConfig == null)
1274             {
1275                 FacesConfig sfc = super.getStandardFacesConfig(ectx);
1276                 FactoryImpl factory = (FactoryImpl) sfc.getFactories().get(0);
1277                 // Override the default vdl factory with a mock one that only load
1278                 // facelet views
1279                 factory.getViewDeclarationLanguageFactory().set(0,
1280                     MockMyFacesViewDeclarationLanguageFactory.class.getName());
1281                 standardFacesConfig = sfc;
1282             }
1283             return standardFacesConfig;
1284         }
1285 
1286         @Override
1287         public FacesConfig getAnnotationsFacesConfig(ExternalContext ectx,
1288                 boolean metadataComplete)
1289         {
1290             FacesConfig facesConfig = jsfConfiguration.getAnnotationsFacesConfig();
1291             if (facesConfig == null)
1292             {
1293                 if (isScanAnnotations())
1294                 {
1295                     facesConfig = super.getAnnotationsFacesConfig(ectx, metadataComplete); 
1296                 }
1297 
1298                 ManagedBeans annoManagedBeans = getTestJavaClass().getAnnotation(ManagedBeans.class);
1299                 if (annoManagedBeans != null)
1300                 {
1301                     if (facesConfig == null)
1302                     {
1303                         facesConfig = new org.apache.myfaces.config.impl.digester.elements.FacesConfigImpl();
1304                     }
1305                     for (PageBean annoPageBean : annoManagedBeans.value())
1306                     {
1307                         org.apache.myfaces.config.impl.digester.elements.ManagedBeanImpl bean = new 
1308                             org.apache.myfaces.config.impl.digester.elements.ManagedBeanImpl();
1309                         bean.setBeanClass(annoPageBean.clazz().getName());
1310                         bean.setName(annoPageBean.name() == null ? 
1311                             annoPageBean.clazz().getName() : annoPageBean.name());
1312                         bean.setScope(annoPageBean.scope() == null ? "request" : annoPageBean.scope());
1313                         bean.setEager(Boolean.toString(annoPageBean.eager()));
1314 
1315                         ((org.apache.myfaces.config.impl.digester.elements.FacesConfigImpl)facesConfig).
1316                             addManagedBean(bean);
1317                     }
1318                 }
1319 
1320                 PageBean annoPageBean = getTestJavaClass().getAnnotation(PageBean.class);
1321                 if (annoPageBean != null)
1322                 {
1323                     if (facesConfig == null)
1324                     {
1325                         facesConfig = new org.apache.myfaces.config.impl.digester.elements.FacesConfigImpl();
1326                     }
1327                     org.apache.myfaces.config.impl.digester.elements.ManagedBeanImpl bean = new 
1328                         org.apache.myfaces.config.impl.digester.elements.ManagedBeanImpl();
1329                     bean.setBeanClass(annoPageBean.clazz().getName());
1330                     bean.setName(annoPageBean.name() == null ? annoPageBean.clazz().getName() : annoPageBean.name());
1331                     bean.setScope(annoPageBean.scope() == null ? "request" : annoPageBean.scope());
1332                     bean.setEager(Boolean.toString(annoPageBean.eager()));
1333 
1334                     ((org.apache.myfaces.config.impl.digester.elements.FacesConfigImpl)facesConfig).
1335                         addManagedBean(bean);
1336                 }
1337                 jsfConfiguration.setAnnotationFacesConfig(facesConfig);
1338             }
1339             return facesConfig;
1340         }
1341 
1342         @Override
1343         public List<FacesConfig> getClassloaderFacesConfig(ExternalContext ectx)
1344         {
1345             List<FacesConfig> list = jsfConfiguration.getClassloaderFacesConfig();
1346             if (list == null)
1347             {
1348                 list = super.getClassloaderFacesConfig(ectx);
1349                 jsfConfiguration.setClassloaderFacesConfig(list);
1350             }
1351             return list;
1352         }
1353 
1354         @Override
1355         public List<FacesConfig> getFaceletTaglibFacesConfig(ExternalContext externalContext)
1356         {
1357             List<FacesConfig> list = jsfConfiguration.getFaceletTaglibFacesConfig();
1358             if (list == null)
1359             {
1360                 list = super.getFaceletTaglibFacesConfig(externalContext);
1361                 jsfConfiguration.setFaceletTaglibFacesConfig(list);
1362             }
1363             return list;
1364         }
1365 
1366         @Override
1367         public List<FacesConfig> getFacesFlowFacesConfig(ExternalContext ectx)
1368         {
1369             List<FacesConfig> list = jsfConfiguration.getFacesFlowFacesConfig();
1370             if (list == null)
1371             {
1372                 list = super.getFacesFlowFacesConfig(ectx);
1373                 jsfConfiguration.setFacesFlowFacesConfig(list);
1374             }
1375             return list;
1376         }
1377 
1378         @Override
1379         public FacesConfig getMetaInfServicesFacesConfig(ExternalContext ectx)
1380         {
1381             FacesConfig facesConfig = jsfConfiguration.getMetaInfServicesFacesConfig();
1382             if (facesConfig == null)
1383             {
1384                 facesConfig = super.getMetaInfServicesFacesConfig(ectx);
1385             }
1386             return facesConfig;
1387         }
1388         
1389         @Override
1390         public List<FacesConfig> getContextSpecifiedFacesConfig(ExternalContext ectx)
1391         {
1392             List<FacesConfig> appConfigResources = super.getContextSpecifiedFacesConfig(ectx);
1393             
1394             DeclareFacesConfig annoFacesConfig = getTestJavaClass().getAnnotation(DeclareFacesConfig.class);
1395             if (annoFacesConfig != null)
1396             {
1397                 Logger log = Logger.getLogger(getTestJavaClass().getName());
1398                 try
1399                 {
1400                     for (String systemId : annoFacesConfig.value())
1401                     {
1402                         if (MyfacesConfig.getCurrentInstance(ectx).isValidateXML())
1403                         {
1404                             URL url = ectx.getResource(systemId);
1405                             if (url != null)
1406                             {
1407                                 validateFacesConfig(ectx, url);
1408                             }
1409                         }   
1410                         InputStream stream = ectx.getResourceAsStream(systemId);
1411                         if (stream == null)
1412                         {
1413                             
1414                             log.severe("Faces config resource " + systemId + " not found");
1415                             continue;
1416                         }
1417             
1418                         if (log.isLoggable(Level.INFO))
1419                         {
1420                             log.info("Reading config " + systemId);
1421                         }
1422                         appConfigResources.add(getUnmarshaller(ectx).getFacesConfig(stream, systemId));
1423                         //getDispenser().feed(getUnmarshaller().getFacesConfig(stream, systemId));
1424                         stream.close();
1425     
1426                     }
1427                 }
1428                 catch (Throwable e)
1429                 {
1430                     throw new FacesException(e);
1431                 }
1432             }
1433             return appConfigResources;
1434         }
1435     }
1436     
1437     private void validateFacesConfig(ExternalContext ectx, URL url) throws IOException, SAXException
1438     {
1439         String version = ConfigFilesXmlValidationUtils.getFacesConfigVersion(url);
1440         if ("1.2".equals(version) || "2.0".equals(version) || "2.1".equals(version))
1441         {
1442             ConfigFilesXmlValidationUtils.validateFacesConfigFile(url, ectx, version);
1443         }
1444     }
1445     
1446     protected class JUnitFacesInitializer extends AbstractFacesInitializer
1447     {
1448         private final AbstractMyFacesTestCase testCase;
1449         
1450         public JUnitFacesInitializer(AbstractMyFacesTestCase testCase)
1451         {
1452             this.testCase = testCase;
1453         }
1454         
1455         @Override
1456         protected void initContainerIntegration(ServletContext servletContext,
1457                 ExternalContext externalContext)
1458         {
1459             ExpressionFactory expressionFactory = createExpressionFactory();
1460 
1461             RuntimeConfig runtimeConfig = buildConfiguration(servletContext, externalContext, expressionFactory);
1462         }
1463 
1464         public AbstractMyFacesTestCase getTestCase()
1465         {
1466             return testCase;
1467         }
1468 
1469     }
1470     
1471     protected class JUnitNoCDIFacesInitializer extends JUnitFacesInitializer
1472     {
1473 
1474         public JUnitNoCDIFacesInitializer(AbstractMyFacesTestCase testCase)
1475         {
1476             super(testCase);
1477         }
1478 
1479         @Override
1480         protected void initCDIIntegration(ServletContext servletContext, ExternalContext externalContext)
1481         {
1482             //super.initCDIIntegration(servletContext, externalContext);
1483         }
1484         
1485     }
1486     
1487     protected static class SharedFacesConfiguration
1488     {
1489         private List<FacesConfig> classloaderFacesConfig;
1490         private FacesConfig annotationFacesConfig;
1491         private List<FacesConfig> faceletTaglibFacesConfig;
1492         private List<FacesConfig> facesFlowFacesConfig;
1493         private FacesConfig metaInfServicesFacesConfig;
1494         private List<FacesConfig> contextSpecifiedFacesConfig;
1495 
1496         /**
1497          * @return the annotationFacesConfig
1498          */
1499         public FacesConfig getAnnotationsFacesConfig()
1500         {
1501             return annotationFacesConfig;
1502         }
1503 
1504         /**
1505          * @param annotationFacesConfig the annotationFacesConfig to set
1506          */
1507         public void setAnnotationFacesConfig(FacesConfig annotationFacesConfig)
1508         {
1509             this.annotationFacesConfig = annotationFacesConfig;
1510         }
1511 
1512         /**
1513          * @return the annotationFacesConfig
1514          */
1515         public FacesConfig getAnnotationFacesConfig()
1516         {
1517             return annotationFacesConfig;
1518         }
1519 
1520         /**
1521          * @return the faceletTaglibFacesConfig
1522          */
1523         public List<FacesConfig> getFaceletTaglibFacesConfig()
1524         {
1525             return faceletTaglibFacesConfig;
1526         }
1527 
1528         /**
1529          * @param faceletTaglibFacesConfig the faceletTaglibFacesConfig to set
1530          */
1531         public void setFaceletTaglibFacesConfig(List<FacesConfig> faceletTaglibFacesConfig)
1532         {
1533             this.faceletTaglibFacesConfig = faceletTaglibFacesConfig;
1534         }
1535 
1536         /**
1537          * @return the facesFlowFacesConfig
1538          */
1539         public List<FacesConfig> getFacesFlowFacesConfig()
1540         {
1541             return facesFlowFacesConfig;
1542         }
1543 
1544         /**
1545          * @param facesFlowFacesConfig the facesFlowFacesConfig to set
1546          */
1547         public void setFacesFlowFacesConfig(List<FacesConfig> facesFlowFacesConfig)
1548         {
1549             this.facesFlowFacesConfig = facesFlowFacesConfig;
1550         }
1551 
1552         /**
1553          * @return the metaInfServicesFacesConfig
1554          */
1555         public FacesConfig getMetaInfServicesFacesConfig()
1556         {
1557             return metaInfServicesFacesConfig;
1558         }
1559 
1560         /**
1561          * @param metaInfServicesFacesConfig the metaInfServicesFacesConfig to set
1562          */
1563         public void setMetaInfServicesFacesConfig(FacesConfig metaInfServicesFacesConfig)
1564         {
1565             this.metaInfServicesFacesConfig = metaInfServicesFacesConfig;
1566         }
1567 
1568         /**
1569          * @return the contextSpecifiedFacesConfig
1570          */
1571         public List<FacesConfig> getContextSpecifiedFacesConfig()
1572         {
1573             return contextSpecifiedFacesConfig;
1574         }
1575 
1576         /**
1577          * @param contextSpecifiedFacesConfig the contextSpecifiedFacesConfig to set
1578          */
1579         public void setContextSpecifiedFacesConfig(List<FacesConfig> contextSpecifiedFacesConfig)
1580         {
1581             this.contextSpecifiedFacesConfig = contextSpecifiedFacesConfig;
1582         }
1583 
1584         /**
1585          * @return the classloaderFacesConfigList
1586          */
1587         public List<FacesConfig> getClassloaderFacesConfig()
1588         {
1589             return classloaderFacesConfig;
1590         }
1591 
1592         /**
1593          * @param classloaderFacesConfigList the classloaderFacesConfigList to set
1594          */
1595         public void setClassloaderFacesConfig(List<FacesConfig> classloaderFacesConfigList)
1596         {
1597             this.classloaderFacesConfig = classloaderFacesConfigList;
1598         }
1599     }
1600 }