Skip to content

Commit

Permalink
Merge pull request #5397 from eclipse-ee4j/mojarra_issue_5396_fix_par…
Browse files Browse the repository at this point in the history
…tial_process_of_reset_values

PartialViewContextImpl should use same VisitContext to reset values as the one used to process the execute and render
  • Loading branch information
BalusC authored Mar 2, 2024
2 parents 0c2052d + 82f8a9c commit 5d700b3
Showing 1 changed file with 40 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import static com.sun.faces.renderkit.RenderKitUtils.PredefinedPostbackParameter.PARTIAL_RENDER_PARAM;
import static com.sun.faces.renderkit.RenderKitUtils.PredefinedPostbackParameter.PARTIAL_RESET_VALUES_PARAM;
import static jakarta.faces.FactoryFinder.VISIT_CONTEXT_FACTORY;
import static jakarta.faces.component.visit.VisitHint.EXECUTE_LIFECYCLE;
import static jakarta.faces.component.visit.VisitHint.SKIP_UNRENDERED;
import static java.util.logging.Level.FINE;
import static java.util.logging.Level.WARNING;

Expand All @@ -31,6 +33,7 @@
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;

Expand All @@ -44,6 +47,7 @@
import jakarta.faces.FacesException;
import jakarta.faces.FactoryFinder;
import jakarta.faces.application.ResourceHandler;
import jakarta.faces.component.EditableValueHolder;
import jakarta.faces.component.NamingContainer;
import jakarta.faces.component.UIComponent;
import jakarta.faces.component.UIViewRoot;
Expand All @@ -68,6 +72,11 @@ public class PartialViewContextImpl extends PartialViewContext {
// Log instance for this class
private static Logger LOGGER = FacesLogger.CONTEXT.getLogger();

private static final Set<VisitHint> SKIP_UNRENDERED_HINT = EnumSet.of(SKIP_UNRENDERED);

private static final Set<VisitHint> SKIP_UNRENDERED_AND_EXECUTE_LIFECYCLE_HINTS = EnumSet.of(SKIP_UNRENDERED, EXECUTE_LIFECYCLE);


private boolean released;

// BE SURE TO ADD NEW IVARS TO THE RELEASE METHOD
Expand Down Expand Up @@ -284,7 +293,7 @@ public void processPartial(PhaseId phaseId) {
writer.startDocument();

if (isResetValues()) {
viewRoot.resetValues(ctx, myRenderIds);
resetValues(viewRoot, myRenderIds, ctx);
}

if (isRenderAll()) {
Expand Down Expand Up @@ -379,11 +388,8 @@ private void processComponents(UIComponent component, PhaseId phaseId, Collectio
// We use the tree visitor mechanism to locate the components to
// process. Create our (partial) VisitContext and the
// VisitCallback that will be invoked for each component that
// is visited. Note that we use the SKIP_UNRENDERED hint as we
// only want to visit the rendered subtree.
EnumSet<VisitHint> hints = EnumSet.of(VisitHint.SKIP_UNRENDERED, VisitHint.EXECUTE_LIFECYCLE);
VisitContextFactory visitContextFactory = (VisitContextFactory) FactoryFinder.getFactory(VISIT_CONTEXT_FACTORY);
VisitContext visitContext = visitContextFactory.getVisitContext(context, phaseClientIds, hints);
// is visited.
VisitContext visitContext = createPartialVisitContext(context, phaseClientIds, true);
PhaseAwareVisitCallback visitCallback = new PhaseAwareVisitCallback(ctx, phaseId);
component.visitTree(visitContext, visitCallback);

Expand All @@ -400,6 +406,34 @@ private void processComponents(UIComponent component, PhaseId phaseId, Collectio
}
}

private static VisitContext createPartialVisitContext(FacesContext context, Collection<String> clientIds, boolean executeLifecycle) {

// Note that we use the SKIP_UNRENDERED hint as
// we only want to visit the rendered subtree.
Set<VisitHint> hints = executeLifecycle ? SKIP_UNRENDERED_AND_EXECUTE_LIFECYCLE_HINTS : SKIP_UNRENDERED_HINT;
VisitContextFactory visitContextFactory = (VisitContextFactory) FactoryFinder.getFactory(VISIT_CONTEXT_FACTORY);
return visitContextFactory.getVisitContext(context, clientIds, hints);
}

private static void resetValues(UIComponent component, Collection<String> clientIds, FacesContext context) {

// NOTE: this is indeed a copy of the one in UIViewRoot#resetValues().
// The difference is that we want to be able to control the visit hints.
// This isn't possible via the UIViewRoot#resetValues() API in its current form.
component.visitTree(createPartialVisitContext(context, clientIds, false), new DoResetValues());
}

private static class DoResetValues implements VisitCallback {

@Override
public VisitResult visit(VisitContext context, UIComponent target) {
if (target instanceof EditableValueHolder) {
((EditableValueHolder) target).resetValue();
}
return VisitResult.ACCEPT;
}
}

/**
* Unwraps {@link PartialVisitContext} from a chain of {@link VisitContextWrapper}s.
*
Expand Down

0 comments on commit 5d700b3

Please sign in to comment.