All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jakarta.faces.component.UIViewParameter Maven / Gradle / Ivy

Go to download

Jakarta Faces defines an MVC framework for building user interfaces for web applications, including UI components, state management, event handing, input validation, page navigation, and support for internationalization and accessibility.

There is a newer version: 4.1.2
Show newest version
/*
 * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0, which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

package jakarta.faces.component;

import java.io.IOException;
import java.util.Iterator;

import jakarta.el.ValueExpression;
import jakarta.faces.FactoryFinder;
import jakarta.faces.application.FacesMessage;
import jakarta.faces.context.FacesContext;
import jakarta.faces.convert.Converter;
import jakarta.faces.convert.ConverterException;
import jakarta.faces.render.RenderKit;
import jakarta.faces.render.RenderKitFactory;
import jakarta.faces.render.Renderer;
import jakarta.faces.validator.RequiredValidator;
import jakarta.faces.validator.Validator;

/**
 * 

* UIViewParameter represents a binding between a * request parameter and a model property or {@link UIViewRoot} property. This is a bi-directional binding. *

* *
* *

* The {@link jakarta.faces.view.ViewDeclarationLanguage} implementation must cause an instance of this component to * appear in the view for each occurrence of an <f:viewParam /> element placed inside of an * <f:metadata /> element. The user must place this facet within the UIViewRoot. *

* *

* Because this class extends UIInput any actions that one would normally take on a UIInput * instance are valid for instances of this class. Instances of this class participate in the regular Jakarta Server * Faces lifecycle, including on Ajax requests. *

* *
* * @since 2.0 */ public class UIViewParameter extends UIInput { // ------------------------------------------------------ Manifest Constants /** *

* The standard component type for this component. *

*/ public static final String COMPONENT_TYPE = "jakarta.faces.ViewParameter"; /** *

* The standard component family for this component. *

*/ public static final String COMPONENT_FAMILY = "jakarta.faces.ViewParameter"; enum PropertyKeys { name, submittedValue } // ------------------------------------------------------ Instance Variables private Renderer inputTextRenderer = null; private transient Boolean emptyStringIsNull; // ------------------------------------------------------------ Constructors /** *

* Create a new {@link UIViewParameter} instance with default property values. *

*/ public UIViewParameter() { super(); setRendererType(null); } // ------------------------------------------------------ Instance Variables /** *

* The raw value is the "implicit" binding for this view parameter. This property maintains the submitted value of the * view parameter for the duration of the request. If the view parameter does not explicitly specify a value expression, * then when the request ends, this value is stored with the state of this component to use as the submitted value on an * ensuing postback. *

*/ private String rawValue; // -------------------------------------------------------------- Properties @Override public String getFamily() { return COMPONENT_FAMILY; } /** *

* Return the request parameter name from which the value is retrieved. *

* * @return the name. * @since 2.0 */ public String getName() { return (String) getStateHelper().eval(PropertyKeys.name); } /** *

* Set the request parameter name from which the value is retrieved. *

* * @param name The new request parameter name. * @since 2.0 */ public void setName(String name) { getStateHelper().put(PropertyKeys.name, name); } /** *

* Return false. The immediate setting is not relevant for view parameters and must be assumed to be * false. *

* * @return true if immediate, false otherwise. * @since 2.0 */ @Override public boolean isImmediate() { return false; } /** *

* Assume that the submitted value is always a string, * but the return type from this method is Object.. *

* * @return the submitted value. * @since 2.0 */ @Override public Object getSubmittedValue() { return getStateHelper().get(PropertyKeys.submittedValue); } /** * PENDING (docs) Interesting that submitted value isn't saved by the parent * * @param submittedValue The new submitted value */ @Override public void setSubmittedValue(Object submittedValue) { getStateHelper().put(PropertyKeys.submittedValue, submittedValue); } // ----------------------------------------------------- UIComponent Methods // This is the "Apply Request Phase" step // QUESTION should we just override processDecodes() directly? // ANSWER: In this case, no. We don't want to take responsibility for // traversing any children we may have in the future. /** *

* Override behavior from superclass to pull a value from the incoming request parameter map under the name given by * {@link #getName} and store it with a call to {@link UIInput#setSubmittedValue}. *

* * @since 2.0 */ @Override public void decode(FacesContext context) { if (context == null) { throw new NullPointerException(); } // QUESTION can we move forward and support an array? no different than UISelectMany; perhaps need to know // if the value expression is single or multi-valued // ANSWER: I'd rather not right now. String paramValue = context.getExternalContext().getRequestParameterMap().get(getName()); // submitted value will stay as previous value (null on initial request) if a parameter is absent if (paramValue != null) { setSubmittedValue(paramValue); } rawValue = (String) getSubmittedValue(); setValid(true); } /** *

* Specialize superclass behavior to treat null differently. In * this class, a null value along with the "required" flag being set to true will cause a * validation failure. Otherwise, If the {@link UIInput#EMPTY_STRING_AS_NULL_PARAM_NAME} * context parameter is true and the value is {@code null}, call {@link UIInput#setSubmittedValue} passing the empty * string as the argument. This will cause the normal validation processing to happen, including bean validation. *

* * @param context the Faces context. * @since 2.0 */ @Override public void processValidators(FacesContext context) { if (context == null) { throw new NullPointerException(); } // Skip processing if our rendered flag is false if (!isRendered()) { return; } Object submittedValue = getSubmittedValue(); // we have to override since UIInput assumes that a null value means don't check if (submittedValue == null && myIsRequired()) { String requiredMessageStr = getRequiredMessage(); FacesMessage message; if (null != requiredMessageStr) { message = new FacesMessage(FacesMessage.SEVERITY_ERROR, requiredMessageStr, requiredMessageStr); } else { message = MessageFactory.getMessage(context, REQUIRED_MESSAGE_ID, MessageFactory.getLabel(context, this)); } context.addMessage(getClientId(context), message); setValid(false); context.validationFailed(); context.renderResponse(); } else { super.processValidators(context); } } private boolean myIsRequired() { return super.isRequired() || isRequiredViaNestedRequiredValidator(); } /* * JAVASERVERFACES-3058. Handle the nested requiredValidator case explicitly in the case of . * */ private boolean isRequiredViaNestedRequiredValidator() { boolean result = false; if (null == validators) { return result; } Iterator iter = validators.iterator(); while (iter.hasNext()) { if (iter.next() instanceof RequiredValidator) { // See JAVASERVERFACES-2526. Note that we can assume // that at this point the validator is not disabled, // so the mere existence of the validator implies it is // enabled. result = true; Object submittedValue = getSubmittedValue(); if (submittedValue == null) { // JAVASERVERFACES-3058 asserts that view parameters // should be treated differently than form parameters // if they are not submitted. I'm not sure if that's // correct, but let's put this in and see how // the community responds. setSubmittedValue(""); } break; } } return result; } /** *

* Call through to superclass {@link UIInput#updateModel} then take the additional action of pushing the value into * request scope if and only if the value is not a value expression, is valid, and the local value was set on this * lifecycle execution. *

* * @since 2.0 */ @Override public void updateModel(FacesContext context) { super.updateModel(context); if (!hasValueExpression() && isValid() && isLocalValueSet()) { // QUESTION should this be done even when a value expression is present? // ANSWER: I don't see why not. context.getExternalContext().getRequestMap().put(getName(), getLocalValue()); } } // This is called during the real "Render Response" phase /** *

* Called specially by {@link UIViewRoot#encodeEnd}, this method simply sets the submitted value to be the return from * {@link #getStringValue}. *

* * @throws IOException when an I/O error occurs. * @since 2.0 */ @Override public void encodeAll(FacesContext context) throws IOException { if (context == null) { throw new NullPointerException(); } // if there is a value expression, update view parameter w/ latest value after render // QUESTION is it okay that a null string value may be suppressing the view parameter value? // ANSWER: I'm not sure. setSubmittedValue(getStringValue(context)); } /** *

* If the value of this parameter comes from a ValueExpression return the value of the expression, * otherwise, return the local value. *

* * @param context the Faces context. * @return the string value. * @since 2.0 */ public String getStringValue(FacesContext context) { String result = null; if (hasValueExpression()) { result = getStringValueFromModel(context); } else { result = null != rawValue ? rawValue : (String) getValue(); } return result; } /** *

* Manually perform standard conversion steps to get a string value from the value expression. *

* * @param context the Faces context. * @return the string value from the model. * @since 2.0 */ public String getStringValueFromModel(FacesContext context) throws ConverterException { ValueExpression ve = getValueExpression("value"); if (ve == null) { return null; } Object currentValue = ve.getValue(context.getELContext()); // If there is a converter attribute, use it to to ask application // instance for a converter with this identifer. Converter c = getConverter(); if (c == null) { // if value is null and no converter attribute is specified, then // return null (null has meaning for a view parameters; it means remove it). if (currentValue == null) { return null; } // Do not look for "by-type" converters for Strings if (currentValue instanceof String) { return (String) currentValue; } // if converter attribute set, try to acquire a converter // using its class type. Class converterType = currentValue.getClass(); c = context.getApplication().createConverter(converterType); // if there is no default converter available for this identifier, // assume the model type to be String. if (c == null) { return currentValue.toString(); } } return c.getAsString(context, this, currentValue); } /** *

* Because this class has no {@link Renderer}, leverage the one from the standard HTML_BASIC {@link RenderKit} with * component-family: jakarta.faces.Input and renderer-type: jakarta.faces.Text and call its * {@link Renderer#getConvertedValue} method. *

* * @param submittedValue the submitted value. * @return the converted value. * @since 2.0 */ @Override protected Object getConvertedValue(FacesContext context, Object submittedValue) throws ConverterException { return getInputTextRenderer(context).getConvertedValue(context, this, submittedValue); } private Renderer getInputTextRenderer(FacesContext context) { if (null == inputTextRenderer) { RenderKitFactory rkf = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY); RenderKit standard = rkf.getRenderKit(context, RenderKitFactory.HTML_BASIC_RENDER_KIT); inputTextRenderer = standard.getRenderer("jakarta.faces.Input", "jakarta.faces.Text"); } assert null != inputTextRenderer; return inputTextRenderer; } // ----------------------------------------------------- Helper Methods private boolean hasValueExpression() { return null != getValueExpression("value"); } /** *

* Inner class to encapsulate a UIViewParameter instance so that it may be safely referenced regardless of * whether or not the current view is the same as the view in which this UIViewParameter resides. *

* * @since 2.0 */ public static class Reference { private final StateHolderSaver saver; private final int indexInParent; private final String viewIdAtTimeOfConstruction; /** *

* Construct a reference to a UIViewParameter. This constructor cause the {@link StateHolder#saveState} * method to be called on argument UIViewParameter. *

* * @param context the FacesContextfor this request * @param param the UIViewParameter. * @param indexInParent the index of the UIViewParameter in its parent UIPanel. * @param viewIdAtTimeOfConstruction the viewId of the view in which the UIViewParameter is included. This * may not be the same as the viewId from the context argument. * * @since 2.0 */ public Reference(FacesContext context, UIViewParameter param, int indexInParent, String viewIdAtTimeOfConstruction) { saver = new StateHolderSaver(context, param); this.indexInParent = indexInParent; this.viewIdAtTimeOfConstruction = viewIdAtTimeOfConstruction; } /** *

* Return the UIViewParameter to which this instance refers. If the current viewId is the same as the * viewId passed to our constructor, use the index passed to the constructor to find the actual * UIViewParameter instance and return it. Otherwise, call {@link StateHolder#restoreState} on the saved * state and return the result. *

* * @param context the FacesContextfor this request * @return the UIViewParameter. * @since 2.0 */ public UIViewParameter getUIViewParameter(FacesContext context) { UIViewParameter result = null; UIViewRoot root = context.getViewRoot(); // If the view root is the same as when we were constructed... if (viewIdAtTimeOfConstruction.equals(root.getViewId())) { // get the actual view parameter from the tree... UIComponent metadataFacet = root.getFacet(UIViewRoot.METADATA_FACET_NAME); result = (UIViewParameter) metadataFacet.getChildren().get(indexInParent); } else { // otherwise, use the saved one result = (UIViewParameter) saver.restore(context); } return result; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy