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.context.servlet;
20  
21  import java.io.IOException;
22  import java.util.ArrayList;
23  import java.util.Collection;
24  import java.util.Collections;
25  import java.util.EnumSet;
26  import java.util.List;
27  import java.util.Set;
28  import java.util.logging.Level;
29  import java.util.logging.Logger;
30  
31  import javax.faces.FactoryFinder;
32  import javax.faces.component.UIComponent;
33  import javax.faces.component.UIViewParameter;
34  import javax.faces.component.UIViewRoot;
35  import javax.faces.component.html.HtmlBody;
36  import javax.faces.component.html.HtmlHead;
37  import javax.faces.component.visit.VisitCallback;
38  import javax.faces.component.visit.VisitContext;
39  import javax.faces.component.visit.VisitContextFactory;
40  import javax.faces.component.visit.VisitHint;
41  import javax.faces.component.visit.VisitResult;
42  import javax.faces.context.ExternalContext;
43  import javax.faces.context.FacesContext;
44  import javax.faces.context.PartialResponseWriter;
45  import javax.faces.context.PartialViewContext;
46  import javax.faces.context.ResponseWriter;
47  import javax.faces.event.PhaseId;
48  import javax.faces.render.RenderKit;
49  import javax.faces.render.RenderKitFactory;
50  import javax.faces.view.ViewMetadata;
51  
52  import org.apache.myfaces.context.PartialResponseWriterImpl;
53  import org.apache.myfaces.context.RequestViewContext;
54  import org.apache.myfaces.shared.config.MyfacesConfig;
55  import org.apache.myfaces.shared.util.ExternalContextUtils;
56  import org.apache.myfaces.shared.util.StringUtils;
57  
58  public class PartialViewContextImpl extends PartialViewContext
59  {
60  
61      private static final String FACES_REQUEST = "Faces-Request";
62      private static final String PARTIAL_AJAX = "partial/ajax";
63      private static final String PARTIAL_PROCESS = "partial/process";
64      private static final String SOURCE_PARAM_NAME = "javax.faces.source";
65      /**
66       * Internal extension for
67       * https://issues.apache.org/jira/browse/MYFACES-2841
68       * will be changed for 2.1 to the official marker
69       */
70      private static final String PARTIAL_IFRAME = "org.apache.myfaces.partial.iframe";
71      
72      private static final  Set<VisitHint> PARTIAL_EXECUTE_HINTS = Collections.unmodifiableSet( 
73              EnumSet.of(VisitHint.EXECUTE_LIFECYCLE, VisitHint.SKIP_UNRENDERED));
74      
75      // unrendered have to be skipped, transient definitely must be added to our list!
76      private static final  Set<VisitHint> PARTIAL_RENDER_HINTS = 
77              Collections.unmodifiableSet(EnumSet.of(VisitHint.SKIP_UNRENDERED));
78  
79      private FacesContext _facesContext = null;
80      private boolean _released = false;
81      // Cached values, since their parent methods could be called
82      // many times and the result does not change during the life time
83      // of this object.
84      private Boolean _ajaxRequest = null;
85  
86      /**
87       * Internal extension for
88       * https://issues.apache.org/jira/browse/MYFACES-2841
89       * will be changed for 2.1 to the official marker
90       */
91      private Boolean _iframeRequest = null;
92  
93      private Collection<String> _executeClientIds = null;
94      private Collection<String> _renderClientIds = null;
95      // Values that need to be saved because exists a setXX method 
96      private Boolean _partialRequest = null;
97      private Boolean _renderAll = null;
98      private PartialResponseWriter _partialResponseWriter = null;
99      private VisitContextFactory _visitContextFactory = null;
100 
101     public PartialViewContextImpl(FacesContext context)
102     {
103         _facesContext = context;
104     }
105     
106     public PartialViewContextImpl(FacesContext context, 
107             VisitContextFactory visitContextFactory)
108     {
109         _facesContext = context;
110         _visitContextFactory = visitContextFactory;
111     }
112 
113     @Override
114     public boolean isAjaxRequest()
115     {
116         assertNotReleased();
117         if (_ajaxRequest == null)
118         {
119             String requestType = _facesContext.getExternalContext().
120                     getRequestHeaderMap().get(FACES_REQUEST);
121             _ajaxRequest = (requestType != null && PARTIAL_AJAX.equals(requestType));
122         }
123         //for now we have to treat the partial iframe request also as ajax request
124         return _ajaxRequest || isIFrameRequest();
125     }
126 
127     @Override
128     public boolean isExecuteAll()
129     {
130         assertNotReleased();
131 
132         if (isAjaxRequest())
133         {
134             String executeMode = _facesContext.getExternalContext().
135                     getRequestParameterMap().get(
136                     PartialViewContext.PARTIAL_EXECUTE_PARAM_NAME);
137             if (PartialViewContext.ALL_PARTIAL_PHASE_CLIENT_IDS.equals(executeMode))
138             {
139                 return true;
140             }
141         }
142         return false;
143     }
144 
145     @Override
146     public boolean isPartialRequest()
147     {
148         assertNotReleased();
149 
150         if (_partialRequest == null)
151         {
152             String requestType = _facesContext.getExternalContext().
153                     getRequestHeaderMap().get(FACES_REQUEST);
154             _partialRequest = (requestType != null && PARTIAL_PROCESS.equals(requestType));
155         }
156         return _partialRequest || isAjaxRequest();
157     }
158 
159     @Override
160     public boolean isRenderAll()
161     {
162         assertNotReleased();
163 
164         if (_renderAll == null)
165         {
166             if (isAjaxRequest())
167             {
168                 String executeMode = _facesContext.getExternalContext().
169                         getRequestParameterMap().get(
170                         PartialViewContext.PARTIAL_RENDER_PARAM_NAME);
171                 if (PartialViewContext.ALL_PARTIAL_PHASE_CLIENT_IDS.equals(executeMode))
172                 {
173                     _renderAll = true;
174                 }
175             }
176             if (_renderAll == null)
177             {
178                 _renderAll = false;
179             }
180         }
181         return _renderAll;
182     }
183 
184     /**
185      * Extension for
186      * https://issues.apache.org/jira/browse/MYFACES-2841
187      * internal extension which detects that the submit is an iframe request
188      * will be changed for the official version which will come in 2.1
189      *
190      * @return true if the current request is an iframe based ajax request
191      */
192     public boolean isIFrameRequest()
193     {
194         if (_iframeRequest == null)
195         {
196             _iframeRequest = _facesContext.getExternalContext().getRequestParameterMap().containsKey(PARTIAL_IFRAME);
197         }
198         return _iframeRequest;
199     }
200 
201     @Override
202     public void setPartialRequest(boolean isPartialRequest)
203     {
204         assertNotReleased();
205 
206         _partialRequest = isPartialRequest;
207 
208     }
209 
210     @Override
211     public void setRenderAll(boolean renderAll)
212     {
213         assertNotReleased();
214 
215         _renderAll = renderAll;
216     }
217 
218     @Override
219     public Collection<String> getExecuteIds()
220     {
221         assertNotReleased();
222 
223         if (_executeClientIds == null)
224         {
225             String executeMode = _facesContext.getExternalContext().
226                     getRequestParameterMap().get(
227                     PartialViewContext.PARTIAL_EXECUTE_PARAM_NAME);
228 
229             if (executeMode != null && !"".equals(executeMode) &&
230                     //!PartialViewContext.NO_PARTIAL_PHASE_CLIENT_IDS.equals(executeMode) &&
231                     !PartialViewContext.ALL_PARTIAL_PHASE_CLIENT_IDS.equals(executeMode))
232             {
233 
234                 String[] clientIds
235                         = StringUtils.splitShortString(_replaceTabOrEnterCharactersWithSpaces(executeMode), ' ');
236 
237                 //The collection must be mutable
238                 List<String> tempList = new ArrayList<String>();
239                 for (String clientId : clientIds)
240                 {
241                     if (clientId.length() > 0)
242                     {
243                         tempList.add(clientId);
244                     }
245                 }
246                 // The "javax.faces.source" parameter needs to be added to the list of
247                 // execute ids if missing (otherwise, we'd never execute an action associated
248                 // with, e.g., a button).
249 
250                 String source = _facesContext.getExternalContext().getRequestParameterMap().get
251                         (PartialViewContextImpl.SOURCE_PARAM_NAME);
252 
253                 if (source != null)
254                 {
255                     source = source.trim();
256 
257                     if (!tempList.contains(source))
258                     {
259                         tempList.add(source);
260                     }
261                 }
262 
263                 _executeClientIds = tempList;
264             }
265             else
266             {
267                 _executeClientIds = new ArrayList<String>();
268             }
269         }
270         return _executeClientIds;
271     }
272 
273     private String _replaceTabOrEnterCharactersWithSpaces(String mode)
274     {
275         StringBuilder builder = new StringBuilder(mode.length());
276         for (int i = 0; i < mode.length(); i++)
277         {
278             if (mode.charAt(i) == '\t' ||
279                     mode.charAt(i) == '\n')
280             {
281                 builder.append(' ');
282             }
283             else
284             {
285                 builder.append(mode.charAt(i));
286             }
287         }
288         return builder.toString();
289     }
290 
291     @Override
292     public Collection<String> getRenderIds()
293     {
294         assertNotReleased();
295 
296         if (_renderClientIds == null)
297         {
298             String renderMode = _facesContext.getExternalContext().
299                     getRequestParameterMap().get(
300                     PartialViewContext.PARTIAL_RENDER_PARAM_NAME);
301 
302             if (renderMode != null && !"".equals(renderMode) &&
303                     //!PartialViewContext.NO_PARTIAL_PHASE_CLIENT_IDS.equals(renderMode) &&
304                     !PartialViewContext.ALL_PARTIAL_PHASE_CLIENT_IDS.equals(renderMode))
305             {
306                 String[] clientIds
307                         = StringUtils.splitShortString(_replaceTabOrEnterCharactersWithSpaces(renderMode), ' ');
308 
309                 //The collection must be mutable
310                 List<String> tempList = new ArrayList<String>();
311                 for (String clientId : clientIds)
312                 {
313                     if (clientId.length() > 0)
314                     {
315                         tempList.add(clientId);
316                     }
317                 }
318                 _renderClientIds = tempList;
319             }
320             else
321             {
322                 _renderClientIds = new ArrayList<String>();
323 
324                 if (PartialViewContext.ALL_PARTIAL_PHASE_CLIENT_IDS.equals(renderMode))
325                 {
326                     _renderClientIds.add(PartialResponseWriter.RENDER_ALL_MARKER);
327                 }
328             }
329         }
330         return _renderClientIds;
331     }
332 
333     @Override
334     public PartialResponseWriter getPartialResponseWriter()
335     {
336         assertNotReleased();
337 
338         if (_partialResponseWriter == null)
339         {
340             ResponseWriter responseWriter = _facesContext.getResponseWriter();
341             if (responseWriter == null)
342             {
343                 // This case happens when getPartialResponseWriter() is called before
344                 // render phase, like in ExternalContext.redirect(). We have to create a
345                 // ResponseWriter from the RenderKit and then wrap if necessary. 
346                 try
347                 {
348                     RenderKit renderKit = _facesContext.getRenderKit();
349                     if (renderKit == null)
350                     {
351                         // If the viewRoot was set to null by some reason, or there is no 
352                         // renderKitId on that view, this could be still an ajax redirect,
353                         // so we have to try to calculate the renderKitId and return a 
354                         // RenderKit instance, to send the response.
355                         String renderKitId
356                                 = _facesContext.getApplication().getViewHandler().calculateRenderKitId(_facesContext);
357                         RenderKitFactory rkf
358                                 = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
359                         renderKit = rkf.getRenderKit(_facesContext, renderKitId);
360                     }
361                     responseWriter = renderKit.createResponseWriter(
362                             _facesContext.getExternalContext().getResponseOutputWriter(), "text/xml",
363                             _facesContext.getExternalContext().getRequestCharacterEncoding());
364                 }
365                 catch (IOException e)
366                 {
367                     throw new IllegalStateException("Cannot create Partial Response Writer", e);
368                 }
369             }
370             // It is possible that the RenderKit return a PartialResponseWriter instance when 
371             // createResponseWriter,  so we should cast here for it and prevent double wrapping.
372             if (responseWriter instanceof PartialResponseWriter)
373             {
374                 _partialResponseWriter = (PartialResponseWriter) responseWriter;
375             }
376             else
377             {
378                 _partialResponseWriter = new PartialResponseWriterImpl(responseWriter);
379             }
380         }
381         return _partialResponseWriter;
382     }
383 
384     /**
385      * process the partial response
386      * allowed phase ids according to the spec
387      *
388      *
389      */
390     @Override
391     public void processPartial(PhaseId phaseId)
392     {
393         assertNotReleased();
394 
395         UIViewRoot viewRoot = _facesContext.getViewRoot();
396 
397         if (phaseId == PhaseId.APPLY_REQUEST_VALUES
398                 || phaseId == PhaseId.PROCESS_VALIDATIONS
399                 || phaseId == PhaseId.UPDATE_MODEL_VALUES)
400         {
401             processPartialExecute(viewRoot, phaseId);
402         }
403         else if (phaseId == PhaseId.RENDER_RESPONSE)
404         {
405             processPartialRendering(viewRoot, phaseId);
406         }
407     }
408 
409     private void processPartialExecute(UIViewRoot viewRoot, PhaseId phaseId)
410     {
411         PartialViewContext pvc = _facesContext.getPartialViewContext();
412         Collection<String> executeIds = pvc.getExecuteIds();
413         if (executeIds == null || executeIds.isEmpty())
414         {
415             return;
416         }
417         
418         VisitContext visitCtx = getVisitContextFactory().getVisitContext(_facesContext, executeIds, 
419                 PARTIAL_EXECUTE_HINTS);
420         viewRoot.visitTree(visitCtx, new PhaseAwareVisitCallback(_facesContext, phaseId));
421     }
422 
423     private void processPartialRendering(UIViewRoot viewRoot, PhaseId phaseId)
424     {
425         //TODO process partial rendering
426         //https://issues.apache.org/jira/browse/MYFACES-2118
427         //Collection<String> renderIds = getRenderIds();
428 
429         // We need to always update the view state marker when processing partial
430         // rendering, because there is no way to check when the state has been changed
431         // or not. Anyway, if we return empty response, according to the spec a javascript
432         // message displayed, so we need to return something.
433         //if (renderIds == null || renderIds.isEmpty()) {
434         //    return;
435         //}
436 
437         // note that we cannot use this.getPartialResponseWriter(), because
438         // this could cause problems if PartialResponseWriter is wrapped
439         PartialResponseWriter writer = _facesContext.getPartialViewContext().getPartialResponseWriter();
440         PartialViewContext pvc = _facesContext.getPartialViewContext();
441 
442         ResponseWriter oldWriter = _facesContext.getResponseWriter();
443         boolean inDocument = false;
444 
445         //response type = text/xml
446         //no caching and no timeout if possible!
447         ExternalContext externalContext = _facesContext.getExternalContext();
448         externalContext.setResponseContentType("text/xml");
449         externalContext.addResponseHeader("Pragma", "no-cache");
450         externalContext.addResponseHeader("Cache-control", "no-cache");
451         //under normal circumstances pragma should be enough, IE needs
452         //a special treatment!
453         //http://support.microsoft.com/kb/234067
454         externalContext.addResponseHeader("Expires", "-1");
455 
456         try
457         {
458             writer.startDocument();
459             inDocument = true;
460             _facesContext.setResponseWriter(writer);
461 
462             if (pvc.isRenderAll())
463             {
464                 processRenderAll(viewRoot, writer);
465             }
466             else
467             {
468                 Collection<String> renderIds = pvc.getRenderIds();
469                 //Only apply partial visit if we have ids to traverse
470                 if (renderIds != null && !renderIds.isEmpty())
471                 {
472                     // render=@all, so output the body.
473                     if (renderIds.contains(PartialResponseWriter.RENDER_ALL_MARKER))
474                     {
475                         processRenderAll(viewRoot, writer);
476                     }
477                     else
478                     {
479                         List<UIComponent> updatedComponents = null;
480                         if (!ExternalContextUtils.isPortlet(_facesContext.getExternalContext()) &&
481                                 MyfacesConfig.getCurrentInstance(externalContext).isStrictJsf2RefreshTargetAjax())
482                         {
483                             RequestViewContext rvc = RequestViewContext.getCurrentInstance(_facesContext);
484                             if (rvc.isRenderTarget("head"))
485                             {
486                                 UIComponent head = findHeadComponent(viewRoot);
487                                 if (head != null)
488                                 {
489                                     writer.startUpdate("javax.faces.ViewHead");
490                                     head.encodeAll(_facesContext);
491                                     writer.endUpdate();
492                                     if (updatedComponents == null)
493                                     {
494                                         updatedComponents = new ArrayList<UIComponent>();
495                                     }
496                                     updatedComponents.add(head);
497                                 }
498                             }
499                             if (rvc.isRenderTarget("body") || rvc.isRenderTarget("form"))
500                             {
501                                 UIComponent body = findBodyComponent(viewRoot);
502                                 if (body != null)
503                                 {
504                                     writer.startUpdate("javax.faces.ViewBody");
505                                     body.encodeAll(_facesContext);
506                                     writer.endUpdate();
507                                     if (updatedComponents == null)
508                                     {
509                                         updatedComponents = new ArrayList<UIComponent>();
510                                     }
511                                     updatedComponents.add(body);
512                                 }
513                             }
514                         }
515 
516                         VisitContext visitCtx = getVisitContextFactory().getVisitContext(
517                                 _facesContext, renderIds, PARTIAL_RENDER_HINTS);
518                         viewRoot.visitTree(visitCtx,
519                                            new PhaseAwareVisitCallback(_facesContext, phaseId, updatedComponents));
520                     }
521                 }
522                 else if (!ExternalContextUtils.isPortlet(_facesContext.getExternalContext()) &&
523                         MyfacesConfig.getCurrentInstance(externalContext).isStrictJsf2RefreshTargetAjax())
524                 {
525                     RequestViewContext rvc = RequestViewContext.getCurrentInstance(_facesContext);
526                     if (rvc.isRenderTarget("head"))
527                     {
528                         UIComponent head = findHeadComponent(viewRoot);
529                         if (head != null)
530                         {
531                             writer.startUpdate("javax.faces.ViewHead");
532                             head.encodeAll(_facesContext);
533                             writer.endUpdate();
534                         }
535                     }
536                     if (rvc.isRenderTarget("body") || rvc.isRenderTarget("form"))
537                     {
538                         UIComponent body = findBodyComponent(viewRoot);
539                         if (body != null)
540                         {
541                             writer.startUpdate("javax.faces.ViewBody");
542                             body.encodeAll(_facesContext);
543                             writer.endUpdate();
544                         }
545                     }
546                 }
547             }
548 
549             // invoke encodeAll() on every UIViewParameter in the view to 
550             // enable every UIViewParameter to save its value in the state
551             // just like UIViewRoot.encodeEnd() does on a normal request
552             // (see MYFACES-2645 for details)
553             Collection<UIViewParameter> viewParams = ViewMetadata.getViewParameters(viewRoot);
554             if (!viewParams.isEmpty())
555             {
556                 for (UIViewParameter param : viewParams)
557                 {
558                     param.encodeAll(_facesContext);
559                 }
560             }
561 
562             //Retrieve the state and apply it if it is not null.
563             String viewState = _facesContext.getApplication().getStateManager().getViewState(_facesContext);
564             if (viewState != null)
565             {
566                 writer.startUpdate(PartialResponseWriter.VIEW_STATE_MARKER);
567                 writer.write(viewState);
568                 writer.endUpdate();
569             }
570         }
571         catch (IOException ex)
572         {
573             Logger log = Logger.getLogger(PartialViewContextImpl.class.getName());
574             if (log.isLoggable(Level.SEVERE))
575             {
576                 log.log(Level.SEVERE, "", ex);
577             }
578 
579         }
580         finally
581         {
582             try
583             {
584                 if (inDocument)
585                 {
586                     writer.endDocument();
587                 }
588                 writer.flush();
589             }
590             catch (IOException ex)
591             {
592                 Logger log = Logger.getLogger(PartialViewContextImpl.class.getName());
593                 if (log.isLoggable(Level.SEVERE))
594                 {
595                     log.log(Level.SEVERE, "", ex);
596                 }
597             }
598 
599             _facesContext.setResponseWriter(oldWriter);
600         }
601 
602     }
603 
604     private void processRenderAll(UIViewRoot viewRoot, PartialResponseWriter writer) throws IOException
605     {
606         //java.util.Iterator<UIComponent> iter = viewRoot.getFacetsAndChildren();
607         writer.startUpdate(PartialResponseWriter.RENDER_ALL_MARKER);
608         //while (iter.hasNext()) 
609         //{ 
610         //UIComponent comp = iter.next();
611 
612         //TODO: Do not check for a specific instance,
613         //just render all children.
614         //if (comp instanceof javax.faces.component.html.HtmlBody)
615         //{
616         //comp.encodeAll (_facesContext);
617         //}
618         //}
619         for (int i = 0, childCount = viewRoot.getChildCount(); i < childCount; i++)
620         {
621             UIComponent comp = viewRoot.getChildren().get(i);
622             comp.encodeAll(_facesContext);
623         }
624         writer.endUpdate();
625     }
626 
627     /**
628      * has to be thrown in many of the methods if the method is called after the instance has been released!
629      */
630     private void assertNotReleased()
631     {
632         if (_released)
633         {
634             throw new IllegalStateException("Error the FacesContext is already released!");
635         }
636     }
637 
638     @Override
639     public void release()
640     {
641         assertNotReleased();
642         _visitContextFactory = null;
643         _executeClientIds = null;
644         _renderClientIds = null;
645         _ajaxRequest = null;
646         _partialRequest = null;
647         _renderAll = null;
648         _facesContext = null;
649         _released = true;
650     }
651 
652     private UIComponent findHeadComponent(UIViewRoot root)
653     {
654         for (UIComponent child : root.getChildren())
655         {
656             if (child instanceof HtmlHead)
657             {
658                 return child;
659             }
660             else
661             {
662                 for (UIComponent grandchild : child.getChildren())
663                 {
664                     if (grandchild instanceof HtmlHead)
665                     {
666                         return grandchild;
667                     }
668                 }
669             }
670         }
671         return null;
672     }
673 
674     private UIComponent findBodyComponent(UIViewRoot root)
675     {
676         for (UIComponent child : root.getChildren())
677         {
678             if (child instanceof HtmlBody)
679             {
680                 return child;
681             }
682             else
683             {
684                 for (UIComponent grandchild : child.getChildren())
685                 {
686                     if (grandchild instanceof HtmlBody)
687                     {
688                         return grandchild;
689                     }
690                 }
691             }
692         }
693         return null;
694     }
695     
696     private VisitContextFactory getVisitContextFactory()
697     {
698         if (_visitContextFactory == null)
699         {
700             _visitContextFactory = (VisitContextFactory)FactoryFinder.getFactory(FactoryFinder.VISIT_CONTEXT_FACTORY);
701         }
702         return _visitContextFactory;
703     }
704 
705     private class PhaseAwareVisitCallback implements VisitCallback
706     {
707 
708         private PhaseId _phaseId;
709         private FacesContext _facesContext;
710         private List<UIComponent> _alreadyUpdatedComponents;
711 
712         public PhaseAwareVisitCallback(FacesContext facesContext, PhaseId phaseId)
713         {
714             this._phaseId = phaseId;
715             this._facesContext = facesContext;
716             this._alreadyUpdatedComponents = null;
717         }
718 
719         public PhaseAwareVisitCallback(FacesContext facesContext, PhaseId phaseId,
720                                        List<UIComponent> alreadyUpdatedComponents)
721         {
722             this._phaseId = phaseId;
723             this._facesContext = facesContext;
724             this._alreadyUpdatedComponents = alreadyUpdatedComponents;
725         }
726 
727         public VisitResult visit(VisitContext context, UIComponent target)
728         {
729             if (_phaseId == PhaseId.APPLY_REQUEST_VALUES)
730             {
731                 target.processDecodes(_facesContext);
732             }
733             else if (_phaseId == PhaseId.PROCESS_VALIDATIONS)
734             {
735                 target.processValidators(_facesContext);
736             }
737             else if (_phaseId == PhaseId.UPDATE_MODEL_VALUES)
738             {
739                 target.processUpdates(_facesContext);
740             }
741             else if (_phaseId == PhaseId.RENDER_RESPONSE)
742             {
743                 processRenderComponent(target);
744             }
745             else
746             {
747                 throw new IllegalStateException("PPR Response, illegale phase called");
748             }
749 
750             // Return VisitResult.REJECT as processDecodes/Validators/Updates already traverse sub tree
751             return VisitResult.REJECT;
752         }
753 
754         /**
755          * the rendering subpart of the tree walker
756          * every component id which is passed down via render must be handled
757          * here!
758          *
759          * @param target the target component to be handled!
760          */
761         private void processRenderComponent(UIComponent target)
762         {
763             boolean inUpdate = false;
764             PartialResponseWriter writer = (PartialResponseWriter) _facesContext.getResponseWriter();
765             if (this._alreadyUpdatedComponents != null)
766             {
767                 //Check if the parent was already updated.
768                 UIComponent parent = target;
769                 while (parent != null)
770                 {
771                     if (this._alreadyUpdatedComponents.contains(parent))
772                     {
773                         return;
774                     }
775                     parent = parent.getParent();
776                 }
777             }
778             try
779             {
780                 writer.startUpdate(target.getClientId(_facesContext));
781                 inUpdate = true;
782                 target.encodeAll(_facesContext);
783             }
784             catch (IOException ex)
785             {
786                 Logger log = Logger.getLogger(PartialViewContextImpl.class.getName());
787                 if (log.isLoggable(Level.SEVERE))
788                 {
789                     log.log(Level.SEVERE, "IOException for rendering component", ex);
790                 }
791             }
792             finally
793             {
794                 if (inUpdate)
795                 {
796                     try
797                     {
798                         writer.endUpdate();
799                     }
800                     catch (IOException ex)
801                     {
802                         Logger log = Logger.getLogger(PartialViewContextImpl.class.getName());
803                         if (log.isLoggable(Level.SEVERE))
804                         {
805                             log.log(Level.SEVERE, "IOException for rendering component, stopping update rendering", ex);
806                         }
807                     }
808                 }
809             }
810         }
811     }
812 }