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; 018 019import java.io.Serializable; 020import java.util.Arrays; 021import java.util.Iterator; 022import java.util.List; 023import java.util.Locale; 024import java.util.Optional; 025 026import org.apache.wicket.ajax.IAjaxRegionMarkupIdProvider; 027import org.apache.wicket.application.IComponentInstantiationListener; 028import org.apache.wicket.authorization.Action; 029import org.apache.wicket.authorization.AuthorizationException; 030import org.apache.wicket.authorization.IAuthorizationStrategy; 031import org.apache.wicket.authorization.UnauthorizedActionException; 032import org.apache.wicket.authorization.strategies.page.SimplePageAuthorizationStrategy; 033import org.apache.wicket.behavior.Behavior; 034import org.apache.wicket.core.request.handler.BookmarkableListenerRequestHandler; 035import org.apache.wicket.core.request.handler.ListenerRequestHandler; 036import org.apache.wicket.core.request.handler.PageAndComponentProvider; 037import org.apache.wicket.core.util.lang.WicketObjects; 038import org.apache.wicket.core.util.string.ComponentStrings; 039import org.apache.wicket.event.Broadcast; 040import org.apache.wicket.event.IEvent; 041import org.apache.wicket.event.IEventSink; 042import org.apache.wicket.event.IEventSource; 043import org.apache.wicket.feedback.FeedbackDelay; 044import org.apache.wicket.feedback.FeedbackMessage; 045import org.apache.wicket.feedback.FeedbackMessages; 046import org.apache.wicket.feedback.IFeedback; 047import org.apache.wicket.feedback.IFeedbackContributor; 048import org.apache.wicket.markup.ComponentTag; 049import org.apache.wicket.markup.IMarkupFragment; 050import org.apache.wicket.markup.Markup; 051import org.apache.wicket.markup.MarkupCache; 052import org.apache.wicket.markup.MarkupElement; 053import org.apache.wicket.markup.MarkupException; 054import org.apache.wicket.markup.MarkupNotFoundException; 055import org.apache.wicket.markup.MarkupStream; 056import org.apache.wicket.markup.WicketTag; 057import org.apache.wicket.markup.head.IHeaderResponse; 058import org.apache.wicket.markup.head.StringHeaderItem; 059import org.apache.wicket.markup.html.IHeaderContributor; 060import org.apache.wicket.markup.html.form.Form; 061import org.apache.wicket.markup.html.form.FormComponent; 062import org.apache.wicket.markup.html.internal.HtmlHeaderContainer; 063import org.apache.wicket.markup.html.panel.DefaultMarkupSourcingStrategy; 064import org.apache.wicket.markup.html.panel.IMarkupSourcingStrategy; 065import org.apache.wicket.model.CompoundPropertyModel; 066import org.apache.wicket.model.IComponentAssignedModel; 067import org.apache.wicket.model.IComponentInheritedModel; 068import org.apache.wicket.model.IModel; 069import org.apache.wicket.model.IModelComparator; 070import org.apache.wicket.model.IWrapModel; 071import org.apache.wicket.protocol.http.WicketFilter; 072import org.apache.wicket.request.IRequestHandler; 073import org.apache.wicket.request.Request; 074import org.apache.wicket.request.Response; 075import org.apache.wicket.request.component.IRequestableComponent; 076import org.apache.wicket.request.component.IRequestablePage; 077import org.apache.wicket.request.cycle.RequestCycle; 078import org.apache.wicket.request.mapper.parameter.PageParameters; 079import org.apache.wicket.request.resource.ResourceReference; 080import org.apache.wicket.response.LazyStringResponse; 081import org.apache.wicket.settings.DebugSettings; 082import org.apache.wicket.settings.ExceptionSettings; 083import org.apache.wicket.util.IHierarchical; 084import org.apache.wicket.util.convert.IConverter; 085import org.apache.wicket.util.io.IClusterable; 086import org.apache.wicket.util.lang.Args; 087import org.apache.wicket.util.lang.Classes; 088import org.apache.wicket.util.string.PrependingStringBuffer; 089import org.apache.wicket.util.string.Strings; 090import org.apache.wicket.util.value.ValueMap; 091import org.apache.wicket.util.visit.IVisitFilter; 092import org.apache.wicket.util.visit.IVisitor; 093import org.apache.wicket.util.visit.Visit; 094import org.slf4j.Logger; 095import org.slf4j.LoggerFactory; 096 097 098/** 099 * Component serves as the highest level abstract base class for all components. 100 * 101 * <ul> 102 * <li><b>Identity </b>- All Components must have a non-null id which is retrieved by calling 103 * getId(). The id must be unique within the {@link MarkupContainer} that holds the Component, but 104 * does not have to be globally unique or unique within a Page's component hierarchy.</li> 105 * <li><b>Hierarchy </b>- A component has a parent which can be retrieved with {@link #getParent()}. 106 * If a component is an instance of MarkupContainer, it may have children. In this way it has a 107 * place in the hierarchy of components contained on a given page. 108 * <p> 109 * The path from the Page at the root of the component hierarchy to a given Component is simply the 110 * concatenation with colon separators of each id along the way. For example, the path "a:b:c" would 111 * refer to the component named "c" inside the MarkupContainer named "b" inside the container named 112 * "a". The path to a component can be retrieved by calling {@link #getPath()}. To get a Component 113 * path relative to the page that contains it, you can call {@link #getPageRelativePath()}.</li> 114 * <li><b>LifeCycle </b>- Components participate in the following lifecycle phases: 115 * <ul> 116 * <li><b>Construction </b>- A Component is constructed with the Java language new operator. 117 * Children may be added during construction if the Component is a MarkupContainer. 118 * {@link IComponentInstantiationListener}s are notified of component instantiation. 119 * <p> 120 * {@link #onInitialize()} is called on the component as soon as the component is part of a page's 121 * component tree. At this state the component is able to access its markup.</li> 122 * <li><b>Request Handling </b>- An incoming request is processed by a protocol request handler such 123 * as {@link WicketFilter}. An associated Application object creates {@link Session}, 124 * {@link Request} and {@link Response} objects for use by a given Component in updating its model 125 * and rendering a response. These objects are stored inside a container called {@link RequestCycle} 126 * which is accessible via {@link Component#getRequestCycle()}. The convenience methods 127 * {@link Component#getRequest()}, {@link Component#getResponse()} and 128 * {@link Component#getSession()} provide easy access to the contents of this container.</li> 129 * <li><b>Listener Invocation </b>- If the request references an {@link IRequestListener} on an 130 * existing Component (or one of its {@link Behavior}s, see below), that listener is notified, 131 * allowing arbitrary user code to handle events such as link clicks or form submits. Although 132 * arbitrary listeners are supported in Wicket, the need to implement a new class of listener is 133 * unlikely for a web application and even the need to implement a listener interface directly is 134 * highly discouraged. Instead, calls to listeners are routed through logic specific to the event, 135 * resulting in calls to user code through other overridable methods. See {@link Form} for an 136 * example of a component which listens for events via {@link IRequestListener}.</li> 137 * <li><b>Rendering </b>- Before a page or part of a page (in case of Ajax updates) is rendered, all 138 * containing components are able to prepare for rendering via two hook methods: 139 * {@link #onConfigure()} (regardless whether they are visible or not) and {@link #onBeforeRender()} 140 * (if visible only) . <br> 141 * A markup response is generated by the Component via {@link Component#render()}, which calls 142 * subclass implementation code contained in {@link Component#onRender()}. Once this phase begins, a 143 * Component becomes immutable. Attempts to alter the Component will result in a 144 * WicketRuntimeException.</li> 145 * <li><b>Detachment </b>- Each request cycle finishes by detaching all touched components. 146 * Subclasses should clean up their state by overriding {@link #onDetach()} or more specifically 147 * {@link #detachModels()} if they keep references to models beside the default model.</li> 148 * </ul> 149 * </li> 150 * <li><b>Visibility </b>- If a component is not visible (see {@link #setVisible(boolean)}) it will 151 * not render a response (nor will their children).</li> 152 * <li><b>Enabling </b>- Component subclasses take into account their enabled state (see 153 * {@link #setEnabled(boolean)} when rendering, and in case of a {@link FormComponent} will not not 154 * update its model while the request is handled.</li> 155 * <li><b>Models </b>- The primary responsibility of a component is to use its model (an object that 156 * implements {@link IModel}) to render a response in an appropriate markup language, such as HTML. 157 * In addition, {@link FormComponent}s know how to update their models based on request information, 158 * see {@link FormComponent#updateModel()}. Since the IModel interface is a wrapper around another 159 * object, a convenience method {@link Component#getDefaultModelObject()} is provided to retrieve 160 * the object from its IModel wrapper. A further convenience method, 161 * {@link Component#getDefaultModelObjectAsString()}, is provided for the very common operation of 162 * converting the wrapped object to a String. <br> 163 * The component's model can be passed in the constructor or set via 164 * {@link Component#setDefaultModel(IModel)}. In neither case a model can be created on demand with 165 * {@link #initModel()}.<br> 166 * Note that a component can have more models besides its default model.</li> 167 * <li><b>Behaviors </b>- You can add multiple {@link Behavior}s to any component if you need to 168 * dynamically alter the behavior of components, e.g. manipulate attributes of the markup tag to 169 * which a Component is attached. Behaviors take part in the component's lifecycle through various 170 * callback methods.</li> 171 * <li><b>Locale </b>- The Locale for a Component is available through {@link #getLocale()}, which 172 * delegates to its parent's locale, finally consulting the {@link Session}'s locale.</li> 173 * <li><b>Style </b>- The Session's style ("skin") is available through 174 * {@link org.apache.wicket.Component#getStyle()}. Styles are intended to give a particular look to 175 * all components or resources in a session that is independent of its Locale. For example, a style 176 * might be a set of resources, including images and markup files, which gives the design look of 177 * "ocean" to the user. If the Session's style is set to "ocean" and these resources are given names 178 * suffixed with "_ocean", Wicket's resource management logic will prefer these resources to other 179 * resources, such as default resources, which are not as good of a match.</li> 180 * <li><b>Variation </b>- Whereas styles are Session (user) specific, variations are component 181 * specific. E.g. if the Style is "ocean" and {@link #getVariation()} returnss "NorthSea", than the 182 * resources are given the names suffixed with "_ocean_NorthSea".</li> 183 * <li><b>String Resources </b>- Components can have associated String resources via the 184 * Application's Localizer, which is available through the method {@link Component#getLocalizer()}. 185 * The convenience methods {@link Component#getString(String key)} and 186 * {@link Component#getString(String key, IModel model)} wrap the identical methods on the 187 * Application Localizer for easy access in Components.</li> 188 * <li><b>Feedback Messages </b>- The {@link Component#debug(Serializable)}, 189 * {@link Component#info(Serializable)}, {@link Component#warn(Serializable)}, 190 * {@link Component#error(java.io.Serializable)} and {@link Component#fatal(Serializable)} methods 191 * associate feedback messages with a Component. It is generally not necessary to use these methods 192 * directly since Wicket validators automatically register feedback messages on Components. Feedback 193 * message for a given Component can be retrieved with {@link Component#getFeedbackMessages}.</li> 194 * <li><b>Versioning </b>- Pages are the unit of versioning in Wicket, but fine-grained control of 195 * which Components should participate in versioning is possible via the 196 * {@link Component#setVersioned(boolean)} method. The versioning participation of a given Component 197 * can be retrieved with {@link Component#isVersioned()}.</li> 198 * <li><b>Page </b>- The Page containing any given Component can be retrieved by calling 199 * {@link Component#getPage()}. If the Component is not attached to a Page, an IllegalStateException 200 * will be thrown. An equivalent method, {@link Component#findPage()} is available for special 201 * circumstances where it might be desirable to get a null reference back instead.</li> 202 * <li><b>Application </b>- The {@link #getApplication()} method provides convenient access to the 203 * {@link Application} for a Component.</li> 204 * <li><b>AJAX support</b>- Components can be re-rendered after the whole Page has been rendered at 205 * least once by calling doRender().</li> 206 * <li><b>Security </b>- All components are subject to an {@link IAuthorizationStrategy} which 207 * controls instantiation, visibility and enabling. See {@link SimplePageAuthorizationStrategy} for 208 * a simple implementation.</li> 209 * </ul> 210 * 211 * @author Jonathan Locke 212 * @author Chris Turner 213 * @author Eelco Hillenius 214 * @author Johan Compagner 215 * @author Juergen Donnerstag 216 * @author Igor Vaynberg (ivaynberg) 217 */ 218public abstract class Component 219 implements 220 IClusterable, 221 IConverterLocator, 222 IRequestableComponent, 223 IHeaderContributor, 224 IHierarchical<Component>, 225 IEventSink, 226 IEventSource, 227 IMetadataContext<Serializable, Component>, 228 IFeedbackContributor 229{ 230 /** Log. */ 231 private static final Logger log = LoggerFactory.getLogger(Component.class); 232 233 private static final long serialVersionUID = 1L; 234 235 /** 236 * Action used with IAuthorizationStrategy to determine whether a component is allowed to be 237 * enabled. 238 * <p> 239 * If enabling is authorized, a component may decide by itself (typically using it's enabled 240 * property) whether it is enabled or not. If enabling is not authorized, the given component is 241 * marked disabled, regardless its enabled property. 242 * <p> 243 * When a component is not allowed to be enabled (in effect disabled through the implementation 244 * of this interface), Wicket will try to prevent model updates too. This is not completely fail 245 * safe, as constructs like: 246 * 247 * <pre> 248 * 249 * User u = (User)getModelObject(); 250 * u.setName("got you there!"); 251 * 252 * </pre> 253 * 254 * can't be prevented. Indeed it can be argued that any model protection is best dealt with in 255 * your model objects to be completely secured. Wicket will catch all normal framework-directed 256 * use though. 257 */ 258 public static final Action ENABLE = new Action(Action.ENABLE); 259 260 /** Separator for component paths */ 261 public static final char PATH_SEPARATOR = ':'; 262 /** Path segment that represents this component's parent */ 263 public static final String PARENT_PATH = ".."; 264 265 /** 266 * Action used with IAuthorizationStrategy to determine whether a component and its children are 267 * allowed to be rendered. 268 * <p> 269 * There are two uses for this method: 270 * <ul> 271 * <li>The 'normal' use is for controlling whether a component is rendered without having any 272 * effect on the rest of the processing. If a strategy lets this method return 'false', then the 273 * target component and its children will not be rendered, in the same fashion as if that 274 * component had visibility property 'false'.</li> 275 * <li>The other use is when a component should block the rendering of the whole page. So 276 * instead of 'hiding' a component, what we generally want to achieve here is that we force the 277 * user to logon/give-credentials for a higher level of authorization. For this functionality, 278 * the strategy implementation should throw a {@link AuthorizationException}, which will then be 279 * handled further by the framework.</li> 280 * </ul> 281 * </p> 282 */ 283 public static final Action RENDER = new Action(Action.RENDER); 284 285 /** meta data for user specified markup id */ 286 private static final MetaDataKey<String> MARKUP_ID_KEY = new MetaDataKey<>() 287 { 288 private static final long serialVersionUID = 1L; 289 }; 290 291 /** meta data for user specified markup id */ 292 private static final MetaDataKey<FeedbackMessages> FEEDBACK_KEY = new MetaDataKey<>() 293 { 294 private static final long serialVersionUID = 1L; 295 }; 296 297 298 /** Basic model IModelComparator implementation for normal object models */ 299 private static final IModelComparator defaultModelComparator = new IModelComparator() 300 { 301 private static final long serialVersionUID = 1L; 302 303 @Override 304 public boolean compare(Component component, Object b) 305 { 306 final Object a = component.getDefaultModelObject(); 307 if (a == null && b == null) 308 { 309 return true; 310 } 311 if (a == null || b == null) 312 { 313 return false; 314 } 315 return a.equals(b); 316 } 317 }; 318 319 /** True when a component is being auto-added */ 320 private static final int FLAG_AUTO = 0x0001; 321 322 /** Flag for escaping HTML in model strings */ 323 private static final int FLAG_ESCAPE_MODEL_STRINGS = 0x0002; 324 325 /** Boolean whether this component's model is inheritable. */ 326 static final int FLAG_INHERITABLE_MODEL = 0x0004; 327 328 /** Versioning boolean */ 329 private static final int FLAG_VERSIONED = 0x0008; 330 331 /** Visibility boolean */ 332 private static final int FLAG_VISIBLE = 0x0010; 333 334 /** Render tag boolean */ 335 private static final int FLAG_RENDER_BODY_ONLY = 0x0020; 336 337 /** Ignore attribute modifiers */ 338 private static final int FLAG_IGNORE_ATTRIBUTE_MODIFIER = 0x0040; 339 340 /** True when a component is enabled for model updates and is reachable. */ 341 private static final int FLAG_ENABLED = 0x0080; 342 343 /** Reserved subclass-definable flag bit */ 344 protected static final int FLAG_RESERVED1 = 0x0100; 345 /** Reserved subclass-definable flag bit */ 346 protected static final int FLAG_RESERVED2 = 0x0200; 347 /** Reserved subclass-definable flag bit */ 348 protected static final int FLAG_RESERVED3 = 0x0400; 349 /** Reserved subclass-definable flag bit */ 350 protected static final int FLAG_RESERVED4 = 0x0800; 351 352 /** Boolean whether this component was rendered at least once for tracking changes. */ 353 private static final int FLAG_HAS_BEEN_RENDERED = 0x1000; 354 355 /** 356 * Internal indicator of whether this component may be rendered given the current context's 357 * authorization. It overrides the visible flag in case this is false. Authorization is done 358 * before trying to render any component (otherwise we would end up with a half rendered page in 359 * the buffer) 360 */ 361 private static final int FLAG_IS_RENDER_ALLOWED = 0x2000; 362 363 /** Whether or not the component should print out its markup id into the id attribute */ 364 private static final int FLAG_OUTPUT_MARKUP_ID = 0x4000; 365 366 /** 367 * Output a placeholder tag if the component is not visible. This is useful in ajax mode to go 368 * to visible(false) to visible(true) without the overhead of repainting a visible parent 369 * container 370 */ 371 private static final int FLAG_PLACEHOLDER = 0x8000; 372 373 /** Reserved subclass-definable flag bit */ 374 protected static final int FLAG_RESERVED5 = 0x10000; 375 /** onInitialize called */ 376 protected static final int FLAG_INITIALIZED = 0x20000; 377 /** Set when a component is removed from the hierarchy */ 378 private static final int FLAG_REMOVED = 0x40000; 379 /** Reserved subclass-definable flag bit */ 380 protected static final int FLAG_RESERVED8 = 0x80000; 381 382 /** 383 * Flag that determines whether the model is set. This is necessary because of the way we 384 * represent component state ({@link #data}). We can't distinguish between model and behavior 385 * using instanceof, because one object can implement both interfaces. Thus we need this flag - 386 * when the flag is set, first object in {@link #data} is always model. 387 */ 388 private static final int FLAG_MODEL_SET = 0x100000; 389 390 /** 391 * Flag that restricts visibility of a component when set to true. This is usually used when a 392 * component wants to restrict visibility of another component. Calling 393 * {@link #setVisible(boolean)} on a component does not always have the desired effect because 394 * isVisible() can be overwritten thus this flag offers an alternative that should always work. 395 */ 396 private static final int FLAG_VISIBILITY_ALLOWED = 0x40000000; 397 398 /** 399 * The name of attribute that will hold markup id 400 */ 401 private static final String MARKUP_ID_ATTR_NAME = "id"; 402 403 /** 404 * Meta data key for line precise error logging for the moment of addition. Made package private 405 * for access in {@link MarkupContainer} and {@link Page} 406 */ 407 static final MetaDataKey<String> ADDED_AT_KEY = new MetaDataKey<>() 408 { 409 private static final long serialVersionUID = 1L; 410 }; 411 412 /** 413 * meta data key for line precise error logging for the moment of construction. Made package 414 * private for access in {@link Page} 415 */ 416 static final MetaDataKey<String> CONSTRUCTED_AT_KEY = new MetaDataKey<>() 417 { 418 private static final long serialVersionUID = 1L; 419 }; 420 421 /** Component flags. See FLAG_* for possible non-exclusive flag values. */ 422 private int flags = FLAG_VISIBLE | FLAG_ESCAPE_MODEL_STRINGS | FLAG_VERSIONED | FLAG_ENABLED | 423 FLAG_IS_RENDER_ALLOWED | FLAG_VISIBILITY_ALLOWED | FLAG_RESERVED5 /* page's stateless hint */; 424 425 // @formatter:off 426 private static final short RFLAG_ENABLED_IN_HIERARCHY_VALUE = 0x1; 427 private static final short RFLAG_ENABLED_IN_HIERARCHY_SET = 0x2; 428 private static final short RFLAG_VISIBLE_IN_HIERARCHY_VALUE = 0x4; 429 private static final short RFLAG_VISIBLE_IN_HIERARCHY_SET = 0x8; 430 /** onconfigure has been called */ 431 private static final short RFLAG_CONFIGURED = 0x10; 432 private static final short RFLAG_BEFORE_RENDER_SUPER_CALL_VERIFIED = 0x20; 433 private static final short RFLAG_INITIALIZE_SUPER_CALL_VERIFIED = 0x40; 434 protected static final short RFLAG_CONTAINER_DEQUEING = 0x80; 435 private static final short RFLAG_ON_RE_ADD_SUPER_CALL_VERIFIED = 0x100; 436 /** 437 * Flag that makes we are in before-render callback phase Set after component.onBeforeRender is 438 * invoked (right before invoking beforeRender on children) 439 */ 440 private static final short RFLAG_RENDERING = 0x200; 441 private static final short RFLAG_PREPARED_FOR_RENDER = 0x400; 442 private static final short RFLAG_AFTER_RENDER_SUPER_CALL_VERIFIED = 0x800; 443 private static final short RFLAG_DETACHING = 0x1000; 444 /** True when a component is being removed from the hierarchy */ 445 private static final short RFLAG_REMOVING_FROM_HIERARCHY = 0x2000; 446 /** 447 * This flag tracks if removals have been set on this component. Clearing this key is an 448 * expensive operation. With this flag this expensive call can be avoided. 449 */ 450 protected static final short RFLAG_CONTAINER_HAS_REMOVALS = 0x4000; 451 private static final short RFLAG_ON_CONFIGURE_SUPER_CALL_VERIFIED = (short) 0x8000; 452 // @formatter:on 453 454 /** 455 * Flags that only keep their value during the request. Useful for cache markers, etc. At the 456 * end of the request the value of this variable is reset to 0 457 */ 458 private transient short requestFlags = 0; 459 460 /** Component id. */ 461 private final String id; 462 463 /** Any parent container. */ 464 private MarkupContainer parent; 465 466 /** 467 * Instead of remembering the whole markupId, we just remember the number for this component so 468 * we can "reconstruct" the markupId on demand. While this could be part of {@link #data}, 469 * profiling showed that having it as separate property consumes less memory. 470 */ 471 int generatedMarkupId = -1; 472 473 /** Must only be used by auto components */ 474 private transient IMarkupFragment markup; 475 476 /** 477 * Will be re-created instead of persisted when session is replicated. Markup sourcing strategy 478 * are typically stateless (but don't have to). 479 */ 480 private transient IMarkupSourcingStrategy markupSourcingStrategy; 481 482 /** 483 * The object that holds the component state. 484 * <p> 485 * What's stored here depends on what attributes are set on component. Data can contains 486 * combination of following attributes: 487 * <ul> 488 * <li>Model (indicated by {@link #FLAG_MODEL_SET}) 489 * <li>MetaDataEntry (optionally {@link MetaDataEntry}[] if more metadata entries are present) * 490 * <li>{@link Behavior}(s) added to component. The behaviors are not stored in separate array, 491 * they are part of the {@link #data} array (this is in order to save the space of the pointer 492 * to an empty array as most components have no behaviours). - FIXME - explain why - is this 493 * correct? 494 * </ul> 495 * If there is only one attribute set (i.e. model or MetaDataEntry([]) or one behavior), the 496 * #data object points directly to value of that attribute. Otherwise the data is of type 497 * Object[] where the attributes are ordered as specified above. 498 * <p> 499 */ 500 Object data = null; 501 502 final int data_start() 503 { 504 return getFlag(FLAG_MODEL_SET) ? 1 : 0; 505 } 506 507 final int data_length() 508 { 509 if (data == null) 510 { 511 return 0; 512 } 513 else if (data instanceof Object[] && !(data instanceof MetaDataEntry<?>[])) 514 { 515 return ((Object[])data).length; 516 } 517 else 518 { 519 return 1; 520 } 521 } 522 523 final Object data_get(int index) 524 { 525 if (data == null) 526 { 527 return null; 528 } 529 else if (data instanceof Object[] && !(data instanceof MetaDataEntry<?>[])) 530 { 531 Object[] array = (Object[])data; 532 return index < array.length ? array[index] : null; 533 } 534 else if (index == 0) 535 { 536 return data; 537 } 538 else 539 { 540 return null; 541 } 542 } 543 544 final void data_set(int index, Object object) 545 { 546 if (index > data_length() - 1) 547 { 548 throw new IndexOutOfBoundsException("can not set data at " + index + 549 " when data_length() is " + data_length()); 550 } 551 else if (index == 0 && !(data instanceof Object[] && !(data instanceof MetaDataEntry<?>[]))) 552 { 553 data = object; 554 } 555 else 556 { 557 Object[] array = (Object[])data; 558 array[index] = object; 559 } 560 } 561 562 final void data_add(Object object) 563 { 564 data_insert(-1, object); 565 } 566 567 final void data_insert(int position, Object object) 568 { 569 int currentLength = data_length(); 570 if (position == -1) 571 { 572 position = currentLength; 573 } 574 if (position > currentLength) 575 { 576 throw new IndexOutOfBoundsException("can not insert data at " + position + 577 " when data_length() is " + currentLength); 578 } 579 if (currentLength == 0) 580 { 581 data = object; 582 } 583 else if (currentLength == 1) 584 { 585 Object[] array = new Object[2]; 586 if (position == 0) 587 { 588 array[0] = object; 589 array[1] = data; 590 } 591 else 592 { 593 array[0] = data; 594 array[1] = object; 595 } 596 data = array; 597 } 598 else 599 { 600 Object[] array = new Object[currentLength + 1]; 601 Object[] current = (Object[])data; 602 int after = currentLength - position; 603 if (position > 0) 604 { 605 System.arraycopy(current, 0, array, 0, position); 606 } 607 array[position] = object; 608 if (after > 0) 609 { 610 System.arraycopy(current, position, array, position + 1, after); 611 } 612 data = array; 613 } 614 } 615 616 final void data_remove(int position) 617 { 618 int currentLength = data_length(); 619 620 if (position > currentLength - 1) 621 { 622 throw new IndexOutOfBoundsException(); 623 } 624 else if (currentLength == 1) 625 { 626 data = null; 627 } 628 else if (currentLength == 2) 629 { 630 Object[] current = (Object[])data; 631 if (position == 0) 632 { 633 data = current[1]; 634 } 635 else 636 { 637 data = current[0]; 638 } 639 } 640 else 641 { 642 Object[] current = (Object[])data; 643 data = new Object[currentLength - 1]; 644 645 if (position > 0) 646 { 647 System.arraycopy(current, 0, data, 0, position); 648 } 649 if (position != currentLength - 1) 650 { 651 final int left = currentLength - position - 1; 652 System.arraycopy(current, position + 1, data, position, left); 653 } 654 } 655 } 656 657 /** 658 * Constructor. All components have names. A component's id cannot be null. This is the minimal 659 * constructor of component. It does not register a model. 660 * 661 * @param id 662 * The non-null id of this component 663 * @throws WicketRuntimeException 664 * Thrown if the component has been given a null id. 665 */ 666 public Component(final String id) 667 { 668 this(id, null); 669 } 670 671 /** 672 * Constructor. All components have names. A component's id cannot be null. This constructor 673 * includes a model. 674 * 675 * @param id 676 * The non-null id of this component 677 * @param model 678 * The component's model 679 * 680 * @throws WicketRuntimeException 681 * Thrown if the component has been given a null id. 682 */ 683 public Component(final String id, final IModel<?> model) 684 { 685 checkId(id); 686 this.id = id; 687 688 init(); 689 690 Application application = getApplication(); 691 application.getComponentInstantiationListeners().onInstantiation(this); 692 693 final DebugSettings debugSettings = application.getDebugSettings(); 694 if (debugSettings.isLinePreciseReportingOnNewComponentEnabled() && debugSettings.getComponentUseCheck()) 695 { 696 setMetaData(CONSTRUCTED_AT_KEY, 697 ComponentStrings.toString(this, new MarkupException("constructed"))); 698 } 699 700 if (model != null) 701 { 702 setModelImpl(wrap(model)); 703 } 704 } 705 706 /** 707 * Let subclasses initialize this instance, before constructors are executed. <br> 708 * This method is intentionally <b>not</b> declared protected, to limit overriding to classes in 709 * this package. 710 */ 711 void init() 712 { 713 } 714 715 /** 716 * Get the Markup associated with the Component. If not subclassed, the parent container is 717 * asked to return the markup of this child component. 718 * <p/> 719 * Components like Panel and Border should return the "calling" markup fragment, e.g. 720 * <code><span wicket:id="myPanel">body</span></code>. You may use 721 * Panel/Border/Enclosure.getMarkup(null) to return the associated markup file. And 722 * Panel/Border/Enclosure.getMarkup(child) will search the child in the appropriate markup 723 * fragment. 724 * 725 * @see MarkupContainer#getMarkup(Component) 726 * 727 * @return The markup fragment 728 */ 729 public IMarkupFragment getMarkup() 730 { 731 // Markup already determined or preset? 732 if (markup != null) 733 { 734 return markup; 735 } 736 737 // No parent, than check associated markup files 738 if (parent == null) 739 { 740 // Must be a MarkupContainer to have associated markup file 741 if (this instanceof MarkupContainer) 742 { 743 MarkupContainer container = (MarkupContainer)this; 744 Markup associatedMarkup = container.getAssociatedMarkup(); 745 if (associatedMarkup != null) 746 { 747 markup = associatedMarkup; 748 return markup; 749 } 750 } 751 752 // Don't know how to find the markup 753 throw new MarkupNotFoundException( 754 "Can not determine Markup. Component is not yet connected to a parent. " + 755 toString()); 756 } 757 758 // Ask the parent for find the markup for me 759 markup = parent.getMarkup(this); 760 return markup; 761 } 762 763 /** 764 * @return The 'id' attribute from the associated markup tag 765 */ 766 public final String getMarkupIdFromMarkup() 767 { 768 ComponentTag tag = getMarkupTag(); 769 if (tag != null) 770 { 771 String id = tag.getAttribute("id"); 772 if (Strings.isEmpty(id) == false) 773 { 774 return id.trim(); 775 } 776 } 777 778 return null; 779 } 780 781 /** 782 * Set the markup for the component. Note that the component's markup variable is transient and 783 * thus must only be used for one render cycle. E.g. auto-component are using it. You may also 784 * it if you subclassed getMarkup(). 785 * 786 * @param markup 787 */ 788 public final Component setMarkup(final IMarkupFragment markup) 789 { 790 this.markup = markup; 791 return this; 792 } 793 794 /** 795 * Called on all components before any component is rendered. This method 796 * should be used to configure such things as visibility and enabled flags. 797 * <p> 798 * Overrides must call {@code super.onConfigure()}, usually before any other code 799 * <p> 800 * NOTE: Component hierarchy should not be modified inside this method, instead it should be 801 * done in {@link #onBeforeRender()} 802 * <p> 803 * NOTE: Why this method is preferrable to directly overriding {@link #isVisible()} and 804 * {@link #isEnabled()}? Because those methods are called multiple times even for processing of 805 * a single request. If they contain expensive logic they can slow down the response time of the 806 * entire page. Further, overriding those methods directly on form components may lead to 807 * inconsistent or unexpected state depending on when those methods are called in the form 808 * processing workflow. It is a better practice to push changes to state rather than pull. 809 * <p> 810 * NOTE: If component's visibility or another property depends on another component you may call 811 * {@code other.configure()} followed by {@code other.isVisible()} as mentioned in 812 * {@link #configure()} javadoc. 813 * <p> 814 * NOTE: Why should {@link #onBeforeRender()} not be used for this? Because if a component's 815 * visibility is controlled inside {@link #onBeforeRender()}, once invisible the component will 816 * never become visible again. 817 */ 818 protected void onConfigure() 819 { 820 setRequestFlag(RFLAG_ON_CONFIGURE_SUPER_CALL_VERIFIED, true); 821 } 822 823 /** 824 * This method is meant to be used as an alternative to initialize components. Usually the 825 * component's constructor is used for this task, but sometimes a component cannot be 826 * initialized in isolation, it may need to access its parent component or its markup in order 827 * to fully initialize. This method is invoked once per component's lifecycle when a path exists 828 * from this component to the {@link Page} thus providing the component with an atomic callback 829 * when the component's environment is built out. 830 * <p> 831 * Overrides must call super#{@link #onInitialize()}. Usually this should be the first thing an 832 * override does, much like a constructor. 833 * </p> 834 * <p> 835 * Parent containers are guaranteed to be initialized before their children 836 * </p> 837 * 838 * <p> 839 * It is safe to use {@link #getPage()} in this method 840 * </p> 841 * 842 * <p> 843 * NOTE:The timing of this call is not precise, the contract is that it is called sometime 844 * before {@link Component#onBeforeRender()}. 845 * </p> 846 * 847 */ 848 protected void onInitialize() 849 { 850 setRequestFlag(RFLAG_INITIALIZE_SUPER_CALL_VERIFIED, true); 851 } 852 853 /** 854 * Checks if the component has been initialized - {@link #onInitialize()} has been called 855 * 856 * @return {@code true} if component has been initialized 857 */ 858 public final boolean isInitialized() 859 { 860 return getFlag(FLAG_INITIALIZED); 861 } 862 863 /** 864 * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT USE IT! 865 * 866 * Used to call {@link #onInitialize()} 867 */ 868 public void internalInitialize() 869 { 870 fireInitialize(); 871 } 872 873 /** 874 * Used to call {@link #onInitialize()} 875 */ 876 final void fireInitialize() 877 { 878 if (!getFlag(FLAG_INITIALIZED)) 879 { 880 setFlag(FLAG_INITIALIZED, true); 881 882 setRequestFlag(RFLAG_INITIALIZE_SUPER_CALL_VERIFIED, false); 883 onInitialize(); 884 verifySuperCall("onInitialize", RFLAG_INITIALIZE_SUPER_CALL_VERIFIED); 885 886 getApplication().getComponentInitializationListeners().onInitialize(this); 887 } 888 else if (getFlag(FLAG_REMOVED)) 889 { 890 setFlag(FLAG_REMOVED, false); 891 892 setRequestFlag(RFLAG_ON_RE_ADD_SUPER_CALL_VERIFIED, false); 893 onReAdd(); 894 verifySuperCall("onReAdd", RFLAG_ON_RE_ADD_SUPER_CALL_VERIFIED); 895 } 896 } 897 898 /** 899 * Called on every component after the page is rendered. Calls hook {@link #onAfterRender()}. 900 */ 901 final void afterRender() 902 { 903 setRequestFlag(RFLAG_PREPARED_FOR_RENDER, false); 904 905 try 906 { 907 setRequestFlag(RFLAG_AFTER_RENDER_SUPER_CALL_VERIFIED, false); 908 909 onAfterRender(); 910 getApplication().getComponentOnAfterRenderListeners().onAfterRender(this); 911 verifySuperCall("onAfterRender", RFLAG_AFTER_RENDER_SUPER_CALL_VERIFIED); 912 } 913 finally 914 { 915 // this flag must always be set to false. 916 setRequestFlag(RFLAG_RENDERING, false); 917 } 918 } 919 920 /** 921 * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT USE IT! 922 * 923 * Called on all components before any component is rendered. Calls hooks 924 * {@link #configure()} and (if visible) {@link #onBeforeRender()} 925 * and delegates to {@link #beforeRender()} of all child components. 926 */ 927 public final void beforeRender() 928 { 929 if (this instanceof IFeedback) 930 { 931 Optional<FeedbackDelay> delay = FeedbackDelay.get(getRequestCycle()); 932 if (delay.isPresent()) { 933 delay.get().postpone((IFeedback)this); 934 return; 935 } 936 } 937 938 configure(); 939 940 if ((determineVisibility()) && !getRequestFlag(RFLAG_RENDERING) && 941 !getRequestFlag(RFLAG_PREPARED_FOR_RENDER)) 942 { 943 try { 944 setRequestFlag(RFLAG_BEFORE_RENDER_SUPER_CALL_VERIFIED, false); 945 946 Application application = getApplication(); 947 application.getComponentPreOnBeforeRenderListeners().onBeforeRender(this); 948 949 onBeforeRender(); 950 application.getComponentPostOnBeforeRenderListeners().onBeforeRender(this); 951 952 verifySuperCall("onBeforeRender", RFLAG_BEFORE_RENDER_SUPER_CALL_VERIFIED); 953 } catch (RuntimeException ex) { 954 setRequestFlag(RFLAG_PREPARED_FOR_RENDER, false); 955 throw ex; 956 } 957 } 958 } 959 960 /** 961 * Triggers {@link #onConfigure()} to be invoked on this component if it has not already during 962 * this request. 963 * <p> 964 * This method should be invoked before any calls to {@link #isVisible()} or 965 * {@link #isEnabled()}. Usually this method will be called by the framework before the 966 * component is rendered and so users should not need to call it; however, in cases where 967 * visibility or enabled or other state of one component depends on the state of another this 968 * method should be manually invoked on the other component by the user. EG to link visiliby of 969 * two markup containers the following should be done: 970 * 971 * <pre> 972 * final WebMarkupContainer source=new WebMarkupContainer("a") { 973 * protected void onConfigure() { 974 * setVisible(Math.rand()>0.5f); 975 * } 976 * }; 977 * 978 * WebMarkupContainer linked=new WebMarkupContainer("b") { 979 * protected void onConfigure() { 980 * source.configure(); // make sure source is configured 981 * setVisible(source.isVisible()); 982 * } 983 * } 984 * </pre> 985 * 986 * </p> 987 */ 988 public final void configure() 989 { 990 if (!getRequestFlag(RFLAG_CONFIGURED)) 991 { 992 clearEnabledInHierarchyCache(); 993 clearVisibleInHierarchyCache(); 994 995 setRequestFlag(RFLAG_ON_CONFIGURE_SUPER_CALL_VERIFIED, false); 996 onConfigure(); 997 verifySuperCall("onConfigure", RFLAG_ON_CONFIGURE_SUPER_CALL_VERIFIED); 998 999 for (Behavior behavior : getBehaviors()) 1000 { 1001 if (isBehaviorAccepted(behavior)) 1002 { 1003 behavior.onConfigure(this); 1004 } 1005 } 1006 1007 // check authorization 1008 setRenderAllowed(); 1009 1010 internalOnAfterConfigure(); 1011 1012 getApplication().getComponentOnConfigureListeners().onConfigure(this); 1013 1014 setRequestFlag(RFLAG_CONFIGURED, true); 1015 } 1016 } 1017 1018 /** 1019 * Verify super calls of an overridden hook method. 1020 */ 1021 private final void verifySuperCall(String method, short flag) 1022 { 1023 if (!getRequestFlag(flag)) 1024 { 1025 throw new IllegalStateException(String.format("%s() in the hierarchy of %s has not called super.%s()", method, getClass().getName(), method)); 1026 } 1027 1028 setRequestFlag(flag, false); 1029 } 1030 1031 /** 1032 * Called after the {@link #onConfigure()}, but before {@link #onBeforeRender()} 1033 */ 1034 void internalOnAfterConfigure() 1035 { 1036 } 1037 1038 /** 1039 * Redirects to any intercept page previously specified by a call to {@link #redirectToInterceptPage(Page)}. 1040 * The redirect is done by throwing an exception. If there is no intercept page no exception 1041 * will be thrown and the program flow will continue uninterrupted. 1042 * 1043 * Example: 1044 * 1045 * <pre> 1046 * add(new Link("login") 1047 * { 1048 * protected void onClick() 1049 * { 1050 * if (authenticate()) 1051 * { 1052 * continueToOriginalDestination(); 1053 * // if we reach this line there was no intercept page, so go to home page 1054 * setResponsePage(WelcomePage.class); 1055 * } 1056 * } 1057 * }); 1058 * 1059 * @see Component#redirectToInterceptPage(Page) 1060 */ 1061 public final void continueToOriginalDestination() 1062 { 1063 RestartResponseAtInterceptPageException.continueToOriginalDestination(); 1064 } 1065 1066 /** 1067 * Clears any data about previously intercepted page. 1068 */ 1069 public final void clearOriginalDestination() 1070 { 1071 RestartResponseAtInterceptPageException.clearOriginalDestination(); 1072 } 1073 1074 /** 1075 * Registers a debug feedback message for this component 1076 * 1077 * @param message 1078 * The feedback message 1079 */ 1080 @Override 1081 public final void debug(final Serializable message) 1082 { 1083 getFeedbackMessages().debug(this, message); 1084 addStateChange(); 1085 } 1086 1087 /** 1088 * Signals this Component that it is removed from the Component hierarchy. 1089 */ 1090 final void internalOnRemove() 1091 { 1092 setRequestFlag(RFLAG_REMOVING_FROM_HIERARCHY, true); 1093 onRemove(); 1094 setFlag(FLAG_REMOVED, true); 1095 if (getRequestFlag(RFLAG_REMOVING_FROM_HIERARCHY)) 1096 { 1097 throw new IllegalStateException(Component.class.getName() + 1098 " has not been properly removed from hierarchy. Something in the hierarchy of " + 1099 getClass().getName() + 1100 " has not called super.onRemove() in the override of onRemove() method"); 1101 } 1102 Behaviors.onRemove(this); 1103 removeChildren(); 1104 } 1105 1106 /** 1107 * Detaches the component. This is called at the end of the request for all the pages that are 1108 * touched in that request. 1109 */ 1110 @Override 1111 public final void detach() 1112 { 1113 try 1114 { 1115 setRequestFlag(RFLAG_DETACHING, true); 1116 onDetach(); 1117 if (getRequestFlag(RFLAG_DETACHING)) 1118 { 1119 throw new IllegalStateException(Component.class.getName() + 1120 " has not been properly detached. Something in the hierarchy of " + 1121 getClass().getName() + 1122 " has not called super.onDetach() in the override of onDetach() method"); 1123 } 1124 1125 // always detach models because they can be attached without the 1126 // component. eg component has a compoundpropertymodel and one of its 1127 // children component's getmodelobject is called 1128 detachModels(); 1129 1130 // detach any behaviors 1131 Behaviors.detach(this); 1132 } 1133 catch (Exception x) 1134 { 1135 throw new WicketRuntimeException("An error occurred while detaching component: " + toString(true), x); 1136 } 1137 1138 // always detach children because components can be attached 1139 // independently of their parents 1140 detachChildren(); 1141 1142 // reset the model to null when the current model is a IWrapModel and 1143 // the model that created it/wrapped in it is a IComponentInheritedModel 1144 // The model will be created next time. 1145 if (getFlag(FLAG_INHERITABLE_MODEL)) 1146 { 1147 setModelImpl(null); 1148 setFlag(FLAG_INHERITABLE_MODEL, false); 1149 } 1150 1151 clearEnabledInHierarchyCache(); 1152 clearVisibleInHierarchyCache(); 1153 1154 // clear request flags but keep super call verifications WICKET-5417 1155 requestFlags &= (RFLAG_INITIALIZE_SUPER_CALL_VERIFIED | RFLAG_ON_CONFIGURE_SUPER_CALL_VERIFIED | RFLAG_BEFORE_RENDER_SUPER_CALL_VERIFIED); 1156 1157 detachFeedback(); 1158 1159 internalDetach(); 1160 1161 // notify any detach listener 1162 IDetachListener detachListener = getApplication().getFrameworkSettings() 1163 .getDetachListener(); 1164 if (detachListener != null) 1165 { 1166 detachListener.onDetach(this); 1167 } 1168 } 1169 1170 private void detachFeedback() 1171 { 1172 FeedbackMessages feedback = getMetaData(FEEDBACK_KEY); 1173 if (feedback != null) 1174 { 1175 feedback.clear(getApplication().getApplicationSettings() 1176 .getFeedbackMessageCleanupFilter()); 1177 1178 if (feedback.isEmpty()) 1179 { 1180 setMetaData(FEEDBACK_KEY, null); 1181 } 1182 else 1183 { 1184 feedback.detach(); 1185 } 1186 } 1187 } 1188 1189 /** 1190 * Removes the cached markup at the end of the request. For the next request it will be get 1191 * either from the parent's markup or from {@link MarkupCache}. 1192 */ 1193 private void internalDetach() 1194 { 1195 markup = null; 1196 } 1197 1198 /** 1199 * Detaches all models 1200 */ 1201 public void detachModels() 1202 { 1203 // Detach any detachable model from this component 1204 detachModel(); 1205 } 1206 1207 /** 1208 * Registers an error feedback message for this component 1209 * 1210 * @param message 1211 * The feedback message 1212 */ 1213 @Override 1214 public final void error(final Serializable message) 1215 { 1216 getFeedbackMessages().error(this, message); 1217 addStateChange(); 1218 } 1219 1220 /** 1221 * Registers a fatal feedback message for this component 1222 * 1223 * @param message 1224 * The feedback message 1225 */ 1226 @Override 1227 public final void fatal(final Serializable message) 1228 { 1229 getFeedbackMessages().fatal(this, message); 1230 addStateChange(); 1231 } 1232 1233 /** 1234 * Finds the first container parent of this component of the given class. 1235 * 1236 * @param <Z> 1237 * type of parent 1238 * 1239 * 1240 * @param c 1241 * MarkupContainer class to search for 1242 * @return First container parent that is an instance of the given class, or null if none can be 1243 * found 1244 */ 1245 public final <Z> Z findParent(final Class<Z> c) 1246 { 1247 // Start with immediate parent 1248 MarkupContainer current = parent; 1249 1250 // Walk up containment hierarchy 1251 while (current != null) 1252 { 1253 // Is current an instance of this class? 1254 if (c.isInstance(current)) 1255 { 1256 return c.cast(current); 1257 } 1258 1259 // Check parent 1260 current = current.getParent(); 1261 } 1262 1263 // Failed to find component 1264 return null; 1265 } 1266 1267 /** 1268 * @return The nearest markup container with associated markup 1269 */ 1270 public final MarkupContainer findParentWithAssociatedMarkup() 1271 { 1272 MarkupContainer container = parent; 1273 while (container != null) 1274 { 1275 if (container.getAssociatedMarkup() != null) 1276 { 1277 return container; 1278 } 1279 container = container.getParent(); 1280 } 1281 1282 // This should never happen since Page always has associated markup 1283 throw new WicketRuntimeException("Unable to find parent with associated markup"); 1284 } 1285 1286 /** 1287 * Gets interface to application that this component is a part of. 1288 * 1289 * @return The application associated with the session that this component is in. 1290 * @see Application 1291 */ 1292 public final Application getApplication() 1293 { 1294 return Application.get(); 1295 } 1296 1297 /** 1298 * @return A path of the form [page-class-name]:[page-relative-path] 1299 * @see Component#getPageRelativePath() 1300 */ 1301 public final String getClassRelativePath() 1302 { 1303 return getClass().getName() + PATH_SEPARATOR + getPageRelativePath(); 1304 } 1305 1306 /** 1307 * Get the converter that should be used by this component, delegates to 1308 * {@link #createConverter(Class)} and then to the application's 1309 * {@link IConverterLocator}. 1310 * 1311 * @param type 1312 * The type to convert to 1313 * 1314 * @return The converter that should be used by this component 1315 */ 1316 @SuppressWarnings("unchecked") 1317 @Override 1318 public <C> IConverter<C> getConverter(Class<C> type) { 1319 IConverter<?> converter = createConverter(type); 1320 if (converter != null) { 1321 return (IConverter<C>) converter; 1322 } 1323 return getApplication().getConverterLocator().getConverter(type); 1324 } 1325 1326 /** 1327 * Factory method for converters to be used by this component, 1328 * returns {@code null} by default. 1329 * 1330 * @param type 1331 * The type to convert to 1332 * 1333 * @return a converter to be used by this component 1334 */ 1335 protected IConverter<?> createConverter(Class<?> type) { 1336 return null; 1337 } 1338 1339 /** 1340 * Gets whether model strings should be escaped. 1341 * 1342 * @return Returns whether model strings should be escaped 1343 */ 1344 public final boolean getEscapeModelStrings() 1345 { 1346 return getFlag(FLAG_ESCAPE_MODEL_STRINGS); 1347 } 1348 1349 /** 1350 * Gets the id of this component. 1351 * 1352 * @return The id of this component 1353 */ 1354 @Override 1355 public String getId() 1356 { 1357 return id; 1358 } 1359 1360 /** 1361 * @return Innermost model for this component 1362 */ 1363 public final IModel<?> getInnermostModel() 1364 { 1365 return getInnermostModel(getDefaultModel()); 1366 } 1367 1368 /** 1369 * Gets the locale for this component. By default, it searches its parents for a locale. If no 1370 * parents (it's a recursive search) returns a locale, it gets one from the session. 1371 * 1372 * @return The locale to be used for this component 1373 * @see Session#getLocale() 1374 */ 1375 public Locale getLocale() 1376 { 1377 if (parent != null) 1378 { 1379 return parent.getLocale(); 1380 } 1381 return getSession().getLocale(); 1382 } 1383 1384 /** 1385 * Convenience method to provide easy access to the localizer object within any component. 1386 * 1387 * @return The localizer object 1388 */ 1389 public final Localizer getLocalizer() 1390 { 1391 return getApplication().getResourceSettings().getLocalizer(); 1392 } 1393 1394 /** 1395 * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT USE IT! 1396 * 1397 * Get the first component tag in the associated markup 1398 * 1399 * @return first component tag 1400 */ 1401 protected final ComponentTag getMarkupTag() 1402 { 1403 IMarkupFragment markup = getMarkup(); 1404 if (markup != null) 1405 { 1406 for (int i = 0; i < markup.size(); i++) 1407 { 1408 MarkupElement elem = markup.get(i); 1409 if (elem instanceof ComponentTag) 1410 { 1411 return (ComponentTag)elem; 1412 } 1413 } 1414 } 1415 return null; 1416 } 1417 1418 /** 1419 * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT USE IT! 1420 * 1421 * Get a copy of the markup's attributes which are associated with the component. 1422 * <p> 1423 * Modifications to the map returned don't change the tags attributes. It is just a copy. 1424 * <p> 1425 * Note: The component must have been added (directly or indirectly) to a container with an 1426 * associated markup file (Page, Panel or Border). 1427 * 1428 * @return markup attributes 1429 */ 1430 public final ValueMap getMarkupAttributes() 1431 { 1432 ComponentTag tag = getMarkupTag(); 1433 if (tag != null) 1434 { 1435 ValueMap attrs = new ValueMap(tag.getAttributes()); 1436 attrs.makeImmutable(); 1437 return attrs; 1438 } 1439 return ValueMap.EMPTY_MAP; 1440 } 1441 1442 /** 1443 * Get the markupId 1444 * 1445 * @return MarkupId 1446 */ 1447 public final Object getMarkupIdImpl() 1448 { 1449 if (generatedMarkupId != -1) 1450 { 1451 return generatedMarkupId; 1452 } 1453 1454 String id = getMetaData(MARKUP_ID_KEY); 1455 1456 // if still no markup id is found, and the component has been attached to a page, try to 1457 // retrieve the id from the markup file. 1458 if (id == null && findPage() != null) 1459 { 1460 id = getMarkupIdFromMarkup(); 1461 } 1462 return id; 1463 } 1464 1465 /** 1466 * Retrieves id by which this component is represented within the markup. This is either the id 1467 * attribute set explicitly via a call to {@link #setMarkupId(String)}, id attribute defined in 1468 * the markup, or an automatically generated id - in that order. 1469 * <p> 1470 * If no id is set and <code>createIfDoesNotExist</code> is false, this method will return null. 1471 * Otherwise it will generate an id value which by default will be unique in the page. This is 1472 * the preferred way as there is no chance of id collision. This will also enable 1473 * {@link #setOutputMarkupId(boolean)}. 1474 * <p> 1475 * 1476 * <p> 1477 * Note: This method should only be called after the component or its parent have been added to 1478 * the page. 1479 * 1480 * @param createIfDoesNotExist 1481 * When there is no existing markup id, determines whether it should be generated or 1482 * whether <code>null</code> should be returned. 1483 * 1484 * @return markup id of the component 1485 */ 1486 public String getMarkupId(boolean createIfDoesNotExist) 1487 { 1488 IMarkupIdGenerator markupIdGenerator = getApplication().getMarkupSettings().getMarkupIdGenerator(); 1489 String markupId = markupIdGenerator.generateMarkupId(this, createIfDoesNotExist); 1490 return markupId; 1491 } 1492 1493 /** 1494 * Retrieves id by which this component is represented within the markup. This is either the id 1495 * attribute set explicitly via a call to {@link #setMarkupId(String)}, id attribute defined in 1496 * the markup, or an automatically generated id - in that order. 1497 * <p> 1498 * If no explicit id is set this function will generate an id value that will be unique in the 1499 * page. This is the preferred way as there is no chance of id collision. This will also enable 1500 * {@link #setOutputMarkupId(boolean)}. 1501 * <p> 1502 * Note: This method should only be called after the component or its parent have been added to 1503 * the page. 1504 * 1505 * @return markup id of the component 1506 */ 1507 public String getMarkupId() 1508 { 1509 return getMarkupId(true); 1510 } 1511 1512 /** 1513 * Gets metadata for this component using the given key. 1514 * 1515 * @param <M> 1516 * The type of the metadata. 1517 * 1518 * @param key 1519 * The key for the data 1520 * @return The metadata or null of no metadata was found for the given key 1521 * @see MetaDataKey 1522 */ 1523 @Override 1524 public final <M extends Serializable> M getMetaData(final MetaDataKey<M> key) 1525 { 1526 return key.get(getMetaData()); 1527 } 1528 1529 /** 1530 * Gets the meta data entries for this component as an array of {@link MetaDataEntry} objects. 1531 * 1532 * @return the meta data entries for this component 1533 */ 1534 private MetaDataEntry<?>[] getMetaData() 1535 { 1536 MetaDataEntry<?>[] metaData = null; 1537 1538 // index where we should expect the entry 1539 int index = getFlag(FLAG_MODEL_SET) ? 1 : 0; 1540 1541 int length = data_length(); 1542 1543 if (index < length) 1544 { 1545 Object object = data_get(index); 1546 if (object instanceof MetaDataEntry<?>[]) 1547 { 1548 metaData = (MetaDataEntry<?>[])object; 1549 } 1550 else if (object instanceof MetaDataEntry) 1551 { 1552 metaData = new MetaDataEntry[] { (MetaDataEntry<?>)object }; 1553 } 1554 } 1555 1556 return metaData; 1557 } 1558 1559 /** 1560 * Gets the model. It returns the object that wraps the backing model. 1561 * 1562 * @return The model 1563 */ 1564 public final IModel<?> getDefaultModel() 1565 { 1566 IModel<?> model = getModelImpl(); 1567 // If model is null 1568 if (model == null) 1569 { 1570 // give subclass a chance to lazy-init model 1571 model = initModel(); 1572 setModelImpl(model); 1573 } 1574 1575 return model; 1576 } 1577 1578 /** 1579 * Gets the backing model object. Unlike getDefaultModel().getObject(), this method returns null 1580 * for a null model. 1581 * 1582 * @return The backing model object 1583 */ 1584 public final Object getDefaultModelObject() 1585 { 1586 final IModel<?> model = getDefaultModel(); 1587 if (model != null) 1588 { 1589 try 1590 { 1591 // Get model value for this component. 1592 return model.getObject(); 1593 } 1594 catch (Exception ex) 1595 { 1596 // wrap the exception so that it brings info about the component 1597 WicketRuntimeException rex = new WicketRuntimeException( 1598 "An error occurred while getting the model object for Component: " + 1599 this.toString(true), ex); 1600 throw rex; 1601 } 1602 } 1603 return null; 1604 } 1605 1606 /** 1607 * Gets a model object as a string. Depending on the "escape model strings" flag of the 1608 * component, the string is either HTML escaped or not. "HTML escaped" meaning that only HTML 1609 * sensitive chars are escaped but not all none-ascii chars. Proper HTML encoding should be used 1610 * instead. In case you really need a fully escaped model string you may call 1611 * {@link Strings#escapeMarkup(CharSequence, boolean, boolean)} on the model string returned. 1612 * 1613 * @see Strings#escapeMarkup(CharSequence, boolean, boolean) 1614 * @see #getEscapeModelStrings() 1615 * 1616 * @return Model object for this component as a string 1617 */ 1618 public final String getDefaultModelObjectAsString() 1619 { 1620 return getDefaultModelObjectAsString(getDefaultModelObject()); 1621 } 1622 1623 /** 1624 * Gets a model object as a string. Depending on the "escape model strings" flag of the 1625 * component, the string is either HTML escaped or not. "HTML escaped" meaning that only HTML 1626 * sensitive chars are escaped but not all none-ascii chars. Proper HTML encoding should be used 1627 * instead. In case you really need a fully escaped model string you may call 1628 * {@link Strings#escapeMarkup(CharSequence, boolean, boolean)} on the model string returned. 1629 * 1630 * @see Strings#escapeMarkup(CharSequence, boolean, boolean) 1631 * @see #getEscapeModelStrings() 1632 * 1633 * @param modelObject 1634 * Model object to convert to string 1635 * @return The string 1636 */ 1637 @SuppressWarnings({ "rawtypes", "unchecked" }) 1638 public final String getDefaultModelObjectAsString(final Object modelObject) 1639 { 1640 if (modelObject != null) 1641 { 1642 // Get converter 1643 final Class<?> objectClass = modelObject.getClass(); 1644 1645 final IConverter converter = getConverter(objectClass); 1646 1647 // Model string from property 1648 final String modelString = converter.convertToString(modelObject, getLocale()); 1649 1650 if (modelString != null) 1651 { 1652 // If we should escape the markup 1653 if (getFlag(FLAG_ESCAPE_MODEL_STRINGS)) 1654 { 1655 // Escape HTML sensitive characters only. Not all none-ascii chars 1656 return Strings.escapeMarkup(modelString, false, false).toString(); 1657 } 1658 return modelString; 1659 } 1660 } 1661 return ""; 1662 } 1663 1664 /** 1665 * Gets whether or not component will output id attribute into the markup. id attribute will be 1666 * set to the value returned from {@link Component#getMarkupId()}. 1667 * 1668 * @return whether or not component will output id attribute into the markup 1669 */ 1670 public final boolean getOutputMarkupId() 1671 { 1672 return getFlag(FLAG_OUTPUT_MARKUP_ID); 1673 } 1674 1675 /** 1676 * Gets whether or not an invisible component will render a placeholder tag. 1677 * 1678 * @return true if a placeholder tag should be rendered 1679 */ 1680 public final boolean getOutputMarkupPlaceholderTag() 1681 { 1682 return getFlag(FLAG_PLACEHOLDER); 1683 } 1684 1685 /** 1686 * Gets the page holding this component. 1687 * 1688 * @return The page holding this component 1689 * @throws WicketRuntimeException 1690 * Thrown if component is not yet attached to a Page. 1691 * @see #findPage() 1692 */ 1693 @Override 1694 public final Page getPage() 1695 { 1696 // Search for nearest Page 1697 final Page page = findPage(); 1698 1699 // If no Page was found 1700 if (page == null) 1701 { 1702 // Give up with a nice exception 1703 throw new WicketRuntimeException("No Page found for component: " + this.toString(true) 1704 + ". You probably forgot to add it to its parent component."); 1705 } 1706 1707 return page; 1708 } 1709 1710 /** 1711 * Gets the path to this component relative to its containing page, i.e. without leading page 1712 * id. 1713 * 1714 * @return The path to this component relative to the page it is in 1715 */ 1716 @Override 1717 public final String getPageRelativePath() 1718 { 1719 return Strings.afterFirstPathComponent(getPath(), PATH_SEPARATOR); 1720 } 1721 1722 /** 1723 * Gets any parent container, or null if there is none. 1724 * 1725 * @return Any parent container, or null if there is none 1726 */ 1727 @Override 1728 public final MarkupContainer getParent() 1729 { 1730 return parent; 1731 } 1732 1733 /** 1734 * Gets this component's path. 1735 * 1736 * @return Colon separated path to this component in the component hierarchy 1737 */ 1738 public final String getPath() 1739 { 1740 final PrependingStringBuffer buffer = new PrependingStringBuffer(32); 1741 for (Component c = this; c != null; c = c.getParent()) 1742 { 1743 if (buffer.length() > 0) 1744 { 1745 buffer.prepend(PATH_SEPARATOR); 1746 } 1747 buffer.prepend(c.getId()); 1748 } 1749 return buffer.toString(); 1750 } 1751 1752 /** 1753 * If false the component's tag will be printed as well as its body (which is default). If true 1754 * only the body will be printed, but not the component's tag. 1755 * 1756 * @return If true, the component tag will not be printed 1757 */ 1758 public final boolean getRenderBodyOnly() 1759 { 1760 return getFlag(FLAG_RENDER_BODY_ONLY); 1761 } 1762 1763 /** 1764 * @return The request for this component's active request cycle 1765 */ 1766 public final Request getRequest() 1767 { 1768 RequestCycle requestCycle = getRequestCycle(); 1769 if (requestCycle == null) 1770 { 1771 // Happens often with WicketTester when one forgets to call 1772 // createRequestCycle() 1773 throw new WicketRuntimeException("No RequestCycle is currently set!"); 1774 } 1775 return requestCycle.getRequest(); 1776 } 1777 1778 /** 1779 * Gets the active request cycle for this component 1780 * 1781 * @return The request cycle 1782 */ 1783 public final RequestCycle getRequestCycle() 1784 { 1785 return RequestCycle.get(); 1786 } 1787 1788 /** 1789 * @return The response for this component's active request cycle 1790 */ 1791 public final Response getResponse() 1792 { 1793 return getRequestCycle().getResponse(); 1794 } 1795 1796 /** 1797 * Gets the current Session object. 1798 * 1799 * @return The Session that this component is in 1800 */ 1801 public Session getSession() 1802 { 1803 return Session.get(); 1804 } 1805 1806 /** 1807 * @return Size of this Component in bytes. Returns {@code 0} - if the size cannot be calculated for some reason 1808 */ 1809 public long getSizeInBytes() 1810 { 1811 final MarkupContainer originalParent = parent; 1812 parent = null; 1813 long size = 0; 1814 try 1815 { 1816 size = WicketObjects.sizeof(this); 1817 } 1818 catch (Exception e) 1819 { 1820 log.error("Exception getting size for component " + this, e); 1821 } 1822 parent = originalParent; 1823 return size; 1824 } 1825 1826 /** 1827 * @param key 1828 * Key of string resource in property file 1829 * @return The String 1830 * @see Localizer 1831 */ 1832 public final String getString(final String key) 1833 { 1834 return getString(key, null); 1835 } 1836 1837 /** 1838 * @param key 1839 * The resource key 1840 * @param model 1841 * The model 1842 * @return The formatted string 1843 * @see Localizer 1844 */ 1845 public final String getString(final String key, final IModel<?> model) 1846 { 1847 return getLocalizer().getString(key, this, model); 1848 } 1849 1850 /** 1851 * @param key 1852 * The resource key 1853 * @param model 1854 * The model 1855 * @param defaultValue 1856 * A default value if the string cannot be found 1857 * @return The formatted string 1858 * @see Localizer 1859 */ 1860 public final String getString(final String key, final IModel<?> model, final String defaultValue) 1861 { 1862 return getLocalizer().getString(key, this, model, defaultValue); 1863 } 1864 1865 /** 1866 * A convenience method to access the Sessions's style. 1867 * 1868 * @return The style of this component respectively the style of the Session. 1869 * 1870 * @see org.apache.wicket.Session#getStyle() 1871 */ 1872 public final String getStyle() 1873 { 1874 Session session = getSession(); 1875 if (session == null) 1876 { 1877 throw new WicketRuntimeException("Wicket Session object not available"); 1878 } 1879 return session.getStyle(); 1880 } 1881 1882 /** 1883 * Gets the variation string of this component that will be used to look up markup for this 1884 * component. Subclasses can override this method to define by an instance what markup variation 1885 * should be picked up. By default it will return null or the value of a parent. 1886 * 1887 * @return The variation of this component. 1888 */ 1889 public String getVariation() 1890 { 1891 if (parent != null) 1892 { 1893 return parent.getVariation(); 1894 } 1895 return null; 1896 } 1897 1898 /** 1899 * Gets whether this component was rendered at least once. 1900 * 1901 * @return true if the component has been rendered before, false if it is merely constructed 1902 */ 1903 public final boolean hasBeenRendered() 1904 { 1905 return getFlag(FLAG_HAS_BEEN_RENDERED); 1906 } 1907 1908 /** 1909 * Gets feedback messages for this component. This method will instantiate a 1910 * {@link FeedbackMessages} instance and add it to the component metadata, even when called on a 1911 * component that has no feedback messages, to avoid the overhead use 1912 * {@link #hasFeedbackMessage()} 1913 * 1914 * @return feedback messages instance 1915 */ 1916 public FeedbackMessages getFeedbackMessages() 1917 { 1918 FeedbackMessages messages = getMetaData(FEEDBACK_KEY); 1919 if (messages == null) 1920 { 1921 messages = new FeedbackMessages(); 1922 setMetaData(FEEDBACK_KEY, messages); 1923 } 1924 return messages; 1925 } 1926 1927 /** 1928 * @return True if this component has an error message 1929 */ 1930 public final boolean hasErrorMessage() 1931 { 1932 FeedbackMessages messages = getMetaData(FEEDBACK_KEY); 1933 if (messages == null) 1934 { 1935 return false; 1936 } 1937 return messages.hasMessage(FeedbackMessage.ERROR); 1938 } 1939 1940 /** 1941 * @return True if this component has some kind of feedback message 1942 * 1943 */ 1944 public final boolean hasFeedbackMessage() 1945 { 1946 FeedbackMessages messages = getMetaData(FEEDBACK_KEY); 1947 if (messages == null) 1948 { 1949 return false; 1950 } 1951 return messages.size() > 0; 1952 } 1953 1954 /** 1955 * Registers an informational feedback message for this component 1956 * 1957 * @param message 1958 * The feedback message 1959 */ 1960 @Override 1961 public final void info(final Serializable message) 1962 { 1963 getFeedbackMessages().info(this, message); 1964 addStateChange(); 1965 } 1966 1967 /** 1968 * Registers an success feedback message for this component 1969 * 1970 * @param message 1971 * The feedback message 1972 */ 1973 @Override 1974 public final void success(final Serializable message) 1975 { 1976 getFeedbackMessages().success(this, message); 1977 addStateChange(); 1978 } 1979 1980 /** 1981 * Authorizes an action for a component. 1982 * 1983 * @param action 1984 * The action to authorize 1985 * @return True if the action is allowed 1986 * @throws AuthorizationException 1987 * Can be thrown by implementation if action is unauthorized 1988 */ 1989 public final boolean isActionAuthorized(Action action) 1990 { 1991 IAuthorizationStrategy authorizationStrategy = getSession().getAuthorizationStrategy(); 1992 if (authorizationStrategy != null) 1993 { 1994 return authorizationStrategy.isActionAuthorized(this, action); 1995 } 1996 return true; 1997 } 1998 1999 /** 2000 * @return true if this component is authorized to be enabled, false otherwise 2001 */ 2002 public final boolean isEnableAllowed() 2003 { 2004 return isActionAuthorized(ENABLE); 2005 } 2006 2007 /** 2008 * Gets whether this component is enabled. Specific components may decide to implement special 2009 * behavior that uses this property, like web form components that add a disabled='disabled' 2010 * attribute when enabled is false. 2011 * 2012 * @return Whether this component is enabled. 2013 */ 2014 public boolean isEnabled() 2015 { 2016 return getFlag(FLAG_ENABLED); 2017 } 2018 2019 /** 2020 * Checks the security strategy if the {@link Component#RENDER} action is allowed on this 2021 * component 2022 * 2023 * @return true if {@link Component#RENDER} action is allowed, false otherwise 2024 */ 2025 public final boolean isRenderAllowed() 2026 { 2027 return getFlag(FLAG_IS_RENDER_ALLOWED); 2028 } 2029 2030 /** 2031 * Returns if the component is stateless or not. It checks the stateless hint if that is false 2032 * it returns directly false. If that is still true it checks all its behaviors if they can be 2033 * stateless. 2034 * 2035 * @return whether the component is stateless. 2036 */ 2037 public final boolean isStateless() 2038 { 2039 if ((isVisibleInHierarchy() && isEnabledInHierarchy()) == false && canCallListener() == false) 2040 { 2041 // the component is either invisible or disabled and it can't call listeners 2042 // then pretend the component is stateless 2043 return true; 2044 } 2045 2046 if (!getStatelessHint()) 2047 { 2048 return false; 2049 } 2050 2051 for (Behavior behavior : getBehaviors()) 2052 { 2053 if (!behavior.getStatelessHint(this)) 2054 { 2055 return false; 2056 } 2057 } 2058 return true; 2059 } 2060 2061 /** 2062 * @return {@code true} if this component should notify its holding page about changes in its 2063 * state. If a {@link Page} is not versioned then it wont track changes in its 2064 * components and will use the same {@link Page#getPageId()} during its lifetime 2065 */ 2066 public boolean isVersioned() 2067 { 2068 // Is the component itself versioned? 2069 if (!getFlag(FLAG_VERSIONED)) 2070 { 2071 return false; 2072 } 2073 else 2074 { 2075 // If there's a parent and this component is versioned 2076 if (parent != null) 2077 { 2078 // Check if the parent is unversioned. If any parent 2079 // (recursively) is unversioned, then this component is too 2080 if (!parent.isVersioned()) 2081 { 2082 return false; 2083 } 2084 } 2085 return true; 2086 } 2087 } 2088 2089 /** 2090 * Gets whether this component and any children are visible. 2091 * <p> 2092 * WARNING: this method can be called multiple times during a request. If you override this 2093 * method, it is a good idea to keep it cheap in terms of processing. Alternatively, you can 2094 * call {@link #setVisible(boolean)}. 2095 * <p> 2096 * 2097 * @return True if component and any children are visible 2098 */ 2099 public boolean isVisible() 2100 { 2101 return getFlag(FLAG_VISIBLE); 2102 } 2103 2104 /** 2105 * Checks if the component itself and all its parents are visible. 2106 * 2107 * @return true if the component and all its parents are visible. 2108 */ 2109 public final boolean isVisibleInHierarchy() 2110 { 2111 if (getRequestFlag(RFLAG_VISIBLE_IN_HIERARCHY_SET)) 2112 { 2113 return getRequestFlag(RFLAG_VISIBLE_IN_HIERARCHY_VALUE); 2114 } 2115 2116 final boolean state; 2117 Component parent = getParent(); 2118 if (parent != null && !parent.isVisibleInHierarchy()) 2119 { 2120 state = false; 2121 } 2122 else 2123 { 2124 state = determineVisibility(); 2125 } 2126 2127 setRequestFlag(RFLAG_VISIBLE_IN_HIERARCHY_SET, true); 2128 setRequestFlag(RFLAG_VISIBLE_IN_HIERARCHY_VALUE, state); 2129 return state; 2130 } 2131 2132 /** 2133 * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT USE IT! 2134 * 2135 * Sets the RENDERING flag and removes the PREPARED_FOR_RENDER flag on component and it's 2136 * children. 2137 * 2138 * @param setRenderingFlag 2139 * if this is false only the PREPARED_FOR_RENDER flag is removed from component, the 2140 * RENDERING flag is not set. 2141 */ 2142 public final void markRendering(boolean setRenderingFlag) 2143 { 2144 internalMarkRendering(setRenderingFlag); 2145 } 2146 2147 /** 2148 * Called to indicate that the model content for this component has been changed 2149 */ 2150 public final void modelChanged() 2151 { 2152 // Call user code 2153 internalOnModelChanged(); 2154 onModelChanged(); 2155 } 2156 2157 /** 2158 * Called to indicate that the model content for this component is about to change 2159 */ 2160 public final void modelChanging() 2161 { 2162 checkHierarchyChange(this); 2163 2164 // Call user code 2165 onModelChanging(); 2166 2167 // Tell the page that our model changed 2168 final Page page = findPage(); 2169 if (page != null) 2170 { 2171 page.componentModelChanging(this); 2172 } 2173 } 2174 2175 /** 2176 * Redirects browser to an intermediate page such as a sign-in page. The current request's URL 2177 * is saved for future use by method {@link #continueToOriginalDestination()}; only use this method when 2178 * you plan to continue to the current URL at some later time; otherwise just set a new response page. 2179 * 2180 * @param page 2181 * The sign in page 2182 * 2183 * @see #setResponsePage(Class) 2184 * @see #setResponsePage(IRequestablePage) 2185 * @see #setResponsePage(Class, PageParameters) 2186 * @see Component#continueToOriginalDestination() 2187 */ 2188 public final void redirectToInterceptPage(final Page page) 2189 { 2190 throw new RestartResponseAtInterceptPageException(page); 2191 } 2192 2193 /** 2194 * Removes this component from its parent. It's important to remember that a component that is 2195 * removed cannot be referenced from the markup still. 2196 * <p> 2197 * You must not use this method in your callback to any of the 2198 * {@link MarkupContainer#visitChildren(IVisitor)} methods. See <a 2199 * href="https://issues.apache.org/jira/browse/WICKET-3229">WICKET-3329</a>. 2200 */ 2201 public final void remove() 2202 { 2203 if (parent == null) 2204 { 2205 throw new IllegalStateException("Cannot remove " + this + " from null parent!"); 2206 } 2207 parent.remove(this); 2208 } 2209 2210 /** 2211 * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT USE IT! 2212 * <p> 2213 * Renders this component as a part of a response - the caller has to 2214 * make sure that this component is prepared for render. 2215 * 2216 * @see #beforeRender() 2217 */ 2218 public final void renderPart() { 2219 Page page = getPage(); 2220 2221 page.startComponentRender(this); 2222 2223 markRendering(true); 2224 2225 render(); 2226 2227 page.endComponentRender(this); 2228 } 2229 2230 /** 2231 * Render this component and all its children. Always calls hook {@link #onAfterRender()} 2232 * regardless of any exception. 2233 */ 2234 public final void render() 2235 { 2236 if (isAuto()) 2237 { 2238 // auto components are prepared when rendered 2239 beforeRender(); 2240 } 2241 2242 // Do the render 2243 RuntimeException exception = null; 2244 try 2245 { 2246 setRequestFlag(RFLAG_RENDERING, true); 2247 2248 internalRender(); 2249 } 2250 catch (final RuntimeException ex) 2251 { 2252 // Remember it as the originating exception 2253 exception = ex; 2254 } 2255 finally 2256 { 2257 try 2258 { 2259 // Cleanup 2260 afterRender(); 2261 } 2262 catch (RuntimeException ex2) 2263 { 2264 // Only remember it if not already another exception happened 2265 if (exception == null) 2266 { 2267 exception = ex2; 2268 } 2269 } 2270 } 2271 2272 // Re-throw if needed 2273 if (exception != null) 2274 { 2275 throw exception; 2276 } 2277 } 2278 2279 /** 2280 * Performs a render of this component as part of a Page level render process. 2281 */ 2282 private void internalRender() 2283 { 2284 // Make sure there is a markup available for the Component 2285 IMarkupFragment markup = getMarkup(); 2286 if (markup == null) 2287 { 2288 throw new MarkupNotFoundException("Markup not found for Component: " + toString()); 2289 } 2290 2291 // MarkupStream is an Iterator for the markup 2292 MarkupStream markupStream = new MarkupStream(markup); 2293 2294 MarkupElement elem = markup.get(0); 2295 if (elem instanceof ComponentTag) 2296 { 2297 // Guarantee that the markupStream is set and determineVisibility not yet tested 2298 // See WICKET-2049 2299 ((ComponentTag)elem).onBeforeRender(this, markupStream); 2300 } 2301 2302 // Determine if component is visible using it's authorization status 2303 // and the isVisible property. 2304 if (determineVisibility()) 2305 { 2306 setFlag(FLAG_HAS_BEEN_RENDERED, true); 2307 2308 // Rendering is beginning 2309 if (log.isDebugEnabled()) 2310 { 2311 log.debug("Begin render {}", this); 2312 } 2313 2314 try 2315 { 2316 notifyBehaviorsComponentBeforeRender(); 2317 onRender(); 2318 notifyBehaviorsComponentRendered(); 2319 2320 // Component has been rendered 2321 rendered(); 2322 } 2323 catch (RuntimeException ex) 2324 { 2325 onException(ex); 2326 } 2327 2328 if (log.isDebugEnabled()) 2329 { 2330 log.debug("End render {}", this); 2331 } 2332 } 2333 // elem is null when rendering a page 2334 else if ((elem != null) && (elem instanceof ComponentTag)) 2335 { 2336 if (getFlag(FLAG_PLACEHOLDER)) 2337 { 2338 renderPlaceholderTag(((ComponentTag)elem).mutable(), getResponse()); 2339 } 2340 } 2341 } 2342 2343 /** 2344 * Called when a runtime exception is caught during the render process 2345 * 2346 * @param ex 2347 * The exception caught. 2348 */ 2349 private void onException(final RuntimeException ex) 2350 { 2351 // Call each behaviors onException() to allow the 2352 // behavior to clean up 2353 for (Behavior behavior : getBehaviors()) 2354 { 2355 if (isBehaviorAccepted(behavior)) 2356 { 2357 try 2358 { 2359 behavior.onException(this, ex); 2360 } 2361 catch (Exception ex2) 2362 { 2363 log.error("Error while cleaning up after exception", ex2); 2364 } 2365 } 2366 } 2367 2368 // Re-throw the exception 2369 throw ex; 2370 } 2371 2372 /** 2373 * Renders a placeholder tag for the component when it is invisible and 2374 * {@link #setOutputMarkupPlaceholderTag(boolean)} has been called with <code>true</code>. 2375 * 2376 * @param tag 2377 * component tag 2378 * @param response 2379 * response 2380 */ 2381 protected void renderPlaceholderTag(final ComponentTag tag, final Response response) 2382 { 2383 String name = Strings.isEmpty(tag.getNamespace()) ? tag.getName() 2384 : tag.getNamespace() + ':' + tag.getName(); 2385 2386 // prefer concatenation over String#format() for performance 2387 response.write( 2388 "<" + name + " id=\"" + getAjaxRegionMarkupId() + 2389 "\" hidden=\"\" data-wicket-placeholder=\"\"></" + name + ">"); 2390 } 2391 2392 2393 /** 2394 * Returns the id of the markup region that will be updated via ajax. This can be different to 2395 * the markup id of the component if a {@link IAjaxRegionMarkupIdProvider} behavior has been 2396 * added. 2397 * 2398 * @return the markup id of the region to be updated via ajax. 2399 */ 2400 public final String getAjaxRegionMarkupId() 2401 { 2402 String markupId = null; 2403 for (Behavior behavior : getBehaviors()) 2404 { 2405 if (behavior instanceof IAjaxRegionMarkupIdProvider && behavior.isEnabled(this)) 2406 { 2407 markupId = ((IAjaxRegionMarkupIdProvider)behavior).getAjaxRegionMarkupId(this); 2408 break; 2409 } 2410 } 2411 if (markupId == null) 2412 { 2413 if (this instanceof IAjaxRegionMarkupIdProvider) 2414 { 2415 markupId = ((IAjaxRegionMarkupIdProvider)this).getAjaxRegionMarkupId(this); 2416 } 2417 } 2418 if (markupId == null) 2419 { 2420 markupId = getMarkupId(); 2421 } 2422 return markupId; 2423 } 2424 2425 2426 /** 2427 * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT USE IT! 2428 * <p> 2429 * Renders the component at the current position in the given markup stream. The method 2430 * onComponentTag() is called to allow the component to mutate the start tag. The method 2431 * onComponentTagBody() is then called to permit the component to render its body. 2432 */ 2433 protected final void internalRenderComponent() 2434 { 2435 final IMarkupFragment markup = getMarkup(); 2436 if (markup == null) 2437 { 2438 throw new MarkupException("Markup not found. Component: " + toString()); 2439 } 2440 2441 final MarkupStream markupStream = new MarkupStream(markup); 2442 2443 // Get mutable copy of next tag 2444 final ComponentTag openTag = markupStream.getTag(); 2445 final ComponentTag tag = openTag.mutable(); 2446 2447 // call application-wide tag listeners 2448 getApplication().getOnComponentTagListeners().onComponentTag(this, tag); 2449 2450 // Call any tag handler 2451 onComponentTag(tag); 2452 2453 // If we're an openclose tag 2454 if (!tag.isOpenClose() && !tag.isOpen()) 2455 { 2456 // We were something other than <tag> or <tag/> 2457 markupStream.throwMarkupException("Method renderComponent called on bad markup element: " + 2458 tag); 2459 } 2460 2461 if (tag.isOpenClose() && openTag.isOpen()) 2462 { 2463 markupStream.throwMarkupException("You can not modify a open tag to open-close: " + tag); 2464 } 2465 2466 try 2467 { 2468 // Render open tag 2469 boolean renderBodyOnly = getRenderBodyOnly(); 2470 if (renderBodyOnly) 2471 { 2472 ExceptionSettings.NotRenderableErrorStrategy notRenderableErrorStrategy = ExceptionSettings.NotRenderableErrorStrategy.LOG_WARNING; 2473 if (Application.exists()) 2474 { 2475 notRenderableErrorStrategy = getApplication().getExceptionSettings().getNotRenderableErrorStrategy(); 2476 } 2477 2478 if (getFlag(FLAG_OUTPUT_MARKUP_ID)) 2479 { 2480 String message = String.format("Markup id set on a component that renders its body only. " + 2481 "Markup id: %s, component id: %s.", getMarkupId(), getId()); 2482 if (notRenderableErrorStrategy == ExceptionSettings.NotRenderableErrorStrategy.THROW_EXCEPTION) 2483 { 2484 throw new IllegalStateException(message); 2485 } 2486 log.warn(message); 2487 } 2488 if (getFlag(FLAG_PLACEHOLDER)) 2489 { 2490 String message = String.format("Placeholder tag set on a component that renders its body only. " + 2491 "Component id: %s.", getId()); 2492 if (notRenderableErrorStrategy == ExceptionSettings.NotRenderableErrorStrategy.THROW_EXCEPTION) 2493 { 2494 throw new IllegalStateException(message); 2495 } 2496 log.warn(message); 2497 } 2498 } 2499 else 2500 { 2501 renderComponentTag(tag); 2502 } 2503 markupStream.next(); 2504 2505 // Render the body only if open-body-close. Do not render if open-close. 2506 if (tag.isOpen()) 2507 { 2508 // Render the body. The default strategy will simply call the component's 2509 // onComponentTagBody() implementation. 2510 getMarkupSourcingStrategy().onComponentTagBody(this, markupStream, tag); 2511 2512 // Render close tag 2513 if (openTag.isOpen()) 2514 { 2515 renderClosingComponentTag(markupStream, tag, renderBodyOnly); 2516 } 2517 else if (renderBodyOnly == false) 2518 { 2519 if (needToRenderTag(openTag)) 2520 { 2521 // Close the manually opened tag. And since the user might have changed the 2522 // tag name ... 2523 tag.writeSyntheticCloseTag(getResponse()); 2524 } 2525 } 2526 } 2527 } 2528 catch (WicketRuntimeException wre) 2529 { 2530 throw wre; 2531 } 2532 catch (RuntimeException re) 2533 { 2534 throw new WicketRuntimeException("Exception in rendering component: " + this, re); 2535 } 2536 } 2537 2538 /** 2539 * 2540 * @param openTag 2541 * @return true, if the tag shall be rendered 2542 */ 2543 private boolean needToRenderTag(final ComponentTag openTag) 2544 { 2545 // If a open-close tag has been modified to be open-body-close then a 2546 // synthetic close tag must be rendered. 2547 boolean renderTag = (openTag != null && !(openTag instanceof WicketTag)); 2548 if (renderTag == false) 2549 { 2550 renderTag = !getApplication().getMarkupSettings().getStripWicketTags(); 2551 } 2552 return renderTag; 2553 } 2554 2555 /** 2556 * Called to indicate that a component has been rendered. This method should only very rarely be 2557 * called at all. Some components may render its children without calling render() on them. 2558 * These components need to call rendered() to indicate that its child components were actually 2559 * rendered, the framework would think they had never been rendered, and in development mode 2560 * this would result in a runtime exception. 2561 */ 2562 public final void rendered() 2563 { 2564 Page page = findPage(); 2565 if (page != null) 2566 { 2567 // Tell the page that the component rendered 2568 page.componentRendered(this); 2569 } 2570 else 2571 { 2572 log.error("Component is not connected to a Page. Cannot register the component as being rendered. Component: " + 2573 toString()); 2574 } 2575 } 2576 2577 /** 2578 * Get the markup sourcing strategy for the component. If null, 2579 * {@link #newMarkupSourcingStrategy()} will be called. 2580 * 2581 * @return Markup sourcing strategy 2582 */ 2583 protected final IMarkupSourcingStrategy getMarkupSourcingStrategy() 2584 { 2585 if (markupSourcingStrategy == null) 2586 { 2587 markupSourcingStrategy = newMarkupSourcingStrategy(); 2588 2589 // If not strategy by provided, than we use a default one. 2590 if (markupSourcingStrategy == null) 2591 { 2592 markupSourcingStrategy = DefaultMarkupSourcingStrategy.get(); 2593 } 2594 } 2595 return markupSourcingStrategy; 2596 } 2597 2598 /** 2599 * If {@link #getMarkupSourcingStrategy()} returns null, this method will be called. By default 2600 * it returns null, which means that a default markup strategy will be attached to the 2601 * component. 2602 * <p> 2603 * Please note that markup source strategies are not persisted. Instead they get re-created by 2604 * calling this method again. That's ok since markup sourcing strategies usually do not maintain 2605 * a state. 2606 * 2607 * @return Markup sourcing strategy 2608 */ 2609 protected IMarkupSourcingStrategy newMarkupSourcingStrategy() 2610 { 2611 return null; 2612 } 2613 2614 /** 2615 * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT USE IT! 2616 * 2617 * Print to the web response what ever the component wants to contribute to the head section. 2618 * Make sure that all attached behaviors are asked as well. 2619 * <p> 2620 * NOT intended for overriding by framework clients. Rather, use 2621 * {@link Component#renderHead(org.apache.wicket.markup.head.IHeaderResponse)} 2622 * </p> 2623 * 2624 * @param container 2625 * The HtmlHeaderContainer 2626 */ 2627 public void internalRenderHead(final HtmlHeaderContainer container) 2628 { 2629 if (isVisibleInHierarchy() && isRenderAllowed()) 2630 { 2631 if (log.isDebugEnabled()) 2632 { 2633 log.debug("internalRenderHead: {}", toString(false)); 2634 } 2635 2636 IHeaderResponse response = container.getHeaderResponse(); 2637 2638 // Allow component to contribute 2639 boolean wasRendered = response.wasRendered(this); 2640 if (wasRendered == false) 2641 { 2642 LazyStringResponse markupHeaderResponse = new LazyStringResponse(); 2643 Response oldResponse = getResponse(); 2644 RequestCycle.get().setResponse(markupHeaderResponse); 2645 try 2646 { 2647 // Make sure the markup source strategy contributes to the header first 2648 // to be backward compatible. WICKET-3761 2649 getMarkupSourcingStrategy().renderHead(this, container); 2650 CharSequence headerContribution = markupHeaderResponse.getBuffer(); 2651 if (Strings.isEmpty(headerContribution) == false) 2652 { 2653 response.render(StringHeaderItem.forString(headerContribution)); 2654 } 2655 } 2656 finally 2657 { 2658 RequestCycle.get().setResponse(oldResponse); 2659 } 2660 // Then let the component itself to contribute to the header 2661 renderHead(response); 2662 } 2663 2664 // Then ask all behaviors 2665 for (Behavior behavior : getBehaviors()) 2666 { 2667 if (isBehaviorAccepted(behavior)) 2668 { 2669 List<IClusterable> pair = List.of(this, behavior); 2670 if (!response.wasRendered(pair)) 2671 { 2672 behavior.renderHead(this, response); 2673 response.markRendered(pair); 2674 } 2675 } 2676 } 2677 2678 if (wasRendered == false) 2679 { 2680 response.markRendered(this); 2681 } 2682 } 2683 } 2684 2685 /** 2686 * Replaces this component with another. The replacing component must have the same component id 2687 * as this component. This method serves as a shortcut to 2688 * 2689 * <code>this.getParent().replace(replacement)</code> 2690 * 2691 * and provides a better context for errors. 2692 * <p> 2693 * Usage: <code>component = component.replaceWith(replacement);</code> 2694 * </p> 2695 * 2696 * @since 1.2.1 2697 * 2698 * @param replacement 2699 * component to replace this one 2700 * @return the component which replaced this one 2701 */ 2702 public Component replaceWith(Component replacement) 2703 { 2704 Args.notNull(replacement, "replacement"); 2705 2706 if (!getId().equals(replacement.getId())) 2707 { 2708 throw new IllegalArgumentException( 2709 "Replacement component must have the same id as the component it will replace. Replacement id [[" + 2710 replacement.getId() + "]], replaced id [[" + getId() + "]]."); 2711 } 2712 if (parent == null) 2713 { 2714 throw new IllegalStateException( 2715 "This method can only be called on a component that has already been added to its parent."); 2716 } 2717 parent.replace(replacement); 2718 return replacement; 2719 } 2720 2721 /** 2722 * @param component 2723 * The component to compare with 2724 * @return True if the given component's model is the same as this component's model. 2725 */ 2726 public final boolean sameInnermostModel(final Component component) 2727 { 2728 return sameInnermostModel(component.getDefaultModel()); 2729 } 2730 2731 /** 2732 * @param model 2733 * The model to compare with 2734 * @return True if the given component's model is the same as this component's model. 2735 */ 2736 public final boolean sameInnermostModel(final IModel<?> model) 2737 { 2738 // Get the two models 2739 IModel<?> thisModel = getDefaultModel(); 2740 2741 // If both models are non-null they could be the same 2742 if (thisModel != null && model != null) 2743 { 2744 return getInnermostModel(thisModel) == getInnermostModel(model); 2745 } 2746 2747 return false; 2748 } 2749 2750 /** 2751 * Sets whether this component is enabled. Specific components may decide to implement special 2752 * behavior that uses this property, like web form components that add a disabled='disabled' 2753 * attribute when enabled is false. If it is not enabled, it will not be allowed to call any 2754 * listener method on it (e.g. Link.onClick) and the model object will be protected (for the 2755 * common use cases, not for programmer's misuse) 2756 * 2757 * @param enabled 2758 * whether this component is enabled 2759 * @return This 2760 */ 2761 public final Component setEnabled(final boolean enabled) 2762 { 2763 // Is new enabled state a change? 2764 if (enabled != getFlag(FLAG_ENABLED)) 2765 { 2766 // Tell the page that this component's enabled was changed 2767 if (isVersioned()) 2768 { 2769 final Page page = findPage(); 2770 if (page != null) 2771 { 2772 addStateChange(); 2773 } 2774 } 2775 2776 // Change visibility 2777 setFlag(FLAG_ENABLED, enabled); 2778 onEnabledStateChanged(); 2779 } 2780 return this; 2781 } 2782 2783 void clearEnabledInHierarchyCache() 2784 { 2785 setRequestFlag(RFLAG_ENABLED_IN_HIERARCHY_SET, false); 2786 } 2787 2788 void onEnabledStateChanged() 2789 { 2790 clearEnabledInHierarchyCache(); 2791 } 2792 2793 /** 2794 * Sets whether model strings should be escaped. 2795 * 2796 * @param escapeMarkup 2797 * True is model strings should be escaped 2798 * @return This 2799 */ 2800 public final Component setEscapeModelStrings(final boolean escapeMarkup) 2801 { 2802 setFlag(FLAG_ESCAPE_MODEL_STRINGS, escapeMarkup); 2803 return this; 2804 } 2805 2806 /** 2807 * Set markup ID, which must be String or Integer 2808 * 2809 * @param markupId 2810 */ 2811 public final void setMarkupIdImpl(Object markupId) 2812 { 2813 if (markupId != null && !(markupId instanceof String) && !(markupId instanceof Integer)) 2814 { 2815 throw new IllegalArgumentException("markupId must be String or Integer"); 2816 } 2817 2818 setOutputMarkupId(true); 2819 if (markupId instanceof Integer) 2820 { 2821 generatedMarkupId = (Integer)markupId; 2822 setMetaData(MARKUP_ID_KEY, null); 2823 return; 2824 } 2825 2826 generatedMarkupId = -1; 2827 setMetaData(MARKUP_ID_KEY, (String)markupId); 2828 2829 } 2830 2831 /** 2832 * Copy markupId 2833 * 2834 * @param comp 2835 */ 2836 final void setMarkupId(Component comp) 2837 { 2838 Args.notNull(comp, "comp"); 2839 2840 generatedMarkupId = comp.generatedMarkupId; 2841 setMetaData(MARKUP_ID_KEY, comp.getMetaData(MARKUP_ID_KEY)); 2842 if (comp.getOutputMarkupId()) 2843 { 2844 setOutputMarkupId(true); 2845 } 2846 } 2847 2848 /** 2849 * Sets this component's markup id to a user defined value. It is up to the user to ensure this 2850 * value is unique. 2851 * <p> 2852 * The recommended way is to let wicket generate the value automatically, this method is here to 2853 * serve as an override for that value in cases where a specific id must be used. 2854 * <p> 2855 * If null is passed in the user defined value is cleared and markup id value will fall back on 2856 * automatically generated value 2857 * 2858 * @see #getMarkupId() 2859 * 2860 * @param markupId 2861 * markup id value or null to clear any previous user defined value 2862 * @return this for chaining 2863 */ 2864 public Component setMarkupId(String markupId) 2865 { 2866 Args.notEmpty(markupId, "markupId"); 2867 2868 // TODO check if an automatic id has already been generated or getmarkupid() called 2869 // previously and throw an illegalstateexception because something else might be depending 2870 // on previous id 2871 2872 setMarkupIdImpl(markupId); 2873 return this; 2874 } 2875 2876 /** 2877 * Sets the metadata for this component using the given key. If the metadata object is not of 2878 * the correct type for the metadata key, an IllegalArgumentException will be thrown. For 2879 * information on creating MetaDataKeys, see {@link MetaDataKey}. 2880 * 2881 * @param <M> 2882 * The type of the metadata 2883 * 2884 * @param key 2885 * The singleton key for the metadata 2886 * @param object 2887 * The metadata object 2888 * @throws IllegalArgumentException 2889 * @see MetaDataKey 2890 */ 2891 @Override 2892 public final <M extends Serializable> Component setMetaData(final MetaDataKey<M> key, final M object) 2893 { 2894 MetaDataEntry<?>[] old = getMetaData(); 2895 2896 Object metaData = null; 2897 MetaDataEntry<?>[] metaDataArray = key.set(old, object); 2898 if (metaDataArray != null && metaDataArray.length > 0) 2899 { 2900 metaData = (metaDataArray.length > 1) ? metaDataArray : metaDataArray[0]; 2901 } 2902 2903 int index = getFlag(FLAG_MODEL_SET) ? 1 : 0; 2904 2905 if (old == null && metaData != null) 2906 { 2907 data_insert(index, metaData); 2908 } 2909 else if (old != null && metaData != null) 2910 { 2911 data_set(index, metaData); 2912 } 2913 else if (old != null && metaData == null) 2914 { 2915 data_remove(index); 2916 } 2917 return this; 2918 } 2919 2920 /** 2921 * Sets the given model. 2922 * <p> 2923 * WARNING: DO NOT OVERRIDE THIS METHOD UNLESS YOU HAVE A VERY GOOD REASON FOR IT. OVERRIDING 2924 * THIS MIGHT OPEN UP SECURITY LEAKS AND BREAK BACK-BUTTON SUPPORT. 2925 * </p> 2926 * 2927 * @param model 2928 * The model 2929 * @return This 2930 */ 2931 public Component setDefaultModel(final IModel<?> model) 2932 { 2933 IModel<?> prevModel = getModelImpl(); 2934 2935 IModel<?> wrappedModel = prevModel; 2936 if (prevModel instanceof IWrapModel) 2937 { 2938 wrappedModel = ((IWrapModel<?>)prevModel).getWrappedModel(); 2939 } 2940 2941 // Change model 2942 if (wrappedModel != model) 2943 { 2944 // Detach the old/current model 2945 if (prevModel != null) 2946 { 2947 prevModel.detach(); 2948 } 2949 2950 modelChanging(); 2951 setModelImpl(wrap(model)); 2952 modelChanged(); 2953 2954 // WICKET-3413 reset 'inherited model' when model is explicitely set 2955 setFlag(FLAG_INHERITABLE_MODEL, false); 2956 } 2957 2958 return this; 2959 } 2960 2961 /** 2962 * @return model 2963 */ 2964 IModel<?> getModelImpl() 2965 { 2966 if (getFlag(FLAG_MODEL_SET)) 2967 { 2968 return (IModel<?>)data_get(0); 2969 } 2970 return null; 2971 } 2972 2973 /** 2974 * 2975 * @param model 2976 */ 2977 void setModelImpl(IModel<?> model) 2978 { 2979 if (getFlag(FLAG_MODEL_SET)) 2980 { 2981 if (model != null) 2982 { 2983 data_set(0, model); 2984 } 2985 else 2986 { 2987 data_remove(0); 2988 setFlag(FLAG_MODEL_SET, false); 2989 } 2990 } 2991 else 2992 { 2993 if (model != null) 2994 { 2995 data_insert(0, model); 2996 setFlag(FLAG_MODEL_SET, true); 2997 } 2998 } 2999 } 3000 3001 /** 3002 * Sets the backing model object. Unlike <code>getDefaultModel().setObject(object)</code>, this 3003 * method checks authorisation and model comparator, and invokes <code>modelChanging</code> and 3004 * <code>modelChanged</code> if the value really changes. 3005 * 3006 * @param object 3007 * The object to set 3008 * @return This 3009 * @throws IllegalStateException If the component has neither its own model nor any of its 3010 * parents uses {@link IComponentInheritedModel} 3011 */ 3012 @SuppressWarnings("unchecked") 3013 public final Component setDefaultModelObject(final Object object) 3014 { 3015 final IModel<Object> model = (IModel<Object>)getDefaultModel(); 3016 3017 // Check whether anything can be set at all 3018 if (model == null) 3019 { 3020 throw new IllegalStateException( 3021 "Attempt to set a model object on a component without a model! " + 3022 "Either pass an IModel to the constructor or use #setDefaultModel(new SomeModel(object)). " + 3023 "Component: " + getPageRelativePath()); 3024 } 3025 3026 // Check authorization 3027 if (!isActionAuthorized(ENABLE)) 3028 { 3029 throw new UnauthorizedActionException(this, ENABLE); 3030 } 3031 3032 // Check whether this will result in an actual change 3033 if (!getModelComparator().compare(this, object)) 3034 { 3035 modelChanging(); 3036 try 3037 { 3038 model.setObject(object); 3039 } 3040 catch (UnsupportedOperationException uox) 3041 { 3042 throw new WicketRuntimeException("You need to use writeable IModel for component " + getPageRelativePath(), uox); 3043 } 3044 modelChanged(); 3045 } 3046 3047 return this; 3048 } 3049 3050 /** 3051 * Sets whether or not component will output id attribute into the markup. id attribute will be 3052 * set to the value returned from {@link Component#getMarkupId()}. 3053 * 3054 * @param output 3055 * True if the component will output the id attribute into markup. Please note that 3056 * the default behavior is to use the same id as the component. This means that your 3057 * component must begin with [a-zA-Z] in order to generate a valid markup id 3058 * according to: http://www.w3.org/TR/html401/types.html#type-name 3059 * 3060 * @return this for chaining 3061 */ 3062 public final Component setOutputMarkupId(final boolean output) 3063 { 3064 setFlag(FLAG_OUTPUT_MARKUP_ID, output); 3065 return this; 3066 } 3067 3068 /** 3069 * Render a placeholder tag when the component is not visible. The tag is of form: 3070 * <componenttag hidden="" id="markupid"/>. This method will also call 3071 * <code>setOutputMarkupId(true)</code>. 3072 * 3073 * This is useful, for example, in ajax situations where the component starts out invisible and 3074 * then becomes visible through an ajax update. With a placeholder tag already in the markup you 3075 * do not need to repaint this component's parent, instead you can repaint the component 3076 * directly. 3077 * 3078 * When this method is called with parameter <code>false</code> the outputmarkupid flag is not 3079 * reverted to false. 3080 * 3081 * @param outputTag 3082 * @return this for chaining 3083 */ 3084 public final Component setOutputMarkupPlaceholderTag(final boolean outputTag) 3085 { 3086 if (outputTag != getFlag(FLAG_PLACEHOLDER)) 3087 { 3088 if (outputTag) 3089 { 3090 setOutputMarkupId(true); 3091 setFlag(FLAG_PLACEHOLDER, true); 3092 } 3093 else 3094 { 3095 setFlag(FLAG_PLACEHOLDER, false); 3096 // I think it's better to not setOutputMarkupId to false... 3097 // user can do it if she want 3098 } 3099 } 3100 return this; 3101 } 3102 3103 /** 3104 * If false the component's tag will be printed as well as its body (which is default). If true 3105 * only the body will be printed, but not the component's tag. 3106 * 3107 * @param renderTag 3108 * If true, the component tag will not be printed 3109 * @return This 3110 */ 3111 public final Component setRenderBodyOnly(final boolean renderTag) 3112 { 3113 setFlag(FLAG_RENDER_BODY_ONLY, renderTag); 3114 return this; 3115 } 3116 3117 /** 3118 * Sets the page that will respond to this request 3119 * 3120 * @param <C> 3121 * 3122 * @param cls 3123 * The response page class 3124 * @see RequestCycle#setResponsePage(Class) 3125 */ 3126 public final <C extends IRequestablePage> void setResponsePage(final Class<C> cls) 3127 { 3128 getRequestCycle().setResponsePage(cls, (PageParameters)null); 3129 } 3130 3131 /** 3132 * Sets the page class and its parameters that will respond to this request 3133 * 3134 * @param <C> 3135 * 3136 * @param cls 3137 * The response page class 3138 * @param parameters 3139 * The parameters for this bookmarkable page. 3140 * @see RequestCycle#setResponsePage(Class, PageParameters) 3141 */ 3142 public final <C extends IRequestablePage> void setResponsePage(final Class<C> cls, 3143 PageParameters parameters) 3144 { 3145 getRequestCycle().setResponsePage(cls, parameters); 3146 } 3147 3148 /** 3149 * Sets the page that will respond to this request 3150 * 3151 * @param page 3152 * The response page 3153 * 3154 * @see RequestCycle#setResponsePage(org.apache.wicket.request.component.IRequestablePage) 3155 */ 3156 public final void setResponsePage(final IRequestablePage page) 3157 { 3158 getRequestCycle().setResponsePage(page); 3159 } 3160 3161 /** 3162 * @param versioned 3163 * True to turn on versioning for this component, false to turn it off for this 3164 * component and any children. 3165 * @return This 3166 */ 3167 public Component setVersioned(boolean versioned) 3168 { 3169 setFlag(FLAG_VERSIONED, versioned); 3170 return this; 3171 } 3172 3173 /** 3174 * Sets whether this component and any children are visible. 3175 * 3176 * @param visible 3177 * True if this component and any children should be visible 3178 * @return This 3179 */ 3180 public final Component setVisible(final boolean visible) 3181 { 3182 // Is new visibility state a change? 3183 if (visible != getFlag(FLAG_VISIBLE)) 3184 { 3185 // record component's visibility change 3186 addStateChange(); 3187 3188 // Change visibility 3189 setFlag(FLAG_VISIBLE, visible); 3190 onVisibleStateChanged(); 3191 } 3192 return this; 3193 } 3194 3195 void clearVisibleInHierarchyCache() 3196 { 3197 setRequestFlag(RFLAG_VISIBLE_IN_HIERARCHY_SET, false); 3198 } 3199 3200 void onVisibleStateChanged() 3201 { 3202 clearVisibleInHierarchyCache(); 3203 } 3204 3205 3206 /** 3207 * Gets the string representation of this component. 3208 * 3209 * @return The path to this component 3210 */ 3211 @Override 3212 public String toString() 3213 { 3214 return toString(false); 3215 } 3216 3217 /** 3218 * @param detailed 3219 * True if a detailed string is desired 3220 * @return The string 3221 */ 3222 public String toString(final boolean detailed) 3223 { 3224 try 3225 { 3226 final StringBuilder buffer = new StringBuilder(); 3227 buffer.append("[Component id = ").append(getId()); 3228 3229 if (detailed) 3230 { 3231 final Page page = findPage(); 3232 if (page == null) 3233 { 3234 buffer.append(", page = <No Page>, path = ") 3235 .append(getPath()) 3236 .append('.') 3237 .append(Classes.simpleName(getClass())); 3238 } 3239 else 3240 { 3241 buffer.append(", page = ") 3242 .append(Classes.name(getPage().getPageClass())) 3243 .append(", path = ") 3244 .append(getPageRelativePath()) 3245 .append(", type = ") 3246 .append(Classes.name(getClass())) 3247 .append(", isVisible = ") 3248 .append((determineVisibility())) 3249 .append(", isVersioned = ") 3250 .append(isVersioned()); 3251 } 3252 3253 if (markup != null) 3254 { 3255 buffer.append(", markup = ").append(new MarkupStream(getMarkup()).toString()); 3256 } 3257 } 3258 3259 buffer.append(']'); 3260 3261 return buffer.toString(); 3262 } 3263 catch (Exception e) 3264 { 3265 log.warn("Error while building toString()", e); 3266 return String.format( 3267 "[Component id = %s <attributes are not available because exception %s was thrown during toString()>]", 3268 getId(), e.getClass().getName()); 3269 } 3270 } 3271 3272 /** 3273 * Returns a bookmarkable URL that references a given page class using a given set of page 3274 * parameters. Since the URL which is returned contains all information necessary to instantiate 3275 * and render the page, it can be stored in a user's browser as a stable bookmark. 3276 * 3277 * @param <C> 3278 * 3279 * @see RequestCycle#urlFor(Class, org.apache.wicket.request.mapper.parameter.PageParameters) 3280 * 3281 * @param pageClass 3282 * Class of page 3283 * @param parameters 3284 * Parameters to page 3285 * @return Bookmarkable URL to page 3286 */ 3287 public final <C extends Page> CharSequence urlFor(final Class<C> pageClass, 3288 final PageParameters parameters) 3289 { 3290 return getRequestCycle().urlFor(pageClass, parameters); 3291 } 3292 3293 /** 3294 * Gets a URL for the listener interface on a behavior (e.g. {@link IRequestListener} on 3295 * {@link org.apache.wicket.ajax.markup.html.navigation.paging.AjaxPagingNavigationBehavior}). 3296 * 3297 * @param behaviour 3298 * The behavior that the URL should point to 3299 * @param parameters 3300 * The parameters that should be rendered into the urls 3301 * @return The URL 3302 */ 3303 public final CharSequence urlForListener(final Behavior behaviour, final PageParameters parameters) 3304 { 3305 int id = getBehaviorId(behaviour); 3306 IRequestHandler handler = createRequestHandler(parameters, id); 3307 return getRequestCycle().urlFor(handler); 3308 } 3309 3310 /** 3311 * Create a suitable request handler depending whether the page is stateless or bookmarkable. 3312 */ 3313 private IRequestHandler createRequestHandler(PageParameters parameters, Integer id) 3314 { 3315 Page page = getPage(); 3316 3317 PageAndComponentProvider provider = new PageAndComponentProvider(page, this, parameters); 3318 3319 if (page.isPageStateless() 3320 || (page.isBookmarkable() && page.wasCreatedBookmarkable())) 3321 { 3322 return new BookmarkableListenerRequestHandler(provider, id); 3323 } 3324 else 3325 { 3326 return new ListenerRequestHandler(provider, id); 3327 } 3328 } 3329 3330 /** 3331 * Returns a URL that references the given request target. 3332 * 3333 * @see RequestCycle#urlFor(IRequestHandler) 3334 * 3335 * @param requestHandler 3336 * the request target to reference 3337 * 3338 * @return a URL that references the given request target 3339 */ 3340 public final CharSequence urlFor(final IRequestHandler requestHandler) 3341 { 3342 return getRequestCycle().urlFor(requestHandler); 3343 } 3344 3345 /** 3346 * Gets a URL for this {@link IRequestListener}. 3347 * 3348 * @see RequestCycle#urlFor(IRequestHandler) 3349 * 3350 * @param parameters 3351 * The parameters that should be rendered into the URL 3352 * @return The URL 3353 */ 3354 public final CharSequence urlForListener(final PageParameters parameters) 3355 { 3356 IRequestHandler handler = createRequestHandler(parameters, null); 3357 return getRequestCycle().urlFor(handler); 3358 } 3359 3360 /** 3361 * Returns a URL that references a shared resource through the provided resource reference. 3362 * 3363 * @see RequestCycle#urlFor(IRequestHandler) 3364 * 3365 * @param resourceReference 3366 * The resource reference 3367 * @param parameters 3368 * parameters or {@code null} if none 3369 * @return The url for the shared resource 3370 */ 3371 public final CharSequence urlFor(final ResourceReference resourceReference, 3372 PageParameters parameters) 3373 { 3374 return getRequestCycle().urlFor(resourceReference, parameters); 3375 } 3376 3377 /** 3378 * Traverses all parent components of the given class in this parentClass, calling the visitor's 3379 * visit method at each one. 3380 * 3381 * @param <R> 3382 * the type of the result object 3383 * @param parentClass 3384 * Class 3385 * @param visitor 3386 * The visitor to call at each parent of the given type 3387 * @return First non-null value returned by visitor callback 3388 */ 3389 public final <R, C extends MarkupContainer> R visitParents(final Class<C> parentClass, 3390 final IVisitor<C, R> visitor) 3391 { 3392 return visitParents(parentClass, visitor, IVisitFilter.ANY); 3393 } 3394 3395 /** 3396 * Traverses all parent components of the given class in this parentClass, calling the visitor's 3397 * visit method at each one. 3398 * 3399 * @param <R> 3400 * the type of the result object 3401 * @param parentClass 3402 * the class of the parent component 3403 * @param visitor 3404 * The visitor to call at each parent of the given type 3405 * @param filter 3406 * a filter that adds an additional logic to the condition whether a parent container 3407 * matches 3408 * @return First non-null value returned by visitor callback 3409 */ 3410 @SuppressWarnings("unchecked") 3411 public final <R, C extends MarkupContainer> R visitParents(final Class<C> parentClass, 3412 final IVisitor<C, R> visitor, IVisitFilter filter) 3413 { 3414 Args.notNull(filter, "filter"); 3415 3416 // Start here 3417 MarkupContainer current = getParent(); 3418 3419 Visit<R> visit = new Visit<R>(); 3420 3421 // Walk up containment hierarchy 3422 while (current != null) 3423 { 3424 // Is current an instance of this class? 3425 if (parentClass.isInstance(current) && filter.visitObject(current)) 3426 { 3427 visitor.component((C)current, visit); 3428 if (visit.isStopped()) 3429 { 3430 return visit.getResult(); 3431 } 3432 } 3433 3434 // Check parent 3435 current = current.getParent(); 3436 } 3437 return null; 3438 } 3439 3440 /** 3441 * Registers a warning feedback message for this component. 3442 * 3443 * @param message 3444 * The feedback message 3445 */ 3446 @Override 3447 public final void warn(final Serializable message) 3448 { 3449 getFeedbackMessages().warn(this, message); 3450 addStateChange(); 3451 } 3452 3453 /** 3454 * {@link Behavior#beforeRender(Component)} Notify all behaviors that are assigned to this 3455 * component that the component is about to be rendered. 3456 */ 3457 private void notifyBehaviorsComponentBeforeRender() 3458 { 3459 for (Behavior behavior : getBehaviors()) 3460 { 3461 if (isBehaviorAccepted(behavior)) 3462 { 3463 behavior.beforeRender(this); 3464 } 3465 } 3466 } 3467 3468 /** 3469 * {@link Behavior#afterRender(Component)} Notify all behaviors that are assigned to this 3470 * component that the component has rendered. 3471 */ 3472 private void notifyBehaviorsComponentRendered() 3473 { 3474 // notify the behaviors that component has been rendered 3475 for (Behavior behavior : getBehaviors()) 3476 { 3477 if (isBehaviorAccepted(behavior)) 3478 { 3479 behavior.afterRender(this); 3480 } 3481 } 3482 } 3483 3484 /** 3485 * TODO WICKET-NG rename to something more useful - like componentChanged(), this method used to 3486 * be called with a Change object 3487 * 3488 * Adds state change to page. 3489 */ 3490 protected final void addStateChange() 3491 { 3492 checkHierarchyChange(this); 3493 final Page page = findPage(); 3494 if (page != null) 3495 { 3496 page.componentStateChanging(this); 3497 } 3498 } 3499 3500 /** 3501 * Checks whether the given type has the expected name. 3502 * 3503 * @param tag 3504 * The tag to check 3505 * @param name 3506 * The expected tag name 3507 * @throws MarkupException 3508 * Thrown if the tag is not of the right name 3509 */ 3510 protected final void checkComponentTag(final ComponentTag tag, final String name) 3511 { 3512 if (!tag.getName().equalsIgnoreCase(name)) 3513 { 3514 String msg = String.format("Component [%s] (path = [%s]) must be " 3515 + "applied to a tag of type [%s], not: %s", getId(), getPath(), name, 3516 tag.toUserDebugString()); 3517 3518 findMarkupStream().throwMarkupException(msg); 3519 } 3520 } 3521 3522 /** 3523 * Checks that a given tag has a required attribute value. 3524 * 3525 * @param tag 3526 * The tag 3527 * @param key 3528 * The attribute key 3529 * @param values 3530 * The required value for the attribute key 3531 * @throws MarkupException 3532 * Thrown if the tag does not have the required attribute value 3533 */ 3534 protected final void checkComponentTagAttribute(final ComponentTag tag, final String key, 3535 final String... values) 3536 { 3537 if (key != null) 3538 { 3539 final String tagAttributeValue = tag.getAttributes().getString(key); 3540 3541 boolean found = false; 3542 if (tagAttributeValue != null) 3543 { 3544 for (String value : values) 3545 { 3546 if (value.equalsIgnoreCase(tagAttributeValue)) 3547 { 3548 found = true; 3549 break; 3550 } 3551 } 3552 } 3553 3554 if (found == false) 3555 { 3556 String msg = String.format("Component [%s] (path = [%s]) must be applied to a tag " 3557 + "with [%s] attribute matching any of %s, not [%s]", getId(), getPath(), key, 3558 Arrays.toString(values), tagAttributeValue); 3559 3560 findMarkupStream().throwMarkupException(msg); 3561 } 3562 } 3563 } 3564 3565 /** 3566 * Checks whether the hierarchy may be changed at all, and throws an exception if this is not 3567 * the case. 3568 * 3569 * @param component 3570 * the component which is about to be added or removed 3571 */ 3572 protected void checkHierarchyChange(final Component component) 3573 { 3574 // Throw exception if modification is attempted during rendering 3575 if (getRequestFlag(RFLAG_RENDERING) && !component.isAuto()) 3576 { 3577 throw new WicketRuntimeException( 3578 "Cannot modify component hierarchy after render phase has started (page version cant change then anymore)"); 3579 } 3580 } 3581 3582 /** 3583 * Detaches the model for this component if it is detachable. 3584 */ 3585 protected void detachModel() 3586 { 3587 IModel<?> model = getModelImpl(); 3588 if (model != null) 3589 { 3590 model.detach(); 3591 } 3592 // also detach the wrapped model of a component assigned wrap (not 3593 // inherited) 3594 if (model instanceof IWrapModel && !getFlag(FLAG_INHERITABLE_MODEL)) 3595 { 3596 ((IWrapModel<?>)model).getWrappedModel().detach(); 3597 } 3598 } 3599 3600 /** 3601 * Suffixes an exception message with useful information about this. component. 3602 * 3603 * @param message 3604 * The message 3605 * @return The modified message 3606 */ 3607 protected final String exceptionMessage(final String message) 3608 { 3609 return message + ":\n" + toString(); 3610 } 3611 3612 /** 3613 * Finds the markup stream for this component. 3614 * 3615 * @return The markup stream for this component. Since a Component cannot have a markup stream, 3616 * we ask this component's parent to search for it. 3617 */ 3618 protected final MarkupStream findMarkupStream() 3619 { 3620 return new MarkupStream(getMarkup()); 3621 } 3622 3623 /** 3624 * If this Component is a Page, returns self. Otherwise, searches for the nearest Page parent in 3625 * the component hierarchy. If no Page parent can be found, {@code null} is returned. 3626 * 3627 * @return The Page or {@code null} if none can be found 3628 */ 3629 protected final Page findPage() 3630 { 3631 // Search for page 3632 return (Page)(this instanceof Page ? this : findParent(Page.class)); 3633 } 3634 3635 /** 3636 * Gets the subset of the currently coupled {@link Behavior}s that are of the provided type as 3637 * an unmodifiable list. Returns an empty list if there are no behaviors coupled to this 3638 * component. 3639 * 3640 * @param type 3641 * The type or null for all 3642 * @return The subset of the currently coupled behaviors that are of the provided type as an 3643 * unmodifiable list 3644 * @param <M> 3645 * A class derived from Behavior 3646 */ 3647 public <M extends Behavior> List<M> getBehaviors(Class<M> type) 3648 { 3649 return Behaviors.getBehaviors(this, type); 3650 } 3651 3652 /** 3653 * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT USE IT! 3654 * 3655 * @param flag 3656 * The flag to test 3657 * @return True if the flag is set 3658 */ 3659 protected final boolean getFlag(final int flag) 3660 { 3661 return (flags & flag) != 0; 3662 } 3663 3664 /** 3665 * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT USE IT! 3666 * 3667 * @param flag 3668 * The flag to test 3669 * @return True if the flag is set 3670 */ 3671 protected final boolean getRequestFlag(final short flag) 3672 { 3673 return (requestFlags & flag) != 0; 3674 } 3675 3676 /** 3677 * Finds the innermost IModel object for an IModel that might contain nested IModel(s). 3678 * 3679 * @param model 3680 * The model 3681 * @return The innermost (most nested) model 3682 */ 3683 protected final IModel<?> getInnermostModel(final IModel<?> model) 3684 { 3685 IModel<?> nested = model; 3686 while (nested != null && nested instanceof IWrapModel) 3687 { 3688 final IModel<?> next = ((IWrapModel<?>)nested).getWrappedModel(); 3689 if (nested == next) 3690 { 3691 throw new WicketRuntimeException("Model for " + nested + " is self-referential"); 3692 } 3693 nested = next; 3694 } 3695 return nested; 3696 } 3697 3698 /** 3699 * Gets the component's current model comparator. Implementations can be used for testing the 3700 * current value of the components model data with the new value that is given. 3701 * 3702 * @return the value defaultModelComparator 3703 */ 3704 public IModelComparator getModelComparator() 3705 { 3706 return defaultModelComparator; 3707 } 3708 3709 /** 3710 * Returns whether the component can be stateless. Also the component behaviors must be 3711 * stateless, otherwise the component will be treat as stateful. In order for page to be 3712 * stateless (and not to be stored in session), all components (and component behaviors) must be 3713 * stateless. 3714 * 3715 * @return whether the component can be stateless 3716 */ 3717 protected boolean getStatelessHint() 3718 { 3719 return true; 3720 } 3721 3722 /** 3723 * Called when a null model is about to be retrieved in order to allow a subclass to provide an 3724 * initial model. 3725 * <p> 3726 * By default this implementation looks components in the parent chain owning a 3727 * {@link IComponentInheritedModel} to provide a model for this component via 3728 * {@link IComponentInheritedModel#wrapOnInheritance(Component)}. 3729 * <p> 3730 * For example a {@link FormComponent} has the opportunity to instantiate a model on the fly 3731 * using its {@code id} and the containing {@link Form}'s model, if the form holds a 3732 * {@link CompoundPropertyModel}. 3733 * 3734 * @return The model 3735 */ 3736 protected IModel<?> initModel() 3737 { 3738 IModel<?> foundModel = null; 3739 // Search parents for IComponentInheritedModel (i.e. CompoundPropertyModel) 3740 for (Component current = getParent(); current != null; current = current.getParent()) 3741 { 3742 // Get model 3743 // Don't call the getModel() that could initialize many in between 3744 // completely useless models. 3745 // IModel model = current.getDefaultModel(); 3746 IModel<?> model = current.getModelImpl(); 3747 3748 if (model instanceof IWrapModel && !(model instanceof IComponentInheritedModel)) 3749 { 3750 model = ((IWrapModel<?>)model).getWrappedModel(); 3751 } 3752 3753 if (model instanceof IComponentInheritedModel) 3754 { 3755 // return the shared inherited 3756 foundModel = ((IComponentInheritedModel<?>)model).wrapOnInheritance(this); 3757 setFlag(FLAG_INHERITABLE_MODEL, true); 3758 break; 3759 } 3760 } 3761 3762 // No model for this component! 3763 return foundModel; 3764 } 3765 3766 /** 3767 * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL OR OVERRIDE. 3768 * 3769 * <p> 3770 * Called anytime a model is changed via setModel or setModelObject. 3771 * </p> 3772 */ 3773 protected void internalOnModelChanged() 3774 { 3775 } 3776 3777 /** 3778 * Components are allowed to reject behavior modifiers. 3779 * 3780 * @param behavior 3781 * @return False, if the component should not apply this behavior 3782 */ 3783 protected boolean isBehaviorAccepted(final Behavior behavior) 3784 { 3785 // Ignore AttributeModifiers when FLAG_IGNORE_ATTRIBUTE_MODIFIER is set 3786 if ((behavior instanceof AttributeModifier) && 3787 (getFlag(FLAG_IGNORE_ATTRIBUTE_MODIFIER) != false)) 3788 { 3789 return false; 3790 } 3791 3792 return behavior.isEnabled(this); 3793 } 3794 3795 /** 3796 * If true, all attribute modifiers will be ignored 3797 * 3798 * @return True, if attribute modifiers are to be ignored 3799 */ 3800 protected final boolean isIgnoreAttributeModifier() 3801 { 3802 return getFlag(FLAG_IGNORE_ATTRIBUTE_MODIFIER); 3803 } 3804 3805 /** 3806 * Called immediately after a component and all its children have been rendered, 3807 * regardless of any exception. 3808 */ 3809 protected void onAfterRender() 3810 { 3811 setRequestFlag(RFLAG_AFTER_RENDER_SUPER_CALL_VERIFIED, true); 3812 } 3813 3814 /** 3815 * Called on all visible components before any component is rendered. 3816 * <p> 3817 * <strong>NOTE</strong>: If you override this, you *must* call super.onBeforeRender() within 3818 * your implementation. 3819 * 3820 * Because this method is responsible for cascading {@link #onBeforeRender()} call to its 3821 * children it is strongly recommended that super call is made at the end of the override. 3822 * </p> 3823 * 3824 * Changes to the component tree can be made only <strong>before</strong> calling 3825 * super.onBeforeRender(). 3826 * 3827 * @see org.apache.wicket.MarkupContainer#addOrReplace(Component...) 3828 */ 3829 protected void onBeforeRender() 3830 { 3831 setRequestFlag(RFLAG_PREPARED_FOR_RENDER, true); 3832 onBeforeRenderChildren(); 3833 setRequestFlag(RFLAG_BEFORE_RENDER_SUPER_CALL_VERIFIED, true); 3834 } 3835 3836 /** 3837 * Processes the component tag. 3838 * 3839 * Overrides of this method most likely should call the super implementation. 3840 * 3841 * @param tag 3842 * Tag to modify 3843 */ 3844 protected void onComponentTag(final ComponentTag tag) 3845 { 3846 // We can't try to get the ID from markup. This could be different than 3847 // id returned from getMarkupId() prior first rendering the component 3848 // (due to transparent resolvers and borders which break the 1:1 3849 // component <-> markup relation) 3850 if (getFlag(FLAG_OUTPUT_MARKUP_ID)) 3851 { 3852 tag.putInternal(MARKUP_ID_ATTR_NAME, getMarkupId()); 3853 } 3854 3855 DebugSettings debugSettings = getApplication().getDebugSettings(); 3856 String componentPathAttributeName = debugSettings.getComponentPathAttributeName(); 3857 if (Strings.isEmpty(componentPathAttributeName) == false) 3858 { 3859 String path = getPageRelativePath(); 3860 path = path.replace("_", "__"); 3861 path = path.replace(':', '_'); 3862 tag.put(componentPathAttributeName, path); 3863 } 3864 3865 // The markup sourcing strategy may also want to work on the tag 3866 getMarkupSourcingStrategy().onComponentTag(this, tag); 3867 } 3868 3869 /** 3870 * Processes the body. 3871 * 3872 * @param markupStream 3873 * The markup stream 3874 * @param openTag 3875 * The open tag for the body 3876 */ 3877 public void onComponentTagBody(final MarkupStream markupStream, final ComponentTag openTag) 3878 { 3879 } 3880 3881 /** 3882 * Called to allow a component to detach resources after use. 3883 * 3884 * Overrides of this method MUST call the super implementation, the most logical place to do 3885 * this is the last line of the override method. 3886 */ 3887 protected void onDetach() 3888 { 3889 setRequestFlag(RFLAG_DETACHING, false); 3890 } 3891 3892 /** 3893 * Called to notify the component it is being removed from the component hierarchy 3894 * 3895 * Overrides of this method MUST call the super implementation, the most logical place to do 3896 * this is the last line of the override method. 3897 */ 3898 protected void onRemove() 3899 { 3900 setRequestFlag(RFLAG_REMOVING_FROM_HIERARCHY, false); 3901 } 3902 3903 /** 3904 * Called anytime a model is changed after the change has occurred 3905 */ 3906 protected void onModelChanged() 3907 { 3908 } 3909 3910 /** 3911 * Called anytime a model is changed, but before the change actually occurs 3912 */ 3913 protected void onModelChanging() 3914 { 3915 } 3916 3917 /** 3918 * Implementation that renders this component. 3919 */ 3920 protected abstract void onRender(); 3921 3922 /** 3923 * Writes a simple tag out to the response stream. Any components that might be referenced by 3924 * the tag are ignored. Also undertakes any tag attribute modifications if they have been added 3925 * to the component. 3926 * 3927 * @param tag 3928 * The tag to write 3929 */ 3930 protected final void renderComponentTag(ComponentTag tag) 3931 { 3932 if (needToRenderTag(tag)) 3933 { 3934 // apply behaviors that are attached to the component tag. 3935 if (tag.hasBehaviors()) 3936 { 3937 Iterator<? extends Behavior> tagBehaviors = tag.getBehaviors(); 3938 while (tagBehaviors.hasNext()) 3939 { 3940 final Behavior behavior = tagBehaviors.next(); 3941 if (behavior.isEnabled(this)) 3942 { 3943 behavior.onComponentTag(this, tag); 3944 } 3945 behavior.detach(this); 3946 } 3947 } 3948 3949 // Apply behavior modifiers 3950 List<? extends Behavior> behaviors = getBehaviors(); 3951 if ((behaviors != null) && !behaviors.isEmpty() && !tag.isClose() && 3952 (isIgnoreAttributeModifier() == false)) 3953 { 3954 tag = tag.mutable(); 3955 for (Behavior behavior : behaviors) 3956 { 3957 // Components may reject some behavior components 3958 if (isBehaviorAccepted(behavior)) 3959 { 3960 behavior.onComponentTag(this, tag); 3961 } 3962 } 3963 } 3964 3965 if ((tag instanceof WicketTag) && !tag.isClose() && 3966 !getFlag(FLAG_IGNORE_ATTRIBUTE_MODIFIER)) 3967 { 3968 ExceptionSettings.NotRenderableErrorStrategy notRenderableErrorStrategy = ExceptionSettings.NotRenderableErrorStrategy.LOG_WARNING; 3969 if (Application.exists()) 3970 { 3971 notRenderableErrorStrategy = getApplication().getExceptionSettings().getNotRenderableErrorStrategy(); 3972 } 3973 3974 String tagName = tag.getNamespace() + ":" + tag.getName(); 3975 String componentId = getId(); 3976 if (getFlag(FLAG_OUTPUT_MARKUP_ID)) 3977 { 3978 String message = String.format("Markup id set on a component that is usually not rendered into markup. " + 3979 "Markup id: %s, component id: %s, component tag: %s.", 3980 getMarkupId(), componentId, tagName); 3981 if (notRenderableErrorStrategy == ExceptionSettings.NotRenderableErrorStrategy.THROW_EXCEPTION) 3982 { 3983 throw new IllegalStateException(message); 3984 } 3985 log.warn(message); 3986 } 3987 if (getFlag(FLAG_PLACEHOLDER)) 3988 { 3989 String message = String.format( 3990 "Placeholder tag set on a component that is usually not rendered into markup. " + 3991 "Component id: %s, component tag: %s.", componentId, tagName); 3992 if (notRenderableErrorStrategy == ExceptionSettings.NotRenderableErrorStrategy.THROW_EXCEPTION) 3993 { 3994 throw new IllegalStateException(message); 3995 } 3996 log.warn(message); 3997 } 3998 } 3999 4000 // Write the tag 4001 tag.writeOutput(getResponse(), !needToRenderTag(null), 4002 getMarkup().getMarkupResourceStream().getWicketNamespace()); 4003 } 4004 } 4005 4006 /** 4007 * Replaces the body with the given one. 4008 * 4009 * @param markupStream 4010 * The markup stream to replace the tag body in 4011 * @param tag 4012 * The tag 4013 * @param body 4014 * The new markup 4015 */ 4016 protected final void replaceComponentTagBody(final MarkupStream markupStream, 4017 final ComponentTag tag, final CharSequence body) 4018 { 4019 // The tag might have been changed from open-close to open. Hence 4020 // we'll need what was in the markup itself 4021 ComponentTag markupOpenTag = null; 4022 4023 // If tag has a body 4024 if (tag.isOpen()) 4025 { 4026 // Get what tag was in the markup; not what the user it might 4027 // have changed it to. 4028 markupOpenTag = markupStream.getPreviousTag(); 4029 4030 // If it was an open tag in the markup as well, than ... 4031 if (markupOpenTag.isOpen()) 4032 { 4033 // skip any raw markup in the body 4034 markupStream.skipRawMarkup(); 4035 } 4036 } 4037 4038 if (body != null) 4039 { 4040 // Write the new body 4041 getResponse().write(body); 4042 } 4043 4044 // If we had an open tag (and not an openclose tag) and we found a 4045 // close tag, we're good 4046 if (tag.isOpen()) 4047 { 4048 // If it was an open tag in the markup, than there must be 4049 // a close tag as well. 4050 if ((markupOpenTag != null) && markupOpenTag.isOpen() && !markupStream.atCloseTag()) 4051 { 4052 // There must be a component in this discarded body 4053 markupStream.throwMarkupException("Expected close tag for '" + markupOpenTag + 4054 "' Possible attempt to embed component(s) '" + markupStream.get() + 4055 "' in the body of this component which discards its body"); 4056 } 4057 } 4058 } 4059 4060 /** 4061 * @param auto 4062 * True to put component into auto-add mode 4063 */ 4064 protected final Component setAuto(final boolean auto) 4065 { 4066 setFlag(FLAG_AUTO, auto); 4067 return this; 4068 } 4069 4070 /** 4071 * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT USE IT! 4072 * 4073 * @param flag 4074 * The flag to set 4075 * @param set 4076 * True to turn the flag on, false to turn it off 4077 */ 4078 protected final Component setFlag(final int flag, final boolean set) 4079 { 4080 if (set) 4081 { 4082 flags |= flag; 4083 } 4084 else 4085 { 4086 flags &= ~flag; 4087 } 4088 return this; 4089 } 4090 4091 /** 4092 * @param flag 4093 * The flag to set 4094 * @param set 4095 * True to turn the flag on, false to turn it off 4096 */ 4097 final Component setRequestFlag(final short flag, final boolean set) 4098 { 4099 if (set) 4100 { 4101 requestFlags |= flag; 4102 } 4103 else 4104 { 4105 requestFlags &= ~flag; 4106 } 4107 return this; 4108 } 4109 4110 /** 4111 * If true, all attribute modifiers will be ignored 4112 * 4113 * @param ignore 4114 * If true, all attribute modifiers will be ignored 4115 * @return This 4116 */ 4117 protected final Component setIgnoreAttributeModifier(final boolean ignore) 4118 { 4119 setFlag(FLAG_IGNORE_ATTRIBUTE_MODIFIER, ignore); 4120 return this; 4121 } 4122 4123 /** 4124 * @param <V> 4125 * The model type 4126 * @param model 4127 * The model to wrap if need be 4128 * @return The wrapped model 4129 */ 4130 protected final <V> IModel<V> wrap(final IModel<V> model) 4131 { 4132 if (model instanceof IComponentAssignedModel) 4133 { 4134 return ((IComponentAssignedModel<V>)model).wrapOnAssignment(this); 4135 } 4136 return model; 4137 } 4138 4139 /** 4140 * Detaches any child components 4141 */ 4142 void detachChildren() 4143 { 4144 } 4145 4146 /** 4147 * Signals this components removal from hierarchy to all its children. 4148 */ 4149 void removeChildren() 4150 { 4151 } 4152 4153 /** 4154 * Gets the component at the given path. 4155 * 4156 * @param path 4157 * Path to component 4158 * @return The component at the path 4159 */ 4160 @Override 4161 public Component get(final String path) 4162 { 4163 // Path to this component is an empty path 4164 if (path.length() == 0) 4165 { 4166 return this; 4167 } 4168 throw new IllegalArgumentException( 4169 exceptionMessage("Component is not a container and so does not contain the path " + 4170 path)); 4171 } 4172 4173 /** 4174 * @param setRenderingFlag 4175 * rendering flag 4176 */ 4177 void internalMarkRendering(boolean setRenderingFlag) 4178 { 4179 // WICKET-5460 no longer prepared for render 4180 setRequestFlag(RFLAG_PREPARED_FOR_RENDER, false); 4181 4182 setRequestFlag(RFLAG_RENDERING, setRenderingFlag); 4183 } 4184 4185 /** 4186 * @return True if this component or any of its parents is in auto-add mode 4187 */ 4188 public final boolean isAuto() 4189 { 4190 // Search up hierarchy for FLAG_AUTO 4191 for (Component current = this; current != null; current = current.getParent()) 4192 { 4193 if (current.getFlag(FLAG_AUTO)) 4194 { 4195 return true; 4196 } 4197 } 4198 return false; 4199 } 4200 4201 /** 4202 * 4203 * @return <code>true</code> if component has been prepared for render 4204 */ 4205 boolean isPreparedForRender() 4206 { 4207 return getRequestFlag(RFLAG_PREPARED_FOR_RENDER); 4208 } 4209 4210 /** 4211 * This method is here for {@link MarkupContainer}. It is broken out of 4212 * {@link #onBeforeRender()} so we can guarantee that it executes as the last in 4213 * onBeforeRender() chain no matter where user places the <code>super.onBeforeRender()</code> 4214 * call. 4215 */ 4216 void onBeforeRenderChildren() 4217 { 4218 } 4219 4220 /** 4221 * Renders the close tag at the current position in the markup stream. 4222 * 4223 * @param markupStream 4224 * the markup stream 4225 * @param openTag 4226 * the tag to render 4227 * @param renderBodyOnly 4228 * if true, the tag will not be written to the output 4229 */ 4230 final void renderClosingComponentTag(final MarkupStream markupStream, 4231 final ComponentTag openTag, final boolean renderBodyOnly) 4232 { 4233 // Tag should be open tag and not openclose tag 4234 if (openTag.isOpen()) 4235 { 4236 // If we found a close tag and it closes the open tag, we're good 4237 if (markupStream.atCloseTag() && markupStream.getTag().closes(openTag)) 4238 { 4239 // Render the close tag 4240 if ((renderBodyOnly == false) && needToRenderTag(openTag)) 4241 { 4242 openTag.writeSyntheticCloseTag(getResponse()); 4243 } 4244 } 4245 else if (openTag.requiresCloseTag()) 4246 { 4247 // Missing close tag. Some tags, e.g. <p> are handled like <p/> by most browsers and 4248 // thus will not throw an exception. 4249 markupStream.throwMarkupException("Expected close tag for " + openTag); 4250 } 4251 } 4252 } 4253 4254 /** 4255 * Sets the id of this component. 4256 * 4257 * @param id 4258 * The non-null id of this component 4259 */ 4260 private void checkId(final String id) 4261 { 4262 if (!(this instanceof Page)) 4263 { 4264 if (Strings.isEmpty(id)) 4265 { 4266 throw new WicketRuntimeException("Null or empty component ID's are not allowed."); 4267 } 4268 } 4269 4270 if ((id != null) && (id.indexOf(':') != -1 || id.indexOf('~') != -1)) 4271 { 4272 throw new WicketRuntimeException("The component ID must not contain ':' or '~' chars."); 4273 } 4274 } 4275 4276 /** 4277 * THIS IS A WICKET INTERNAL API. DO NOT USE IT. 4278 * 4279 * Sets the parent of a component. Typically what you really want is parent.add(child). 4280 * <p/> 4281 * Note that calling setParent() and not parent.add() will connect the child to the parent, but 4282 * the parent will not know the child. This might not be a problem in some cases, but e.g. 4283 * child.onDetach() will not be invoked (since the parent doesn't know it is his child). 4284 * 4285 * @param parent 4286 * The parent container 4287 */ 4288 public final void setParent(final MarkupContainer parent) 4289 { 4290 if (this.parent != null && log.isDebugEnabled()) 4291 { 4292 log.debug("Replacing parent " + this.parent + " with " + parent); 4293 } 4294 this.parent = parent; 4295 } 4296 4297 /** 4298 * Sets the render allowed flag. 4299 * 4300 * @param renderAllowed 4301 */ 4302 final void setRenderAllowed(boolean renderAllowed) 4303 { 4304 setFlag(FLAG_IS_RENDER_ALLOWED, renderAllowed); 4305 } 4306 4307 /** 4308 * Sets the render allowed flag. 4309 * 4310 * Visit all this page's children (overridden in MarkupContainer) to check rendering 4311 * authorization, as appropriate. We set any result; positive or negative as a temporary boolean 4312 * in the components, and when a authorization exception is thrown it will block the rendering 4313 * of this page 4314 */ 4315 void setRenderAllowed() 4316 { 4317 setRenderAllowed(isActionAuthorized(RENDER)); 4318 } 4319 4320 /** 4321 * Sets whether or not this component is allowed to be visible. This method is meant to be used 4322 * by components to control visibility of other components. A call to 4323 * {@link #setVisible(boolean)} will not always have a desired effect because that component may 4324 * have {@link #isVisible()} overridden. Both {@link #setVisibilityAllowed(boolean)} and 4325 * {@link #isVisibilityAllowed()} are <code>final</code> so their contract is enforced always. 4326 * 4327 * @param allowed 4328 * @return <code>this</code> for chaining 4329 */ 4330 public final Component setVisibilityAllowed(boolean allowed) 4331 { 4332 if (allowed != getFlag(FLAG_VISIBILITY_ALLOWED)) 4333 { 4334 setFlag(FLAG_VISIBILITY_ALLOWED, allowed); 4335 onVisibleStateChanged(); 4336 } 4337 return this; 4338 } 4339 4340 /** 4341 * Gets whether or not visibility is allowed on this component. See 4342 * {@link #setVisibilityAllowed(boolean)} for details. 4343 * 4344 * @return true if this component is allowed to be visible, false otherwise. 4345 */ 4346 public final boolean isVisibilityAllowed() 4347 { 4348 return getFlag(FLAG_VISIBILITY_ALLOWED); 4349 } 4350 4351 /** 4352 * Determines whether or not a component should be visible, taking into account all the factors: 4353 * {@link #isVisible()}, {@link #isVisibilityAllowed()}, {@link #isRenderAllowed()} 4354 * 4355 * @return <code>true</code> if the component should be visible, <code>false</code> otherwise 4356 */ 4357 public final boolean determineVisibility() 4358 { 4359 return isVisible() && isRenderAllowed() && isVisibilityAllowed(); 4360 } 4361 4362 4363 /** 4364 * Calculates enabled state of the component taking its hierarchy into account. A component is 4365 * enabled iff it is itself enabled ({@link #isEnabled()} and {@link #isEnableAllowed()} both 4366 * return <code>true</code>), and all of its parents are enabled. 4367 * 4368 * @return <code>true</code> if this component is enabled</code> 4369 */ 4370 public boolean isEnabledInHierarchy() 4371 { 4372 if (getRequestFlag(RFLAG_ENABLED_IN_HIERARCHY_SET)) 4373 { 4374 return getRequestFlag(RFLAG_ENABLED_IN_HIERARCHY_VALUE); 4375 } 4376 4377 final boolean state; 4378 Component parent = getParent(); 4379 if (parent != null && !parent.isEnabledInHierarchy()) 4380 { 4381 state = false; 4382 } 4383 else 4384 { 4385 state = isEnabled() && isEnableAllowed(); 4386 } 4387 4388 setRequestFlag(RFLAG_ENABLED_IN_HIERARCHY_SET, true); 4389 setRequestFlag(RFLAG_ENABLED_IN_HIERARCHY_VALUE, state); 4390 return state; 4391 } 4392 4393 /** 4394 * Says if the component is rendering currently. 4395 * 4396 * @return true if this component is rendering, false otherwise. 4397 */ 4398 public final boolean isRendering() 4399 { 4400 return getRequestFlag(RFLAG_PREPARED_FOR_RENDER) || getRequestFlag(RFLAG_RENDERING); 4401 } 4402 4403 /** 4404 * Checks whether or not an {@link IRequestListener} can be invoked on this component. Usually components 4405 * deny these invocations if they are either invisible or disabled in hierarchy. 4406 * <p> 4407 * WARNING: be careful when overriding this method because it may open security holes - such as 4408 * allowing a user to click on a link that should be disabled. 4409 * </p> 4410 * <p> 4411 * Example usecase for overriding: Suppose you are building an component that displays images. 4412 * The component generates a callback to itself using {@link IRequestListener} interface and 4413 * uses this callback to stream image data. If such a component is placed inside a disabled 4414 * {@code WebMarkupContainer} we still want to allow the invocation of the request listener callback 4415 * method so that image data can be streamed. Such a component would override this method and 4416 * return {@literal true}. 4417 * </p> 4418 * 4419 * @return {@literal true} iff the listener method can be invoked on this component 4420 */ 4421 public boolean canCallListener() 4422 { 4423 return isEnabledInHierarchy() && isVisibleInHierarchy(); 4424 } 4425 4426 /** 4427 * Render to the web response whatever the component wants to contribute to the head section. 4428 * 4429 * @param response 4430 * Response object 4431 */ 4432 @Override 4433 public void renderHead(IHeaderResponse response) 4434 { 4435 // noop 4436 } 4437 4438 /** {@inheritDoc} */ 4439 @Override 4440 public void onEvent(IEvent<?> event) 4441 { 4442 } 4443 4444 /** {@inheritDoc} */ 4445 @Override 4446 public final <T> void send(IEventSink sink, Broadcast type, T payload) 4447 { 4448 // if there are no event dispatchers then don't even try to send event 4449 if (getApplication().getFrameworkSettings().hasAnyEventDispatchers()) 4450 { 4451 new ComponentEventSender(this, getApplication().getFrameworkSettings()).send(sink, type, 4452 payload); 4453 } 4454 } 4455 4456 /** 4457 * Removes behavior from component 4458 * 4459 * @param behaviors 4460 * behaviors to remove 4461 * 4462 * @return this (to allow method call chaining) 4463 */ 4464 public Component remove(final Behavior... behaviors) 4465 { 4466 for (Behavior behavior : behaviors) 4467 { 4468 Behaviors.remove(this, behavior); 4469 } 4470 return this; 4471 } 4472 4473 /** {@inheritDoc} */ 4474 @Override 4475 public final Behavior getBehaviorById(int id) 4476 { 4477 return Behaviors.getBehaviorById(this, id); 4478 } 4479 4480 /** {@inheritDoc} */ 4481 @Override 4482 public final int getBehaviorId(Behavior behavior) 4483 { 4484 if (behavior.isTemporary(this)) 4485 { 4486 throw new IllegalArgumentException( 4487 "Cannot get a stable id for temporary behavior " + behavior); 4488 } 4489 return Behaviors.getBehaviorId(this, behavior); 4490 } 4491 4492 /** 4493 * Adds a behavior modifier to the component. 4494 * 4495 * @param behaviors 4496 * The behavior modifier(s) to be added 4497 * @return this (to allow method call chaining) 4498 */ 4499 public Component add(final Behavior... behaviors) 4500 { 4501 Behaviors.add(this, behaviors); 4502 return this; 4503 } 4504 4505 /** 4506 * Gets the currently coupled {@link Behavior}s as an unmodifiable list. Returns an empty list 4507 * rather than null if there are no behaviors coupled to this component. 4508 * 4509 * @return The currently coupled behaviors as an unmodifiable list 4510 */ 4511 public final List<? extends Behavior> getBehaviors() 4512 { 4513 return getBehaviors(null); 4514 } 4515 4516 @Override 4517 public boolean canCallListenerAfterExpiry() 4518 { 4519 return getApplication().getPageSettings() 4520 .getCallListenerAfterExpiry() || isStateless(); 4521 } 4522 /** 4523 * This method is called whenever a component is re-added to the page's component tree, if it 4524 * had been removed at some earlier time, i.e., if it is already initialized 4525 * (see {@link org.apache.wicket.Component#isInitialized()}). 4526 * 4527 * This is similar to onInitialize, but only comes after the component has been removed and 4528 * then added again: 4529 * 4530 * <ul> 4531 * <li>onInitialize is only called the very first time a component is added</li> 4532 * <li>onReAdd is not called the first time, but every time it is re-added after having been 4533 * removed</li> 4534 * </ul> 4535 * 4536 * You can think of it as the opposite of onRemove. A component that was once removed will 4537 * not be re-initialized but only re-added. 4538 * 4539 * Subclasses that override this must call super.onReAdd(). 4540 */ 4541 protected void onReAdd() 4542 { 4543 setRequestFlag(RFLAG_ON_RE_ADD_SUPER_CALL_VERIFIED, true); 4544 } 4545}