1 16 package org.apache.cocoon.forms.formmodel; 17 18 import org.apache.cocoon.forms.FormsConstants; 19 import org.apache.cocoon.forms.FormContext; 20 import org.apache.cocoon.forms.datatype.Datatype; 21 import org.apache.cocoon.forms.datatype.SelectionList; 22 import org.apache.cocoon.forms.datatype.convertor.ConversionResult; 23 import org.apache.cocoon.forms.event.*; 24 import org.apache.cocoon.forms.util.I18nMessage; 25 import org.apache.cocoon.forms.validation.ValidationError; 26 import org.apache.cocoon.forms.validation.ValidationErrorAware; 27 import org.apache.cocoon.xml.AttributesImpl; 28 import org.apache.cocoon.xml.XMLUtils; 29 import org.apache.commons.lang.ObjectUtils; 30 import org.xml.sax.ContentHandler ; 31 import org.xml.sax.SAXException ; 32 33 import java.util.Locale ; 34 35 48 public class Field extends AbstractWidget 49 implements ValidationErrorAware, DataWidget, SelectableWidget, ValueChangedListenerEnabled { 50 51 private static final String FIELD_EL = "field"; 52 private static final String VALUE_EL = "value"; 53 private static final String VALIDATION_MSG_EL = "validation-message"; 54 55 56 protected SelectionList selectionList; 57 58 private ValueChangedListener listener; 59 60 private final FieldDefinition fieldDefinition; 61 62 protected String enteredValue; 63 protected Object value; 64 65 protected boolean required; 66 67 71 protected final static int VALUE_UNPARSED = 0; 72 73 77 protected final static int VALUE_PARSED = 1; 78 79 83 protected final static int VALUE_PARSE_ERROR = 2; 84 85 89 protected final static int VALUE_DISPLAY_PARSE_ERROR = 3; 90 91 96 protected final static int VALUE_VALIDATING = 4; 97 98 102 protected final static int VALUE_VALIDATED = 5; 103 104 108 protected final static int VALUE_DISPLAY_VALIDATION = 6; 109 110 116 protected int valueState = VALUE_PARSED; 117 118 protected ValidationError validationError; 119 120 121 public Field(FieldDefinition fieldDefinition) { 122 super(fieldDefinition); 123 this.fieldDefinition = fieldDefinition; 124 this.listener = fieldDefinition.getValueChangedListener(); 125 } 126 127 public final FieldDefinition getFieldDefinition() { 128 return this.fieldDefinition; 129 } 130 131 public WidgetDefinition getDefinition() { 132 return this.fieldDefinition; 133 } 134 135 public void initialize() { 136 Object value = this.fieldDefinition.getInitialValue(); 137 if (value != null) { 138 setValue(value); 139 } 140 this.selectionList = this.fieldDefinition.getSelectionList(); 141 this.required = this.fieldDefinition.isRequired(); 142 super.initialize(); 143 } 144 145 public Object getValue() { 146 if (this.valueState == VALUE_VALIDATING) { 149 return this.value; 150 } 151 152 ValidationError oldError = this.validationError; 153 154 if (this.valueState == VALUE_UNPARSED) { 156 doParse(); 157 } 158 159 if (this.valueState == VALUE_PARSED) { 161 doValidate(); 162 } 163 164 if (oldError != null && this.validationError == null) { 165 getForm().addWidgetUpdate(this); 168 } 169 170 return this.validationError == null ? this.value : null; 171 } 172 173 public void setValue(Object newValue) { 174 if (newValue != null && !getDatatype().getTypeClass().isAssignableFrom(newValue.getClass())) { 175 throw new RuntimeException ("Incorrect value type for \"" + getRequestParameterName() + 176 "\" (expected " + getDatatype().getTypeClass() + 177 ", got " + newValue.getClass() + ")."); 178 } 179 180 boolean changed; 182 if (this.valueState == VALUE_UNPARSED) { 183 changed = true; 185 } else if (this.value == null) { 186 changed = (newValue != null); 188 } else { 189 changed = !this.value.equals(newValue); 191 } 192 193 if (changed || newValue == null) { 196 boolean callListeners = changed && (hasValueChangedListeners() || this.getForm().hasFormHandler()); 198 Object oldValue = callListeners ? getValue() : null; 199 200 this.value = newValue; 201 this.validationError = null; 202 this.valueState = VALUE_PARSED; 204 if (newValue != null) { 205 this.enteredValue = getDatatype().convertToString(newValue, getForm().getLocale()); 206 } else { 207 this.enteredValue = null; 208 } 209 210 if (callListeners) { 211 getForm().addWidgetEvent(new ValueChangedEvent(this, oldValue, newValue)); 212 } 213 getForm().addWidgetUpdate(this); 214 } 215 } 216 217 public void readFromRequest(FormContext formContext) { 218 if (!getCombinedState().isAcceptingInputs()) { 219 return; 220 } 221 222 String newEnteredValue = formContext.getRequest().getParameter(getRequestParameterName()); 223 readFromRequest(newEnteredValue); 230 } 232 233 protected void readFromRequest(String newEnteredValue) { 234 if (newEnteredValue != null) { 236 newEnteredValue = newEnteredValue.trim(); 238 if (newEnteredValue.length() == 0) { 239 newEnteredValue = null; 240 } 241 } 242 243 boolean changed; 246 if (enteredValue == null) { 247 changed = (newEnteredValue != null); 248 } else { 249 changed = !enteredValue.equals(newEnteredValue); 250 } 251 252 if (changed) { 253 ValidationError oldError = this.validationError; 254 255 boolean hasListeners = hasValueChangedListeners() || this.getForm().hasFormHandler(); 258 Object oldValue = hasListeners ? getValue() : null; 259 260 enteredValue = newEnteredValue; 261 validationError = null; 262 value = null; 263 this.valueState = VALUE_UNPARSED; 264 265 if (hasListeners) { 266 getForm().addWidgetEvent(new DeferredValueChangedEvent(this, oldValue)); 269 } 270 271 if (oldError != null) { 272 getForm().addWidgetUpdate(this); 275 } 276 } 277 } 278 279 282 public boolean validate() { 283 if (!getCombinedState().isValidatingValues()) { 284 this.wasValid = true; 285 return true; 286 } 287 288 if (this.valueState == VALUE_UNPARSED) { 289 doParse(); 290 } 291 292 if (this.valueState >= VALUE_VALIDATED) { 294 this.valueState = VALUE_PARSED; 295 } 296 297 if (this.valueState == VALUE_PARSED) { 298 doValidate(); 299 this.valueState = VALUE_DISPLAY_VALIDATION; 300 if (this.validationError != null) { 301 getForm().addWidgetUpdate(this); 302 } 303 } else if (this.valueState == VALUE_PARSE_ERROR) { 304 this.valueState = VALUE_DISPLAY_PARSE_ERROR; 305 getForm().addWidgetUpdate(this); 306 } 307 308 this.wasValid = this.validationError == null; 309 return this.wasValid; 310 } 311 312 321 private void doParse() { 322 if (this.valueState != VALUE_UNPARSED) { 323 throw new IllegalStateException ("Field is not in UNPARSED state (" + this.valueState + ")"); 324 } 325 326 this.value = null; 328 this.validationError = null; 329 330 if (this.enteredValue != null) { 331 ConversionResult conversionResult = getDatatype().convertFromString(this.enteredValue, getForm().getLocale()); 333 if (conversionResult.isSuccessful()) { 334 this.value = conversionResult.getResult(); 335 this.valueState = VALUE_PARSED; 336 } else { 337 this.validationError = conversionResult.getValidationError(); 339 this.valueState = VALUE_PARSE_ERROR; 341 } 342 } else { 343 this.valueState = VALUE_PARSED; 345 } 346 } 347 348 354 private void doValidate() { 355 if (this.valueState != VALUE_PARSED) { 356 throw new IllegalStateException ("Field is not in PARSED state (" + this.valueState + ")"); 357 } 358 359 this.valueState = VALUE_VALIDATING; 361 362 this.validationError = null; 364 365 try { 366 if (this.value == null && this.required) { 367 this.validationError = new ValidationError(new I18nMessage("general.field-required", FormsConstants.I18N_CATALOGUE)); 369 } else if (!super.validate()) { 370 } else if (this.value != null) { 372 this.validationError = getDatatype().validate(this.value, new ExpressionContextImpl(this)); 374 } 375 } finally { 376 this.valueState = VALUE_VALIDATED; 378 } 379 } 380 381 388 public ValidationError getValidationError() { 389 return this.validationError; 390 } 391 392 398 public void setValidationError(ValidationError error) { 399 if (this.valueState >= VALUE_VALIDATED) { 400 this.valueState = VALUE_DISPLAY_VALIDATION; 401 } 402 403 if (!ObjectUtils.equals(this.validationError, error)) { 404 this.validationError = error; 405 getForm().addWidgetUpdate(this); 406 } 407 } 408 409 public boolean isRequired() { 410 return this.required; 411 } 412 413 public void setRequired(boolean required) { 414 this.required = required; 415 } 416 417 420 public String getXMLElementName() { 421 return FIELD_EL; 422 } 423 424 427 public AttributesImpl getXMLElementAttributes() { 428 AttributesImpl attrs = super.getXMLElementAttributes(); 429 attrs.addCDATAAttribute("required", String.valueOf(isRequired())); 430 return attrs; 431 } 432 433 public void generateItemSaxFragment(ContentHandler contentHandler, Locale locale) throws SAXException { 434 if (locale == null) { 435 locale = getForm().getLocale(); 436 } 437 438 if (enteredValue != null || value != null) { 439 contentHandler.startElement(FormsConstants.INSTANCE_NS, VALUE_EL, FormsConstants.INSTANCE_PREFIX_COLON + VALUE_EL, XMLUtils.EMPTY_ATTRIBUTES); 440 String stringValue; 441 if (value != null) { 442 stringValue = getDatatype().convertToString(value, locale); 443 } else { 444 stringValue = enteredValue; 445 } 446 contentHandler.characters(stringValue.toCharArray(), 0, stringValue.length()); 447 contentHandler.endElement(FormsConstants.INSTANCE_NS, VALUE_EL, FormsConstants.INSTANCE_PREFIX_COLON + VALUE_EL); 448 } 449 450 if (validationError != null && (this.valueState == VALUE_DISPLAY_VALIDATION || this.valueState == VALUE_DISPLAY_PARSE_ERROR)) { 452 contentHandler.startElement(FormsConstants.INSTANCE_NS, VALIDATION_MSG_EL, FormsConstants.INSTANCE_PREFIX_COLON + VALIDATION_MSG_EL, XMLUtils.EMPTY_ATTRIBUTES); 453 validationError.generateSaxFragment(contentHandler); 454 contentHandler.endElement(FormsConstants.INSTANCE_NS, VALIDATION_MSG_EL, FormsConstants.INSTANCE_PREFIX_COLON + VALIDATION_MSG_EL); 455 } 456 457 if (selectionList != null) { 459 selectionList.generateSaxFragment(contentHandler, locale); 460 } 461 462 fieldDefinition.getDatatype().generateSaxFragment(contentHandler, locale); 464 } 465 466 467 471 public void setSelectionList(SelectionList selectionList) { 472 if (selectionList != null && 473 selectionList.getDatatype() != null && 474 selectionList.getDatatype() != getDatatype()) { 475 throw new RuntimeException ("Tried to assign a SelectionList that is not associated with this widget's datatype."); 476 } 477 this.selectionList = selectionList; 478 getForm().addWidgetUpdate(this); 479 } 480 481 490 public void setSelectionList(String uri) { 491 setSelectionList(getFieldDefinition().buildSelectionList(uri)); 492 } 493 494 510 public void setSelectionList(Object model, String valuePath, String labelPath) { 511 setSelectionList(getFieldDefinition().buildSelectionListFromModel(model, valuePath, labelPath)); 512 } 513 514 public SelectionList getSuggestionList() { 515 return getFieldDefinition().getSuggestionList(); 516 } 517 518 public Datatype getDatatype() { 519 return getFieldDefinition().getDatatype(); 520 } 521 522 527 public void addValueChangedListener(ValueChangedListener listener) { 528 this.listener = WidgetEventMulticaster.add(this.listener, listener); 529 } 530 531 public void removeValueChangedListener(ValueChangedListener listener) { 532 this.listener = WidgetEventMulticaster.remove(this.listener, listener); 533 } 534 535 public boolean hasValueChangedListeners() { 536 return this.listener != null; 537 } 538 539 public void broadcastEvent(WidgetEvent event) { 540 if (event instanceof ValueChangedEvent) { 541 if (this.listener != null) { 542 this.listener.valueChanged((ValueChangedEvent)event); 543 } 544 } else { 545 super.broadcastEvent(event); 547 } 548 } 549 } 550 | Popular Tags |