1 15 package org.apache.tapestry.form; 16 17 import java.util.ArrayList ; 18 import java.util.Arrays ; 19 import java.util.Collections ; 20 import java.util.HashMap ; 21 import java.util.HashSet ; 22 import java.util.Iterator ; 23 import java.util.List ; 24 import java.util.Map ; 25 import java.util.Set ; 26 27 import org.apache.hivemind.ApplicationRuntimeException; 28 import org.apache.hivemind.HiveMind; 29 import org.apache.hivemind.Location; 30 import org.apache.hivemind.Resource; 31 import org.apache.hivemind.util.ClasspathResource; 32 import org.apache.hivemind.util.Defense; 33 import org.apache.tapestry.IComponent; 34 import org.apache.tapestry.IForm; 35 import org.apache.tapestry.IMarkupWriter; 36 import org.apache.tapestry.IRender; 37 import org.apache.tapestry.IRequestCycle; 38 import org.apache.tapestry.NestedMarkupWriter; 39 import org.apache.tapestry.PageRenderSupport; 40 import org.apache.tapestry.StaleLinkException; 41 import org.apache.tapestry.Tapestry; 42 import org.apache.tapestry.TapestryUtils; 43 import org.apache.tapestry.engine.ILink; 44 import org.apache.tapestry.services.ServiceConstants; 45 import org.apache.tapestry.util.IdAllocator; 46 47 53 public class FormSupportImpl implements FormSupport 54 { 55 60 61 public static final String FORM_IDS = "formids"; 62 63 68 69 public static final String RESERVED_FORM_IDS = "reservedids"; 70 71 75 76 public static final String SUBMIT_MODE = "submitmode"; 77 78 public static final String SCRIPT = "/org/apache/tapestry/form/Form.js"; 79 80 private final static Set _standardReservedIds; 81 82 static 83 { 84 Set set = new HashSet (); 85 86 set.addAll(Arrays.asList(ServiceConstants.RESERVED_IDS)); 87 set.add(FORM_IDS); 88 set.add(RESERVED_FORM_IDS); 89 set.add(SUBMIT_MODE); 90 91 _standardReservedIds = Collections.unmodifiableSet(set); 92 } 93 94 private final static Set _submitModes; 95 96 static 97 { 98 Set set = new HashSet (); 99 set.add(FormConstants.SUBMIT_CANCEL); 100 set.add(FormConstants.SUBMIT_NORMAL); 101 set.add(FormConstants.SUBMIT_REFRESH); 102 103 _submitModes = Collections.unmodifiableSet(set); 104 } 105 106 110 111 private int _allocatedIdIndex; 112 113 117 118 private final List _allocatedIds = new ArrayList (); 119 120 private final IRequestCycle _cycle; 121 122 private final IdAllocator _elementIdAllocator = new IdAllocator(); 123 124 private String _encodingType; 125 126 private final List _deferredRunnables = new ArrayList (); 127 128 131 132 private final Map _prerenderMap = new HashMap (); 133 134 139 140 private Map _events; 141 142 private final IForm _form; 143 144 private final List _hiddenValues = new ArrayList (); 145 146 private boolean _rewinding; 147 148 private final IMarkupWriter _writer; 149 150 private final Resource _script; 151 152 public FormSupportImpl(IMarkupWriter writer, IRequestCycle cycle, IForm form) 153 { 154 Defense.notNull(writer, "writer"); 155 Defense.notNull(cycle, "cycle"); 156 Defense.notNull(form, "form"); 157 158 _writer = writer; 159 _cycle = cycle; 160 _form = form; 161 162 _rewinding = cycle.isRewound(form); 163 _allocatedIdIndex = 0; 164 165 _script = new ClasspathResource(cycle.getEngine().getClassResolver(), SCRIPT); 166 } 167 168 171 172 public void addEventHandler(FormEventType type, String functionName) 173 { 174 if (_events == null) 175 _events = new HashMap (); 176 177 List functionList = (List ) _events.get(type); 178 179 183 if (functionList == null) 184 { 185 functionList = new ArrayList (); 186 187 _events.put(type, functionList); 188 } 189 190 functionList.add(functionName); 191 } 192 193 201 202 private void addHiddenFieldsForLinkParameters(ILink link) 203 { 204 String [] names = link.getParameterNames(); 205 int count = Tapestry.size(names); 206 207 StringBuffer extraIds = new StringBuffer (); 208 String sep = ""; 209 boolean hasExtra = false; 210 211 216 preallocateReservedIds(); 217 218 for (int i = 0; i < count; i++) 219 { 220 String name = names[i]; 221 222 224 if (!_standardReservedIds.contains(name)) 225 { 226 _elementIdAllocator.allocateId(name); 227 228 extraIds.append(sep); 229 extraIds.append(name); 230 231 sep = ","; 232 hasExtra = true; 233 } 234 235 addHiddenFieldsForLinkParameter(link, name); 236 } 237 238 if (hasExtra) 239 addHiddenValue(RESERVED_FORM_IDS, extraIds.toString()); 240 } 241 242 public void addHiddenValue(String name, String value) 243 { 244 _hiddenValues.add(new HiddenFieldData(name, value)); 245 } 246 247 public void addHiddenValue(String name, String id, String value) 248 { 249 _hiddenValues.add(new HiddenFieldData(name, id, value)); 250 } 251 252 257 258 private String buildAllocatedIdList() 259 { 260 StringBuffer buffer = new StringBuffer (); 261 int count = _allocatedIds.size(); 262 263 for (int i = 0; i < count; i++) 264 { 265 if (i > 0) 266 buffer.append(','); 267 268 buffer.append(_allocatedIds.get(i)); 269 } 270 271 return buffer.toString(); 272 } 273 274 private void emitEventHandlers(String eventManager) 275 { 276 if (_events == null || _events.isEmpty()) 277 return; 278 279 PageRenderSupport pageRenderSupport = TapestryUtils.getPageRenderSupport(_cycle, _form); 280 281 StringBuffer buffer = new StringBuffer (); 282 283 Iterator i = _events.entrySet().iterator(); 284 285 while (i.hasNext()) 286 { 287 Map.Entry entry = (Map.Entry ) i.next(); 288 FormEventType type = (FormEventType) entry.getKey(); 289 Object value = entry.getValue(); 290 291 buffer.append(eventManager); 292 buffer.append("."); 293 buffer.append(type.getAddListenerMethodName()); 294 295 297 buffer.append("(function (event)\n{"); 298 299 List l = (List ) value; 300 int count = l.size(); 301 302 for (int j = 0; j < count; j++) 303 { 304 String functionName = (String ) l.get(j); 305 306 if (j > 0) 307 { 308 buffer.append(";"); 309 } 310 311 buffer.append("\n "); 312 buffer.append(functionName); 313 314 317 if (!functionName.endsWith(")")) 318 { 319 buffer.append("()"); 320 } 321 } 322 323 buffer.append(";\n});\n"); 324 } 325 326 pageRenderSupport.addInitializationScript(buffer.toString()); 327 } 328 329 337 338 public String getElementId(IFormComponent component) 339 { 340 return getElementId(component, component.getId()); 341 } 342 343 351 352 public String getElementId(IFormComponent component, String baseId) 353 { 354 String result = _elementIdAllocator.allocateId(baseId); 355 356 if (_rewinding) 357 { 358 if (_allocatedIdIndex >= _allocatedIds.size()) 359 { 360 throw new StaleLinkException(FormMessages.formTooManyIds(_form, _allocatedIds 361 .size(), component), component); 362 } 363 364 String expected = (String ) _allocatedIds.get(_allocatedIdIndex); 365 366 if (!result.equals(expected)) 367 throw new StaleLinkException(FormMessages.formIdMismatch( 368 _form, 369 _allocatedIdIndex, 370 expected, 371 result, 372 component), component); 373 } 374 else 375 { 376 _allocatedIds.add(result); 377 } 378 379 _allocatedIdIndex++; 380 381 component.setName(result); 382 383 return result; 384 } 385 386 public boolean isRewinding() 387 { 388 return _rewinding; 389 } 390 391 private void preallocateReservedIds() 392 { 393 for (int i = 0; i < ServiceConstants.RESERVED_IDS.length; i++) 394 _elementIdAllocator.allocateId(ServiceConstants.RESERVED_IDS[i]); 395 } 396 397 406 407 private void reinitializeIdAllocatorForRewind() 408 { 409 String allocatedFormIds = _cycle.getParameter(FORM_IDS); 410 411 String [] ids = TapestryUtils.split(allocatedFormIds); 412 413 for (int i = 0; i < ids.length; i++) 414 _allocatedIds.add(ids[i]); 415 416 419 preallocateReservedIds(); 420 421 String extraReservedIds = _cycle.getParameter(RESERVED_FORM_IDS); 422 423 ids = TapestryUtils.split(extraReservedIds); 424 425 for (int i = 0; i < ids.length; i++) 426 _elementIdAllocator.allocateId(ids[i]); 427 } 428 429 public void render(String method, IRender informalParametersRenderer, ILink link) 430 { 431 String eventManager = emitEventManagerInitialization(); 432 433 436 addHiddenFieldsForLinkParameters(link); 437 438 441 addHiddenValue(SUBMIT_MODE, null); 442 443 IMarkupWriter nested = _writer.getNestedWriter(); 444 445 _form.renderBody(nested, _cycle); 446 447 runDeferredRunnables(); 448 449 writeTag(_writer, method, link.getURL(null, false)); 450 451 _writer.attribute("name", _form.getName()); 452 453 if (_encodingType != null) 454 _writer.attribute("enctype", _encodingType); 455 456 458 emitEventHandlers(eventManager); 459 460 informalParametersRenderer.render(_writer, _cycle); 461 462 464 _writer.println(); 465 466 writeHiddenField(FORM_IDS, null, buildAllocatedIdList()); 467 writeHiddenFields(); 468 469 471 nested.close(); 472 473 475 _writer.end(); 476 } 477 478 482 protected String emitEventManagerInitialization() 483 { 484 PageRenderSupport pageRenderSupport = TapestryUtils.getOptionalPageRenderSupport(_cycle); 485 486 if (pageRenderSupport == null) 487 return null; 488 489 pageRenderSupport.addExternalScript(_script); 490 491 String formName = _form.getName(); 492 493 String eventManager = formName + "_events"; 494 495 pageRenderSupport.addInitializationScript("var " + eventManager 496 + " = new FormEventManager(document." + formName + ");"); 497 498 return eventManager; 499 } 500 501 public String rewind() 502 { 503 _form.getDelegate().clear(); 504 505 String mode = _cycle.getParameter(SUBMIT_MODE); 506 507 509 if (FormConstants.SUBMIT_CANCEL.equals(mode)) 510 return mode; 511 512 reinitializeIdAllocatorForRewind(); 513 514 _form.renderBody(_writer, _cycle); 515 516 int expected = _allocatedIds.size(); 517 518 522 if (_allocatedIdIndex < expected) 523 { 524 String nextExpectedId = (String ) _allocatedIds.get(_allocatedIdIndex); 525 526 throw new StaleLinkException(FormMessages.formTooFewIds(_form, expected 527 - _allocatedIdIndex, nextExpectedId), _form); 528 } 529 530 runDeferredRunnables(); 531 532 if (_submitModes.contains(mode)) 533 return mode; 534 535 538 return FormConstants.SUBMIT_NORMAL; 539 540 } 541 542 private void runDeferredRunnables() 543 { 544 Iterator i = _deferredRunnables.iterator(); 545 while (i.hasNext()) 546 { 547 Runnable r = (Runnable ) i.next(); 548 549 r.run(); 550 } 551 } 552 553 public void setEncodingType(String encodingType) 554 { 555 556 if (_encodingType != null && !_encodingType.equals(encodingType)) 557 throw new ApplicationRuntimeException(FormMessages.encodingTypeContention( 558 _form, 559 _encodingType, 560 encodingType), _form, null, null); 561 562 _encodingType = encodingType; 563 } 564 565 protected void writeHiddenField(IMarkupWriter writer, String name, String id, String value) 566 { 567 writer.beginEmpty("input"); 568 writer.attribute("type", "hidden"); 569 writer.attribute("name", name); 570 571 if (HiveMind.isNonBlank(id)) 572 writer.attribute("id", id); 573 574 writer.attribute("value", value == null ? "" : value); 575 writer.println(); 576 } 577 578 private void writeHiddenField(String name, String id, String value) 579 { 580 writeHiddenField(_writer, name, id, value); 581 } 582 583 587 588 private void writeHiddenFields() 589 { 590 Iterator i = _hiddenValues.iterator(); 591 while (i.hasNext()) 592 { 593 HiddenFieldData data = (HiddenFieldData) i.next(); 594 595 writeHiddenField(data.getName(), data.getId(), data.getValue()); 596 } 597 } 598 599 private void addHiddenFieldsForLinkParameter(ILink link, String parameterName) 600 { 601 String [] values = link.getParameterValues(parameterName); 602 603 605 if (values == null) 606 return; 607 608 for (int i = 0; i < values.length; i++) 609 { 610 addHiddenValue(parameterName, values[i]); 611 } 612 } 613 614 protected void writeTag(IMarkupWriter writer, String method, String url) 615 { 616 writer.begin("form"); 617 writer.attribute("method", method); 618 writer.attribute("action", url); 619 } 620 621 public void prerenderField(IMarkupWriter writer, IComponent field, Location location) 622 { 623 Defense.notNull(writer, "writer"); 624 Defense.notNull(field, "field"); 625 626 String key = field.getExtendedId(); 627 628 if (_prerenderMap.containsKey(key)) 629 throw new ApplicationRuntimeException(FormMessages.fieldAlreadyPrerendered(field), 630 location, null); 631 632 NestedMarkupWriter nested = writer.getNestedWriter(); 633 634 field.render(nested, _cycle); 635 636 _prerenderMap.put(key, nested.getBuffer()); 637 } 638 639 public boolean wasPrerendered(IMarkupWriter writer, IComponent field) 640 { 641 String key = field.getExtendedId(); 642 643 String buffer = (String ) _prerenderMap.get(key); 644 645 if (buffer == null) 646 return false; 647 648 writer.printRaw(buffer); 649 650 _prerenderMap.remove(key); 651 652 return true; 653 } 654 655 public void addDeferredRunnable(Runnable runnable) 656 { 657 Defense.notNull(runnable, "runnable"); 658 659 _deferredRunnables.add(runnable); 660 } 661 } | Popular Tags |