| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.myfaces.context.servlet; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.EnumSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| |
| import javax.faces.FactoryFinder; |
| import javax.faces.component.UIComponent; |
| import javax.faces.component.UIViewParameter; |
| import javax.faces.component.UIViewRoot; |
| import javax.faces.component.behavior.ClientBehaviorContext; |
| import javax.faces.component.visit.VisitCallback; |
| import javax.faces.component.visit.VisitContext; |
| import javax.faces.component.visit.VisitContextFactory; |
| import javax.faces.component.visit.VisitHint; |
| import javax.faces.component.visit.VisitResult; |
| import javax.faces.context.ExternalContext; |
| import javax.faces.context.FacesContext; |
| import javax.faces.context.PartialResponseWriter; |
| import javax.faces.context.PartialViewContext; |
| import javax.faces.context.ResponseWriter; |
| import javax.faces.event.PhaseId; |
| import javax.faces.lifecycle.ClientWindow; |
| import javax.faces.render.RenderKit; |
| import javax.faces.render.RenderKitFactory; |
| import javax.faces.view.ViewMetadata; |
| import org.apache.myfaces.application.ResourceHandlerImpl; |
| import org.apache.myfaces.application.viewstate.StateTokenProcessor; |
| |
| import org.apache.myfaces.context.PartialResponseWriterImpl; |
| import org.apache.myfaces.context.RequestViewContext; |
| import org.apache.myfaces.renderkit.html.HtmlResponseStateManager; |
| import org.apache.myfaces.renderkit.html.util.JSFAttr; |
| import org.apache.myfaces.renderkit.html.util.ResourceUtils; |
| import org.apache.myfaces.util.lang.StringUtils; |
| import org.apache.myfaces.component.visit.MyFacesVisitHints; |
| |
| public class PartialViewContextImpl extends PartialViewContext |
| { |
| private static final Logger log = Logger.getLogger(PartialViewContextImpl.class.getName()); |
| |
| private static final String FACES_REQUEST = "Faces-Request"; |
| private static final String PARTIAL_AJAX = "partial/ajax"; |
| private static final String PARTIAL_AJAX_REQ = "javax.faces.partial.ajax"; |
| private static final String PARTIAL_PROCESS = "partial/process"; |
| |
| private static final Set<VisitHint> PARTIAL_EXECUTE_HINTS = Collections.unmodifiableSet( |
| EnumSet.of(VisitHint.EXECUTE_LIFECYCLE, VisitHint.SKIP_UNRENDERED)); |
| |
| private FacesContext context = null; |
| private boolean _released = false; |
| // Cached values, since their parent methods could be called |
| // many times and the result does not change during the life time |
| // of this object. |
| private Boolean _ajaxRequest = null; |
| |
| private Collection<String> _executeClientIds = null; |
| private Collection<String> _renderClientIds = null; |
| // Values that need to be saved because exists a setXX method |
| private Boolean _partialRequest = null; |
| private Boolean _renderAll = null; |
| private PartialResponseWriter _partialResponseWriter = null; |
| private VisitContextFactory visitContextFactory = null; |
| private Boolean _resetValues = null; |
| private List<String> _evalScripts = new ArrayList<>(); |
| |
| public PartialViewContextImpl(FacesContext context) |
| { |
| this.context = context; |
| } |
| |
| public PartialViewContextImpl(FacesContext context, VisitContextFactory visitContextFactory) |
| { |
| this.context = context; |
| this.visitContextFactory = visitContextFactory; |
| } |
| |
| @Override |
| public boolean isAjaxRequest() |
| { |
| assertNotReleased(); |
| if (_ajaxRequest == null) |
| { |
| String requestType = context.getExternalContext().getRequestHeaderMap().get(FACES_REQUEST); |
| _ajaxRequest = (requestType != null && PARTIAL_AJAX.equals(requestType)); |
| String reqParmamterPartialAjax = context.getExternalContext() |
| .getRequestParameterMap().get(PARTIAL_AJAX_REQ); |
| //jsdoc reference in an ajax request the javax.faces.partial.ajax must be set as ajax parameter |
| //the other one is Faces-Request == partial/ajax which is basically the same |
| _ajaxRequest = _ajaxRequest || reqParmamterPartialAjax != null; |
| } |
| return _ajaxRequest; |
| } |
| |
| @Override |
| public boolean isExecuteAll() |
| { |
| assertNotReleased(); |
| |
| if (isAjaxRequest()) |
| { |
| String executeMode = context.getExternalContext(). |
| getRequestParameterMap().get(PartialViewContext.PARTIAL_EXECUTE_PARAM_NAME); |
| if (PartialViewContext.ALL_PARTIAL_PHASE_CLIENT_IDS.equals(executeMode)) |
| { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean isPartialRequest() |
| { |
| assertNotReleased(); |
| |
| if (_partialRequest == null) |
| { |
| String requestType = context.getExternalContext().getRequestHeaderMap().get(FACES_REQUEST); |
| _partialRequest = (requestType != null && PARTIAL_PROCESS.equals(requestType)); |
| } |
| return _partialRequest || isAjaxRequest(); |
| } |
| |
| @Override |
| public boolean isRenderAll() |
| { |
| assertNotReleased(); |
| |
| if (_renderAll == null) |
| { |
| if (isAjaxRequest()) |
| { |
| String executeMode = context.getExternalContext(). |
| getRequestParameterMap().get(PartialViewContext.PARTIAL_RENDER_PARAM_NAME); |
| if (PartialViewContext.ALL_PARTIAL_PHASE_CLIENT_IDS.equals(executeMode)) |
| { |
| _renderAll = true; |
| } |
| } |
| if (_renderAll == null) |
| { |
| _renderAll = false; |
| } |
| } |
| return _renderAll; |
| } |
| |
| @Override |
| public void setPartialRequest(boolean isPartialRequest) |
| { |
| assertNotReleased(); |
| |
| _partialRequest = isPartialRequest; |
| } |
| |
| @Override |
| public void setRenderAll(boolean renderAll) |
| { |
| assertNotReleased(); |
| |
| _renderAll = renderAll; |
| } |
| |
| @Override |
| public Collection<String> getExecuteIds() |
| { |
| assertNotReleased(); |
| |
| if (_executeClientIds == null) |
| { |
| String executeMode = context.getExternalContext(). |
| getRequestParameterMap().get(PartialViewContext.PARTIAL_EXECUTE_PARAM_NAME); |
| |
| if (executeMode != null && !executeMode.isEmpty() |
| && !PartialViewContext.ALL_PARTIAL_PHASE_CLIENT_IDS.equals(executeMode)) |
| { |
| |
| String[] clientIds |
| = StringUtils.splitShortString(_replaceTabOrEnterCharactersWithSpaces(executeMode), ' '); |
| |
| //The collection must be mutable |
| List<String> tempList = new ArrayList<>(clientIds.length); |
| for (String clientId : clientIds) |
| { |
| if (clientId.length() > 0) |
| { |
| tempList.add(clientId); |
| } |
| } |
| // The "javax.faces.source" parameter needs to be added to the list of |
| // execute ids if missing (otherwise, we'd never execute an action associated |
| // with, e.g., a button). |
| |
| String source = context.getExternalContext().getRequestParameterMap().get |
| (ClientBehaviorContext.BEHAVIOR_SOURCE_PARAM_NAME); |
| |
| if (source != null) |
| { |
| source = source.trim(); |
| |
| if (!tempList.contains(source)) |
| { |
| tempList.add(source); |
| } |
| } |
| |
| _executeClientIds = tempList; |
| } |
| else |
| { |
| _executeClientIds = new ArrayList<>(5); |
| } |
| } |
| return _executeClientIds; |
| } |
| |
| private String _replaceTabOrEnterCharactersWithSpaces(String mode) |
| { |
| if (mode == null) |
| { |
| return null; |
| } |
| |
| char[] escaped = null; |
| |
| int modeLength = mode.length(); |
| for (int i = 0; i < modeLength; i++) |
| { |
| char c = mode.charAt(i); |
| if (c == '\t' || c == '\n') |
| { |
| if (escaped == null) |
| { |
| escaped = mode.toCharArray(); |
| } |
| escaped[i] = ' '; |
| } |
| } |
| |
| if (escaped != null) |
| { |
| return String.valueOf(escaped); |
| } |
| |
| return mode; |
| } |
| |
| @Override |
| public Collection<String> getRenderIds() |
| { |
| assertNotReleased(); |
| |
| if (_renderClientIds == null) |
| { |
| String renderMode = context.getExternalContext(). |
| getRequestParameterMap().get( |
| PartialViewContext.PARTIAL_RENDER_PARAM_NAME); |
| |
| if (renderMode != null && !renderMode.isEmpty() |
| && !PartialViewContext.ALL_PARTIAL_PHASE_CLIENT_IDS.equals(renderMode)) |
| { |
| String[] clientIds |
| = StringUtils.splitShortString(_replaceTabOrEnterCharactersWithSpaces(renderMode), ' '); |
| |
| //The collection must be mutable |
| List<String> tempList = new ArrayList<>(clientIds.length); |
| for (String clientId : clientIds) |
| { |
| if (clientId.length() > 0) |
| { |
| tempList.add(clientId); |
| } |
| } |
| _renderClientIds = tempList; |
| } |
| else |
| { |
| _renderClientIds = new ArrayList<>(5); |
| if (PartialViewContext.ALL_PARTIAL_PHASE_CLIENT_IDS.equals(renderMode)) |
| { |
| _renderClientIds.add(PartialResponseWriter.RENDER_ALL_MARKER); |
| } |
| } |
| } |
| return _renderClientIds; |
| } |
| |
| @Override |
| public PartialResponseWriter getPartialResponseWriter() |
| { |
| assertNotReleased(); |
| |
| if (_partialResponseWriter == null) |
| { |
| ResponseWriter responseWriter = context.getResponseWriter(); |
| if (responseWriter == null) |
| { |
| // This case happens when getPartialResponseWriter() is called before |
| // render phase, like in ExternalContext.redirect(). We have to create a |
| // ResponseWriter from the RenderKit and then wrap if necessary. |
| try |
| { |
| RenderKit renderKit = context.getRenderKit(); |
| if (renderKit == null) |
| { |
| // If the viewRoot was set to null by some reason, or there is no |
| // renderKitId on that view, this could be still an ajax redirect, |
| // so we have to try to calculate the renderKitId and return a |
| // RenderKit instance, to send the response. |
| String renderKitId |
| = context.getApplication().getViewHandler().calculateRenderKitId(context); |
| RenderKitFactory rkf |
| = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY); |
| renderKit = rkf.getRenderKit(context, renderKitId); |
| } |
| responseWriter = renderKit.createResponseWriter( |
| context.getExternalContext().getResponseOutputWriter(), "text/xml", |
| context.getExternalContext().getRequestCharacterEncoding()); |
| } |
| catch (IOException e) |
| { |
| throw new IllegalStateException("Cannot create Partial Response Writer", e); |
| } |
| } |
| // It is possible that the RenderKit return a PartialResponseWriter instance when |
| // createResponseWriter, so we should cast here for it and prevent double wrapping. |
| if (responseWriter instanceof PartialResponseWriter) |
| { |
| _partialResponseWriter = (PartialResponseWriter) responseWriter; |
| } |
| else |
| { |
| _partialResponseWriter = new PartialResponseWriterImpl(responseWriter); |
| } |
| } |
| return _partialResponseWriter; |
| } |
| |
| @Override |
| public List<String> getEvalScripts() |
| { |
| return _evalScripts; |
| } |
| |
| /** |
| * process the partial response |
| * allowed phase ids according to the spec |
| * |
| * |
| */ |
| @Override |
| public void processPartial(PhaseId phaseId) |
| { |
| assertNotReleased(); |
| |
| UIViewRoot viewRoot = context.getViewRoot(); |
| |
| if (phaseId == PhaseId.APPLY_REQUEST_VALUES |
| || phaseId == PhaseId.PROCESS_VALIDATIONS |
| || phaseId == PhaseId.UPDATE_MODEL_VALUES) |
| { |
| processPartialExecute(viewRoot, phaseId); |
| } |
| else if (phaseId == PhaseId.RENDER_RESPONSE) |
| { |
| processPartialRendering(viewRoot, phaseId); |
| } |
| } |
| |
| private void processPartialExecute(UIViewRoot viewRoot, PhaseId phaseId) |
| { |
| PartialViewContext pvc = context.getPartialViewContext(); |
| Collection<String> executeIds = pvc.getExecuteIds(); |
| if (executeIds == null || executeIds.isEmpty()) |
| { |
| return; |
| } |
| |
| VisitContext visitCtx = getVisitContextFactory().getVisitContext(context, executeIds, |
| PARTIAL_EXECUTE_HINTS); |
| viewRoot.visitTree(visitCtx, new PhaseAwareVisitCallback(context, phaseId)); |
| } |
| |
| private void processPartialRendering(UIViewRoot viewRoot, PhaseId phaseId) |
| { |
| // note that we cannot use this.getPartialResponseWriter(), because |
| // this could cause problems if PartialResponseWriter is wrapped |
| PartialResponseWriter writer = context.getPartialViewContext().getPartialResponseWriter(); |
| PartialViewContext pvc = context.getPartialViewContext(); |
| |
| ResponseWriter oldWriter = context.getResponseWriter(); |
| boolean inDocument = false; |
| |
| //response type = text/xml |
| //no caching and no timeout if possible! |
| ExternalContext externalContext = context.getExternalContext(); |
| externalContext.setResponseContentType("text/xml"); |
| externalContext.addResponseHeader("Pragma", "no-cache"); |
| externalContext.addResponseHeader("Cache-control", "no-cache"); |
| //under normal circumstances pragma should be enough, IE needs |
| //a special treatment! |
| //http://support.microsoft.com/kb/234067 |
| externalContext.addResponseHeader("Expires", "-1"); |
| |
| try |
| { |
| String currentEncoding = writer.getCharacterEncoding(); |
| |
| writer.startDocument(); |
| |
| writer.writeAttribute("id", viewRoot.getContainerClientId(context),"id"); |
| |
| inDocument = true; |
| context.setResponseWriter(writer); |
| |
| if (isResetValues()) |
| { |
| viewRoot.resetValues(context, getRenderIds()); |
| } |
| |
| if (pvc.isRenderAll()) |
| { |
| processRenderAll(viewRoot, writer); |
| } |
| else |
| { |
| Collection<String> renderIds = pvc.getRenderIds(); |
| //Only apply partial visit if we have ids to traverse |
| if (renderIds != null && !renderIds.isEmpty()) |
| { |
| // render=@all, so output the body. |
| if (renderIds.contains(PartialResponseWriter.RENDER_ALL_MARKER)) |
| { |
| processRenderAll(viewRoot, writer); |
| } |
| else |
| { |
| // In JSF 2.3 it was added javax.faces.Resource as an update target to add scripts or |
| // stylesheets inside <head> tag |
| |
| List<UIComponent> updatedComponents = new ArrayList<>(); |
| RequestViewContext rvc = RequestViewContext.getCurrentInstance(context); |
| processRenderResource(context, writer, rvc, updatedComponents, "head"); |
| processRenderResource(context, writer, rvc, updatedComponents, "body"); |
| processRenderResource(context, writer, rvc, updatedComponents, "form"); |
| |
| VisitContext visitCtx = getVisitContextFactory().getVisitContext(context, renderIds, |
| MyFacesVisitHints.SET_SKIP_UNRENDERED); |
| viewRoot.visitTree(visitCtx, |
| new PhaseAwareVisitCallback(context, phaseId, updatedComponents)); |
| } |
| } |
| else |
| { |
| List<UIComponent> updatedComponents = new ArrayList<>(); |
| RequestViewContext rvc = RequestViewContext.getCurrentInstance(context); |
| processRenderResource(context, writer, rvc, updatedComponents, "head"); |
| processRenderResource(context, writer, rvc, updatedComponents, "body"); |
| processRenderResource(context, writer, rvc, updatedComponents, "form"); |
| } |
| |
| List<String> evalScripts = pvc.getEvalScripts(); |
| if (evalScripts != null && evalScripts.size() > 0) |
| { |
| for (String script : evalScripts) |
| { |
| writer.startEval(); |
| writer.write(script); |
| writer.endEval(); |
| } |
| } |
| } |
| |
| // invoke encodeAll() on every UIViewParameter in the view to |
| // enable every UIViewParameter to save its value in the state |
| // just like UIViewRoot.encodeEnd() does on a normal request |
| // (see MYFACES-2645 for details) |
| Collection<UIViewParameter> viewParams = ViewMetadata.getViewParameters(viewRoot); |
| if (!viewParams.isEmpty()) |
| { |
| for (UIViewParameter param : viewParams) |
| { |
| param.encodeAll(context); |
| } |
| } |
| |
| //Retrieve the state and apply it if it is not null. |
| String viewState = context.getApplication().getStateManager().getViewState(context); |
| if (viewState != null) |
| { |
| writer.startUpdate(HtmlResponseStateManager.generateUpdateViewStateId(context)); |
| writer.write(viewState); |
| writer.endUpdate(); |
| } |
| else if (viewRoot.isTransient()) |
| { |
| writer.startUpdate(HtmlResponseStateManager.generateUpdateViewStateId(context)); |
| writer.write(StateTokenProcessor.STATELESS_TOKEN); |
| writer.endUpdate(); |
| } |
| |
| |
| ClientWindow cw = context.getExternalContext().getClientWindow(); |
| if (cw != null) |
| { |
| writer.startUpdate(HtmlResponseStateManager.generateUpdateClientWindowId(context)); |
| writer.writeText(cw.getId(), null); |
| writer.endUpdate(); |
| } |
| } |
| catch (IOException ex) |
| { |
| if (log.isLoggable(Level.SEVERE)) |
| { |
| log.log(Level.SEVERE, "", ex); |
| } |
| } |
| finally |
| { |
| try |
| { |
| if (inDocument) |
| { |
| writer.endDocument(); |
| } |
| writer.flush(); |
| } |
| catch (IOException ex) |
| { |
| if (log.isLoggable(Level.SEVERE)) |
| { |
| log.log(Level.SEVERE, "", ex); |
| } |
| } |
| |
| context.setResponseWriter(oldWriter); |
| } |
| |
| } |
| |
| private void processRenderResource(FacesContext facesContext, PartialResponseWriter writer, RequestViewContext rvc, |
| List<UIComponent> updatedComponents, String target) throws IOException |
| { |
| if (rvc.isRenderTarget(target)) |
| { |
| List<UIComponent> list = rvc.getRenderTargetComponentList(target); |
| if (list != null && !list.isEmpty()) |
| { |
| writer.startUpdate("javax.faces.Resource"); |
| for (UIComponent component : list) |
| { |
| boolean resourceRendered = false; |
| if (ResourceUtils.DEFAULT_SCRIPT_RENDERER_TYPE.equals(component.getRendererType()) |
| || ResourceUtils.DEFAULT_STYLESHEET_RENDERER_TYPE.equals(component.getRendererType())) |
| { |
| String resourceName = (String) component.getAttributes().get(JSFAttr.NAME_ATTR); |
| String libraryName = (String) component.getAttributes().get(JSFAttr.LIBRARY_ATTR); |
| |
| if (resourceName == null || resourceName.isEmpty()) |
| { |
| // No resource, render all |
| component.encodeAll(facesContext); |
| continue; |
| } |
| |
| int index = resourceName.indexOf('?'); |
| if (index >= 0) |
| { |
| resourceName = resourceName.substring(0, index); |
| } |
| // Is resource, render only if it has not been rendered before. |
| if (!context.getApplication().getResourceHandler().isResourceRendered( |
| context, resourceName, libraryName)) |
| { |
| component.encodeAll(facesContext); |
| } |
| } |
| else |
| { |
| component.encodeAll(facesContext); |
| } |
| if (!resourceRendered) |
| { |
| if (updatedComponents == null) |
| { |
| updatedComponents = new ArrayList<UIComponent>(); |
| } |
| updatedComponents.add(component); |
| } |
| } |
| writer.endUpdate(); |
| } |
| } |
| } |
| |
| private void processRenderAll(UIViewRoot viewRoot, PartialResponseWriter writer) throws IOException |
| { |
| // Before render all we need to clear rendered resources set to be sure every component resource is |
| // rendered. Remember renderAll means the whole page is replaced, so everything inside <head> is replaced. |
| // and there is no way to diff between the old and the new content of <head>. |
| Map<String, Boolean> map = (Map) viewRoot.getTransientStateHelper().getTransient( |
| ResourceHandlerImpl.RENDERED_RESOURCES_SET); |
| if (map != null) |
| { |
| map.clear(); |
| } |
| |
| writer.startUpdate(PartialResponseWriter.RENDER_ALL_MARKER); |
| for (int i = 0, childCount = viewRoot.getChildCount(); i < childCount; i++) |
| { |
| UIComponent comp = viewRoot.getChildren().get(i); |
| comp.encodeAll(context); |
| } |
| writer.endUpdate(); |
| } |
| |
| /** |
| * has to be thrown in many of the methods if the method is called after the instance has been released! |
| */ |
| private void assertNotReleased() |
| { |
| if (_released) |
| { |
| throw new IllegalStateException("Error the FacesContext is already released!"); |
| } |
| } |
| |
| @Override |
| public void release() |
| { |
| assertNotReleased(); |
| visitContextFactory = null; |
| _executeClientIds = null; |
| _renderClientIds = null; |
| _ajaxRequest = null; |
| _partialRequest = null; |
| _renderAll = null; |
| context = null; |
| _released = true; |
| } |
| |
| private VisitContextFactory getVisitContextFactory() |
| { |
| if (visitContextFactory == null) |
| { |
| visitContextFactory = (VisitContextFactory)FactoryFinder.getFactory(FactoryFinder.VISIT_CONTEXT_FACTORY); |
| } |
| return visitContextFactory; |
| } |
| |
| @Override |
| public boolean isResetValues() |
| { |
| if (_resetValues == null) |
| { |
| String value = context.getExternalContext().getRequestParameterMap(). |
| get(RESET_VALUES_PARAM_NAME); |
| _resetValues = "true".equals(value); |
| } |
| return _resetValues; |
| } |
| |
| private class PhaseAwareVisitCallback implements VisitCallback |
| { |
| private PhaseId _phaseId; |
| private FacesContext _facesContext; |
| private List<UIComponent> _alreadyUpdatedComponents; |
| |
| public PhaseAwareVisitCallback(FacesContext facesContext, PhaseId phaseId) |
| { |
| this._phaseId = phaseId; |
| this._facesContext = facesContext; |
| this._alreadyUpdatedComponents = null; |
| } |
| |
| public PhaseAwareVisitCallback(FacesContext facesContext, PhaseId phaseId, |
| List<UIComponent> alreadyUpdatedComponents) |
| { |
| this._phaseId = phaseId; |
| this._facesContext = facesContext; |
| this._alreadyUpdatedComponents = alreadyUpdatedComponents; |
| } |
| |
| @Override |
| public VisitResult visit(VisitContext context, UIComponent target) |
| { |
| if (_phaseId == PhaseId.APPLY_REQUEST_VALUES) |
| { |
| target.processDecodes(_facesContext); |
| } |
| else if (_phaseId == PhaseId.PROCESS_VALIDATIONS) |
| { |
| target.processValidators(_facesContext); |
| } |
| else if (_phaseId == PhaseId.UPDATE_MODEL_VALUES) |
| { |
| target.processUpdates(_facesContext); |
| } |
| else if (_phaseId == PhaseId.RENDER_RESPONSE) |
| { |
| processRenderComponent(target); |
| } |
| else |
| { |
| throw new IllegalStateException("PPR Response, illegale phase called"); |
| } |
| |
| // Return VisitResult.REJECT as processDecodes/Validators/Updates already traverse sub tree |
| return VisitResult.REJECT; |
| } |
| |
| /** |
| * the rendering subpart of the tree walker |
| * every component id which is passed down via render must be handled |
| * here! |
| * |
| * @param target the target component to be handled! |
| */ |
| private void processRenderComponent(UIComponent target) |
| { |
| boolean inUpdate = false; |
| PartialResponseWriter writer = (PartialResponseWriter) _facesContext.getResponseWriter(); |
| if (this._alreadyUpdatedComponents != null) |
| { |
| //Check if the parent was already updated. |
| UIComponent parent = target; |
| while (parent != null) |
| { |
| if (this._alreadyUpdatedComponents.contains(parent)) |
| { |
| return; |
| } |
| parent = parent.getParent(); |
| } |
| } |
| try |
| { |
| writer.startUpdate(target.getClientId(_facesContext)); |
| inUpdate = true; |
| target.encodeAll(_facesContext); |
| } |
| catch (IOException ex) |
| { |
| if (log.isLoggable(Level.SEVERE)) |
| { |
| log.log(Level.SEVERE, "IOException for rendering component", ex); |
| } |
| } |
| finally |
| { |
| if (inUpdate) |
| { |
| try |
| { |
| writer.endUpdate(); |
| } |
| catch (IOException ex) |
| { |
| if (log.isLoggable(Level.SEVERE)) |
| { |
| log.log(Level.SEVERE, "IOException for rendering component, stopping update rendering", ex); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |