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(&quot;got you there!&quot;);
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>&lt;span wicket:id="myPanel"&gt;body&lt;/span&gt;</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()&gt;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(&quot;login&quot;)
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         * &lt;componenttag hidden="" id="markupid"/&gt;. 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}