/* * Copyright 2017 OmniFaces * * Licensed 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.omnifaces.component; import java.util.Iterator; import java.util.Map; import javax.faces.component.EditableValueHolder; import javax.faces.component.StateHelper; import javax.faces.component.UIComponent; import javax.faces.component.UIComponentBase; import javax.faces.context.FacesContext; /** * Helper class to save and restore state of an {@link EditableValueHolder}. * * @author Bauke Scholtz. */ public final class EditableValueHolderStateHelper { // UIData and UIRepeat have a similar nested class. Too bad that they aren't publicly reusable. // Variables ------------------------------------------------------------------------------------------------------ private Object submittedValue; private boolean valid = true; private Object localValue; private boolean localValueSet; // Actions -------------------------------------------------------------------------------------------------------- /** * Save the state of the given {@link EditableValueHolder}. * @param holder The {@link EditableValueHolder} to save the state for. */ public void save(EditableValueHolder holder) { submittedValue = holder.getSubmittedValue(); valid = holder.isValid(); localValue = holder.getLocalValue(); localValueSet = holder.isLocalValueSet(); } /** * Restore the state of the given {@link EditableValueHolder}. * @param holder The {@link EditableValueHolder} to restore the state for. */ public void restore(EditableValueHolder holder) { holder.setSubmittedValue(submittedValue); holder.setValid(valid); holder.setValue(localValue); holder.setLocalValueSet(localValueSet); } // Utility -------------------------------------------------------------------------------------------------------- /** * Save state of any {@link EditableValueHolder} children. * @param context The faces context to work with. * @param stateHelper The state helper of the parent component. * @param children An iterator with all child facets and components of the parent component as obtained by * {@link UIComponentBase#getFacetsAndChildren()}. */ public static void save(FacesContext context, StateHelper stateHelper, Iterator<UIComponent> children) { while (children.hasNext()) { UIComponent child = children.next(); if (child instanceof EditableValueHolder && !child.isTransient()) { get(stateHelper, child.getClientId(context)).save((EditableValueHolder) child); } if (child.getFacetCount() > 0 || child.getChildCount() > 0) { save(context, stateHelper, child.getFacetsAndChildren()); } } } /** * Restore state of any {@link EditableValueHolder} children. * @param context The faces context to work with. * @param stateHelper The state helper of the parent component. * @param children An iterator with all child facets and components of the parent component as obtained by * {@link UIComponentBase#getFacetsAndChildren()}. */ public static void restore(FacesContext context, StateHelper stateHelper, Iterator<UIComponent> children) { while (children.hasNext()) { UIComponent child = children.next(); child.setId(child.getId()); // This implicitly resets the cached client ID. See JSF spec 3.1.6. if (child instanceof EditableValueHolder && !child.isTransient()) { get(stateHelper, child.getClientId(context)).restore((EditableValueHolder) child); } if (child.getFacetCount() > 0 || child.getChildCount() > 0) { restore(context, stateHelper, child.getFacetsAndChildren()); } } } /** * Returns the state helper of the {@link EditableValueHolder} child associated with the given client ID. * @param stateHelper The state helper of the parent component. * @param clientId The client ID of the {@link EditableValueHolder} child to return the state helper for. * @return The state helper of the {@link EditableValueHolder} child associated with the given client ID. */ @SuppressWarnings("unchecked") public static EditableValueHolderStateHelper get(StateHelper stateHelper, String clientId) { Map<String, EditableValueHolderStateHelper> childState = (Map<String, EditableValueHolderStateHelper>) stateHelper.get(EditableValueHolderStateHelper.class); EditableValueHolderStateHelper state = null; if (childState != null) { state = childState.get(clientId); } if (state == null) { state = new EditableValueHolderStateHelper(); stateHelper.put(EditableValueHolderStateHelper.class, clientId, state); } return state; } }