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

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

The newest version!
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

package javax.faces.component;

import java.io.IOException;
import java.util.Iterator;
import javax.el.ValueExpression;
import javax.faces.FactoryFinder;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.faces.render.RenderKit;
import javax.faces.render.RenderKitFactory;
import javax.faces.render.Renderer;
import javax.faces.validator.RequiredValidator;
import javax.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 javax.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 JSF 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 = "javax.faces.ViewParameter"; /** *

The standard component family for this component.

*/ public static final String COMPONENT_FAMILY = "javax.faces.ViewParameter"; enum PropertyKeys { name, submittedValue } // ------------------------------------------------------ Instance Variables private Renderer inputTextRenderer = null; // ------------------------------------------------------------ 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.

* @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.

* @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..

* @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.

* @param 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; } // we have to override since UIInput assumes that a null value means don't check if (getSubmittedValue() == 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. this.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}.

* @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.

* * @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.

* * @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: javax.faces.Input * and renderer-type: javax.faces.Text and call its * {@link Renderer#getConvertedValue} method.

* * @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("javax.faces.Input", "javax.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 StateHolderSaver saver; private int indexInParent; private 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 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) { this.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 * * @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 (this.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) this.saver.restore(context); } return result; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy