javax.faces.component.UIInput Maven / Gradle / Ivy
Show all versions of myfaces-api Show documentation
/*
* Copyright 2004 The Apache Software Foundation.
*
* 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 javax.faces.component;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.faces.el.EvaluationException;
import javax.faces.el.MethodBinding;
import javax.faces.el.ValueBinding;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.FacesEvent;
import javax.faces.event.ValueChangeEvent;
import javax.faces.event.ValueChangeListener;
import javax.faces.render.Renderer;
import javax.faces.validator.Validator;
import java.util.ArrayList;
import java.util.List;
/**
* see Javadoc of JSF Specification
*
* @author Manfred Geiler (latest modification by $Author: schof $)
* @version $Revision: 393267 $ $Date: 2006-04-11 17:36:34 +0000 (Tue, 11 Apr 2006) $
*/
public class UIInput
extends UIOutput
implements EditableValueHolder
{
public static final String CONVERSION_MESSAGE_ID = "javax.faces.component.UIInput.CONVERSION";
public static final String REQUIRED_MESSAGE_ID = "javax.faces.component.UIInput.REQUIRED";
private static final String PARTIAL_ENABLED = "org.apache.myfaces.IsPartialPhaseExecutionEnabled";
private static final Validator[] EMPTY_VALIDATOR_ARRAY = new Validator[0];
private Object _submittedValue = null;
private boolean _localValueSet = false;
private boolean _valid = true;
private MethodBinding _validator = null;
private MethodBinding _valueChangeListener = null;
private List _validatorList = null;
// use javadoc inherited from EditableValueHolder
public Object getSubmittedValue()
{
return _submittedValue;
}
// use javadoc inherited from EditableValueHolder
public void setSubmittedValue(Object submittedValue)
{
_submittedValue = submittedValue;
}
/**
* Store the specified object as the "local value" of this component.
* The value-binding named "value" (if any) is ignored; the object is
* only stored locally on this component. During the "update model"
* phase, if there is a value-binding named "value" then this local
* value will be stored via that value-binding and the "local value"
* reset to null.
*/
public void setValue(Object value)
{
setLocalValueSet(true);
super.setValue(value);
}
// use javadoc inherited from EditableValueHolder
public boolean isLocalValueSet()
{
return _localValueSet;
}
// use javadoc inherited from EditableValueHolder
public void setLocalValueSet(boolean localValueSet)
{
_localValueSet = localValueSet;
}
// use javadoc inherited from EditableValueHolder
public boolean isValid()
{
return _valid;
}
// use javadoc inherited from EditableValueHolder
public void setValid(boolean valid)
{
_valid = valid;
}
// use javadoc inherited from EditableValueHolder
public MethodBinding getValidator()
{
return _validator;
}
// use javadoc inherited from EditableValueHolder
public void setValidator(MethodBinding validator)
{
_validator = validator;
}
// use javadoc inherited from EditableValueHolder
public MethodBinding getValueChangeListener()
{
return _valueChangeListener;
}
// use javadoc inherited from EditableValueHolder
public void setValueChangeListener(MethodBinding valueChangeListener)
{
_valueChangeListener = valueChangeListener;
}
/**
* Set the "submitted value" of this component from the relevant data
* in the current servet request object.
*
* If this component is not rendered, then do nothing; no output would
* have been sent to the client so no input is expected.
*
* Invoke the inherited functionality, which typically invokes the
* renderer associated with this component to extract and set this
* component's "submitted value".
*
* If this component is marked "immediate", then immediately apply
* validation to the submitted value found. On error, call context
* method "renderResponse" which will force processing to leap to
* the "render response" phase as soon as the "decode" step has
* completed for all other components.
*/
public void processDecodes(FacesContext context)
{
if (context == null) throw new NullPointerException("context");
if (!isRendered()) return;
super.processDecodes(context);
if (isImmediate())
{
try
{
validate(context);
}
catch (RuntimeException e)
{
context.renderResponse();
throw e;
}
if (!isValid())
{
context.renderResponse();
}
}
}
public void processValidators(FacesContext context)
{
if (context == null) throw new NullPointerException("context");
if (!isRendered()) return;
super.processValidators(context);
if (!isImmediate())
{
try
{
validate(context);
}
catch (RuntimeException e)
{
context.renderResponse();
throw e;
}
if (!isValid())
{
context.renderResponse();
}
}
}
public void processUpdates(FacesContext context)
{
if (context == null) throw new NullPointerException("context");
if (!isRendered()) return;
super.processUpdates(context);
try
{
updateModel(context);
}
catch (RuntimeException e)
{
context.renderResponse();
throw e;
}
if (!isValid())
{
context.renderResponse();
}
}
public void decode(FacesContext context)
{
//We (re)set to valid, so that component automatically gets (re)validated
setValid(true);
super.decode(context);
}
public void broadcast(FacesEvent event)
throws AbortProcessingException
{
if (!(event instanceof ValueChangeEvent))
{
throw new IllegalArgumentException("FacesEvent of class " + event.getClass().getName() + " not supported by UIInput");
}
// invoke standard listeners attached to this component first
super.broadcast(event);
// invoke the single listener defined directly on the component
MethodBinding valueChangeListenerBinding = getValueChangeListener();
if (valueChangeListenerBinding != null)
{
try
{
valueChangeListenerBinding.invoke(getFacesContext(),
new Object[]{event});
}
catch (EvaluationException e)
{
Throwable cause = e.getCause();
if (cause != null && cause instanceof AbortProcessingException)
{
throw (AbortProcessingException)cause;
}
else
{
throw e;
}
}
}
}
public void updateModel(FacesContext context)
{
if (!isValid()) return;
if (!isLocalValueSet()) return;
ValueBinding vb = getValueBinding("value");
if (vb == null) return;
try
{
vb.setValue(context, getLocalValue());
setValue(null);
setLocalValueSet(false);
}
catch (EvaluationException ee)
{
String exceptionMessage = ee.getMessage();
if (exceptionMessage == null)
{
_MessageUtils.addErrorMessage(context, this,
CONVERSION_MESSAGE_ID, new Object[] { getId() });
}
else
{
_MessageUtils.addErrorMessage(context, this, ee);
}
setValid(false);
}
catch (RuntimeException e)
{
//Object[] args = {getId()};
context.getExternalContext().log(e.getMessage(), e);
_MessageUtils.addErrorMessage(context, this,CONVERSION_MESSAGE_ID,new Object[]{getId()});
setValid(false);
}
}
protected void validateValue(FacesContext context,Object convertedValue)
{
boolean empty = convertedValue == null ||
(convertedValue instanceof String
&& ((String)convertedValue).length() == 0);
if (isRequired() && empty)
{
_MessageUtils.addErrorMessage(context, this, REQUIRED_MESSAGE_ID,new Object[]{getId()});
setValid(false);
return;
}
if (!empty)
{
_ComponentUtils.callValidators(context, this, convertedValue);
}
}
/**
* Determine whether the new value is valid, and queue a ValueChangeEvent
* if necessary.
*
* The "submitted value" is converted to the necessary type; conversion
* failure is reported as an error and validation processing terminates
* for this component. See documentation for method getConvertedValue
* for details on the conversion process.
*
* Any validators attached to this component are then run, passing
* the converted value.
*
* The old value of this component is then fetched (possibly involving
* the evaluation of a value-binding expression, ie invoking a method
* on a user object). The old value is compared to the new validated
* value, and if they are different then a ValueChangeEvent is queued
* for later processing.
*
* On successful completion of this method:
*
* - isValid() is true
*
- isLocalValueSet() is true
*
- submittedValue is reset to null
*
- a ValueChangeEvent is queued if the new value != old value
*
*/
public void validate(FacesContext context)
{
if (context == null) throw new NullPointerException("context");
Object submittedValue = getSubmittedValue();
if (submittedValue == null) return;
Object convertedValue = getConvertedValue(context, submittedValue);
if (!isValid()) return;
validateValue(context, convertedValue);
if (!isValid()) return;
Object previousValue = getValue();
setValue(convertedValue);
setSubmittedValue(null);
if (compareValues(previousValue, convertedValue))
{
queueEvent(new ValueChangeEvent(this, previousValue, convertedValue));
}
}
/**
* Convert the provided object to the desired value.
*
* If there is a renderer for this component, then call the renderer's
* getConvertedValue method. While this can of course be implemented in
* any way the renderer desires, it typically performs exactly the same
* processing that this method would have done anyway (ie that described
* below for the no-renderer case).
*
* Otherwise:
*
* - If the submittedValue is not a String then just return the
* submittedValue unconverted.
*
- If there is no "value" value-binding then just return the
* submittedValue unconverted.
*
- Use introspection to determine the type of the target
* property specified by the value-binding, and then use
* Application.createConverter to find a converter that can
* map from String to the required type. Apply the converter
* to the submittedValue and return the result.
*
*/
protected Object getConvertedValue(FacesContext context, Object submittedValue)
{
try
{
Renderer renderer = getRenderer(context);
if (renderer != null)
{
return renderer.getConvertedValue(context, this, submittedValue);
}
else if (submittedValue instanceof String)
{
Converter converter = _SharedRendererUtils.findUIOutputConverter(context, this);
if (converter != null)
{
return converter.getAsObject(context, this, (String)submittedValue);
}
}
}
catch (ConverterException e)
{
FacesMessage facesMessage = e.getFacesMessage();
if (facesMessage != null)
{
context.addMessage(getClientId(context), facesMessage);
}
else
{
_MessageUtils.addErrorMessage(context, this, CONVERSION_MESSAGE_ID,new Object[]{getId()});
}
setValid(false);
}
return submittedValue;
}
protected boolean compareValues(Object previous,
Object value)
{
return previous==null?(value!=null):(!previous.equals(value));
}
public void addValidator(Validator validator)
{
if (validator == null) throw new NullPointerException("validator");
if (_validatorList == null)
{
_validatorList = new ArrayList();
}
_validatorList.add(validator);
}
public Validator[] getValidators()
{
return _validatorList != null ?
(Validator[])_validatorList.toArray(new Validator[_validatorList.size()]) :
EMPTY_VALIDATOR_ARRAY;
}
public void removeValidator(Validator validator)
{
if (validator == null) throw new NullPointerException("validator");
if (_validatorList != null)
{
_validatorList.remove(validator);
}
}
public void addValueChangeListener(ValueChangeListener listener)
{
addFacesListener(listener);
}
public ValueChangeListener[] getValueChangeListeners()
{
return (ValueChangeListener[])getFacesListeners(ValueChangeListener.class);
}
public void removeValueChangeListener(ValueChangeListener listener)
{
removeFacesListener(listener);
}
public Object saveState(FacesContext context)
{
Object values[] = new Object[9];
values[0] = super.saveState(context);
values[1] = _immediate;
values[2] = Boolean.valueOf(_localValueSet);
values[3] = _required;
values[4] = _submittedValue;
values[5] = Boolean.valueOf(_valid);
values[6] = saveAttachedState(context, _validator);
values[7] = saveAttachedState(context, _valueChangeListener);
values[8] = saveAttachedState(context, _validatorList);
return ((Object)(values));
}
public void restoreState(FacesContext context, Object state)
{
Object values[] = (Object[])state;
super.restoreState(context, values[0]);
_immediate = (Boolean)values[1];
_localValueSet = ((Boolean)values[2]).booleanValue();
_required = (Boolean)values[3];
_submittedValue = (Object)values[4];
_valid = ((Boolean)values[5]).booleanValue();
_validator = (MethodBinding)restoreAttachedState(context, values[6]);
_valueChangeListener = (MethodBinding)restoreAttachedState(context, values[7]);
_validatorList = (List)restoreAttachedState(context, values[8]);
}
//------------------ GENERATED CODE BEGIN (do not modify!) --------------------
public static final String COMPONENT_TYPE = "javax.faces.Input";
public static final String COMPONENT_FAMILY = "javax.faces.Input";
private static final String DEFAULT_RENDERER_TYPE = "javax.faces.Text";
private static final boolean DEFAULT_IMMEDIATE = false;
private static final boolean DEFAULT_REQUIRED = false;
private Boolean _immediate = null;
private Boolean _required = null;
public UIInput()
{
setRendererType(DEFAULT_RENDERER_TYPE);
}
public String getFamily()
{
return COMPONENT_FAMILY;
}
public void setImmediate(boolean immediate)
{
_immediate = Boolean.valueOf(immediate);
}
public boolean isImmediate()
{
if (_immediate != null) return _immediate.booleanValue();
ValueBinding vb = getValueBinding("immediate");
Boolean v = vb != null ? (Boolean)vb.getValue(getFacesContext()) : null;
return v != null ? v.booleanValue() : DEFAULT_IMMEDIATE;
}
public void setRequired(boolean required)
{
_required = Boolean.valueOf(required);
}
public boolean isRequired()
{
if (_required != null) return _required.booleanValue();
ValueBinding vb = getValueBinding("required");
Boolean v = vb != null ? (Boolean)vb.getValue(getFacesContext()) : null;
return v != null ? v.booleanValue() : DEFAULT_REQUIRED;
}
//------------------ GENERATED CODE END ---------------------------------------
}