001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License version 2
011: * as published by the Free Software Foundation.
012: *
013: * Resin Open Source is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
016: * of NON-INFRINGEMENT. See the GNU General Public License for more
017: * details.
018: *
019: * You should have received a copy of the GNU General Public License
020: * along with Resin Open Source; if not, write to the
021: *
022: * Free Software Foundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Scott Ferguson
027: */
028:
029: package javax.faces.component;
030:
031: import java.util.*;
032: import java.util.logging.*;
033:
034: import javax.el.*;
035:
036: import javax.faces.*;
037: import javax.faces.application.*;
038: import javax.faces.context.*;
039: import javax.faces.convert.*;
040: import javax.faces.el.*;
041: import javax.faces.event.*;
042: import javax.faces.render.*;
043: import javax.faces.validator.*;
044:
045: public class UIInput extends UIOutput implements EditableValueHolder {
046: private static final Logger log = Logger.getLogger(UIInput.class
047: .getName());
048:
049: public static final String COMPONENT_FAMILY = "javax.faces.Input";
050: public static final String COMPONENT_TYPE = "javax.faces.Input";
051:
052: public static final String CONVERSION_MESSAGE_ID = "javax.faces.component.UIInput.CONVERSION";
053: public static final String REQUIRED_MESSAGE_ID = "javax.faces.component.UIInput.REQUIRED";
054: public static final String UPDATE_MESSAGE_ID = "javax.faces.component.UIInput.UPDATE";
055:
056: private static final Validator[] NULL_VALIDATORS = new Validator[0];
057:
058: private static final HashMap<String, PropEnum> _propMap = new HashMap<String, PropEnum>();
059:
060: private ValueExpression _valueExpr;
061:
062: private Boolean _required;
063: private ValueExpression _requiredExpr;
064:
065: private Boolean _immediate;
066: private ValueExpression _immediateExpr;
067:
068: private String _requiredMessage;
069: private ValueExpression _requiredMessageExpr;
070:
071: private String _converterMessage;
072: private ValueExpression _converterMessageExpr;
073:
074: private String _validatorMessage;
075: private ValueExpression _validatorMessageExpr;
076:
077: //
078:
079: private boolean _isValid = true;
080: private boolean _isLocalValueSet;
081:
082: private Object _submittedValue;
083:
084: private ArrayList<Validator> _validatorList;
085: private Validator[] _validators = NULL_VALIDATORS;
086:
087: public UIInput() {
088: setRendererType("javax.faces.Text");
089: }
090:
091: /**
092: * Returns the component family, used to select the renderer.
093: */
094: public String getFamily() {
095: return COMPONENT_FAMILY;
096: }
097:
098: //
099: // properties
100: //
101:
102: public String getRequiredMessage() {
103: if (_requiredMessage != null)
104: return _requiredMessage;
105: else if (_requiredMessageExpr != null)
106: return Util.evalString(_requiredMessageExpr,
107: getFacesContext());
108: else
109: return null;
110: }
111:
112: public void setRequiredMessage(String value) {
113: _requiredMessage = value;
114: }
115:
116: public String getConverterMessage() {
117: if (_converterMessage != null)
118: return _converterMessage;
119: else if (_converterMessageExpr != null)
120: return Util.evalString(_converterMessageExpr,
121: getFacesContext());
122: else
123: return null;
124: }
125:
126: public void setConverterMessage(String value) {
127: _converterMessage = value;
128: }
129:
130: public String getValidatorMessage() {
131: if (_validatorMessage != null)
132: return _validatorMessage;
133: else if (_validatorMessageExpr != null)
134: return Util.evalString(_validatorMessageExpr,
135: getFacesContext());
136: else
137: return null;
138: }
139:
140: public void setValidatorMessage(String value) {
141: _validatorMessage = value;
142: }
143:
144: /**
145: * Returns the value expression with the given name.
146: */
147: @Override
148: public ValueExpression getValueExpression(String name) {
149: PropEnum prop = _propMap.get(name);
150:
151: if (prop != null) {
152: switch (_propMap.get(name)) {
153: case VALUE:
154: return _valueExpr;
155: case IMMEDIATE:
156: return _immediateExpr;
157: case REQUIRED:
158: return _requiredExpr;
159: case REQUIRED_MESSAGE:
160: return _requiredMessageExpr;
161: case CONVERTER_MESSAGE:
162: return _converterMessageExpr;
163: case VALIDATOR_MESSAGE:
164: return _validatorMessageExpr;
165: }
166: }
167:
168: return super .getValueExpression(name);
169: }
170:
171: /**
172: * Sets the value expression with the given name.
173: */
174: @Override
175: public void setValueExpression(String name, ValueExpression expr) {
176: PropEnum prop = _propMap.get(name);
177:
178: if (prop != null) {
179: switch (_propMap.get(name)) {
180: case VALUE:
181: if (expr != null && !expr.isLiteralText())
182: _valueExpr = expr;
183: break;
184:
185: case IMMEDIATE:
186: if (expr != null && expr.isLiteralText()) {
187: _immediate = (Boolean) expr.getValue(null);
188: return;
189: } else
190: _immediateExpr = expr;
191: break;
192:
193: case REQUIRED:
194: if (expr != null && expr.isLiteralText()) {
195: _required = (Boolean) expr.getValue(null);
196: return;
197: } else
198: _requiredExpr = expr;
199: break;
200:
201: case REQUIRED_MESSAGE:
202: if (expr != null && expr.isLiteralText()) {
203: _requiredMessage = (String) expr.getValue(null);
204: return;
205: } else
206: _requiredMessageExpr = expr;
207: break;
208:
209: case CONVERTER_MESSAGE:
210: if (expr != null && expr.isLiteralText()) {
211: _converterMessage = (String) expr.getValue(null);
212: return;
213: } else
214: _converterMessageExpr = expr;
215: break;
216:
217: case VALIDATOR_MESSAGE:
218: if (expr != null && expr.isLiteralText()) {
219: _validatorMessage = (String) expr.getValue(null);
220: return;
221: } else
222: _validatorMessageExpr = expr;
223: break;
224: }
225: }
226:
227: super .setValueExpression(name, expr);
228: }
229:
230: //
231: // EditableValueHolder properties.
232: //
233:
234: public boolean isRequired() {
235: if (_required != null)
236: return _required;
237: else if (_requiredExpr != null)
238: return Util.evalBoolean(_requiredExpr, getFacesContext());
239: else
240: return false;
241: }
242:
243: public void setRequired(boolean required) {
244: _required = required;
245: }
246:
247: public boolean isImmediate() {
248: if (_immediate != null)
249: return _immediate;
250: else if (_immediateExpr != null)
251: return Util.evalBoolean(_immediateExpr, getFacesContext());
252: else
253: return false;
254: }
255:
256: public void setImmediate(boolean immediate) {
257: _immediate = immediate;
258: }
259:
260: public Object getSubmittedValue() {
261: return _submittedValue;
262: }
263:
264: public void setSubmittedValue(Object submittedValue) {
265: _submittedValue = submittedValue;
266: }
267:
268: public void setValue(Object value) {
269: super .setValue(value);
270:
271: setLocalValueSet(true);
272: }
273:
274: public boolean isLocalValueSet() {
275: return _isLocalValueSet;
276: }
277:
278: public void setLocalValueSet(boolean isSet) {
279: _isLocalValueSet = isSet;
280: }
281:
282: public void resetValue() {
283: setValue(null);
284: setSubmittedValue(null);
285: setLocalValueSet(false);
286: setValid(true);
287: }
288:
289: public boolean isValid() {
290: return _isValid;
291: }
292:
293: public void setValid(boolean valid) {
294: _isValid = valid;
295: }
296:
297: @Deprecated
298: public MethodBinding getValueChangeListener() {
299: FacesListener[] listeners = getFacesListeners(FacesListener.class);
300: for (int i = 0; i < listeners.length; i++) {
301: if (listeners[i] instanceof ValueChangeListenerAdapter) {
302: ValueChangeListenerAdapter adapter = (ValueChangeListenerAdapter) listeners[i];
303:
304: return adapter.getBinding();
305: }
306: }
307:
308: return null;
309: }
310:
311: @Deprecated
312: public void setValueChangeListener(MethodBinding binding) {
313: ValueChangeListener listener = new ValueChangeListenerAdapter(
314: binding);
315:
316: FacesListener[] listeners = getFacesListeners(FacesListener.class);
317: for (int i = 0; i < listeners.length; i++) {
318: if (listeners[i] instanceof ValueChangeListenerAdapter) {
319: removeFacesListener(listeners[i]);
320: }
321: }
322:
323: addValueChangeListener(listener);
324: }
325:
326: public void addValidator(Validator validator) {
327: Validator[] newValidators = new Validator[_validators.length + 1];
328: System.arraycopy(_validators, 0, newValidators, 0,
329: _validators.length);
330: newValidators[_validators.length] = validator;
331:
332: _validators = newValidators;
333: }
334:
335: public void removeValidator(Validator validator) {
336: int length = _validators.length;
337: for (int i = 0; i < length; i++) {
338: if (_validators[i] == validator) {
339: Validator[] newValidators = new Validator[length - 1];
340: System.arraycopy(_validators, 0, newValidators, 0, i);
341: System.arraycopy(_validators, i + 1, newValidators, i,
342: length - i - 1);
343: _validators = newValidators;
344: return;
345: }
346: }
347: }
348:
349: public Validator[] getValidators() {
350: return _validators;
351: }
352:
353: @Deprecated
354: public MethodBinding getValidator() {
355: int length = _validators.length;
356: for (int i = 0; i < length; i++) {
357: Validator validator = _validators[i];
358:
359: if (validator instanceof ValidatorAdapter) {
360: ValidatorAdapter adapter = (ValidatorAdapter) validator;
361:
362: return adapter.getBinding();
363: }
364: }
365:
366: return null;
367: }
368:
369: @Deprecated
370: public void setValidator(MethodBinding binding) {
371: ValidatorAdapter adapter = new ValidatorAdapter(binding);
372:
373: int length = _validators.length;
374: for (int i = 0; i < length; i++) {
375: Validator validator = _validators[i];
376:
377: if (validator instanceof ValidatorAdapter) {
378: _validators[i] = adapter;
379: return;
380: }
381: }
382:
383: addValidator(adapter);
384: }
385:
386: public void addValueChangeListener(ValueChangeListener listener) {
387: addFacesListener(listener);
388: }
389:
390: public void removeValueChangeListener(ValueChangeListener listener) {
391: removeFacesListener(listener);
392: }
393:
394: public ValueChangeListener[] getValueChangeListeners() {
395: return (ValueChangeListener[]) getFacesListeners(ValueChangeListener.class);
396: }
397:
398: //
399: // processing
400: //
401:
402: @Override
403: public void decode(FacesContext context) {
404: setValid(true);
405: super .decode(context);
406: }
407:
408: public void processDecodes(FacesContext context) {
409: if (isRendered()) {
410: super .processDecodes(context);
411:
412: if (isImmediate()) {
413: try {
414: validate(context);
415: } catch (RuntimeException e) {
416: context.renderResponse();
417:
418: throw e;
419: }
420:
421: if (!isValid())
422: context.renderResponse();
423: }
424: }
425: }
426:
427: public void processUpdates(FacesContext context) {
428: if (isRendered()) {
429: super .processUpdates(context);
430:
431: try {
432: updateModel(context);
433: } catch (RuntimeException e) {
434: context.renderResponse();
435:
436: throw e;
437: }
438:
439: if (!isValid())
440: context.renderResponse();
441: }
442: }
443:
444: public void updateModel(FacesContext context) {
445: if (!isValid())
446: return;
447:
448: if (!isLocalValueSet())
449: return;
450:
451: if (_valueExpr == null)
452: return;
453:
454: try {
455: _valueExpr
456: .setValue(context.getELContext(), getLocalValue());
457:
458: setValue(null);
459: setLocalValueSet(false);
460: } catch (RuntimeException e) {
461: log.log(Level.FINE, e.toString(), e);
462:
463: setValid(false);
464:
465: String summary = Util
466: .l10n(
467: context,
468: UPDATE_MESSAGE_ID,
469: "{0}: An error occurred while processing your submitted information.",
470: Util.getLabel(context, this ));
471:
472: String detail = summary;
473:
474: FacesMessage msg = new FacesMessage(summary, detail);
475:
476: context.addMessage(getClientId(context), msg);
477:
478: // jsf/5011
479: // if the spec lets us throw this, it's useful for development
480: throw new FacesException("id=" + getClientId(context) + " "
481: + e.toString(), e);
482: }
483: }
484:
485: @Override
486: public void processValidators(FacesContext context) {
487: if (isRendered()) {
488: super .processValidators(context);
489:
490: try {
491: if (!isImmediate())
492: validate(context);
493:
494: if (!isValid())
495: context.renderResponse();
496: } catch (RuntimeException e) {
497: context.renderResponse();
498:
499: throw e;
500: }
501: }
502: }
503:
504: public void validate(FacesContext context) {
505: Object submittedValue = getSubmittedValue();
506: if (submittedValue == null)
507: return;
508:
509: Object value;
510:
511: try {
512: value = getConvertedValue(context, submittedValue);
513:
514: validateValue(context, value);
515:
516: if (!isValid()) {
517: context.renderResponse();
518: return;
519: }
520: } catch (ConverterException e) {
521: log.log(Level.FINE, e.toString(), e);
522: setValid(false);
523: context.renderResponse();
524:
525: FacesMessage msg = e.getFacesMessage();
526: if (msg != null)
527: context.addMessage(getClientId(context), msg);
528: else {
529: String summary = Util.l10n(context,
530: CONVERSION_MESSAGE_ID,
531: "{0}: Conversion error occurred.", Util
532: .getLabel(context, this ));
533:
534: String detail = summary;
535:
536: msg = new FacesMessage(summary, detail);
537:
538: context.addMessage(getClientId(context), msg);
539: }
540: return;
541: }
542:
543: Object oldValue = getValue();
544: setValue(value);
545: setSubmittedValue(null);
546:
547: if (compareValues(oldValue, value)
548: && getFacesListeners(FacesListener.class).length > 0) {
549: ValueChangeEvent event = new ValueChangeEvent(this ,
550: oldValue, value);
551:
552: broadcast(event);
553: }
554: }
555:
556: protected Object getConvertedValue(FacesContext context,
557: Object submittedValue) throws ConverterException {
558: Renderer renderer = getRenderer(context);
559:
560: if (renderer != null)
561: return renderer.getConvertedValue(context, this ,
562: submittedValue);
563: else if (submittedValue instanceof String) {
564: Converter converter = getConverter();
565:
566: if (converter != null)
567: return converter.getAsObject(context, this ,
568: (String) submittedValue);
569:
570: if (_valueExpr != null) {
571: Class type = _valueExpr.getType(context.getELContext());
572:
573: if (type != null) {
574: converter = context.getApplication()
575: .createConverter(type);
576:
577: if (converter != null) {
578: return converter.getAsObject(context, this ,
579: (String) submittedValue);
580: }
581: }
582: }
583: }
584:
585: return submittedValue;
586: }
587:
588: protected boolean compareValues(Object oldValue, Object newValue) {
589: if (oldValue == newValue)
590: return false;
591: else if (oldValue == null || newValue == null)
592: return true;
593: else
594: return !oldValue.equals(newValue);
595: }
596:
597: public void validateValue(FacesContext context, Object value) {
598: if (!isValid()) {
599: } else if (value != null && !"".equals(value)) {
600: for (Validator validator : getValidators()) {
601: try {
602: validator.validate(context, this , value);
603: } catch (ValidatorException e) {
604: log.log(Level.FINER, e.toString(), e);
605:
606: if (e.getFacesMessage() != null)
607: context.addMessage(getClientId(context), e
608: .getFacesMessage());
609: else {
610: FacesMessage msg = new FacesMessage(e
611: .getMessage(), e.toString());
612: context.addMessage(getClientId(context), msg);
613: }
614:
615: setValid(false);
616: }
617: }
618: } else if (isRequired()) {
619: final FacesMessage msg;
620:
621: String requiredMessage = getRequiredMessage();
622:
623: if (requiredMessage != null)
624: msg = new FacesMessage(requiredMessage, requiredMessage);
625: else {
626: String summary = Util
627: .l10n(
628: context,
629: REQUIRED_MESSAGE_ID,
630: "{0}: UIInput validation Error: Value is required.",
631: Util.getLabel(context, this ));
632:
633: String detail = summary;
634: msg = new FacesMessage(summary, detail);
635: }
636:
637: context.addMessage(getClientId(context), msg);
638:
639: setValid(false);
640: return;
641: }
642:
643: }
644:
645: //
646: // state
647: //
648:
649: public Object saveState(FacesContext context) {
650: int offset = 6;
651:
652: Object[] state = new Object[offset + 2 * _validators.length];
653:
654: state[0] = super .saveState(context);
655: state[1] = _immediate;
656: state[2] = _required;
657: state[3] = _requiredMessage;
658: state[4] = _converterMessage;
659: state[5] = _validatorMessage;
660:
661: if (_validators.length > 0) {
662: for (int i = 0; i < _validators.length; i++) {
663: Validator validator = _validators[i];
664:
665: int index = offset + 2 * i;
666:
667: state[index] = validator.getClass();
668:
669: if (validator instanceof StateHolder) {
670: StateHolder holder = (StateHolder) validator;
671:
672: state[index + 1] = holder.saveState(context);
673: }
674: }
675: }
676:
677: return state;
678: }
679:
680: public void restoreState(FacesContext context, Object value) {
681: Object[] state = (Object[]) value;
682:
683: super .restoreState(context, state[0]);
684:
685: _immediate = (Boolean) state[1];
686: _required = (Boolean) state[2];
687: _requiredMessage = (String) state[3];
688: _converterMessage = (String) state[4];
689: _validatorMessage = (String) state[5];
690:
691: _valueExpr = super .getValueExpression("value");
692:
693: int offset = 6;
694:
695: if (offset < state.length) {
696: _validators = new Validator[(state.length - offset) / 2];
697:
698: for (int i = 0; i < _validators.length; i++) {
699: int index = offset + 2 * i;
700:
701: Class cl = (Class) state[index];
702:
703: try {
704: Validator validator = (Validator) cl.newInstance();
705:
706: if (validator instanceof StateHolder) {
707: StateHolder holder = (StateHolder) validator;
708:
709: holder.restoreState(context, state[index + 1]);
710: }
711:
712: _validators[i] = validator;
713: } catch (Exception e) {
714: throw new FacesException(e);
715: }
716: }
717: }
718: }
719:
720: //
721: // private helpers
722: //
723:
724: private static enum PropEnum {
725: IMMEDIATE, REQUIRED, VALUE, REQUIRED_MESSAGE, CONVERTER_MESSAGE, VALIDATOR_MESSAGE,
726: }
727:
728: private static class ValueChangeListenerAdapter implements
729: ValueChangeListener {
730: private MethodBinding _binding;
731:
732: public ValueChangeListenerAdapter(MethodBinding binding) {
733: _binding = binding;
734: }
735:
736: MethodBinding getBinding() {
737: return _binding;
738: }
739:
740: public void processValueChange(ValueChangeEvent event)
741: throws AbortProcessingException {
742: FacesContext facesContext = FacesContext
743: .getCurrentInstance();
744:
745: _binding.invoke(facesContext, new Object[] { event });
746: }
747:
748: public String toString() {
749: return "ValueChangeListenerAdapter[" + _binding + "]";
750: }
751: }
752:
753: private static class ValidatorAdapter implements Validator {
754: private MethodBinding _binding;
755:
756: public ValidatorAdapter(MethodBinding binding) {
757: _binding = binding;
758: }
759:
760: MethodBinding getBinding() {
761: return _binding;
762: }
763:
764: public void validate(FacesContext context,
765: UIComponent component, Object value)
766: throws ValidatorException {
767: try {
768: FacesContext facesContext = FacesContext
769: .getCurrentInstance();
770:
771: _binding.invoke(facesContext, new Object[] { context,
772: component, value });
773: } catch (EvaluationException e) {
774: if (e.getCause() instanceof ValidatorException)
775: throw (ValidatorException) e.getCause();
776: else if (e.getCause() instanceof RuntimeException)
777: throw (RuntimeException) e.getCause();
778: else
779: throw e;
780: }
781: }
782:
783: public String toString() {
784: return "ValueChangeListenerAdapter[" + _binding + "]";
785: }
786: }
787:
788: static {
789: _propMap.put("value", PropEnum.VALUE);
790: _propMap.put("immediate", PropEnum.IMMEDIATE);
791: _propMap.put("required", PropEnum.REQUIRED);
792: _propMap.put("requiredMessage", PropEnum.REQUIRED_MESSAGE);
793: _propMap.put("converterMessage", PropEnum.CONVERTER_MESSAGE);
794: _propMap.put("validatorMessage", PropEnum.VALIDATOR_MESSAGE);
795: }
796: }
|