Save This Page
Home » mojarra-1.2_09-b02-FCS-source » javax.faces.component » [javadoc | source]
    1   /*
    2    * $Id: UIInput.java,v 1.93.4.2 2007/11/05 21:48:57 rlubke Exp $
    3    */
    4   
    5   /*
    6    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    7    * 
    8    * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
    9    * 
   10    * The contents of this file are subject to the terms of either the GNU
   11    * General Public License Version 2 only ("GPL") or the Common Development
   12    * and Distribution License("CDDL") (collectively, the "License").  You
   13    * may not use this file except in compliance with the License. You can obtain
   14    * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
   15    * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
   16    * language governing permissions and limitations under the License.
   17    * 
   18    * When distributing the software, include this License Header Notice in each
   19    * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
   20    * Sun designates this particular file as subject to the "Classpath" exception
   21    * as provided by Sun in the GPL Version 2 section of the License file that
   22    * accompanied this code.  If applicable, add the following below the License
   23    * Header, with the fields enclosed by brackets [] replaced by your own
   24    * identifying information: "Portions Copyrighted [year]
   25    * [name of copyright owner]"
   26    * 
   27    * Contributor(s):
   28    * 
   29    * If you wish your version of this file to be governed by only the CDDL or
   30    * only the GPL Version 2, indicate your decision by adding "[Contributor]
   31    * elects to include this software in this distribution under the [CDDL or GPL
   32    * Version 2] license."  If you don't indicate a single choice of license, a
   33    * recipient has the option to distribute your version of this file under
   34    * either the CDDL, the GPL Version 2 or to extend the choice of license to
   35    * its licensees as provided above.  However, if you add GPL Version 2 code
   36    * and therefore, elected the GPL Version 2 license, then the option applies
   37    * only if the new code is made subject to such option by the copyright
   38    * holder.
   39    */
   40   
   41   package javax.faces.component;
   42   
   43   import java.util.ArrayList;
   44   import java.util.Iterator;
   45   import java.util.List;
   46   import java.util.logging.Level;
   47   import java.util.logging.Logger;
   48   
   49   import javax.el.ELException;
   50   import javax.el.ValueExpression;
   51   import javax.faces.FacesException;
   52   import javax.faces.application.Application;
   53   import javax.faces.application.FacesMessage;
   54   import javax.faces.context.FacesContext;
   55   import javax.faces.convert.Converter;
   56   import javax.faces.convert.ConverterException;
   57   import javax.faces.el.MethodBinding;
   58   import javax.faces.event.ValueChangeEvent;
   59   import javax.faces.event.ValueChangeListener;
   60   import javax.faces.render.Renderer;
   61   import javax.faces.validator.Validator;
   62   import javax.faces.validator.ValidatorException;
   63   
   64   /**
   65    * <p><strong>UIInput</strong> is a {@link UIComponent} that represents
   66    * a component that both displays output to the user (like
   67    * {@link UIOutput} components do) and processes request parameters on the
   68    * subsequent request that need to be decoded.  There are no restrictions
   69    * on the data type of the local value, or the object referenced by the
   70    * value binding expression (if any); however, individual
   71    * {@link javax.faces.render.Renderer}s will generally impose restrictions
   72    * on the type of data they know how to display.</p>
   73    * <p/>
   74    * <p>During the <em>Apply Request Values</em> phase of the request
   75    * processing lifecycle, the decoded value of this component, usually
   76    * but not necessarily a String, must be stored - but not yet converted -
   77    * using <code>setSubmittedValue()</code>.  If the component wishes
   78    * to indicate that no particular value was submitted, it can either
   79    * do nothing, or set the submitted value to <code>null</code>.</p>
   80    * <p></p>
   81    * <p>By default, during the <em>Process Validators</em> phase of the
   82    * request processing lifecycle, the submitted value will be converted
   83    * to a typesafe object, and, if validation succeeds, stored as a
   84    * local value using <code>setValue()</code>.  However, if the
   85    * <code>immediate</code> property is set to <code>true</code>, this
   86    * processing will occur instead at the end of the
   87    * <em>Apply Request Values</em> phase.
   88    * </p>
   89    * <p>During the <em>Render Response</em> phase of the request processing
   90    * lifecycle, conversion for output occurs as for {@link UIOutput}.</p>
   91    * <p/>
   92    * <p>When the <code>validate()</code> method of this {@link UIInput}
   93    * detects that a value change has actually occurred, and that all validations
   94    * have been successfully passed, it will queue a
   95    * {@link ValueChangeEvent}.  Later on, the <code>broadcast()</code>
   96    * method will ensure that this event is broadcast to all interested
   97    * listeners.  This event will be delivered by default in the
   98    * <em>Process Validators</em> phase, but can be delivered instead
   99    * during <em>Apply Request Values</em> if the <code>immediate</code>
  100    * property is set to <code>true</code>.</p>
  101    * <p/>
  102    * <p>By default, the <code>rendererType</code> property must be set to
  103    * "<code>Text</code>".  This value can be changed by calling the
  104    * <code>setRendererType()</code> method.</p>
  105    */
  106   
  107   public class UIInput extends UIOutput implements EditableValueHolder {
  108   
  109       // ------------------------------------------------------ Manifest Constants
  110   
  111   
  112       /**
  113        * <p>The standard component type for this component.</p>
  114        */
  115       public static final String COMPONENT_TYPE = "javax.faces.Input";
  116   
  117   
  118       /**
  119        * <p>The standard component family for this component.</p>
  120        */
  121       public static final String COMPONENT_FAMILY = "javax.faces.Input";
  122   
  123   
  124       /**
  125        * <p>The message identifier of the
  126        * {@link javax.faces.application.FacesMessage} to be created if
  127        * a conversion error occurs, and neither the page author nor
  128        * the {@link ConverterException} provides a message.</p>
  129        */
  130       public static final String CONVERSION_MESSAGE_ID =
  131            "javax.faces.component.UIInput.CONVERSION";
  132   
  133   
  134       /**
  135        * <p>The message identifier of the
  136        * {@link javax.faces.application.FacesMessage} to be created if
  137        * a required check fails.</p>
  138        */
  139       public static final String REQUIRED_MESSAGE_ID =
  140            "javax.faces.component.UIInput.REQUIRED";
  141   
  142       /**
  143        * <p>The message identifier of the
  144        * {@link javax.faces.application.FacesMessage} to be created if
  145        * a model update error occurs, and the thrown exception has
  146        * no message.</p>
  147        */
  148       public static final String UPDATE_MESSAGE_ID =
  149            "javax.faces.component.UIInput.UPDATE";
  150       private static final Validator[] EMPTY_VALIDATOR = new Validator[0];
  151   
  152       /**
  153        * The <code>Logger</code> for this class.
  154        */
  155       private static final Logger LOGGER =
  156             Logger.getLogger("javax.faces.component", "javax.faces.LogStrings");
  157   
  158       // ------------------------------------------------------------ Constructors
  159   
  160   
  161       /**
  162        * <p>Create a new {@link UIInput} instance with default property
  163        * values.</p>
  164        */
  165       public UIInput() {
  166   
  167           super();
  168           setRendererType("javax.faces.Text");
  169   
  170       }
  171   
  172       // -------------------------------------------------------------- Properties
  173   
  174   
  175       public String getFamily() {
  176   
  177           return (COMPONENT_FAMILY);
  178   
  179       }
  180   
  181   
  182       /**
  183        * <p>The submittedValue value of this {@link UIInput} component.</p>
  184        */
  185       private Object submittedValue = null;
  186   
  187   
  188       /**
  189        * <p>Return the submittedValue value of this {@link UIInput} component.
  190        * This method should only be used by the <code>decode()</code> and
  191        * <code>validate()</code> method of this component, or
  192        * its corresponding {@link Renderer}.</p>
  193        */
  194       public Object getSubmittedValue() {
  195   
  196           return (this.submittedValue);
  197   
  198       }
  199   
  200   
  201       /**
  202        * <p>Set the submittedValue value of this {@link UIInput} component.
  203        * This method should only be used by the <code>decode()</code> and
  204        * <code>validate()</code> method of this component, or
  205        * its corresponding {@link Renderer}.</p>
  206        *
  207        * @param submittedValue The new submitted value
  208        */
  209       public void setSubmittedValue(Object submittedValue) {
  210   
  211           this.submittedValue = submittedValue;
  212   
  213       }
  214   
  215       public void setValue(Object value) {
  216           super.setValue(value);
  217           // Mark the local value as set.
  218           setLocalValueSet(true);
  219       }
  220   
  221       /**
  222        * <p>Convenience method to reset this component's value to the
  223        * un-initialized state.  This method does the following:</p>
  224        * <p/>
  225        * <p>Call {@link #setValue} passing <code>null</code>.</p>
  226        * <p/>
  227        * <p>Call {@link #setSubmittedValue} passing <code>null</code>.</p>
  228        * <p/>
  229        * <p>Call {@link #setLocalValueSet} passing <code>false</code>.</p>
  230        * <p/>
  231        * <p>Call {@link #setValid} passing <code>true</code>.</p>
  232        * <p/>
  233        * <p>Upon return from this call if the instance had a
  234        * <code>ValueBinding</code> associated with it for the "value"
  235        * property, this binding is evaluated when {@link
  236        * UIOutput#getValue} is called.  Otherwise, <code>null</code> is
  237        * returned from <code>getValue()</code>.</p>
  238        */
  239   
  240       public void resetValue() {
  241           this.setValue(null);
  242           this.setSubmittedValue(null);
  243           this.setLocalValueSet(false);
  244           this.setValid(true);
  245       }
  246   
  247       /**
  248        * <p>The "localValueSet" state for this component.
  249        */
  250       private boolean localValueSet;
  251   
  252       /**
  253        * Return the "local value set" state for this component.
  254        * Calls to <code>setValue()</code> automatically reset
  255        * this property to <code>true</code>.
  256        */
  257       public boolean isLocalValueSet() {
  258           return localValueSet;
  259       }
  260   
  261       /**
  262        * Sets the "local value set" state for this component.
  263        */
  264       public void setLocalValueSet(boolean localValueSet) {
  265           this.localValueSet = localValueSet;
  266       }
  267   
  268   
  269       /**
  270        * <p>The "required field" state for this component.</p>
  271        */
  272       private Boolean required;
  273   
  274       /**
  275        * <p>Return the "required field" state for this component.</p>
  276        */
  277       public boolean isRequired() {
  278   
  279           if (required != null) {
  280               return (this.required);
  281           }
  282           ValueExpression ve = getValueExpression("required");
  283           if (ve != null) {
  284               try {
  285                   return (Boolean.TRUE.equals(ve.getValue(getFacesContext().getELContext())));
  286               }
  287               catch (ELException e) {
  288                   throw new FacesException(e);
  289               }
  290           } else {
  291               return (false);
  292           }
  293   
  294       }
  295   
  296       private String requiredMessage;
  297   
  298       /**
  299        * <p>If there has been a call to {@link #setRequiredMessage} on this
  300        * instance, return the message.  Otherwise, call {@link #getValueExpression}
  301        * passing the key "requiredMessage", get the result of the expression, and return it.
  302        * Any {@link ELException}s thrown during the call to <code>getValue()</code>
  303        * must be wrapped in a {@link FacesException} and rethrown.
  304        */
  305   
  306       public String getRequiredMessage() {
  307           if (requiredMessage != null) {
  308               return requiredMessage;
  309           }
  310   
  311           ValueExpression ve = getValueExpression("requiredMessage");
  312           if (ve != null) {
  313               try {
  314                   return ((String) ve.getValue(getFacesContext().getELContext()));
  315               }
  316               catch (ELException e) {
  317                   throw new FacesException(e);
  318               }
  319           } else {
  320               return (null);
  321           }
  322   
  323       }
  324   
  325       /**
  326        * <p>Override any {@link ValueExpression} set for the "requiredMessage"
  327        * with the literal argument provided to this method.  Subsequent calls
  328        * to {@link #getRequiredMessage} will return this value;</p>
  329        *
  330        * @param message the literal message value to be displayed in the event
  331        *                the user hasn't supplied a value and one is required.
  332        */
  333   
  334       public void setRequiredMessage(String message) {
  335           requiredMessage = message;
  336       }
  337   
  338       private String converterMessage;
  339   
  340       /**
  341        * <p>If there has been a call to {@link #setConverterMessage} on this
  342        * instance, return the message.  Otherwise, call {@link #getValueExpression}
  343        * passing the key "converterMessage", get the result of the expression, and return it.
  344        * Any {@link ELException}s thrown during the call to <code>getValue()</code>
  345        * must be wrapped in a {@link FacesException} and rethrown.
  346        */
  347   
  348       public String getConverterMessage() {
  349           if (converterMessage != null) {
  350               return converterMessage;
  351           }
  352   
  353           ValueExpression ve = getValueExpression("converterMessage");
  354           if (ve != null) {
  355               try {
  356                   return ((String) ve.getValue(getFacesContext().getELContext()));
  357               }
  358               catch (ELException e) {
  359                   throw new FacesException(e);
  360               }
  361           } else {
  362               return (null);
  363           }
  364   
  365       }
  366   
  367       /**
  368        * <p>Override any {@link ValueExpression} set for the "converterMessage"
  369        * with the literal argument provided to this method.  Subsequent calls
  370        * to {@link #getConverterMessage} will return this value;</p>
  371        *
  372        * @param message the literal message value to be displayed in the event
  373        *                conversion fails.
  374        */
  375   
  376       public void setConverterMessage(String message) {
  377           converterMessage = message;
  378       }
  379   
  380       private String validatorMessage;
  381   
  382       /**
  383        * <p>If there has been a call to {@link #setValidatorMessage} on this
  384        * instance, return the message.  Otherwise, call {@link #getValueExpression}
  385        * passing the key "validatorMessage", get the result of the expression, and return it.
  386        * Any {@link ELException}s thrown during the call to <code>getValue()</code>
  387        * must be wrapped in a {@link FacesException} and rethrown.
  388        */
  389   
  390       public String getValidatorMessage() {
  391           if (validatorMessage != null) {
  392               return validatorMessage;
  393           }
  394   
  395           ValueExpression ve = getValueExpression("validatorMessage");
  396           if (ve != null) {
  397               try {
  398                   return ((String) ve.getValue(getFacesContext().getELContext()));
  399               }
  400               catch (ELException e) {
  401                   throw new FacesException(e);
  402               }
  403           } else {
  404               return (null);
  405           }
  406   
  407       }
  408   
  409       /**
  410        * <p>Override any {@link ValueExpression} set for the "validatorMessage"
  411        * with the literal argument provided to this method.  Subsequent calls
  412        * to {@link #getValidatorMessage} will return this value;</p>
  413        *
  414        * @param message the literal message value to be displayed in the event
  415        *                validation fails.
  416        */
  417   
  418       public void setValidatorMessage(String message) {
  419           validatorMessage = message;
  420       }
  421   
  422       private boolean valid = true;
  423   
  424   
  425       public boolean isValid() {
  426   
  427           return (this.valid);
  428   
  429       }
  430   
  431   
  432       public void setValid(boolean valid) {
  433   
  434           this.valid = valid;
  435   
  436       }
  437   
  438   
  439       /**
  440        * <p>Set the "required field" state for this component.</p>
  441        *
  442        * @param required The new "required field" state
  443        */
  444       public void setRequired(boolean required) {
  445   
  446           this.required = required;
  447   
  448       }
  449   
  450       /**
  451        * <p>The immediate flag.</p>
  452        */
  453       private Boolean immediate;
  454   
  455   
  456       public boolean isImmediate() {
  457   
  458           if (this.immediate != null) {
  459               return (this.immediate);
  460           }
  461           ValueExpression ve = getValueExpression("immediate");
  462           if (ve != null) {
  463               try {
  464                   return (Boolean.TRUE.equals(ve.getValue(getFacesContext().getELContext())));
  465               }
  466               catch (ELException e) {
  467                   throw new FacesException(e);
  468               }
  469   
  470           } else {
  471               return (false);
  472           }
  473   
  474       }
  475   
  476   
  477       public void setImmediate(boolean immediate) {
  478   
  479           this.immediate = immediate;
  480   
  481       }
  482   
  483   
  484       /**
  485        * <p>Return a <code>MethodBinding</code> pointing at a
  486        * method that will be called during <em>Process Validations</em>
  487        * phase of the request processing lifecycle, to validate the current
  488        * value of this component.</p>
  489        *
  490        * @deprecated {@link #getValidators} should be used instead.
  491        */
  492       public MethodBinding getValidator() {
  493           MethodBinding result = null;
  494   
  495           Validator[] curValidators = getValidators();
  496           // go through our lisetners list and find the one and only
  497           // MethodBindingValidator instance, if present.
  498           if (null != curValidators) {
  499               for (int i = 0; i < curValidators.length; i++) {
  500                   // We are guaranteed to have at most one instance of
  501                   // MethodBindingValidator in the curValidators list.
  502                   if (MethodBindingValidator.class ==
  503                        curValidators[i].getClass()) {
  504                       result = ((MethodBindingValidator) curValidators[i]).
  505                            getWrapped();
  506                       break;
  507                   }
  508               }
  509           }
  510           return result;
  511   
  512       }
  513   
  514   
  515       /**
  516        * <p>Set a <code>MethodBinding</code> pointing at a
  517        * method that will be called during <em>Process Validations</em>
  518        * phase of the request processing lifecycle, to validate the current
  519        * value of this component.</p>
  520        * <p/>
  521        * <p>Any method referenced by such an expression must be public, with
  522        * a return type of <code>void</code>, and accept parameters of type
  523        * {@link FacesContext}, {@link UIComponent}, and <code>Object</code>.</p>
  524        *
  525        * @param validatorBinding The new <code>MethodBinding</code> instance
  526        * @deprecated Use {@link #addValidator} instead, obtaining the
  527        *             argument {@link Validator} by creating an instance of {@link
  528        *             javax.faces.validator.MethodExpressionValidator}.
  529        */
  530       public void setValidator(MethodBinding validatorBinding) {
  531           Validator[] curValidators = getValidators();
  532           // see if we need to null-out, or replace an existing validator
  533           if (null != curValidators) {
  534               for (int i = 0; i < curValidators.length; i++) {
  535                   // if we want to remove the validatorBinding
  536                   if (null == validatorBinding) {
  537                       // We are guaranteed to have at most one instance of
  538                       // MethodBindingValidator in the curValidators
  539                       // list.
  540                       if (MethodBindingValidator.class ==
  541                            curValidators[i].getClass()) {
  542                           removeValidator(curValidators[i]);
  543                           return;
  544                       }
  545                   }
  546                   // if we want to replace the validatorBinding
  547                   else //noinspection ObjectEquality
  548                       if (validatorBinding == curValidators[i]) {
  549                       removeValidator(curValidators[i]);
  550                       break;
  551                   }
  552               }
  553           }
  554           addValidator(new MethodBindingValidator(validatorBinding));
  555   
  556       }
  557   
  558       public MethodBinding getValueChangeListener() {
  559           MethodBinding result = null;
  560   
  561           ValueChangeListener[] curListeners = getValueChangeListeners();
  562           // go through our lisetners list and find the one and only
  563           // MethodBindingValueChangeListener instance, if present.
  564           if (null != curListeners) {
  565               for (int i = 0; i < curListeners.length; i++) {
  566                   // We are guaranteed to have at most one instance of
  567                   // MethodBindingValueChangeListener in the curListeners list.
  568                   if (MethodBindingValueChangeListener.class ==
  569                        curListeners[i].getClass()) {
  570                       result = ((MethodBindingValueChangeListener) curListeners[i]).
  571                            getWrapped();
  572                       break;
  573                   }
  574               }
  575           }
  576           return result;
  577       }
  578   
  579   
  580       /**
  581        * {@inheritDoc}
  582        *
  583        * @deprecated Use {@link #addValueChangeListener} instead, obtaining the
  584        *             argument {@link ValueChangeListener} by creating an instance of {@link
  585        *             javax.faces.event.MethodExpressionValueChangeListener}.
  586        */
  587       public void setValueChangeListener(MethodBinding valueChangeListener) {
  588   
  589           ValueChangeListener[] curListeners = getValueChangeListeners();
  590           // see if we need to null-out, or replace an existing listener
  591           if (null != curListeners) {
  592               for (int i = 0; i < curListeners.length; i++) {
  593                   // if we want to remove the valueChangeListener
  594                   if (null == valueChangeListener) {
  595                       // We are guaranteed to have at most one instance of
  596                       // MethodBindingValueChangeListener in the curListeners
  597                       // list.
  598                       if (MethodBindingValueChangeListener.class ==
  599                            curListeners[i].getClass()) {
  600                           removeFacesListener(curListeners[i]);
  601                           return;
  602                       }
  603                   }
  604                   // if we want to replace the valueChangeListener
  605                   else //noinspection ObjectEquality
  606                       if (valueChangeListener == curListeners[i]) {
  607                       removeFacesListener(curListeners[i]);
  608                       break;
  609                   }
  610               }
  611           }
  612           addValueChangeListener(new MethodBindingValueChangeListener(valueChangeListener));
  613       }
  614   
  615       // ----------------------------------------------------- UIComponent Methods
  616   
  617       /**
  618        * <p>Specialized decode behavior on top of that provided by the
  619        * superclass.  In addition to the standard
  620        * <code>processDecodes</code> behavior inherited from {@link
  621        * UIComponentBase}, calls <code>validate()</code> if the the
  622        * <code>immediate</code> property is true; if the component is
  623        * invalid afterwards or a <code>RuntimeException</code> is thrown,
  624        * calls {@link FacesContext#renderResponse}.  </p>
  625        *
  626        * @throws NullPointerException {@inheritDoc}
  627        */
  628       public void processDecodes(FacesContext context) {
  629   
  630           if (context == null) {
  631               throw new NullPointerException();
  632           }
  633   
  634           // Skip processing if our rendered flag is false
  635           if (!isRendered()) {
  636               return;
  637           }
  638   
  639           super.processDecodes(context);
  640   
  641           if (isImmediate()) {
  642               executeValidate(context);
  643           }
  644       }
  645   
  646       /**
  647        * <p>In addition to the standard <code>processValidators</code> behavior
  648        * inherited from {@link UIComponentBase}, calls <code>validate()</code>
  649        * if the <code>immediate</code> property is false (which is the
  650        * default);  if the component is invalid afterwards, calls
  651        * {@link FacesContext#renderResponse}.
  652        * If a <code>RuntimeException</code> is thrown during
  653        * validation processing, calls {@link FacesContext#renderResponse}
  654        * and re-throw the exception.
  655        * </p>
  656        *
  657        * @throws NullPointerException {@inheritDoc}
  658        */
  659       public void processValidators(FacesContext context) {
  660   
  661           if (context == null) {
  662               throw new NullPointerException();
  663           }
  664   
  665           // Skip processing if our rendered flag is false
  666           if (!isRendered()) {
  667               return;
  668           }
  669   
  670           super.processValidators(context);
  671           if (!isImmediate()) {
  672               executeValidate(context);
  673           }
  674       }
  675   
  676       /**
  677        * <p>In addition to the standard <code>processUpdates</code> behavior
  678        * inherited from {@link UIComponentBase}, calls
  679        * <code>updateModel()</code>.
  680        * If the component is invalid afterwards, calls
  681        * {@link FacesContext#renderResponse}.
  682        * If a <code>RuntimeException</code> is thrown during
  683        * update processing, calls {@link FacesContext#renderResponse}
  684        * and re-throw the exception.
  685        * </p>
  686        *
  687        * @throws NullPointerException {@inheritDoc}
  688        */
  689       public void processUpdates(FacesContext context) {
  690   
  691           if (context == null) {
  692               throw new NullPointerException();
  693           }
  694   
  695           // Skip processing if our rendered flag is false
  696           if (!isRendered()) {
  697               return;
  698           }
  699   
  700           super.processUpdates(context);
  701   
  702           try {
  703               updateModel(context);
  704           } catch (RuntimeException e) {
  705               context.renderResponse();
  706               throw e;
  707           }
  708   
  709           if (!isValid()) {
  710               context.renderResponse();
  711           }
  712       }
  713   
  714       /**
  715        * @throws NullPointerException {@inheritDoc}
  716        */
  717       public void decode(FacesContext context) {
  718   
  719           if (context == null) {
  720               throw new NullPointerException();
  721           }
  722   
  723           // Force validity back to "true"
  724           setValid(true);
  725           super.decode(context);
  726       }
  727   
  728       /**
  729        * <p>Perform the following algorithm to update the model data
  730        * associated with this {@link UIInput}, if any, as appropriate.</p>
  731        * <ul>
  732        * <li>If the <code>valid</code> property of this component is
  733        * <code>false</code>, take no further action.</li>
  734        * <li>If the <code>localValueSet</code> property of this component is
  735        * <code>false</code>, take no further action.</li>
  736        * <li>If no {@link ValueExpression} for <code>value</code> exists,
  737        * take no further action.</li>
  738        * <li>Call <code>setValue()</code> method of the {@link ValueExpression}
  739        * to update the value that the {@link ValueExpression} points at.</li>
  740        * <li>If the <code>setValue()</code> method returns successfully:
  741        * <ul>
  742        * <li>Clear the local value of this {@link UIInput}.</li>
  743        * <li>Set the <code>localValueSet</code> property of this
  744        * {@link UIInput} to false.</li>
  745        * </ul></li>
  746        * <li>If the <code>setValue()</code> method call fails:
  747        * <ul>
  748        * <li>Enqueue an error message by calling <code>addMessage()</code>
  749        * on the specified {@link FacesContext} instance.</li>
  750        * <li>Set the <code>valid</code> property of this {@link UIInput}
  751        * to <code>false</code>.</li>
  752        * </ul></li>
  753        * </ul>
  754        *
  755        * @param context {@link FacesContext} for the request we are processing
  756        * @throws NullPointerException if <code>context</code>
  757        *                              is <code>null</code>
  758        */
  759       public void updateModel(FacesContext context) {
  760   
  761           if (context == null) {
  762               throw new NullPointerException();
  763           }
  764   
  765           if (!isValid() || !isLocalValueSet()) {
  766               return;
  767           }
  768           ValueExpression ve = getValueExpression("value");
  769           if (ve != null) {
  770               try {
  771                   ve.setValue(context.getELContext(), getLocalValue());
  772                   setValue(null);
  773                   setLocalValueSet(false);
  774               } catch (ELException e) {
  775                   String messageStr = e.getMessage();
  776                   Throwable result = e.getCause();
  777                   while (null != result &&
  778                        result.getClass().isAssignableFrom(ELException.class)) {
  779                       messageStr = result.getMessage();
  780                       result = result.getCause();
  781                   }
  782                   FacesMessage message;
  783                   if (null == messageStr) {
  784                       message =
  785                            MessageFactory.getMessage(context, UPDATE_MESSAGE_ID,
  786                                 MessageFactory.getLabel(
  787                                      context, this));
  788                   } else {
  789                       message = new FacesMessage(FacesMessage.SEVERITY_ERROR,
  790                                                  messageStr,
  791                                                  messageStr);
  792                   }
  793                   LOGGER.log(Level.SEVERE, message.getSummary(), result);
  794                   context.addMessage(getClientId(context), message);
  795                   setValid(false);
  796               } catch (IllegalArgumentException e) {
  797                   FacesMessage message =
  798                        MessageFactory.getMessage(context, UPDATE_MESSAGE_ID,
  799                             MessageFactory.getLabel(
  800                                  context, this));
  801                   LOGGER.log(Level.SEVERE, message.getSummary(), e);
  802                   context.addMessage(getClientId(context), message);
  803                   setValid(false);
  804               } catch (Exception e) {
  805                   FacesMessage message =
  806                        MessageFactory.getMessage(context, UPDATE_MESSAGE_ID,
  807                             MessageFactory.getLabel(
  808                                  context, this));
  809                   LOGGER.log(Level.SEVERE, message.getSummary(), e);
  810                   context.addMessage(getClientId(context), message);
  811                   setValid(false);
  812               }
  813           }
  814       }
  815   
  816       // ------------------------------------------------------ Validation Methods
  817   
  818   
  819       /**
  820        * <p>Perform the following algorithm to validate the local value of
  821        * this {@link UIInput}.</p>
  822        * <ul>
  823        * <li>Retrieve the submitted value with <code>getSubmittedValue()</code>.
  824        * If this returns null, exit without further processing.  (This
  825        * indicates that no value was submitted for this component.)</li>
  826        * <p/>
  827        * <li> Convert the submitted value into a "local value" of the
  828        * appropriate data type by calling {@link #getConvertedValue}.</li>
  829        * <p/>
  830        * <li>Validate the property by calling {@link #validateValue}.</li>
  831        * <p/>
  832        * <li>If the <code>valid</code> property of this component is still
  833        * <code>true</code>, retrieve the previous value of the component
  834        * (with <code>getValue()</code>), store the new local value using
  835        * <code>setValue()</code>, and reset the submitted value to
  836        * null.  If the local value is different from
  837        * the previous value of this component, fire a
  838        * {@link ValueChangeEvent} to be broadcast to all interested
  839        * listeners.</li>
  840        * </ul>
  841        * <p/>
  842        * <p>Application components implementing {@link UIInput} that wish to
  843        * perform validation with logic embedded in the component should perform
  844        * their own correctness checks, and then call the
  845        * <code>super.validate()</code> method to perform the standard
  846        * processing described above.</p>
  847        *
  848        * @param context The {@link FacesContext} for the current request
  849        * @throws NullPointerException if <code>context</code>
  850        *                              is null
  851        */
  852       public void validate(FacesContext context) {
  853   
  854           if (context == null) {
  855               throw new NullPointerException();
  856           }
  857   
  858           // Submitted value == null means "the component was not submitted
  859           // at all";  validation should not continue
  860           Object submittedValue = getSubmittedValue();
  861           if (submittedValue == null) {
  862               return;
  863           }
  864   
  865           Object newValue = null;
  866   
  867           try {
  868               newValue = getConvertedValue(context, submittedValue);
  869           }
  870           catch (ConverterException ce) {
  871               addConversionErrorMessage(context, ce, submittedValue);
  872               setValid(false);
  873           }
  874   
  875           validateValue(context, newValue);
  876   
  877           // If our value is valid, store the new value, erase the
  878           // "submitted" value, and emit a ValueChangeEvent if appropriate
  879           if (isValid()) {
  880               Object previous = getValue();
  881               setValue(newValue);
  882               setSubmittedValue(null);
  883               if (compareValues(previous, newValue)) {
  884                   queueEvent(new ValueChangeEvent(this, previous, newValue));
  885               }
  886           }
  887   
  888       }
  889   
  890       /**
  891        * <p>Convert the submitted value into a "local value" of the
  892        * appropriate data type, if necessary.  Employ the following
  893        * algorithm to do so:</p>
  894        * <ul>
  895        * <li>If a <code>Renderer</code> is present, call
  896        * <code>getConvertedValue()</code> to convert the submitted
  897        * value.</li>
  898        * <li>If no <code>Renderer</code> is present, and the submitted
  899        * value is a String, locate a {@link Converter} as follows:
  900        * <ul>
  901        * <li>If <code>getConverter()</code> returns a non-null {@link Converter},
  902        * use that instance.</li>
  903        * <li>Otherwise, if a value binding for <code>value</code> exists,
  904        * call <code>getType()</code> on it.
  905        * <ul>
  906        * <li>If this call returns <code>null</code>, assume the output
  907        * type is <code>String</code> and perform no conversion.</li>
  908        * <li>Otherwise, call
  909        * <code>Application.createConverter(Class)</code>
  910        * to locate any registered {@link Converter} capable of
  911        * converting data values of the specified type.</li>
  912        * </ul>
  913        * </li>
  914        * </ul>
  915        * <li>If a {@link Converter} instance was located, call its
  916        * <code>getAsObject()</code> method to perform the conversion.
  917        * If conversion fails:
  918        * <ul>
  919        * <li>Enqueue an appropriate error message by calling the
  920        * <code>addMessage()</code> method on the
  921        * <code>FacesContext</code>.</li>
  922        * <li>Set the <code>valid</code> property
  923        * on this component to <code>false</code> </li>
  924        * </ul></li>
  925        * <li>Otherwise, use the submitted value without any conversion</li>
  926        * </ul>
  927        * </li>
  928        * <p/>
  929        * </p>
  930        * <p/>
  931        * <p>This method can be overridden by subclasses for more specific
  932        * behavior.</p>
  933        */
  934   
  935   
  936       protected Object getConvertedValue(FacesContext context,
  937                                          Object newSubmittedValue) throws ConverterException {
  938           Renderer renderer = getRenderer(context);
  939           Object newValue;
  940   
  941           if (renderer != null) {
  942               newValue = renderer.getConvertedValue(context, this,
  943                    newSubmittedValue);
  944           } else if (newSubmittedValue instanceof String) {
  945               // If there's no Renderer, and we've got a String,
  946               // run it through the Converter (if any)
  947               Converter converter = getConverterWithType(context);
  948               if (converter != null) {
  949                   newValue = converter.getAsObject(context, this,
  950                        (String) newSubmittedValue);
  951               } else {
  952                   newValue = newSubmittedValue;
  953               }
  954           } else {
  955               newValue = newSubmittedValue;
  956           }
  957           return newValue;
  958       }
  959   
  960       /**
  961        * <p>Set the "valid" property according to the below algorithm.</p>
  962        * <p/>
  963        * <ul>
  964        * <p/>
  965        * <li>If the <code>valid</code> property on this component is still
  966        * <code>true</code>, and the <code>required</code> property is also
  967        * true, ensure that the local value is not empty (where "empty" is
  968        * defined as <code>null</code> or a zero-length String.  If the local
  969        * value is empty:
  970        * <ul>
  971        * <li>Enqueue an appropriate error message by calling the
  972        * <code>addMessage()</code> method on the <code>FacesContext</code>
  973        * instance for the current request.  If the {@link #getRequiredMessage}
  974        * returns non-<code>null</code>, use the value as the <code>summary</code>
  975        * and <code>detail</code> in the {@link FacesMessage} that
  976        * is enqueued on the <code>FacesContext</code>, otherwise
  977        * use the message for the {@link #REQUIRED_MESSAGE_ID}.
  978        * </li>
  979        * <li>Set the <code>valid</code> property on this component to
  980        * <code>false</code>.</li>
  981        * </ul></li>
  982        * <li>If the <code>valid</code> property on this component is still
  983        * <code>true</code>, and the local value is not empty, call the
  984        * <code>validate()</code> method of each {@link Validator}
  985        * registered for this {@link UIInput}, followed by the method
  986        * pointed at by the <code>validatorBinding</code> property (if any).
  987        * If any of these validators or the method throws a
  988        * {@link ValidatorException}, catch the exception, add
  989        * its message (if any) to the {@link FacesContext}, and set
  990        * the <code>valid</code> property of this component to false.</li>
  991        * <p/>
  992        * </ul>
  993        */
  994   
  995       protected void validateValue(FacesContext context, Object newValue) {
  996           // If our value is valid, enforce the required property if present
  997           if (isValid() && isRequired() && isEmpty(newValue)) {
  998               String requiredMessageStr = getRequiredMessage();
  999               FacesMessage message;
 1000               if (null != requiredMessageStr) {
 1001                   message = new FacesMessage(FacesMessage.SEVERITY_ERROR,
 1002                                              requiredMessageStr,
 1003                                              requiredMessageStr);
 1004               } else {
 1005                   message =
 1006                        MessageFactory.getMessage(context, REQUIRED_MESSAGE_ID,
 1007                             MessageFactory.getLabel(
 1008                                  context, this));
 1009               }
 1010               context.addMessage(getClientId(context), message);
 1011               setValid(false);
 1012           }
 1013   
 1014           // If our value is valid and not empty, call all validators
 1015           if (isValid() && !isEmpty(newValue)) {
 1016               if (this.validators != null) {
 1017                   for (Validator validator : this.validators) {
 1018                       try {
 1019                           validator.validate(context, this, newValue);
 1020                       }
 1021                       catch (ValidatorException ve) {
 1022                           // If the validator throws an exception, we're
 1023                           // invalid, and we need to add a message
 1024                           setValid(false);
 1025                           FacesMessage message;
 1026                           String validatorMessageString = getValidatorMessage();
 1027   
 1028                           if (null != validatorMessageString) {
 1029                               message =
 1030                                     new FacesMessage(FacesMessage.SEVERITY_ERROR,
 1031                                                      validatorMessageString,
 1032                                                      validatorMessageString);
 1033                               message.setSeverity(FacesMessage.SEVERITY_ERROR);
 1034                           } else {
 1035                               message = ve.getFacesMessage();
 1036                           }
 1037                           if (message != null) {
 1038                               context.addMessage(getClientId(context), message);
 1039                           }
 1040                       }
 1041                   }
 1042               }
 1043           }
 1044       }
 1045   
 1046   
 1047       /**
 1048        * <p>Return <code>true</code> if the new value is different from the
 1049        * previous value.</p>
 1050        *
 1051        * @param previous old value of this component (if any)
 1052        * @param value    new value of this component (if any)
 1053        */
 1054       protected boolean compareValues(Object previous, Object value) {
 1055   
 1056           if (previous == null) {
 1057               return (value != null);
 1058           } else if (value == null) {
 1059               return (true);
 1060           } else {
 1061               return (!(previous.equals(value)));
 1062           }
 1063   
 1064       }
 1065   
 1066   
 1067       /**
 1068        * Executes validation logic.
 1069        */
 1070       private void executeValidate(FacesContext context) {
 1071           try {
 1072               validate(context);
 1073           } catch (RuntimeException e) {
 1074               context.renderResponse();
 1075               throw e;
 1076           }
 1077   
 1078           if (!isValid()) {
 1079               context.renderResponse();
 1080           }
 1081       }
 1082   
 1083       private static boolean isEmpty(Object value) {
 1084   
 1085           if (value == null) {
 1086               return (true);
 1087           } else if ((value instanceof String) &&
 1088                (((String) value).length() < 1)) {
 1089               return (true);
 1090           } else if (value.getClass().isArray()) {
 1091               if (0 == java.lang.reflect.Array.getLength(value)) {
 1092                   return (true);
 1093               }
 1094           } else if (value instanceof List) {
 1095               if (((List) value).isEmpty()) {
 1096                   return (true);
 1097               }
 1098           }
 1099           return (false);
 1100       }
 1101   
 1102   
 1103       /**
 1104        * <p>The set of {@link Validator}s associated with this
 1105        * <code>UIComponent</code>.</p>
 1106        */
 1107       List<Validator> validators = null;
 1108   
 1109   
 1110       /**
 1111        * <p>Add a {@link Validator} instance to the set associated with
 1112        * this {@link UIInput}.</p>
 1113        *
 1114        * @param validator The {@link Validator} to add
 1115        * @throws NullPointerException if <code>validator</code>
 1116        *                              is null
 1117        */
 1118       public void addValidator(Validator validator) {
 1119   
 1120           if (validator == null) {
 1121               throw new NullPointerException();
 1122           }
 1123           if (validators == null) {
 1124               //noinspection CollectionWithoutInitialCapacity
 1125               validators = new ArrayList<Validator>();
 1126           }
 1127           validators.add(validator);
 1128   
 1129       }
 1130   
 1131   
 1132       /**
 1133        * <p>Return the set of registered {@link Validator}s for this
 1134        * {@link UIInput} instance.  If there are no registered validators,
 1135        * a zero-length array is returned.</p>
 1136        */
 1137       public Validator[] getValidators() {
 1138   
 1139           if (validators == null) {
 1140               return EMPTY_VALIDATOR;
 1141           } else {
 1142               return (validators.toArray(new Validator[validators.size()]));
 1143           }
 1144   
 1145       }
 1146   
 1147   
 1148       /**
 1149        * <p>Remove a {@link Validator} instance from the set associated with
 1150        * this {@link UIInput}, if it was previously associated.
 1151        * Otherwise, do nothing.</p>
 1152        *
 1153        * @param validator The {@link Validator} to remove
 1154        */
 1155       public void removeValidator(Validator validator) {
 1156   
 1157           if (validators != null) {
 1158               validators.remove(validator);
 1159           }
 1160   
 1161       }
 1162   
 1163       // ------------------------------------------------ Event Processing Methods
 1164   
 1165   
 1166       /**
 1167        * <p>Add a new {@link ValueChangeListener} to the set of listeners
 1168        * interested in being notified when {@link ValueChangeEvent}s occur.</p>
 1169        *
 1170        * @param listener The {@link ValueChangeListener} to be added
 1171        * @throws NullPointerException if <code>listener</code>
 1172        *                              is <code>null</code>
 1173        */
 1174       public void addValueChangeListener(ValueChangeListener listener) {
 1175   
 1176           addFacesListener(listener);
 1177   
 1178       }
 1179   
 1180   
 1181       /**
 1182        * <p>Return the set of registered {@link ValueChangeListener}s for this
 1183        * {@link UIInput} instance.  If there are no registered listeners,
 1184        * a zero-length array is returned.</p>
 1185        */
 1186       public ValueChangeListener[] getValueChangeListeners() {
 1187   
 1188           return (ValueChangeListener[]) getFacesListeners(ValueChangeListener.class);
 1189       }
 1190   
 1191   
 1192       /**
 1193        * <p>Remove an existing {@link ValueChangeListener} (if any) from the
 1194        * set of listeners interested in being notified when
 1195        * {@link ValueChangeEvent}s occur.</p>
 1196        *
 1197        * @param listener The {@link ValueChangeListener} to be removed
 1198        * @throws NullPointerException if <code>listener</code>
 1199        *                              is <code>null</code>
 1200        */
 1201       public void removeValueChangeListener(ValueChangeListener listener) {
 1202   
 1203           removeFacesListener(listener);
 1204   
 1205       }
 1206   
 1207       // ----------------------------------------------------- StateHolder Methods
 1208   
 1209   
 1210       private Object[] values;
 1211   
 1212       public Object saveState(FacesContext context) {
 1213   
 1214           if (values == null) {
 1215               values = new Object[9];
 1216           }
 1217   
 1218           values[0] = super.saveState(context);
 1219           values[1] = localValueSet;
 1220           values[2] = required;
 1221           values[3] = requiredMessage;
 1222           values[4] = converterMessage;
 1223           values[5] = validatorMessage;
 1224           values[6] = valid;
 1225           values[7] = immediate;
 1226           values[8] = saveAttachedState(context, validators);
 1227           return (values);
 1228   
 1229       }
 1230   
 1231   
 1232       public void restoreState(FacesContext context, Object state) {
 1233   
 1234           values = (Object[]) state;
 1235           super.restoreState(context, values[0]);
 1236           localValueSet = (Boolean) values[1];
 1237           required = (Boolean) values[2];
 1238           requiredMessage = ((String) values[3]);
 1239           converterMessage = ((String) values[4]);
 1240           validatorMessage = ((String) values[5]);
 1241           valid = (Boolean) values[6];
 1242           immediate = (Boolean) values[7];
 1243           List<Validator> restoredValidators;
 1244           Iterator<Validator> iter;
 1245   
 1246           if (null != (restoredValidators = TypedCollections.dynamicallyCastList((List)
 1247                restoreAttachedState(context, values[8]), Validator.class))) {
 1248               // if there were some validators registered prior to this
 1249               // method being invoked, merge them with the list to be
 1250               // restored.
 1251               if (null != validators) {
 1252                   iter = restoredValidators.iterator();
 1253                   while (iter.hasNext()) {
 1254                       validators.add(iter.next());
 1255                   }
 1256               } else {
 1257                   validators = restoredValidators;
 1258               }
 1259           }
 1260   
 1261       }
 1262   
 1263       private Converter getConverterWithType(FacesContext context) {
 1264           Converter converter = getConverter();
 1265           if (converter != null) {
 1266               return converter;
 1267           }
 1268   
 1269           ValueExpression valueExpression = getValueExpression("value");
 1270           if (valueExpression == null) {
 1271               return null;
 1272           }
 1273   
 1274           Class converterType;
 1275           try {
 1276               converterType = valueExpression.getType(context.getELContext());
 1277           }
 1278           catch (ELException e) {
 1279               throw new FacesException(e);
 1280           }
 1281   
 1282           // if converterType is null, String, or Object, assume
 1283           // no conversion is needed
 1284           if (converterType == null ||
 1285                converterType == String.class ||
 1286                converterType == Object.class) {
 1287               return null;
 1288           }
 1289   
 1290           // if getType returns a type for which we support a default
 1291           // conversion, acquire an appropriate converter instance.
 1292           try {
 1293               Application application = context.getApplication();
 1294               return application.createConverter(converterType);
 1295           } catch (Exception e) {
 1296               return (null);
 1297           }
 1298       }
 1299   
 1300       private void addConversionErrorMessage(FacesContext context,
 1301                                              ConverterException ce, Object value) {
 1302           FacesMessage message;
 1303           String converterMessageString = getConverterMessage();
 1304           if (null != converterMessageString) {
 1305               message = new FacesMessage(FacesMessage.SEVERITY_ERROR,
 1306                                          converterMessageString,
 1307                                          converterMessageString);
 1308           } else {
 1309               message = ce.getFacesMessage();
 1310               if (message == null) {
 1311                   message = MessageFactory.getMessage(context,
 1312                        CONVERSION_MESSAGE_ID);                
 1313                   if (message.getDetail() == null) {
 1314                       message.setDetail(ce.getMessage());
 1315                   }
 1316               }
 1317           }
 1318   
 1319           context.addMessage(getClientId(context), message);
 1320       }
 1321   
 1322   }

Save This Page
Home » mojarra-1.2_09-b02-FCS-source » javax.faces.component » [javadoc | source]