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 java.io.ByteArrayInputStream;
22  import java.io.ByteArrayOutputStream;
23  import java.io.IOException;
24  import java.io.ObjectInputStream;
25  import java.io.ObjectOutputStream;
26  import java.util.AbstractCollection;
27  import java.util.ArrayList;
28  import java.util.Collection;
29  import java.util.Collections;
30  import java.util.EnumSet;
31  import java.util.Iterator;
32  import java.util.List;
33  
34  import javax.faces.application.StateManager;
35  import javax.faces.component.html.HtmlPanelGroup;
36  import javax.faces.component.visit.VisitCallback;
37  import javax.faces.component.visit.VisitContext;
38  import javax.faces.component.visit.VisitHint;
39  import javax.faces.component.visit.VisitResult;
40  import javax.faces.context.FacesContext;
41  import javax.faces.event.AbortProcessingException;
42  import javax.faces.event.FacesEvent;
43  import javax.faces.event.PhaseId;
44  import javax.faces.render.Renderer;
45  import static junit.framework.TestCase.assertEquals;
46  
47  import org.apache.myfaces.Assert;
48  import org.apache.myfaces.TestRunner;
49  import org.apache.myfaces.mock.MockRenderedValueExpression;
50  import org.apache.myfaces.test.base.AbstractJsfTestCase;
51  import org.apache.myfaces.test.mock.visit.MockVisitContext;
52  import org.easymock.classextension.EasyMock;
53  import org.easymock.classextension.IMocksControl;
54  
55  public class UIDataTest extends AbstractJsfTestCase
56  {
57  
58      public UIDataTest(String name)
59      {
60          super(name);
61      }
62  
63      private IMocksControl _mocksControl;
64      private UIData _testImpl;
65  
66      @Override
67      protected void setUp() throws Exception
68      {
69          super.setUp();
70          _mocksControl = EasyMock.createControl();
71          _testImpl = new UIData();
72      }
73  
74      /**
75       * Test method for
76       * {@link javax.faces.component.UIData#setValueExpression(java.lang.String, javax.el.ValueExpression)}.
77       */
78      public void testValueExpression()
79      {
80          assertSetValueExpressionException(IllegalArgumentException.class, "rowIndex");
81          assertSetValueExpressionException(NullPointerException.class, null);
82      }
83  
84      private void assertSetValueExpressionException(Class<? extends Throwable> expected, final String name)
85      {
86          Assert.assertException(expected, new TestRunner()
87          {
88              public void run() throws Throwable
89              {
90                  _testImpl.setValueExpression(name, null);
91              }
92          });
93      }
94  
95      /**
96       * Test method for {@link javax.faces.component.UIData#getClientId(javax.faces.context.FacesContext)}.
97       */
98      public void testGetClientId()
99      {
100         _testImpl.setId("xxx");
101         Renderer renderer = _mocksControl.createMock(Renderer.class);
102         renderKit.addRenderer(UIData.COMPONENT_FAMILY, UIData.COMPONENT_TYPE, renderer);
103         assertEquals("xxx", _testImpl.getClientId(facesContext));
104         _testImpl.setRowIndex(99);
105         //MYFACES-2744 UIData.getClientId() should not append rowIndex, instead use UIData.getContainerClientId()
106         assertEquals("xxx", _testImpl.getClientId(facesContext)); 
107         assertEquals("xxx:99", _testImpl.getContainerClientId(facesContext));
108     }
109 
110     /**
111      * Test method for
112      * {@link javax.faces.component.UIData#invokeOnComponent(javax.faces.context.FacesContext, java.lang.String, javax.faces.component.ContextCallback)}
113      * .
114      * Tests, if invokeOnComponent also checks the facets of the h:column children (MYFACES-2370)
115      */
116     public void testInvokeOnComponentFacesContextStringContextCallback()
117     {
118         /**
119          * Concrete class of ContextCallback needed to test invokeOnComponent. 
120          */
121         final class MyContextCallback implements ContextCallback
122         {
123             
124             private boolean invoked = false;
125 
126             public void invokeContextCallback(FacesContext context,
127                     UIComponent target)
128             {
129                 this.invoked = true;
130             }
131             
132         }
133         
134         UIComponent facet = new UIOutput();
135         facet.setId("facet");
136         UIColumn column = new UIColumn();
137         column.setId("column");
138         column.getFacets().put("header", facet);
139         _testImpl.setId("uidata");
140         _testImpl.getChildren().add(column);
141         
142         MyContextCallback callback = new MyContextCallback();
143         _testImpl.invokeOnComponent(facesContext, facet.getClientId(facesContext), callback);
144         // the callback should have been invoked
145         assertTrue(callback.invoked);
146     }
147 
148     /**
149      * Test method for {@link javax.faces.component.UIData#broadcast(javax.faces.event.FacesEvent)}.
150      */
151     public void testBroadcastFacesEvent()
152     {
153         // create event mock
154         final FacesEvent originalEvent = _mocksControl.createMock(FacesEvent.class);
155         
156         // create the component for the event
157         UIComponent eventComponent = new UICommand()
158         {
159 
160             @Override
161             public void broadcast(FacesEvent event)
162                     throws AbortProcessingException
163             {
164                 // the event must be the originalEvent
165                 assertEquals(originalEvent, event);
166                 
167                 // the current row index must be the row index from the time the event was queued
168                 assertEquals(5, _testImpl.getRowIndex());
169                 
170                 // the current component must be this (pushComponentToEL() must have happened)
171                 assertEquals(this, UIComponent.getCurrentComponent(facesContext));
172                 
173                 // to be able to verify that broadcast() really has been called
174                 getAttributes().put("broadcastCalled", Boolean.TRUE);
175             }
176             
177         };
178         
179         // set component on event
180         EasyMock.expect(originalEvent.getComponent()).andReturn(eventComponent).anyTimes();
181         // set phase on event
182         EasyMock.expect(originalEvent.getPhaseId()).andReturn(PhaseId.INVOKE_APPLICATION).anyTimes();
183         _mocksControl.replay();
184         
185         // set PhaseId for event processing
186         facesContext.setCurrentPhaseId(PhaseId.INVOKE_APPLICATION);
187         // set row index for event
188         _testImpl.setRowIndex(5);
189         // UIData must be a child of UIViewRoot to queue and event
190         facesContext.getViewRoot().getChildren().add(_testImpl);
191         // queue event (this will create a FacesEventWrapper with the current row index)
192         _testImpl.queueEvent(originalEvent);
193         // change the current row index
194         _testImpl.setRowIndex(0);
195         // now broadcast the event (this will call UIData.broadcast())
196         facesContext.getViewRoot().broadcastEvents(facesContext, PhaseId.INVOKE_APPLICATION);
197         
198         // -= Assertions =-
199         
200         // the current component must be null (popComponentFromEL() must have happened)
201         assertNull(UIComponent.getCurrentComponent(facesContext));
202         
203         // the row index must now be 0 (at broadcast() it must be 5)
204         assertEquals(0, _testImpl.getRowIndex());
205         
206         // verify mock behavior
207         _mocksControl.verify();
208         
209         // verify that broadcast() really has been called
210         assertEquals(Boolean.TRUE, eventComponent.getAttributes().get("broadcastCalled"));
211     }
212 
213     /**
214      * Test method for {@link javax.faces.component.UIData#encodeBegin(javax.faces.context.FacesContext)}.
215      */
216     public void testEncodeBeginFacesContext()
217     {
218         // TODO
219     }
220 
221     /**
222      * Test method for {@link javax.faces.component.UIData#encodeEnd(javax.faces.context.FacesContext)}.
223      */
224     public void testEncodeEndFacesContext()
225     {
226         // TODO
227     }
228 
229     /**
230      * Test method for {@link javax.faces.component.UIData#queueEvent(javax.faces.event.FacesEvent)}.
231      */
232     public void testQueueEventFacesEvent()
233     {
234         // TODO
235     }
236 
237     /**
238      * Test method for {@link javax.faces.component.UIData#processDecodes(javax.faces.context.FacesContext)}.
239      */
240     public void testProcessDecodesFacesContext()
241     {
242         // TODO
243     }
244 
245     /**
246      * Test method for {@link javax.faces.component.UIData#processValidators(javax.faces.context.FacesContext)}.
247      */
248     public void testProcessValidatorsFacesContext()
249     {
250         // TODO
251     }
252 
253     /**
254      * Test method for {@link javax.faces.component.UIData#processUpdates(javax.faces.context.FacesContext)}.
255      */
256     public void testProcessUpdatesFacesContext()
257     {
258         // TODO
259     }
260 
261     /**
262      * Test method for {@link javax.faces.component.UIData#saveState(javax.faces.context.FacesContext)}.
263      */
264     public void testSaveState()
265     {
266         // TODO
267     }
268 
269     /**
270      * Test method for
271      * {@link javax.faces.component.UIData#restoreState(javax.faces.context.FacesContext, java.lang.Object)}.
272      */
273     public void testRestoreState()
274     {
275         // TODO
276     }
277 
278     /**
279      * Test method for {@link javax.faces.component.UIData#UIData()}.
280      */
281     public void testUIData()
282     {
283         // TODO
284     }
285 
286     /**
287      * Test method for {@link javax.faces.component.UIData#setFooter(javax.faces.component.UIComponent)}.
288      */
289     public void testSetFooter()
290     {
291         // TODO
292     }
293 
294     /**
295      * Test method for {@link javax.faces.component.UIData#getFooter()}.
296      */
297     public void testGetFooter()
298     {
299         // TODO
300     }
301 
302     /**
303      * Test method for {@link javax.faces.component.UIData#setHeader(javax.faces.component.UIComponent)}.
304      */
305     public void testSetHeader()
306     {
307         // TODO
308     }
309 
310     /**
311      * Test method for {@link javax.faces.component.UIData#getHeader()}.
312      */
313     public void testGetHeader()
314     {
315         // TODO
316     }
317 
318     /**
319      * Test method for {@link javax.faces.component.UIData#isRowAvailable()}.
320      */
321     public void testIsRowAvailable()
322     {
323         // TODO
324     }
325 
326     /**
327      * Test method for {@link javax.faces.component.UIData#getRowCount()}.
328      */
329     public void testGetRowCount()
330     {
331         // TODO
332     }
333 
334     /**
335      * Test method for {@link javax.faces.component.UIData#getRowData()}.
336      */
337     public void testGetRowData()
338     {
339         // TODO
340     }
341 
342     /**
343      * Test method for {@link javax.faces.component.UIData#getRowIndex()}.
344      */
345     public void testGetRowIndex()
346     {
347         // TODO
348     }
349 
350     /**
351      * Test method for {@link javax.faces.component.UIData#setRowIndex(int)}.
352      */
353     public void testSetRowIndex()
354     {
355         // TODO
356     }
357 
358     /**
359      * Test method for {@link javax.faces.component.UIData#getDataModel()}.
360      */
361     public void testGetDataModel()
362     {
363         // TODO
364     }
365 
366     /**
367      * Test method for {@link javax.faces.component.UIData#setDataModel(javax.faces.model.DataModel)}.
368      */
369     public void testSetDataModel()
370     {
371         // TODO
372     }
373 
374     /**
375      * Test method for {@link javax.faces.component.UIData#setValue(java.lang.Object)}.
376      */
377     public void testSetValue()
378     {
379         // TODO
380     }
381 
382     /**
383      * Test method for {@link javax.faces.component.UIData#setRows(int)}.
384      */
385     public void testSetRows()
386     {
387         // TODO
388     }
389 
390     /**
391      * Test method for {@link javax.faces.component.UIData#setFirst(int)}.
392      */
393     public void testSetFirst()
394     {
395         // TODO
396     }
397 
398     /**
399      * Test method for {@link javax.faces.component.UIData#getValue()}.
400      */
401     public void testGetValue()
402     {
403         // TODO
404     }
405 
406     /**
407      * Test method for {@link javax.faces.component.UIData#getVar()}.
408      */
409     public void testGetVar()
410     {
411         // TODO
412     }
413 
414     /**
415      * Test method for {@link javax.faces.component.UIData#setVar(java.lang.String)}.
416      */
417     public void testSetVar()
418     {
419         // TODO
420     }
421 
422     /**
423      * Test method for {@link javax.faces.component.UIData#getRows()}.
424      */
425     public void testGetRows()
426     {
427         // TODO
428     }
429 
430     /**
431      * Test method for {@link javax.faces.component.UIData#getFirst()}.
432      */
433     public void testGetFirst()
434     {
435         // TODO
436     }
437 
438     /**
439      * Test method for {@link javax.faces.component.UIData#getFamily()}.
440      */
441     public void testGetFamily()
442     {
443         // TODO
444     }
445     
446     /**
447      * Test method for 
448      * {@link javax.faces.component.UIData#visitTree(javax.faces.component.visit.VisitContext, javax.faces.component.visit.VisitCallback)}.
449      */
450     public void testVisitTree() {
451         UIData uidata = new UIData();
452         // value
453         Collection<String> value = new ArrayList<String>();
454         value.add("value#1");
455         value.add("value#2");
456         uidata.setValue(value);
457         // header facet
458         UIComponent headerFacet = new HtmlPanelGroup();
459         headerFacet.setId("headerFacet");
460         uidata.setHeader(headerFacet);
461         // footer facet
462         UIComponent footerFacet = new HtmlPanelGroup();
463         footerFacet.setId("footerFacet");
464         uidata.setFooter(footerFacet);
465         // first child
466         UIComponent child1 = new UIColumn();
467         // facet of first child
468         UIComponent facetOfChild1 = new HtmlPanelGroup();
469         child1.getFacets().put("someFacet", facetOfChild1);
470         // child of first child
471         UIOutput childOfChild1 = new UIOutput();
472         childOfChild1.setId("childOfColumn");
473         child1.getChildren().add(childOfChild1);
474         uidata.getChildren().add(child1);
475         // second child (should not be processed --> != UIColumn)
476         UIComponent child2 = new HtmlPanelGroup(); 
477         uidata.getChildren().add(child2);
478         VisitCallback callback = null;
479         
480         IMocksControl control = EasyMock.createControl();
481         VisitContext visitContextMock = control.createMock(VisitContext.class);
482         EasyMock.expect(visitContextMock.getFacesContext()).andReturn(facesContext).anyTimes();
483         EasyMock.expect(visitContextMock.getHints()).andReturn(Collections.<VisitHint>emptySet()).anyTimes();
484         Collection<String> subtreeIdsToVisit = new ArrayList<String>();
485         subtreeIdsToVisit.add("1");
486         EasyMock.expect(visitContextMock.getSubtreeIdsToVisit(uidata)).andReturn(subtreeIdsToVisit);
487         EasyMock.expect(visitContextMock.invokeVisitCallback(uidata, callback)).andReturn(VisitResult.ACCEPT);
488         EasyMock.expect(visitContextMock.invokeVisitCallback(headerFacet, callback)).andReturn(VisitResult.ACCEPT);
489         EasyMock.expect(visitContextMock.invokeVisitCallback(footerFacet, callback)).andReturn(VisitResult.ACCEPT);
490         EasyMock.expect(visitContextMock.invokeVisitCallback(facetOfChild1, callback)).andReturn(VisitResult.ACCEPT);
491         EasyMock.expect(visitContextMock.invokeVisitCallback(child1, callback)).andReturn(VisitResult.ACCEPT);
492         EasyMock.expect(visitContextMock.invokeVisitCallback(childOfChild1, callback)).andReturn(VisitResult.ACCEPT).times(2);
493         control.replay();
494         
495         uidata.visitTree(visitContextMock, callback);
496         
497         control.verify();
498         
499         // VisitHint.SKIP_ITERATION test:
500         
501         // (1) uiData with two rows - should iterate over row twice
502         MockVisitContext mockVisitContext = new MockVisitContext(facesContext, null);
503         CountingVisitCallback countingVisitCallback = new CountingVisitCallback(2);
504         uidata.visitTree(mockVisitContext, countingVisitCallback);
505         countingVisitCallback.verify();
506         
507         // (2) uiData with two values - should iterate over row ones - SKIP_ITERATION is used
508         mockVisitContext = new MockVisitContext(facesContext, EnumSet.of(VisitHint.SKIP_ITERATION));
509         countingVisitCallback = new CountingVisitCallback(1);
510         uidata.visitTree(mockVisitContext, countingVisitCallback);
511         countingVisitCallback.verify();
512         
513         // (3) uiData with five values - should iterate over row five times
514         value = new ArrayList<String>();
515         value.add("1");
516         value.add("2");
517         value.add("3");
518         value.add("4");
519         value.add("5");
520         uidata.setValue(value);
521         mockVisitContext = new MockVisitContext(facesContext, null);
522         countingVisitCallback = new CountingVisitCallback(5);
523         uidata.visitTree(mockVisitContext, countingVisitCallback);
524         countingVisitCallback.verify();
525         
526         // (4) uiData with five values - should iterate over child ones - SKIP_ITERATION is used
527         mockVisitContext = new MockVisitContext(facesContext, EnumSet.of(VisitHint.SKIP_ITERATION));
528         countingVisitCallback = new CountingVisitCallback(1);
529         uidata.visitTree(mockVisitContext, countingVisitCallback);
530         countingVisitCallback.verify();
531     }
532 
533     
534     public static class RowData
535     {
536         private String text;
537 
538         public RowData(String text, String style)
539         {
540            super();
541             this.text = text;
542             this.style = style;
543         }
544 
545         private String style;
546         
547         public String getText()
548         {
549             return text;
550         }
551 
552         public void setText(String text)
553         {
554             this.text = text;
555         }
556 
557         public String getStyle()
558         {
559             return style;
560         }
561 
562         public void setStyle(String style)
563         {
564             this.style = style;
565         }
566     }
567     
568     public void testPreserveRowComponentState1() throws Exception
569     {
570         List<RowData> model = new ArrayList<RowData>();
571         model.add(new RowData("text1","style1"));
572         model.add(new RowData("text1","style2"));
573         model.add(new RowData("text1","style3"));
574         model.add(new RowData("text1","style4"));
575         
576         //Put on request map to be resolved later
577         request.setAttribute("list", model);
578         
579         UIViewRoot root = facesContext.getViewRoot();
580         UIData table = new UIData();
581         UIColumn column = new UIColumn();
582         UIOutput text = new UIOutput();
583         
584         //This is only required if markInitiaState fix is not used 
585         root.setId(root.createUniqueId());
586         table.setId(root.createUniqueId());
587         column.setId(root.createUniqueId());
588         text.setId(root.createUniqueId());
589         
590         table.setVar("row");
591         table.setRowStatePreserved(true);
592         table.setValueExpression("value", application.
593                 getExpressionFactory().createValueExpression(
594                         facesContext.getELContext(),"#{list}",List.class));
595         
596         text.setValueExpression("value", application.
597                 getExpressionFactory().createValueExpression(
598                         facesContext.getELContext(),"#{row.text}",String.class));
599         
600         root.getChildren().add(table);
601         table.getChildren().add(column);
602         column.getChildren().add(text);
603 
604         //Simulate markInitialState call.
605         facesContext.getAttributes().put(StateManager.IS_BUILDING_INITIAL_STATE, Boolean.TRUE);
606         root.markInitialState();
607         table.markInitialState();
608         column.markInitialState();
609         text.markInitialState();
610         facesContext.getAttributes().remove(StateManager.IS_BUILDING_INITIAL_STATE);
611         
612         //Check the value expressions are working and change the component state 
613         for (int i = 0; i < model.size(); i++)
614         {
615             RowData rowData = model.get(i); 
616             table.setRowIndex(i);
617             assertEquals(rowData.getText(), text.getValue());
618             text.getAttributes().put("style", rowData.getStyle());
619         }
620         
621         //Reset row index
622         table.setRowIndex(-1);
623 
624         //Check the values were not lost
625         for (int i = 0; i < model.size(); i++)
626         {
627             table.setRowIndex(i);
628             assertEquals(model.get(i).getStyle(), text.getAttributes().get("style"));
629         }
630         
631     }
632         
633     public void testCollectionDataModel() throws Exception
634     {
635         SimpleCollection<RowData> model = new SimpleCollection<RowData>();
636         model.add(new RowData("text1","style1"));
637         model.add(new RowData("text1","style2"));
638         model.add(new RowData("text1","style3"));
639         model.add(new RowData("text1","style4"));
640         
641         //Put on request map to be resolved later
642         request.setAttribute("list", model);
643         
644         UIViewRoot root = facesContext.getViewRoot();
645         UIData table = new UIData();
646         UIColumn column = new UIColumn();
647         UIOutput text = new UIOutput();
648         
649         //This is only required if markInitiaState fix is not used 
650         root.setId(root.createUniqueId());
651         table.setId(root.createUniqueId());
652         column.setId(root.createUniqueId());
653         text.setId(root.createUniqueId());
654         
655         table.setVar("row");
656         table.setRowStatePreserved(true);
657         table.setValueExpression("value", application.
658                 getExpressionFactory().createValueExpression(
659                         facesContext.getELContext(),"#{list}", Collection.class));
660         
661         text.setValueExpression("value", application.
662                 getExpressionFactory().createValueExpression(
663                         facesContext.getELContext(),"#{row.text}",String.class));
664         
665         root.getChildren().add(table);
666         table.getChildren().add(column);
667         column.getChildren().add(text);
668         
669         //Check the value expressions are working and change the component state
670         int i = 0;
671         for (Iterator<RowData> it = model.iterator(); it.hasNext();)
672         {
673             RowData rowData = it.next(); 
674             table.setRowIndex(i);
675             assertEquals(rowData.getText(), text.getValue());
676             i++;
677         }
678         
679         //Reset row index
680         table.setRowIndex(-1);
681     }
682 
683     
684     private final class SimpleCollection<T> extends AbstractCollection<T>
685     {
686         private List<T> delegate = new ArrayList();
687 
688         public boolean add(T e)
689         {
690             return delegate.add(e);
691         }
692             
693         @Override
694         public Iterator<T> iterator()
695         {
696             return delegate.iterator();
697         }
698 
699         @Override
700         public int size()
701         {
702             return delegate.size();
703         }
704     }
705 
706     private final class CountingVisitCallback implements VisitCallback {
707         
708         public final int expectedVisits;
709         
710         public CountingVisitCallback(int expectedRowVisits) {
711             super();
712             this.expectedVisits = expectedRowVisits;
713         }
714 
715         public int headerFacetVisits = 0;
716         public int footerFacetVisits = 0;
717         public int rowVisits = 0;
718         
719         public VisitResult visit(VisitContext context, UIComponent target) {
720             
721             if ("headerFacet".equals(target.getId())) {
722                 headerFacetVisits++;
723             } else if ("footerFacet".equals(target.getId())) {
724                 footerFacetVisits++;
725             } else if ("childOfColumn".equals(target.getId())) {
726                 rowVisits++;
727             }
728             return VisitResult.ACCEPT;
729         }
730         
731         public void verify() {
732                 assertEquals("header facet must be visited only ones", 1, headerFacetVisits);
733                 assertEquals("footer facet must be visited only ones", 1, footerFacetVisits);
734                 assertEquals("Expected row visit does not match", expectedVisits, rowVisits);
735         }
736     }
737     
738     public void testProcessDecodesRenderedFalse() throws Exception {
739         UIData uiData = new VerifyNoLifecycleMethodComponent();
740         UIComponent parent = MockRenderedValueExpression.setUpComponentStack(facesContext,  uiData, false);
741         
742         uiData.processDecodes(facesContext);
743         
744         assertEquals("processDecodes must not change currentComponent", parent, UIComponent.getCurrentComponent(facesContext));
745         
746     }
747     
748     public void testProcessDecodesRenderedTrue() throws Exception {
749         
750         UIComponent parent = MockRenderedValueExpression.setUpComponentStack(facesContext, _testImpl, true);
751         _addColumn();
752         
753         _testImpl.processDecodes(facesContext);
754         
755         assertEquals("processDecodes must not change currentComponent", parent, UIComponent.getCurrentComponent(facesContext));
756     }
757     
758     
759     public void testProcessValidatorsRenderedFalse() throws Exception {
760         UIData uiData = new VerifyNoLifecycleMethodComponent();
761         UIComponent parent = MockRenderedValueExpression.setUpComponentStack(facesContext,  uiData, false);
762         
763         uiData.processValidators(facesContext);
764         
765         assertEquals("processDecodes must not change currentComponent", parent, UIComponent.getCurrentComponent(facesContext));
766         
767     }
768     
769     public void testProcessValidatorsRenderedTrue() throws Exception {
770         
771         UIComponent parent = MockRenderedValueExpression.setUpComponentStack(facesContext, _testImpl, true);
772         _addColumn();
773         
774         _testImpl.processValidators(facesContext);
775         
776         assertEquals("processValidators must not change currentComponent", parent, UIComponent.getCurrentComponent(facesContext));
777     }
778     
779     public void testProcessUpdatesRenderedFalse() throws Exception {
780         UIData uiData = new VerifyNoLifecycleMethodComponent();
781         UIComponent parent = MockRenderedValueExpression.setUpComponentStack(facesContext,  uiData, false);
782         
783         uiData.processUpdates(facesContext);
784         
785         assertEquals("processUpdates must not change currentComponent", parent, UIComponent.getCurrentComponent(facesContext));
786         
787     }
788     
789     public void testProcessUpdatesRenderedTrue() throws Exception {
790         
791         UIComponent parent = MockRenderedValueExpression.setUpComponentStack(facesContext, _testImpl, true);
792         _addColumn();
793         
794         _testImpl.processUpdates(facesContext);
795         
796         assertEquals("processUpdates must not change currentComponent", parent, UIComponent.getCurrentComponent(facesContext));
797     }
798 
799     private void _addColumn() {
800         UIColumn uiColumn = new UIColumn();
801         uiColumn.setId("testId");
802         _testImpl.getChildren().add(uiColumn);
803         MockRenderedValueExpression ve = new MockRenderedValueExpression("#{component.is eq 'testId'}", Boolean.class, uiColumn, true);
804         uiColumn.setValueExpression("rendered", ve);
805     }
806     
807 
808     /** Verifies no call to encode* and process* methods */
809     public class VerifyNoLifecycleMethodComponent extends UIData
810     {
811         public void setRowIndex(int rowIndex) {
812             fail();
813         }
814         public void decode(FacesContext context) {
815             fail();
816         }
817         public void validate(FacesContext context) {
818             fail();
819         }
820         public void updateModel(FacesContext context) {
821             fail();
822         }
823         public void encodeBegin(FacesContext context) throws IOException {
824             fail();
825         }
826         public void encodeChildren(FacesContext context) throws IOException {
827             fail();
828         }
829         public void encodeEnd(FacesContext context) throws IOException {
830             fail();
831         }
832     }   
833     
834     
835     /**
836      * Test state save and restore cycle taking in consideration portlet case.
837      * 
838      * In portlets, saveState() could be called on INVOKE_APPLICATION phase and
839      * restoreState() could be called in RENDER_RESPONSE phase.
840      * 
841      * This test is active when PSS is disabled.
842      * 
843      * @throws Exception 
844      */
845     public void testSaveAndRestorePortletLifecycleWithoutPss1() throws Exception
846     {
847         List<RowData> model = new ArrayList<RowData>();
848         model.add(new RowData("text1","style1"));
849         model.add(new RowData("text2","style2"));
850         model.add(new RowData("text3","style3"));
851         model.add(new RowData("text4","style4"));
852         
853         //Put on request map to be resolved later
854         request.setAttribute("list", model);
855         
856         UIViewRoot root = facesContext.getViewRoot();
857         createSimpleTable(root);
858         UIData table = (UIData) root.getChildren().get(0);
859         UIColumn column = (UIColumn) table.getChildren().get(0);
860         UIInput text = (UIInput) column.getChildren().get(0);
861         
862         facesContext.setCurrentPhaseId(PhaseId.APPLY_REQUEST_VALUES);
863         
864         //Check the value expressions are working and change the component state 
865         for (int i = 0; i < model.size(); i++)
866         {
867             RowData rowData = model.get(i); 
868             table.setRowIndex(i);
869             assertEquals(rowData.getText(), text.getValue());
870             text.setSubmittedValue("value"+(i+1));
871             //text.getAttributes().put("style", rowData.getStyle());
872         }
873         
874         //Reset row index
875         table.setRowIndex(-1);
876         
877         facesContext.setCurrentPhaseId(PhaseId.INVOKE_APPLICATION);
878         
879         Object state = table.saveState(facesContext);
880         
881         ByteArrayOutputStream baos = new ByteArrayOutputStream(128);
882         ObjectOutputStream oos = new ObjectOutputStream(baos);
883         oos.writeObject(state);
884         oos.flush();
885         baos.flush();
886         ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
887         ObjectInputStream ois = new ObjectInputStream(bais);
888         Object restoredState = (Object) ois.readObject();
889         oos.close();
890         ois.close();
891         
892         facesContext.setCurrentPhaseId(PhaseId.RENDER_RESPONSE);
893         
894         facesContext.setViewRoot(new UIViewRoot());
895         root = facesContext.getViewRoot();
896         createSimpleTable(root);
897         table = (UIData) root.getChildren().get(0);
898         column = (UIColumn) table.getChildren().get(0);
899         text = (UIInput) column.getChildren().get(0);
900         
901         table.restoreState(facesContext, restoredState);
902 
903         //Check the values were not lost
904         for (int i = 0; i < model.size(); i++)
905         {
906             RowData rowData = model.get(i); 
907             table.setRowIndex(i);
908             assertEquals("value"+(i+1), text.getSubmittedValue());
909             //assertEquals(model.get(i).getStyle(), text.getAttributes().get("style"));
910         }
911     }
912     
913     private void createSimpleTable(UIViewRoot root)
914     {
915         createSimpleTable(root, false);
916     }
917     
918     private void createSimpleTable(UIViewRoot root, boolean rowStatePreserved)
919     {
920         UIData table = new UIData();
921         UIColumn column = new UIColumn();
922         UIInput text = new UIInput();
923         
924         //This is only required if markInitiaState fix is not used 
925         root.setId(root.createUniqueId());
926         table.setId(root.createUniqueId());
927         column.setId(root.createUniqueId());
928         text.setId(root.createUniqueId());
929         
930         table.setVar("row");
931         if (rowStatePreserved)
932         {
933             table.setRowStatePreserved(true);
934         }
935         table.setValueExpression("value", application.
936                 getExpressionFactory().createValueExpression(
937                         facesContext.getELContext(),"#{list}",List.class));
938         
939         text.setValueExpression("value", application.
940                 getExpressionFactory().createValueExpression(
941                         facesContext.getELContext(),"#{row.text}",String.class));
942         
943         root.getChildren().add(table);
944         table.getChildren().add(column);
945         column.getChildren().add(text);
946     }
947     
948     /**
949      * Test state save and restore cycle taking in consideration portlet case.
950      * 
951      * In portlets, saveState() could be called on INVOKE_APPLICATION phase and
952      * restoreState() could be called in RENDER_RESPONSE phase.
953      * 
954      * This test is active when PSS is enabled.
955      * 
956      * @throws Exception 
957      */
958     public void testSaveAndRestorePortletLifecycleWithPss1() throws Exception
959     {
960         facesContext.getRenderKit().addRenderer("javax.faces.Data", "javax.faces.Table",new Renderer(){});
961         
962         List<RowData> model = new ArrayList<RowData>();
963         model.add(new RowData("text1","style1"));
964         model.add(new RowData("text2","style2"));
965         model.add(new RowData("text3","style3"));
966         model.add(new RowData("text4","style4"));
967         
968         //Put on request map to be resolved later
969         request.setAttribute("list", model);
970         
971         UIViewRoot root = facesContext.getViewRoot();
972         createSimpleTable(root);
973         UIData table = (UIData) root.getChildren().get(0);
974         UIColumn column = (UIColumn) table.getChildren().get(0);
975         UIInput text = (UIInput) column.getChildren().get(0);
976         
977         //Simulate markInitialState call.
978         facesContext.getAttributes().put(StateManager.IS_BUILDING_INITIAL_STATE, Boolean.TRUE);
979         root.markInitialState();
980         table.markInitialState();
981         column.markInitialState();
982         text.markInitialState();
983         facesContext.getAttributes().remove(StateManager.IS_BUILDING_INITIAL_STATE);        
984         
985         facesContext.setCurrentPhaseId(PhaseId.APPLY_REQUEST_VALUES);
986         
987         //Check the value expressions are working and change the component state 
988         for (int i = 0; i < model.size(); i++)
989         {
990             RowData rowData = model.get(i); 
991             table.setRowIndex(i);
992             assertEquals(rowData.getText(), text.getValue());
993             text.setSubmittedValue("value"+(i+1));
994             //text.getAttributes().put("style", rowData.getStyle());
995         }
996         
997         //Reset row index
998         table.setRowIndex(-1);
999         
1000         facesContext.setCurrentPhaseId(PhaseId.INVOKE_APPLICATION);
1001         
1002         Object state = table.saveState(facesContext);
1003         
1004         ByteArrayOutputStream baos = new ByteArrayOutputStream(128);
1005         ObjectOutputStream oos = new ObjectOutputStream(baos);
1006         oos.writeObject(state);
1007         oos.flush();
1008         baos.flush();
1009         ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
1010         ObjectInputStream ois = new ObjectInputStream(bais);
1011         Object restoredState = (Object) ois.readObject();
1012         oos.close();
1013         ois.close();
1014         
1015         facesContext.setCurrentPhaseId(PhaseId.RENDER_RESPONSE);
1016         
1017         facesContext.setViewRoot(new UIViewRoot());
1018         root = facesContext.getViewRoot();
1019         root.setRenderKitId("HTML_BASIC");
1020         
1021         createSimpleTable(root);
1022         table = (UIData) root.getChildren().get(0);
1023         column = (UIColumn) table.getChildren().get(0);
1024         text = (UIInput) column.getChildren().get(0);
1025         
1026         //Simulate markInitialState call.
1027         facesContext.getAttributes().put(StateManager.IS_BUILDING_INITIAL_STATE, Boolean.TRUE);
1028         root.markInitialState();
1029         table.markInitialState();
1030         column.markInitialState();
1031         text.markInitialState();
1032         facesContext.getAttributes().remove(StateManager.IS_BUILDING_INITIAL_STATE);        
1033         
1034         table.restoreState(facesContext, restoredState);
1035 
1036         //Check the values were not lost
1037         for (int i = 0; i < model.size(); i++)
1038         {
1039             RowData rowData = model.get(i); 
1040             table.setRowIndex(i);
1041             assertEquals("value"+(i+1), text.getSubmittedValue());
1042             //assertEquals(model.get(i).getStyle(), text.getAttributes().get("style"));
1043         }
1044         
1045     }
1046     
1047     /**
1048      * Test state save and restore cycle taking in consideration portlet case.
1049      * 
1050      * In portlets, saveState() could be called on INVOKE_APPLICATION phase and
1051      * restoreState() could be called in RENDER_RESPONSE phase.
1052      * 
1053      * This test is active when PSS is enabled.
1054      * 
1055      * @throws Exception 
1056      */
1057     public void testSaveAndRestorePortletLifecycleWithPss2() throws Exception
1058     {
1059         facesContext.getRenderKit().addRenderer("javax.faces.Data", "javax.faces.Table",new Renderer(){});
1060         
1061         List<RowData> model = new ArrayList<RowData>();
1062         model.add(new RowData("text1","style1"));
1063         model.add(new RowData("text2","style2"));
1064         model.add(new RowData("text3","style3"));
1065         model.add(new RowData("text4","style4"));
1066         
1067         //Put on request map to be resolved later
1068         request.setAttribute("list", model);
1069         
1070         UIViewRoot root = facesContext.getViewRoot();
1071         createSimpleTable(root, true);
1072         UIData table = (UIData) root.getChildren().get(0);
1073         UIColumn column = (UIColumn) table.getChildren().get(0);
1074         UIInput text = (UIInput) column.getChildren().get(0);
1075         
1076         //Simulate markInitialState call.
1077         facesContext.getAttributes().put(StateManager.IS_BUILDING_INITIAL_STATE, Boolean.TRUE);
1078         root.markInitialState();
1079         table.markInitialState();
1080         column.markInitialState();
1081         text.markInitialState();
1082         facesContext.getAttributes().remove(StateManager.IS_BUILDING_INITIAL_STATE);        
1083         
1084         facesContext.setCurrentPhaseId(PhaseId.APPLY_REQUEST_VALUES);
1085         
1086         //Check the value expressions are working and change the component state 
1087         for (int i = 0; i < model.size(); i++)
1088         {
1089             RowData rowData = model.get(i); 
1090             table.setRowIndex(i);
1091             assertEquals(rowData.getText(), text.getValue());
1092             text.setSubmittedValue("value"+(i+1));
1093             text.getTransientStateHelper().putTransient("key", "value"+(i+1));
1094             //text.getAttributes().put("style", rowData.getStyle());
1095         }
1096         
1097         //Reset row index
1098         table.setRowIndex(-1);
1099         
1100         facesContext.setCurrentPhaseId(PhaseId.INVOKE_APPLICATION);
1101         
1102         Object state = table.saveState(facesContext);
1103         
1104         ByteArrayOutputStream baos = new ByteArrayOutputStream(128);
1105         ObjectOutputStream oos = new ObjectOutputStream(baos);
1106         oos.writeObject(state);
1107         oos.flush();
1108         baos.flush();
1109         ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
1110         ObjectInputStream ois = new ObjectInputStream(bais);
1111         Object restoredState = (Object) ois.readObject();
1112         oos.close();
1113         ois.close();
1114         
1115         facesContext.setCurrentPhaseId(PhaseId.RENDER_RESPONSE);
1116         
1117         facesContext.setViewRoot(new UIViewRoot());
1118         root = facesContext.getViewRoot();
1119         root.setRenderKitId("HTML_BASIC");
1120         
1121         createSimpleTable(root, true);
1122         table = (UIData) root.getChildren().get(0);
1123         column = (UIColumn) table.getChildren().get(0);
1124         text = (UIInput) column.getChildren().get(0);
1125         
1126         //Simulate markInitialState call.
1127         facesContext.getAttributes().put(StateManager.IS_BUILDING_INITIAL_STATE, Boolean.TRUE);
1128         root.markInitialState();
1129         table.markInitialState();
1130         column.markInitialState();
1131         text.markInitialState();
1132         facesContext.getAttributes().remove(StateManager.IS_BUILDING_INITIAL_STATE);        
1133         
1134         table.restoreState(facesContext, restoredState);
1135 
1136         //Check the values were not lost
1137         for (int i = 0; i < model.size(); i++)
1138         {
1139             RowData rowData = model.get(i); 
1140             table.setRowIndex(i);
1141             assertEquals("value"+(i+1), text.getSubmittedValue());
1142             assertEquals("value"+(i+1), text.getTransientStateHelper().getTransient("key"));
1143             //assertEquals(model.get(i).getStyle(), text.getAttributes().get("style"));
1144         }
1145         
1146     }
1147 
1148 }