1 18 package org.apache.beehive.netui.tags.databinding.repeater; 19 20 import javax.servlet.jsp.JspException ; 21 import javax.servlet.jsp.tagext.*; 22 import java.util.Iterator ; 23 import java.util.List ; 24 import java.util.Collections ; 25 26 import org.apache.beehive.netui.script.common.DataAccessProviderStack; 27 import org.apache.beehive.netui.script.common.IDataAccessProvider; 28 import org.apache.beehive.netui.tags.AbstractClassicTag; 29 import org.apache.beehive.netui.tags.ExpressionHandling; 30 import org.apache.beehive.netui.tags.databinding.repeater.pad.PadContext; 31 import org.apache.beehive.netui.util.Bundle; 32 import org.apache.beehive.netui.util.exception.LocalizedUnsupportedOperationException; 33 import org.apache.beehive.netui.util.internal.InternalStringBuilder; 34 import org.apache.beehive.netui.util.iterator.IteratorFactory; 35 import org.apache.beehive.netui.util.logging.Logger; 36 37 161 public class Repeater 162 extends AbstractClassicTag 163 implements IDataAccessProvider, TryCatchFinally { 164 165 private static final Logger LOGGER = Logger.getInstance(Repeater.class); 166 167 170 public static final int INIT = 0; 171 172 176 public static final int HEADER = 1; 177 178 183 public static final int ITEM = 2; 184 185 189 public static final int FOOTER = 3; 190 191 194 public static final int END = 4; 195 196 private boolean _ignoreNulls = false; 197 private boolean _haveKids = false; 198 private boolean _containerInPageContext = false; 199 private int _currentIndex = -1; 200 private int _renderedItems = 0; 201 private int _renderState = INIT; 202 private Object _defaultText = null; 203 private Object _currentItem = null; 204 private String _dataSource = null; 205 private Iterator _iterator = null; 206 private PadContext _padContext = null; 207 private InternalStringBuilder _contentBuffer = null; 208 209 215 public String getTagName() { 216 return "Repeater"; 217 } 218 219 229 public void setIgnoreNulls(boolean ignoreNulls) { 230 _ignoreNulls = ignoreNulls; 231 } 232 233 236 public void setPadContext(PadContext padContext) { 237 if(_padContext == null) 238 _padContext = padContext; 239 240 LOGGER.debug("Repeater has a padContext with text: " + _padContext); 241 242 return; 243 } 244 245 255 public void setDefaultText(Object defaultText) { 256 _defaultText = defaultText; 257 } 258 259 269 public int getCurrentIndex() { 270 return _currentIndex; 271 } 272 273 283 public Object getCurrentItem() { 284 return _currentItem; 285 } 286 287 294 public Object getCurrentMetadata() { 295 LocalizedUnsupportedOperationException uoe = 296 new LocalizedUnsupportedOperationException("The " + getTagName() + "does not export metadata for its iterated items."); 297 uoe.setLocalizedMessage(Bundle.getErrorString("Tags_DataAccessProvider_metadataUnsupported", new Object []{getTagName()})); 298 throw uoe; 299 } 300 301 311 public IDataAccessProvider getProviderParent() { 312 IDataAccessProvider dap = (IDataAccessProvider)SimpleTagSupport.findAncestorWithClass(this, IDataAccessProvider.class); 313 return dap; 314 } 315 316 323 public int getRenderState() { 324 return _renderState; 325 } 326 327 335 public void addContent(String content) { 336 if(_contentBuffer == null) { 337 int size = (content != null ? (5 * content.length()) : 1024); 338 _contentBuffer = new InternalStringBuilder(size); 339 } 340 341 _contentBuffer.append(content); 342 } 343 344 350 public void registerChildTag(RepeaterComponent repeaterComponent) { 351 _haveKids = true; 352 } 353 354 359 public int doStartTag() 360 throws JspException { 361 Object source = evaluateDataSource(); 362 363 if(hasErrors()) 365 return SKIP_BODY; 366 367 _renderState = INIT; 368 369 boolean empty = false; 370 if(source != null) { 371 _iterator = IteratorFactory.createIterator(source); 372 if(_iterator == null) { 373 LOGGER.warn(Bundle.getString("Tags_Repeater_nullIterator")); 374 _iterator = Collections.EMPTY_LIST.iterator(); 375 } 376 377 if(_iterator.hasNext()) { 378 _currentIndex = 0; 379 _currentItem = _iterator.next(); 380 381 if(_ignoreNulls && _currentItem == null) { 382 390 advanceToNonNullItem(); 391 392 396 if(_currentItem == null) 397 empty = true; 398 } 399 } 400 401 else empty = true; 402 } 403 404 else { 405 _iterator = Collections.EMPTY_LIST.iterator(); 406 empty = true; 407 } 408 409 if(empty) { 410 411 if(_defaultText != null) 412 addContent(_defaultText.toString()); 413 return SKIP_BODY; 414 } 415 else { 416 DataAccessProviderStack.addDataAccessProvider(this, pageContext); 417 _containerInPageContext = true; 418 return EVAL_BODY_BUFFERED; 419 } 420 } 421 422 429 public int doAfterBody() { 430 431 if(hasErrors()) 432 return SKIP_BODY; 433 434 LOGGER.debug("structured repeater: " + _haveKids + " render state: " + renderStateToString(_renderState)); 435 436 440 if(_haveKids) 441 return renderStructured(); 442 446 else { 447 if(bodyContent != null) { 448 addContent(bodyContent.getString()); 449 bodyContent.clearBody(); 450 } 451 452 if(_iterator.hasNext()) { 453 _currentIndex++; 454 _currentItem = _iterator.next(); 455 456 if(_ignoreNulls && _currentItem == null) { 457 advanceToNonNullItem(); 458 459 460 if(_currentItem == null) 461 return SKIP_BODY; 462 } 463 464 465 return EVAL_BODY_AGAIN; 466 } 467 468 else return SKIP_BODY; 469 } 470 } 471 472 477 public int doEndTag() 478 throws JspException { 479 480 if(hasErrors()) 481 reportErrors(); 482 else if(_contentBuffer != null) 483 write(_contentBuffer.toString()); 484 485 return EVAL_PAGE; 486 } 487 488 public void doFinally() { 489 localRelease(); 490 } 491 492 public void doCatch(Throwable t) 493 throws Throwable { 494 throw t; 495 } 496 497 500 protected void localRelease() { 501 super.localRelease(); 502 _currentItem = null; 503 _currentIndex = -1; 504 _iterator = null; 505 _defaultText = null; 506 _renderState = INIT; 507 _haveKids = false; 508 _contentBuffer = null; 509 _padContext = null; 510 _ignoreNulls = false; 511 _renderedItems = 0; 512 if(_containerInPageContext) { 513 DataAccessProviderStack.removeDataAccessProvider(pageContext); 514 _containerInPageContext = false; 515 } 516 } 517 518 527 528 private int renderStructured() { 529 if(LOGGER.isDebugEnabled() && _padContext != null) 530 LOGGER.debug("\ncurrentIndex: " + _currentIndex + "\n" + 531 "checkMaxRepeat: " + _padContext.checkMaxRepeat(_currentIndex) + "\n" + 532 "checkMinRepeat: " + _padContext.checkMinRepeat(_currentIndex) + "\n"); 533 534 if(_renderState == INIT) { 535 _renderState = HEADER; 536 return EVAL_BODY_AGAIN; 537 } 538 539 if(_renderState == HEADER) { 540 assert _renderedItems == 0; 541 542 543 if(_padContext != null && _padContext.checkMaxRepeat(_renderedItems)) { 544 _renderState = FOOTER; 545 return EVAL_BODY_AGAIN; 546 } 547 548 if(_currentItem == null && _ignoreNulls) { 549 advanceToNonNullItem(); 550 551 552 if(_currentItem == null) { 553 doPadding(); 554 _renderState = FOOTER; 556 } 557 558 else _renderState = ITEM; 559 } 560 561 else _renderState = ITEM; 562 563 return EVAL_BODY_AGAIN; 564 } 565 566 if(_renderState == ITEM) { 567 _renderedItems++; 568 569 570 if(_iterator.hasNext() && (_padContext == null || (_padContext != null && !_padContext.checkMaxRepeat(_renderedItems)))) { 571 _currentIndex++; 572 _currentItem = _iterator.next(); 573 574 if(_ignoreNulls && _currentItem == null) { 575 advanceToNonNullItem(); 576 577 578 if(_currentItem == null) { 579 doPadding(); 580 581 582 _renderState = FOOTER; 583 return EVAL_BODY_AGAIN; 584 } 585 } 586 587 588 return EVAL_BODY_AGAIN; 589 } 590 598 else { 599 doPadding(); 600 601 _renderState = FOOTER; 602 return EVAL_BODY_AGAIN; 603 } 604 } 605 606 if(_renderState == FOOTER) { 607 _renderState = END; 608 return SKIP_BODY; 609 } 610 611 return SKIP_BODY; 612 } 613 614 636 private final void advanceToNonNullItem() { 637 assert _iterator != null; 638 assert _currentItem == null; 639 640 while(_iterator.hasNext() && _currentItem == null) { 641 _currentItem = _iterator.next(); 642 _currentIndex++; 643 } 644 } 645 646 652 private final void doPadding() { 653 if(_padContext != null && !_padContext.checkMinRepeat(_renderedItems)) { 654 658 _currentItem = null; 659 660 for(int i = _renderedItems; !_padContext.checkMinRepeat(i); i++) { 661 _currentIndex++; 662 addContent(_padContext.getPadText()); 663 } 664 } 665 } 666 667 670 private static final String renderStateToString(int state) { 671 switch(state) { 672 case INIT: 673 return "INIT"; 674 case HEADER: 675 return "HEADER"; 676 case ITEM: 677 return "ITEM"; 678 case FOOTER: 679 return "FOOTER"; 680 case END: 681 return "END"; 682 default: 683 return "INVALID STATE"; 684 } 685 } 686 687 693 protected List getNamingChain() { 694 return AbstractClassicTag.DefaultNamingChain; 695 } 696 697 729 public void setDataSource(String dataSource) { 730 _dataSource = dataSource; 731 } 732 733 737 public String getDataSource() { 738 return "{" + _dataSource + "}"; 739 } 740 741 746 private Object evaluateDataSource() 747 throws JspException { 748 ExpressionHandling expr = new ExpressionHandling(this); 749 String dataSource = getDataSource(); 750 String ds = expr.ensureValidExpression(dataSource, "dataSource", "DataSourceError"); 751 if (ds == null) 752 return null; 753 754 755 return expr.evaluateExpression(dataSource, "dataSource", pageContext); 756 } 757 } 758 | Popular Tags |