From e1238fc7ae04fa4e07b1555ac1a47248ce9516c4 Mon Sep 17 00:00:00 2001 From: Gaboros Date: Thu, 31 Jan 2019 15:25:40 +0100 Subject: [PATCH] visit tree performance upgrade --- .../FaceletFullStateManagementStrategy.java | 98 ++------ ...FaceletPartialStateManagementStrategy.java | 99 ++------ .../view/FaceletViewHandlingStrategy.java | 231 ++++++++---------- 3 files changed, 161 insertions(+), 267 deletions(-) diff --git a/jsf-ri/src/main/java/com/sun/faces/application/view/FaceletFullStateManagementStrategy.java b/jsf-ri/src/main/java/com/sun/faces/application/view/FaceletFullStateManagementStrategy.java index a1955b4561..ce88fef627 100644 --- a/jsf-ri/src/main/java/com/sun/faces/application/view/FaceletFullStateManagementStrategy.java +++ b/jsf-ri/src/main/java/com/sun/faces/application/view/FaceletFullStateManagementStrategy.java @@ -178,70 +178,6 @@ private void captureRest(List tree, int pos, UIComponent c) { } } - /** - * Find the given component in the component tree. - * - * @param context the Faces context. - * @param clientId the client id of the component to find. - */ - private UIComponent locateComponentByClientId(final FacesContext context, final UIComponent subTree, final String clientId) { - if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.log(Level.FINEST, "FaceletFullStateManagementStrategy.locateComponentByClientId", clientId); - } - - final List found = new ArrayList(); - UIComponent result = null; - - try { - context.getAttributes().put(SKIP_ITERATION_HINT, true); - Set hints = EnumSet.of(VisitHint.SKIP_ITERATION); - - VisitContext visitContext = VisitContext.createVisitContext(context, null, hints); - subTree.visitTree(visitContext, new VisitCallback() { - - public VisitResult visit(VisitContext visitContext, UIComponent component) { - VisitResult result = VisitResult.ACCEPT; - if (component.getClientId(visitContext.getFacesContext()).equals(clientId)) { - /* - * If the client id matches up we have found our match. - */ - found.add(component); - result = VisitResult.COMPLETE; - } else if (component instanceof UIForm) { - /* - * If the component is a UIForm and it is prepending its - * id then we can short circuit out of here if the the - * client id of the component we are trying to find does - * not begin with the id of the UIForm. - */ - UIForm form = (UIForm) component; - if (form.isPrependId() && !clientId.startsWith(form.getClientId(visitContext.getFacesContext()))) { - result = VisitResult.REJECT; - } - } else if (component instanceof NamingContainer - && !clientId.startsWith(component.getClientId(visitContext.getFacesContext()))) { - /* - * If the component is a naming container then assume it - * is prepending its id so if our client id we are - * looking for does not start with the naming container - * id we can skip visiting this tree. - */ - result = VisitResult.REJECT; - } - - return result; - } - }); - } finally { - context.getAttributes().remove(SKIP_ITERATION_HINT); - } - - if (!found.isEmpty()) { - result = found.get(0); - } - return result; - } - /** * Create a new component instance. * @@ -378,15 +314,33 @@ private void restoreDynamicActions(FacesContext context, StateContext stateConte List savedActions = (List) viewRoot.getAttributes().get(DYNAMIC_ACTIONS); List actions = stateContext.getDynamicActions(); + final Map compCache = new HashMap<>(); + try { + context.getAttributes().put(SKIP_ITERATION_HINT, true); + Set hints = EnumSet.of(VisitHint.SKIP_ITERATION); + VisitContext visitContext = VisitContext.createVisitContext(context, null, hints); + context.getViewRoot().visitTree(visitContext, new VisitCallback() { + + @Override + public VisitResult visit(VisitContext visitContext, UIComponent component) { + compCache.put(component.getClientId(visitContext.getFacesContext()), component); + return VisitResult.ACCEPT; + } + + }); + } finally { + context.getAttributes().remove(SKIP_ITERATION_HINT); + } + if (savedActions != null && !savedActions.isEmpty()) { for (Object object : savedActions) { ComponentStruct action = new ComponentStruct(); action.restoreState(context, object); if (ComponentStruct.ADD.equals(action.action)) { - restoreDynamicAdd(context, state, action); + restoreDynamicAdd(context, state, action, compCache); } if (ComponentStruct.REMOVE.equals(action.action)) { - restoreDynamicRemove(context, action); + restoreDynamicRemove(context, action, compCache); } pruneAndReAddToDynamicActions(actions, action); } @@ -400,15 +354,15 @@ private void restoreDynamicActions(FacesContext context, StateContext stateConte * @param state the state. * @param struct the component struct. */ - private void restoreDynamicAdd(FacesContext context, Map state, ComponentStruct struct) { + private void restoreDynamicAdd(FacesContext context, Map state, ComponentStruct struct, Map compCache) { if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("FaceletFullStateManagementStrategy.restoreDynamicAdd"); } - UIComponent parent = locateComponentByClientId(context, context.getViewRoot(), struct.parentClientId); + UIComponent parent = compCache.get(struct.parentClientId); if (parent != null) { - UIComponent child = locateComponentByClientId(context, parent, struct.clientId); + UIComponent child = compCache.get(struct.clientId); /* * If Facelets engine restored the child before us we are going to @@ -465,6 +419,7 @@ private void restoreDynamicAdd(FacesContext context, Map state, } child.getAttributes().put(DYNAMIC_COMPONENT, child.getParent().getChildren().indexOf(child)); stateContext.getDynamicComponents().put(struct.clientId, child); + compCache.put(struct.clientId, child); } } } @@ -475,17 +430,18 @@ private void restoreDynamicAdd(FacesContext context, Map state, * @param context the Faces context. * @param struct the component struct. */ - private void restoreDynamicRemove(FacesContext context, ComponentStruct struct) { + private void restoreDynamicRemove(FacesContext context, ComponentStruct struct, Map compCache) { if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("FaceletFullStateManagementStrategy.restoreDynamicRemove"); } - UIComponent child = locateComponentByClientId(context, context.getViewRoot(), struct.clientId); + UIComponent child = compCache.get(struct.clientId); if (child != null) { StateContext stateContext = StateContext.getStateContext(context); stateContext.getDynamicComponents().put(struct.clientId, child); UIComponent parent = child.getParent(); parent.getChildren().remove(child); + compCache.remove(struct.clientId); } } diff --git a/jsf-ri/src/main/java/com/sun/faces/application/view/FaceletPartialStateManagementStrategy.java b/jsf-ri/src/main/java/com/sun/faces/application/view/FaceletPartialStateManagementStrategy.java index 50cdac1e71..4cceaaa4cc 100644 --- a/jsf-ri/src/main/java/com/sun/faces/application/view/FaceletPartialStateManagementStrategy.java +++ b/jsf-ri/src/main/java/com/sun/faces/application/view/FaceletPartialStateManagementStrategy.java @@ -101,70 +101,6 @@ public FaceletPartialStateManagementStrategy() { public FaceletPartialStateManagementStrategy(FacesContext context) { } - /** - * Find the given component in the component tree. - * - * @param context the Faces context. - * @param clientId the client id of the component to find. - */ - private UIComponent locateComponentByClientId(final FacesContext context, final UIComponent subTree, final String clientId) { - if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.log(Level.FINEST, "FaceletPartialStateManagementStrategy.locateComponentByClientId", clientId); - } - - final List found = new ArrayList(); - UIComponent result = null; - - try { - context.getAttributes().put(SKIP_ITERATION_HINT, true); - Set hints = EnumSet.of(VisitHint.SKIP_ITERATION); - - VisitContext visitContext = VisitContext.createVisitContext(context, null, hints); - subTree.visitTree(visitContext, new VisitCallback() { - - public VisitResult visit(VisitContext visitContext, UIComponent component) { - VisitResult result = VisitResult.ACCEPT; - if (component.getClientId(visitContext.getFacesContext()).equals(clientId)) { - /* - * If the client id matches up we have found our match. - */ - found.add(component); - result = VisitResult.COMPLETE; - } else if (component instanceof UIForm) { - /* - * If the component is a UIForm and it is prepending its - * id then we can short circuit out of here if the the - * client id of the component we are trying to find does - * not begin with the id of the UIForm. - */ - UIForm form = (UIForm) component; - if (form.isPrependId() && !clientId.startsWith(form.getClientId(visitContext.getFacesContext()))) { - result = VisitResult.REJECT; - } - } else if (component instanceof NamingContainer && - !clientId.startsWith(component.getClientId(visitContext.getFacesContext()))) { - /* - * If the component is a naming container then assume it - * is prepending its id so if our client id we are - * looking for does not start with the naming container - * id we can skip visiting this tree. - */ - result = VisitResult.REJECT; - } - - return result; - } - }); - } finally { - context.getAttributes().remove(SKIP_ITERATION_HINT); - } - - if (!found.isEmpty()) { - result = found.get(0); - } - return result; - } - /** * Methods that takes care of pruning and re-adding an action to the dynamic * action list. @@ -218,15 +154,32 @@ private void restoreDynamicActions(FacesContext context, StateContext stateConte List savedActions = (List) stateMap.get(DYNAMIC_ACTIONS); List actions = stateContext.getDynamicActions(); + final Map compCache = new HashMap<>(); + try { + context.getAttributes().put(SKIP_ITERATION_HINT, true); + Set hints = EnumSet.of(VisitHint.SKIP_ITERATION); + VisitContext visitContext = VisitContext.createVisitContext(context, null, hints); + context.getViewRoot().visitTree(visitContext, new VisitCallback() { + + @Override + public VisitResult visit(VisitContext visitContext, UIComponent component) { + compCache.put(component.getClientId(visitContext.getFacesContext()), component); + return VisitResult.ACCEPT; + } + }); + } finally { + context.getAttributes().remove(SKIP_ITERATION_HINT); + } + if (savedActions != null && !savedActions.isEmpty()) { for (Object object : savedActions) { ComponentStruct action = new ComponentStruct(); action.restoreState(context, object); if (ComponentStruct.ADD.equals(action.action)) { - restoreDynamicAdd(context, stateMap, action); + restoreDynamicAdd(context, stateMap, action, compCache); } if (ComponentStruct.REMOVE.equals(action.action)) { - restoreDynamicRemove(context, action); + restoreDynamicRemove(context, action, compCache); } pruneAndReAddToDynamicActions(actions, action); } @@ -240,15 +193,15 @@ private void restoreDynamicActions(FacesContext context, StateContext stateConte * @param state the state. * @param struct the component struct. */ - private void restoreDynamicAdd(FacesContext context, Map state, ComponentStruct struct) { + private void restoreDynamicAdd(FacesContext context, Map state, ComponentStruct struct, Map compCache) { if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("FaceletPartialStateManagementStrategy.restoreDynamicAdd"); } - UIComponent parent = locateComponentByClientId(context, context.getViewRoot(), struct.parentClientId); + UIComponent parent = compCache.get(struct.parentClientId); if (parent != null) { - UIComponent child = locateComponentByClientId(context, parent, struct.clientId); + UIComponent child = compCache.get(struct.clientId); /* * If Facelets engine restored the child before us we are going to @@ -305,6 +258,7 @@ private void restoreDynamicAdd(FacesContext context, Map state, } child.getAttributes().put(DYNAMIC_COMPONENT, child.getParent().getChildren().indexOf(child)); stateContext.getDynamicComponents().put(struct.clientId, child); + compCache.put(struct.clientId, child); } } } @@ -315,17 +269,18 @@ private void restoreDynamicAdd(FacesContext context, Map state, * @param context the Faces context. * @param struct the component struct. */ - private void restoreDynamicRemove(FacesContext context, ComponentStruct struct) { + private void restoreDynamicRemove(FacesContext context, ComponentStruct struct, Map compCache) { if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("FaceletPartialStateManagementStrategy.restoreDynamicRemove"); } - UIComponent child = locateComponentByClientId(context, context.getViewRoot(), struct.clientId); + UIComponent child = compCache.get(struct.clientId); if (child != null) { StateContext stateContext = StateContext.getStateContext(context); stateContext.getDynamicComponents().put(struct.clientId, child); UIComponent parent = child.getParent(); parent.getChildren().remove(child); + compCache.remove(struct.clientId); } } @@ -417,7 +372,7 @@ private void saveDynamicActions(FacesContext context, StateContext stateContext, List actions = stateContext.getDynamicActions(); HashMap componentMap = stateContext.getDynamicComponents(); - + if (actions != null) { List savedActions = new ArrayList(actions.size()); for (ComponentStruct action : actions) { diff --git a/jsf-ri/src/main/java/com/sun/faces/application/view/FaceletViewHandlingStrategy.java b/jsf-ri/src/main/java/com/sun/faces/application/view/FaceletViewHandlingStrategy.java index e7b6b5ebef..95ed6865e9 100644 --- a/jsf-ri/src/main/java/com/sun/faces/application/view/FaceletViewHandlingStrategy.java +++ b/jsf-ri/src/main/java/com/sun/faces/application/view/FaceletViewHandlingStrategy.java @@ -45,6 +45,8 @@ import com.sun.faces.config.WebConfiguration; import com.sun.faces.config.WebConfiguration.WebContextInitParameter; import com.sun.faces.context.StateContext; + +import javax.faces.component.visit.VisitHint; import javax.faces.view.facelets.Facelet; import com.sun.faces.facelets.el.ContextualCompositeMethodExpression; import com.sun.faces.facelets.el.VariableMapperWrapper; @@ -66,10 +68,12 @@ import java.io.IOException; import java.io.Writer; import java.util.ArrayList; +import java.util.EnumSet; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import javax.el.ExpressionFactory; @@ -148,11 +152,11 @@ public class FaceletViewHandlingStrategy extends ViewHandlingStrategy { // Array of viewId prefixes that should be handled by Facelets private String[] prefixesArray; - + public static final String IS_BUILDING_METADATA = FaceletViewHandlingStrategy.class.getName() + ".IS_BUILDING_METADATA"; - - public static final String RESOURCE_LIBRARY_CONTRACT_DATA_STRUCTURE_KEY = + + public static final String RESOURCE_LIBRARY_CONTRACT_DATA_STRUCTURE_KEY = FaceletViewHandlingStrategy.class.getName() + ".RESOURCE_LIBRARY_CONTRACT_DATA_STRUCTURE"; private MethodRetargetHandlerManager retargetHandlerManager = @@ -192,28 +196,28 @@ public static boolean isBuildingMetadata(FacesContext context) { @Override public StateManagementStrategy getStateManagementStrategy(FacesContext context, String viewId) { StateManagementStrategy result; - + StateContext stateCtx = StateContext.getStateContext(context); if (stateCtx.isPartialStateSaving(context, viewId)) { result = new FaceletPartialStateManagementStrategy(context); } else { // Spec for this method says: - - // Implementations that provide the VDL for Facelets for JSF 2.0 + + // Implementations that provide the VDL for Facelets for JSF 2.0 // and later must return non-null from this method. - + // Limit the specification violating change to the case where // we are running in Trinidad. - // + // result = isTrinidadStateManager ? null : new JspStateManagementStrategy(context); } - + return result; } - + /* * Called by Application._createComponent(Resource). - * + * * This method creates two temporary UIComponent instances to aid in * the creation of the compcomp metadata. These instances no longer * needed after the method returns and can be safely garbage @@ -239,7 +243,7 @@ public StateManagementStrategy getStateManagementStrategy(FacesContext context, */ @Override - public BeanInfo getComponentMetadata(FacesContext context, + public BeanInfo getComponentMetadata(FacesContext context, Resource ccResource) { DefaultFaceletFactory factory = (DefaultFaceletFactory) @@ -251,7 +255,7 @@ public BeanInfo getComponentMetadata(FacesContext context, return metadataCache.get(ccResource); } - + public BeanInfo createComponentMetadata(FacesContext context, Resource ccResource) { @@ -279,9 +283,9 @@ public BeanInfo createComponentMetadata(FacesContext context, tmp.getFacets().put(UIComponent.COMPOSITE_FACET_NAME, facetComponent); // We have to put the resource in here just so the classes that eventually // get called by facelets have access to it. - tmp.getAttributes().put(Resource.COMPONENT_RESOURCE_KEY, + tmp.getAttributes().put(Resource.COMPONENT_RESOURCE_KEY, ccResource); - + Facelet f; try { @@ -292,7 +296,7 @@ public BeanInfo createComponentMetadata(FacesContext context, public ValueExpression resolveVariable(String variable) { return super.resolveVariable(variable); } - + }; ctx.setVariableMapper(wrapper); context.getAttributes().put(IS_BUILDING_METADATA, Boolean.TRUE); @@ -332,9 +336,9 @@ public ValueExpression resolveVariable(String variable) { // to discard tmp and facetComponent. The compcomp metadata // should be cacheable and shareable across threads, but this is // not yet implemented. - result = (CompositeComponentBeanInfo) + result = (CompositeComponentBeanInfo) tmp.getAttributes().get(UIComponent.BEANINFO_KEY); - + return result; } @@ -346,7 +350,7 @@ public ViewMetadata getViewMetadata(FacesContext context, String viewId) { return new ViewMetadataImpl(viewId); } - + /** * @see javax.faces.view.ViewDeclarationLanguage#getScriptComponentResource(javax.faces.context.FacesContext, javax.faces.application.Resource) */ @@ -362,13 +366,13 @@ public Resource getScriptComponentResource(FacesContext context, String resourceName = componentResource.getResourceName(); if (resourceName.endsWith(".xhtml")) { - resourceName = resourceName.substring(0, + resourceName = resourceName.substring(0, resourceName.length() - 6) + ".groovy"; ResourceHandler resourceHandler = context.getApplication().getResourceHandler(); - result = resourceHandler.createResource(resourceName, + result = resourceHandler.createResource(resourceName, componentResource.getLibraryName()); } - + return result; } @@ -406,19 +410,19 @@ public void renderView(FacesContext ctx, } ExternalContext extContext = ctx.getExternalContext(); - + /* * Make sure we have a session here if we are using server state * saving. The WriteBehindStateWriter needs an active session when * it writes out state to a server session. - * + * * Note if you flag a view as transient then we won't acquire the * session as you are stating it does not need one. */ if (isServerStateSaving() && !viewToRender.isTransient()) { getSession(ctx); - } - + } + Writer outputWriter = extContext.getResponseOutputWriter(); stateWriter = new WriteBehindStateWriter(outputWriter, ctx, @@ -441,7 +445,7 @@ public void renderView(FacesContext ctx, if (ctx.isProjectStage(ProjectStage.Development)) { FormOmittedChecker.check(ctx); } - + // render the view to the response String XMLDECL = Util.getXMLDECLFromFacesContextAttributes(ctx); if (null != XMLDECL) { @@ -490,7 +494,7 @@ public void renderView(FacesContext ctx, /** * Are we saving state server side? - * + * * @return true if we are, false otherwise. */ private boolean isServerStateSaving() { @@ -504,7 +508,7 @@ private boolean isServerStateSaving() { /** * Get a session (if we are using server state saving). - * + * * @param context the Faces context. * @return the session, or null if we are not using server state saving. */ @@ -516,13 +520,13 @@ private HttpSession getSession(FacesContext context) { } return result; } - + /** *

* If {@link UIDebug#debugRequest(javax.faces.context.FacesContext)}} is true, * simply return a new UIViewRoot(), otherwise, call the default logic. *

- * @see ViewDeclarationLanguage#restoreView(javax.faces.context.FacesContext, java.lang.String) + * @see ViewDeclarationLanguage#restoreView(javax.faces.context.FacesContext, java.lang.String) */ @Override public UIViewRoot restoreView(FacesContext context, @@ -533,21 +537,21 @@ public UIViewRoot restoreView(FacesContext context, if (UIDebug.debugRequest(context)) { context.getApplication().createComponent(UIViewRoot.COMPONENT_TYPE); } - + UIViewRoot viewRoot; - + /* * Check if we are stateless. */ ViewHandler outerViewHandler = context.getApplication().getViewHandler(); String renderKitId = outerViewHandler.calculateRenderKitId(context); ResponseStateManager rsm = RenderKitUtils.getResponseStateManager(context, renderKitId); - + if (rsm.isStateless(context, viewId)) { try { context.setProcessingEvents(true); ViewDeclarationLanguage vdl = vdlFactory.getViewDeclarationLanguage(viewId); - viewRoot = vdl.createView(context, viewId); + viewRoot = vdl.createView(context, viewId); context.setViewRoot(viewRoot); vdl.buildView(context, viewRoot); if (!viewRoot.isTransient()) { @@ -558,7 +562,7 @@ public UIViewRoot restoreView(FacesContext context, throw new FacesException(ioe); } } - + if (StateContext.getStateContext(context).isPartialStateSaving(context, viewId)) { try { context.setProcessingEvents(false); @@ -589,14 +593,14 @@ public UIViewRoot restoreView(FacesContext context, } UIViewRoot root = super.restoreView(context, viewId); - + ViewHandler viewHandler = context.getApplication().getViewHandler(); ViewDeclarationLanguage vdl = viewHandler.getViewDeclarationLanguage(context, viewId); - context.setResourceLibraryContracts(vdl.calculateResourceLibraryContracts(context, viewId)); - + context.setResourceLibraryContracts(vdl.calculateResourceLibraryContracts(context, viewId)); + StateContext stateCtx = StateContext.getStateContext(context); stateCtx.startTrackViewModifications(context, root); - + return root; } @@ -619,15 +623,15 @@ public void retargetAttachedObjects(FacesContext context, if (handlers == null || handlers.isEmpty()) { return; } - - BeanInfo componentBeanInfo = (BeanInfo) + + BeanInfo componentBeanInfo = (BeanInfo) topLevelComponent.getAttributes().get(UIComponent.BEANINFO_KEY); // PENDING(edburns): log error message if componentBeanInfo is null; if (null == componentBeanInfo) { return; } BeanDescriptor componentDescriptor = componentBeanInfo.getBeanDescriptor(); - // There is an entry in targetList for each attached object in the + // There is an entry in targetList for each attached object in the // section of the composite component. List targetList = (List) componentDescriptor.getValue(AttachedObjectTarget.ATTACHED_OBJECT_TARGETS_KEY); @@ -676,7 +680,7 @@ else if (curHandler instanceof ValueHolderAttachedObjectHandler && } break; } - } else if(curHandler instanceof BehaviorHolderAttachedObjectHandler && + } else if(curHandler instanceof BehaviorHolderAttachedObjectHandler && curTarget instanceof BehaviorHolderAttachedObjectTarget) { BehaviorHolderAttachedObjectHandler behaviorHandler = (BehaviorHolderAttachedObjectHandler) curHandler; BehaviorHolderAttachedObjectTarget behaviorTarget = (BehaviorHolderAttachedObjectTarget) curTarget; @@ -703,7 +707,7 @@ public void retargetMethodExpressions(FacesContext context, Util.notNull("context", context); Util.notNull("topLevelComponent", topLevelComponent); - BeanInfo componentBeanInfo = (BeanInfo) + BeanInfo componentBeanInfo = (BeanInfo) topLevelComponent.getAttributes().get(UIComponent.BEANINFO_KEY); // PENDING(edburns): log error message if componentBeanInfo is null; if (null == componentBeanInfo) { @@ -826,9 +830,9 @@ public UIViewRoot createView(FacesContext ctx, ViewDeclarationLanguage vdl = viewHandler.getViewDeclarationLanguage(ctx, viewId); ctx.setResourceLibraryContracts(vdl.calculateResourceLibraryContracts(ctx, viewId)); - + return result; - + } @Override @@ -837,13 +841,13 @@ public UIComponent createComponent(FacesContext context, String taglibURI, Strin Util.notNull("taglibURI", taglibURI); Util.notNull("tagName", tagName); UIComponent result = null; - + DefaultFaceletFactory ff = associate.getFaceletFactory(); result = ff._createComponent(context, taglibURI, tagName, attributes); - + return result; } - + @Override public List calculateResourceLibraryContracts(FacesContext context, String viewId) { List result = null; @@ -851,11 +855,11 @@ public List calculateResourceLibraryContracts(FacesContext context, Stri if (null == contractMappings) { return Collections.emptyList(); } - + String longestMatch = null; for (Map.Entry> mappings : contractMappings.entrySet()) { String urlPattern = mappings.getKey(); - if (urlPattern.endsWith("*")) { + if (urlPattern.endsWith("*")) { String prefix = urlPattern.substring(0, urlPattern.length() - 1); if (viewId.startsWith(prefix)) { if (longestPattern == null) { @@ -871,18 +875,18 @@ public List calculateResourceLibraryContracts(FacesContext context, Stri break; } } - + if (longestPattern != null) { result = contractMappings.get(longestPattern); } - + if (result == null) { result = contractMappings.get("*"); } - + return result; } - + // --------------------------------------- Methods from ViewHandlingStrategy @@ -898,7 +902,7 @@ public List calculateResourceLibraryContracts(FacesContext context, Stri @Override public boolean handlesViewId(String viewId) { if (viewId != null) { - + if (viewId.endsWith(RIConstants.FLOW_DEFINITION_ID_SUFFIX)) { return true; } @@ -936,7 +940,7 @@ private boolean isMatchedWithFaceletsSuffix(String viewId) { for ( String suffix :defaultsuffixes ) { if (viewId.endsWith(suffix)) { return true; - } + } } return false; } @@ -970,7 +974,7 @@ public void buildView(FacesContext ctx, UIViewRoot view) if (Util.isViewPopulated(ctx, view)) { Facelet f = faceletFactory.getFacelet(ctx, view.getViewId()); // Disable events from being intercepted by the StateContext by - // virute of re-applying the handlers. + // virute of re-applying the handlers. try { stateCtx.setTrackViewModifications(false); f.apply(ctx, view); @@ -1004,7 +1008,7 @@ public void buildView(FacesContext ctx, UIViewRoot view) ctx.getAttributes().put(IS_BUILDING_INITIAL_STATE, Boolean.TRUE); stateCtx.setTrackViewModifications(false); f.apply(ctx, view); - + if (f instanceof XMLFrontMatterSaver) { XMLFrontMatterSaver frontMatterSaver = (XMLFrontMatterSaver) f; String DOCTYPE = frontMatterSaver.getSavedDoctype(); @@ -1016,11 +1020,11 @@ public void buildView(FacesContext ctx, UIViewRoot view) Util.saveXMLDECLToFacesContextAttributes(XMLDECL); } } - + if (!stateCtx.isPartialStateSaving(ctx, view.getViewId())) { reapplyDynamicActions(ctx); } - + doPostBuildActions(ctx, view); } finally { ctx.getAttributes().remove(IS_BUILDING_INITIAL_STATE); @@ -1030,13 +1034,13 @@ public void buildView(FacesContext ctx, UIViewRoot view) UIViewRoot.class, view); markInitialState(ctx, view); - + Util.setViewPopulated(ctx, view); } @Override - public boolean viewExists(FacesContext context, + public boolean viewExists(FacesContext context, String viewId) { boolean result = false; if (handlesViewId(viewId)) { @@ -1046,11 +1050,11 @@ public boolean viewExists(FacesContext context, } result = null != faceletFactory.getResourceResolver().resolveUrl(viewId); } - + return result; } - @Override + @Override public String getId() { return FACELETS_VIEW_DECLARATION_LANGUAGE_ID; } @@ -1098,8 +1102,8 @@ public BeanInfo newInstance(Resource ccResource) throws InterruptedException { FacesContext context = FacesContext.getCurrentInstance(); ExternalContext extContext = context.getExternalContext(); Map appMap = extContext.getApplicationMap(); - Map> contractDataStructure = - (Map>) + Map> contractDataStructure = + (Map>) appMap.remove(RESOURCE_LIBRARY_CONTRACT_DATA_STRUCTURE_KEY); if (null != contractDataStructure && !contractDataStructure.isEmpty()) { contractMappings = new ConcurrentHashMap>(); @@ -1114,7 +1118,7 @@ public BeanInfo newInstance(Resource ccResource) throws InterruptedException { if (null != stateManager) { isTrinidadStateManager = stateManager.getClass().getName().contains("trinidad"); } - } + } } @@ -1148,7 +1152,7 @@ protected void initializeMappings() { extensionsArray = new String[extensionsList.size()]; extensionsList.toArray(extensionsArray); - + prefixesArray = new String[prefixesList.size()]; prefixesList.toArray(prefixesArray); } @@ -1377,7 +1381,7 @@ private String getCompositeComponentName(UIComponent compositeComponent) { } - + private void doPostBuildActions(FacesContext ctx, UIViewRoot root) { StateContext stateCtx = StateContext.getStateContext(ctx); // if (stateCtx.isPartialStateSaving(ctx, root.getViewId())) { @@ -1400,7 +1404,7 @@ private void markInitialState(FacesContext ctx, UIViewRoot root) } } } - + private void markInitialState(final UIComponent component) { component.markInitialState(); @@ -1410,7 +1414,7 @@ private void markInitialState(final UIComponent component) markInitialState(child); } } - } + } private void retargetHandler(FacesContext context, @@ -2066,48 +2070,6 @@ public void flush() { } // END NullWriter - /** - * Find the given component in the component tree. - * - * @param context the Faces context. - * @param clientId the client id of the component to find. - */ - private UIComponent locateComponentByClientId(final FacesContext context, final UIComponent parent, final String clientId) { - final List found = new ArrayList(); - UIComponent result = null; - - parent.invokeOnComponent(context, clientId, new ContextCallback() { - - public void invokeContextCallback(FacesContext context, UIComponent target) { - found.add(target); - } - }); - - /* - * Since we did not find it the cheaper way we need to assume there is a - * UINamingContainer that does not prepend its ID. So we are going to - * walk the tree to find it. - */ - if (found.isEmpty()) { - VisitContext visitContext = VisitContext.createVisitContext(context); - parent.visitTree(visitContext, new VisitCallback() { - - public VisitResult visit(VisitContext visitContext, UIComponent component) { - VisitResult result = VisitResult.ACCEPT; - if (component.getClientId(visitContext.getFacesContext()).equals(clientId)) { - found.add(component); - result = VisitResult.COMPLETE; - } - return result; - } - }); - } - if (!found.isEmpty()) { - result = found.get(0); - } - return result; - } - /** * Reapply the dynamic actions after Facelets reapply. * @@ -2121,13 +2083,32 @@ public VisitResult visit(VisitContext visitContext, UIComponent component) { private void reapplyDynamicActions(FacesContext context) { StateContext stateContext = StateContext.getStateContext(context); List actions = stateContext.getDynamicActions(); + + final Map compCache = new HashMap<>(); + try { + context.getAttributes().put(SKIP_ITERATION_HINT, true); + Set hints = EnumSet.of(VisitHint.SKIP_ITERATION); + VisitContext visitContext = VisitContext.createVisitContext(context, null, hints); + context.getViewRoot().visitTree(visitContext, new VisitCallback() { + + @Override + public VisitResult visit(VisitContext visitContext, UIComponent component) { + compCache.put(component.getClientId(visitContext.getFacesContext()), component); + + return VisitResult.ACCEPT; + } + }); + } finally { + context.getAttributes().remove(SKIP_ITERATION_HINT); + } + if (actions != null) { for (ComponentStruct action : actions) { if (ComponentStruct.REMOVE.equals(action.action)) { - reapplyDynamicRemove(context, action); + reapplyDynamicRemove(context, action, compCache); } if (ComponentStruct.ADD.equals(action.action)) { - reapplyDynamicAdd(context, action); + reapplyDynamicAdd(context, action, compCache); } } } @@ -2136,15 +2117,15 @@ private void reapplyDynamicActions(FacesContext context) { /** * Reapply the dynamic add after Facelets reapply. * - * @param context the Faces context. + * @param context the Faces context. * @param struct the component struct. */ - private void reapplyDynamicAdd(FacesContext context, ComponentStruct struct) { - UIComponent parent = locateComponentByClientId(context, context.getViewRoot(), struct.parentClientId); + private void reapplyDynamicAdd(FacesContext context, ComponentStruct struct, Map compCache) { + UIComponent parent = compCache.get(struct.parentClientId); if (parent != null) { - - UIComponent child = locateComponentByClientId(context, parent, struct.clientId); + + UIComponent child = compCache.get(struct.clientId); StateContext stateContext = StateContext.getStateContext(context); if (child == null) { @@ -2171,6 +2152,7 @@ private void reapplyDynamicAdd(FacesContext context, ComponentStruct struct) { child.getAttributes().put(DYNAMIC_COMPONENT, child.getParent().getChildren().indexOf(child)); } stateContext.getDynamicComponents().put(struct.clientId, child); + compCache.put(struct.clientId, child); } } } @@ -2181,13 +2163,14 @@ private void reapplyDynamicAdd(FacesContext context, ComponentStruct struct) { * @param context the Faces context. * @param struct the component struct. */ - private void reapplyDynamicRemove(FacesContext context, ComponentStruct struct) { - UIComponent child = locateComponentByClientId(context, context.getViewRoot(), struct.clientId); + private void reapplyDynamicRemove(FacesContext context, ComponentStruct struct, Map compCache) { + UIComponent child = compCache.get(struct.clientId); if (child != null) { StateContext stateContext = StateContext.getStateContext(context); stateContext.getDynamicComponents().put(struct.clientId, child); UIComponent parent = child.getParent(); parent.getChildren().remove(child); + compCache.remove(struct.clientId); } } }