001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.wicket.markup; 018 019import java.lang.ref.WeakReference; 020import java.util.ArrayList; 021import java.util.Collections; 022import java.util.HashMap; 023import java.util.Iterator; 024import java.util.List; 025import java.util.Map; 026 027import org.apache.wicket.Component; 028import org.apache.wicket.MarkupContainer; 029import org.apache.wicket.behavior.Behavior; 030import org.apache.wicket.markup.parser.XmlTag; 031import org.apache.wicket.markup.parser.XmlTag.TagType; 032import org.apache.wicket.markup.parser.filter.HtmlHandler; 033import org.apache.wicket.request.Response; 034import org.apache.wicket.util.lang.Args; 035import org.apache.wicket.util.lang.Generics; 036import org.apache.wicket.util.string.StringValue; 037import org.apache.wicket.util.string.Strings; 038import org.apache.wicket.util.value.IValueMap; 039import org.slf4j.Logger; 040import org.slf4j.LoggerFactory; 041 042 043/** 044 * A subclass of MarkupElement which represents a "significant" markup tag, such as a component open 045 * tag. Insignificant markup tags (those which are merely concerned with markup formatting 046 * operations and do not denote components or component nesting) are coalesced into instances of 047 * RawMarkup (also a subclass of MarkupElement). 048 * 049 * @author Jonathan Locke 050 */ 051public class ComponentTag extends MarkupElement 052{ 053 /** 054 * Factory that creates component during markup root container's initialization. These 055 * components get queued, which allows other components to be dequeued under these auto 056 * components. 057 * 058 * @author igor 059 */ 060 public interface IAutoComponentFactory 061 { 062 /** 063 * Creates a new instance of auto component to be queued 064 * 065 * @param container 066 * The component that will become a parent of the newly created auto component 067 * @param tag 068 * The markup element for the newly created auto component 069 */ 070 Component newComponent(MarkupContainer container, ComponentTag tag); 071 } 072 073 074 /** Log. */ 075 private static final Logger log = LoggerFactory.getLogger(ComponentTag.class); 076 077 /** True if a href attribute is available and autolinking is on */ 078 private final static int AUTOLINK = 0x0001; 079 080 /** True, if attributes have been modified or added */ 081 private final static int MODIFIED = 0x0002; 082 083 /** If true, then the MarkupParser will ignore (remove) it. Temporary working variable */ 084 private final static int IGNORE = 0x0004; 085 086 /** If true, then the tag contain an automatically created wicket id */ 087 private final static int AUTO_COMPONENT = 0x0008; 088 089 /** Some HTML tags are allow to have no close tag, e.g. 'br' */ 090 private final static int NO_CLOSE_TAG = 0x0010; 091 092 /** Render the tag as RawMarkup even if no Component can be found */ 093 public final static int RENDER_RAW = 0x0020; 094 095 /** If true, the current tag contains a child or a descendant with the "wicket:id" attribute */ 096 public final static int CONTAINS_WICKET_ID = 0x0040; 097 098 /** If close tag, than reference to the corresponding open tag */ 099 private ComponentTag openTag; 100 101 /** The underlying xml tag */ 102 protected final XmlTag xmlTag; 103 104 /** Boolean flags. See above */ 105 private int flags = 0; 106 107 /** 108 * By default this is equal to the wicket:id="xxx" attribute value, but may be provided e.g. for 109 * auto-tags 110 */ 111 private String id; 112 113 /** 114 * In case of inherited markup, the base and the extended markups are merged and the information 115 * about the tags origin is lost. In some cases like wicket:head and wicket:link this 116 * information however is required. 117 */ 118 private WeakReference<Class<? extends Component>> markupClassRef = null; 119 120 /** added behaviors */ 121 private List<Behavior> behaviors; 122 123 /** Filters and Handlers may add their own attributes to the tag */ 124 private Map<String, Object> userData; 125 126 private IAutoComponentFactory autoComponentFactory; 127 128 /** 129 * Automatically create a XmlTag, assign the name and the type, and construct a ComponentTag 130 * based on this XmlTag. 131 * 132 * @param name 133 * The name of html tag 134 * @param type 135 * The type of tag 136 */ 137 public ComponentTag(final String name, final XmlTag.TagType type) 138 { 139 final XmlTag tag = new XmlTag(); 140 tag.setName(name); 141 tag.setType(type); 142 xmlTag = tag; 143 } 144 145 /** 146 * Construct. 147 * 148 * @param tag 149 * The underlying xml tag 150 */ 151 public ComponentTag(final XmlTag tag) 152 { 153 super(); 154 xmlTag = tag; 155 } 156 157 /** 158 * Constructor 159 * 160 * @param tag 161 * The ComponentTag tag which this wicket tag is based upon. 162 */ 163 public ComponentTag(final ComponentTag tag) 164 { 165 this(tag.getXmlTag()); 166 tag.copyPropertiesTo(this); 167 } 168 169 /** 170 * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT USE IT! 171 * 172 * @param flag 173 * The flag to set 174 * @param set 175 * True to turn the flag on, false to turn it off 176 */ 177 public final void setFlag(final int flag, final boolean set) 178 { 179 if (set) 180 { 181 flags |= flag; 182 } 183 else 184 { 185 flags &= ~flag; 186 } 187 } 188 189 /** 190 * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT USE IT! 191 * 192 * @param flag 193 * The flag to test 194 * @return True if the flag is set 195 */ 196 public final boolean getFlag(final int flag) 197 { 198 return (flags & flag) != 0; 199 } 200 201 /** 202 * Adds a behavior to this component tag. 203 * 204 * @param behavior 205 */ 206 public final void addBehavior(final Behavior behavior) 207 { 208 Args.notNull(behavior, "behavior"); 209 210 if (behaviors == null) 211 { 212 behaviors = Generics.newArrayList(); 213 } 214 behaviors.add(behavior); 215 } 216 217 /** 218 * @return true if this tag has any behaviors added, false otherwise 219 */ 220 public final boolean hasBehaviors() 221 { 222 return behaviors != null; 223 } 224 225 /** 226 * @return read only iterator over added behaviors 227 */ 228 // TODO change to return unmodifiable list which will never be null. See Component.getBehavior 229 public final Iterator<? extends Behavior> getBehaviors() 230 { 231 if (behaviors == null) 232 { 233 List<Behavior> lst = Collections.emptyList(); 234 return lst.iterator(); 235 } 236 237 return Collections.unmodifiableCollection(behaviors).iterator(); 238 } 239 240 /** 241 * Gets whether this tag closes the provided open tag. 242 * 243 * @param open 244 * The open tag 245 * @return True if this tag closes the given open tag 246 */ 247 @Override 248 public final boolean closes(final MarkupElement open) 249 { 250 if (open instanceof ComponentTag) 251 { 252 return (openTag == open) || getXmlTag().closes(((ComponentTag)open).getXmlTag()); 253 } 254 255 return false; 256 } 257 258 /** 259 * If autolink is set to true, href attributes will automatically be converted into Wicket 260 * bookmarkable URLs. 261 * 262 * @param autolink 263 * enable/disable automatic href conversion 264 */ 265 public final void enableAutolink(final boolean autolink) 266 { 267 setFlag(AUTOLINK, autolink); 268 } 269 270 /** 271 * @see org.apache.wicket.markup.parser.XmlTag#getAttributes() 272 * @return The tag#s attributes 273 */ 274 public final IValueMap getAttributes() 275 { 276 return xmlTag.getAttributes(); 277 } 278 279 /** 280 * A convenient method. The same as getAttributes().getString(name) 281 * 282 * @param name 283 * @return The attributes value 284 */ 285 public final String getAttribute(String name) 286 { 287 return xmlTag.getAttributes().getString(name); 288 } 289 290 /** 291 * Get the tag's component id 292 * 293 * @return The component id attribute of this tag 294 */ 295 public final String getId() 296 { 297 return id; 298 } 299 300 /** 301 * Gets the length of the tag in characters. 302 * 303 * @return The tag's length 304 */ 305 public final int getLength() 306 { 307 return xmlTag.getLength(); 308 } 309 310 /** 311 * @return The tag's name 312 */ 313 public final String getName() 314 { 315 return xmlTag.getName(); 316 } 317 318 /** 319 * @return The tag's namespace 320 */ 321 public final String getNamespace() 322 { 323 return xmlTag.getNamespace(); 324 } 325 326 /** 327 * If set, return the corresponding open tag (ComponentTag). 328 * 329 * @return The corresponding open tag 330 */ 331 public final ComponentTag getOpenTag() 332 { 333 return openTag; 334 } 335 336 /** 337 * @see org.apache.wicket.markup.parser.XmlTag#getPos() 338 * @return Tag location (index in input string) 339 */ 340 public final int getPos() 341 { 342 return xmlTag.getPos(); 343 } 344 345 /** 346 * @return the tag type (OPEN, CLOSE or OPEN_CLOSE). 347 */ 348 public final TagType getType() 349 { 350 return xmlTag.getType(); 351 } 352 353 /** 354 * True if autolink is enabled and the tag contains a href attribute. 355 * 356 * @return True, if the href contained should automatically be converted 357 */ 358 public final boolean isAutolinkEnabled() 359 { 360 return getFlag(AUTOLINK); 361 } 362 363 /** 364 * @see org.apache.wicket.markup.parser.XmlTag#isClose() 365 * @return True if this tag is a close tag 366 */ 367 public final boolean isClose() 368 { 369 return xmlTag.isClose(); 370 } 371 372 /** 373 * @see org.apache.wicket.markup.parser.XmlTag#isOpen() 374 * @return True if this tag is an open tag 375 */ 376 public final boolean isOpen() 377 { 378 return xmlTag.isOpen(); 379 } 380 381 /** 382 * @param id 383 * Required component id 384 * @return True if this tag is an open tag with the given component name 385 * @see org.apache.wicket.markup.parser.XmlTag#isOpen() 386 */ 387 public final boolean isOpen(String id) 388 { 389 return xmlTag.isOpen() && this.id.equals(id); 390 } 391 392 /** 393 * @see org.apache.wicket.markup.parser.XmlTag#isOpenClose() 394 * @return True if this tag is an open and a close tag 395 */ 396 public final boolean isOpenClose() 397 { 398 return xmlTag.isOpenClose(); 399 } 400 401 /** 402 * @param id 403 * Required component id 404 * @return True if this tag is an openclose tag with the given component id 405 * @see org.apache.wicket.markup.parser.XmlTag#isOpenClose() 406 */ 407 public final boolean isOpenClose(String id) 408 { 409 return xmlTag.isOpenClose() && this.id.equals(id); 410 } 411 412 /** 413 * Makes this tag object immutable by making the attribute map unmodifiable. Immutable tags 414 * cannot be made mutable again. They can only be copied into new mutable tag objects. 415 */ 416 public final void makeImmutable() 417 { 418 xmlTag.makeImmutable(); 419 } 420 421 /** 422 * Gets this tag if it is already mutable, or a mutable copy of this tag if it is immutable. 423 * 424 * @return This tag if it is already mutable, or a mutable copy of this tag if it is immutable. 425 */ 426 public ComponentTag mutable() 427 { 428 if (xmlTag.isMutable()) 429 { 430 return this; 431 } 432 else 433 { 434 ComponentTag tag = new ComponentTag(xmlTag.mutable()); 435 copyPropertiesTo(tag); 436 return tag; 437 } 438 } 439 440 /** 441 * Copies all internal properties from this tag to <code>dest</code>. This is basically cloning 442 * without instance creation. 443 * 444 * @param dest 445 * tag whose properties will be set 446 */ 447 void copyPropertiesTo(final ComponentTag dest) 448 { 449 dest.id = id; 450 dest.flags = flags; 451 dest.autoComponentFactory = autoComponentFactory; 452 453 if (markupClassRef != null) 454 { 455 dest.setMarkupClass(markupClassRef.get()); 456 } 457 if (behaviors != null) 458 { 459 dest.behaviors = new ArrayList<>(behaviors); 460 } 461 if (userData != null) 462 { 463 dest.userData = new HashMap<>(userData); 464 } 465 } 466 467 /** 468 * @see org.apache.wicket.markup.parser.XmlTag#put(String, boolean) 469 * @param key 470 * The key 471 * @param value 472 * The value 473 */ 474 public final void put(final String key, final boolean value) 475 { 476 xmlTag.put(key, value); 477 setModified(true); 478 } 479 480 /** 481 * @see org.apache.wicket.markup.parser.XmlTag#put(String, int) 482 * @param key 483 * The key 484 * @param value 485 * The value 486 */ 487 public final void put(final String key, final int value) 488 { 489 xmlTag.put(key, value); 490 setModified(true); 491 } 492 493 /** 494 * @see org.apache.wicket.markup.parser.XmlTag#put(String, CharSequence) 495 * @param key 496 * The key 497 * @param value 498 * The value 499 */ 500 public final void put(String key, CharSequence value) 501 { 502 checkIdAttribute(key); 503 putInternal(key, value); 504 } 505 506 /** 507 * THIS METHOD IS NOT PART OF THE PUBLIC API, DO NOT CALL IT 508 * 509 * @see org.apache.wicket.markup.parser.XmlTag#put(String, CharSequence) 510 * @param key 511 * The key 512 * @param value 513 * The value 514 */ 515 public final void putInternal(String key, CharSequence value) 516 { 517 xmlTag.put(key, value); 518 setModified(true); 519 } 520 521 /** 522 * @param key 523 */ 524 private void checkIdAttribute(String key) 525 { 526 if ("id".equalsIgnoreCase(key)) 527 { 528 log.warn("Please use component.setMarkupId(String) to change the tag's 'id' attribute."); 529 } 530 } 531 532 /** 533 * Appends specified {@code value} to the attribute 534 * 535 * @param key 536 * The key 537 * @param value 538 * The value 539 * @param separator 540 * The separator used to append the value 541 */ 542 public final void append(String key, CharSequence value, String separator) 543 { 544 String current = getAttribute(key); 545 if (Strings.isEmpty(current)) 546 { 547 xmlTag.put(key, value); 548 } 549 else 550 { 551 xmlTag.put(key, current + separator + value); 552 } 553 554 setModified(true); 555 } 556 557 /** 558 * @see org.apache.wicket.markup.parser.XmlTag#put(String, StringValue) 559 * @param key 560 * The key 561 * @param value 562 * The value 563 */ 564 public final void put(String key, StringValue value) 565 { 566 xmlTag.put(key, value); 567 setModified(true); 568 } 569 570 /** 571 * @see org.apache.wicket.markup.parser.XmlTag#putAll(Map) 572 * @param map 573 * a key/value map 574 */ 575 public final void putAll(final Map<String, Object> map) 576 { 577 xmlTag.putAll(map); 578 setModified(true); 579 } 580 581 /** 582 * @see org.apache.wicket.markup.parser.XmlTag#remove(String) 583 * @param key 584 * The key to remove 585 */ 586 public final void remove(String key) 587 { 588 xmlTag.remove(key); 589 setModified(true); 590 } 591 592 /** 593 * Gets whether this tag does not require a closing tag. 594 * 595 * @return True if this tag does not require a closing tag 596 */ 597 public final boolean requiresCloseTag() 598 { 599 if (getNamespace() == null) 600 { 601 return HtmlHandler.requiresCloseTag(getName()); 602 } 603 else 604 { 605 return HtmlHandler.requiresCloseTag(getNamespace() + ":" + getName()); 606 } 607 } 608 609 /** 610 * Set the component's id. The value is usually taken from the tag's id attribute, e.g. 611 * wicket:id="componentId". 612 * 613 * @param id 614 * The component's id assigned to the tag. 615 */ 616 public final void setId(final String id) 617 { 618 this.id = id; 619 } 620 621 /** 622 * @see org.apache.wicket.markup.parser.XmlTag#setName(String) 623 * @param name 624 * New tag name 625 */ 626 public final void setName(String name) 627 { 628 xmlTag.setName(name); 629 } 630 631 /** 632 * @see org.apache.wicket.markup.parser.XmlTag#setNamespace(String) 633 * @param namespace 634 * New tag name namespace 635 */ 636 public final void setNamespace(String namespace) 637 { 638 xmlTag.setNamespace(namespace); 639 } 640 641 /** 642 * Assuming this is a close tag, assign it's corresponding open tag. 643 * 644 * @param tag 645 * the open-tag 646 * @throws RuntimeException 647 * if 'this' is not a close tag 648 */ 649 public final void setOpenTag(final ComponentTag tag) 650 { 651 openTag = tag; 652 getXmlTag().setOpenTag(tag.getXmlTag()); 653 } 654 655 /** 656 * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL IT. 657 * 658 * @param type 659 * The new type 660 */ 661 public final void setType(final TagType type) 662 { 663 if (type != xmlTag.getType()) 664 { 665 xmlTag.setType(type); 666 setModified(true); 667 } 668 } 669 670 /** 671 * Writes the synthetic close tag for this tag to the response 672 * 673 * @param response 674 * The response to write to 675 */ 676 public final void writeSyntheticCloseTag(Response response) 677 { 678 response.write("</"); 679 if (getNamespace() != null) 680 { 681 response.write(getNamespace()); 682 response.write(":"); 683 } 684 response.write(getName()); 685 response.write(">"); 686 } 687 688 /** 689 * @see org.apache.wicket.markup.MarkupElement#toCharSequence() 690 */ 691 @Override 692 public CharSequence toCharSequence() 693 { 694 return xmlTag.toCharSequence(); 695 } 696 697 /** 698 * Converts this object to a string representation. 699 * 700 * @return String version of this object 701 */ 702 @Override 703 public final String toString() 704 { 705 return toCharSequence().toString(); 706 } 707 708 /** 709 * Write the tag to the response 710 * 711 * @param response 712 * The response to write to 713 * @param stripWicketAttributes 714 * if true, wicket:id are removed from output 715 * @param namespace 716 * Wicket's namespace to use 717 */ 718 public final void writeOutput(final Response response, final boolean stripWicketAttributes, 719 final String namespace) 720 { 721 response.write("<"); 722 723 if (getType() == TagType.CLOSE) 724 { 725 response.write("/"); 726 } 727 728 if (getNamespace() != null) 729 { 730 response.write(getNamespace()); 731 response.write(":"); 732 } 733 734 response.write(getName()); 735 736 String namespacePrefix = null; 737 if (stripWicketAttributes == true) 738 { 739 namespacePrefix = namespace + ":"; 740 } 741 742 if (getAttributes().size() > 0) 743 { 744 for (String key : getAttributes().keySet()) 745 { 746 if (key == null) 747 { 748 continue; 749 } 750 751 if ((namespacePrefix == null) || (key.startsWith(namespacePrefix) == false)) 752 { 753 response.write(" "); 754 response.write(key); 755 CharSequence value = getAttribute(key); 756 757 // attributes without values are possible, e.g.' disabled' 758 if (value != null) 759 { 760 response.write("=\""); 761 value = Strings.escapeMarkup(value); 762 response.write(value); 763 response.write("\""); 764 } 765 } 766 } 767 } 768 769 if (getType() == TagType.OPEN_CLOSE) 770 { 771 response.write("/"); 772 } 773 774 response.write(">"); 775 } 776 777 /** 778 * Converts this object to a string representation including useful information for debugging 779 * 780 * @return String version of this object 781 */ 782 @Override 783 public final String toUserDebugString() 784 { 785 return xmlTag.toUserDebugString(); 786 } 787 788 /** 789 * @return Returns the underlying xml tag. 790 */ 791 public final XmlTag getXmlTag() 792 { 793 return xmlTag; 794 } 795 796 /** 797 * Manually mark the ComponentTag being modified. Flagging the tag being modified does not 798 * happen automatically. 799 * 800 * @param modified 801 */ 802 public final void setModified(final boolean modified) 803 { 804 setFlag(MODIFIED, modified); 805 } 806 807 /** 808 * 809 * @return True, if the component tag has been marked modified 810 */ 811 final boolean isModified() 812 { 813 return getFlag(MODIFIED); 814 } 815 816 /** 817 * 818 * @return True if the HTML tag (e.g. br) has no close tag 819 */ 820 public boolean hasNoCloseTag() 821 { 822 return getFlag(NO_CLOSE_TAG); 823 } 824 825 /** 826 * True if the HTML tag (e.g. br) has no close tag 827 * 828 * @param hasNoCloseTag 829 */ 830 public void setHasNoCloseTag(boolean hasNoCloseTag) 831 { 832 setFlag(NO_CLOSE_TAG, hasNoCloseTag); 833 } 834 835 /** 836 * Sets the flag to indicate if the current tag contains a child 837 * or a descendant with the "wicket:id" attribute. 838 * 839 * @param containsWicketId 840 */ 841 public void setContainsWicketId(boolean containsWicketId) 842 { 843 setFlag(CONTAINS_WICKET_ID, containsWicketId); 844 } 845 846 /** 847 * Says if the current tag contains a child or a descendant with the "wicket:id" attribute. 848 * @return true if the current tag contains a child or a descendant with the "wicket:id" attribute. 849 */ 850 public boolean containsWicketId() 851 { 852 return getFlag(CONTAINS_WICKET_ID); 853 } 854 855 /** 856 * In case of inherited markup, the base and the extended markups are merged and the information 857 * about the tags origin is lost. In some cases like wicket:head and wicket:link this 858 * information however is required. 859 * 860 * @return wicketHeaderClass 861 */ 862 public Class<? extends Component> getMarkupClass() 863 { 864 return (markupClassRef == null ? null : markupClassRef.get()); 865 } 866 867 /** 868 * Set the class of wicket component which contains the wicket:head tag. 869 * 870 * @param <C> 871 * 872 * @param wicketHeaderClass 873 * wicketHeaderClass 874 */ 875 public <C extends Component> void setMarkupClass(Class<C> wicketHeaderClass) 876 { 877 if (wicketHeaderClass == null) 878 { 879 markupClassRef = null; 880 } 881 else 882 { 883 markupClassRef = new WeakReference<Class<? extends Component>>(wicketHeaderClass); 884 } 885 } 886 887 /** 888 * @see org.apache.wicket.markup.MarkupElement#equalTo(org.apache.wicket.markup.MarkupElement) 889 */ 890 @Override 891 public boolean equalTo(final MarkupElement element) 892 { 893 if (element instanceof ComponentTag) 894 { 895 final ComponentTag that = (ComponentTag)element; 896 return getXmlTag().equalTo(that.getXmlTag()); 897 } 898 return false; 899 } 900 901 /** 902 * Gets ignore. 903 * 904 * @return If true than MarkupParser will remove it from the markup 905 */ 906 public boolean isIgnore() 907 { 908 return getFlag(IGNORE); 909 } 910 911 /** 912 * Sets ignore. 913 * 914 * @param ignore 915 * If true than MarkupParser will remove it from the markup 916 */ 917 public void setIgnore(boolean ignore) 918 { 919 setFlag(IGNORE, ignore); 920 } 921 922 /** 923 * @return True, if wicket:id has been automatically created (internal component) 924 */ 925 public boolean isAutoComponentTag() 926 { 927 return getFlag(AUTO_COMPONENT); 928 } 929 930 /** 931 * @param auto 932 * True, if wicket:id has been automatically created (internal component) 933 */ 934 public void setAutoComponentTag(boolean auto) 935 { 936 setFlag(AUTO_COMPONENT, auto); 937 } 938 939 /** 940 * Gets userData. 941 * 942 * @param key 943 * The key to store and retrieve the value 944 * @return userData 945 */ 946 public Object getUserData(final String key) 947 { 948 if (userData == null) 949 { 950 return null; 951 } 952 953 return userData.get(key); 954 } 955 956 /** 957 * Sets userData. 958 * 959 * @param key 960 * The key to store and retrieve the value 961 * @param value 962 * The user specific value to store 963 */ 964 public void setUserData(final String key, final Object value) 965 { 966 if (userData == null) 967 { 968 userData = new HashMap<>(); 969 } 970 userData.put(key, value); 971 } 972 973 /** 974 * For subclasses to override. Gets called just before a Component gets rendered. It is 975 * guaranteed that the markupStream is set on the Component and determineVisibility is not yet 976 * called. 977 * 978 * @param component 979 * The component that is about to be rendered 980 * @param markupStream 981 * The current markup stream 982 */ 983 public void onBeforeRender(final Component component, final MarkupStream markupStream) 984 { 985 } 986 987 public IAutoComponentFactory getAutoComponentFactory() 988 { 989 return autoComponentFactory; 990 } 991 992 public void setAutoComponentFactory(IAutoComponentFactory autoComponentFactory) 993 { 994 this.autoComponentFactory = autoComponentFactory; 995 } 996 997 998}