Source Code Cross Referenced for Component.java in  » J2EE » wicket » org » apache » wicket » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » J2EE » wicket » org.apache.wicket 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Licensed to the Apache Software Foundation (ASF) under one or more
0003:         * contributor license agreements.  See the NOTICE file distributed with
0004:         * this work for additional information regarding copyright ownership.
0005:         * The ASF licenses this file to You under the Apache License, Version 2.0
0006:         * (the "License"); you may not use this file except in compliance with
0007:         * the License.  You may obtain a copy of the License at
0008:         *
0009:         *      http://www.apache.org/licenses/LICENSE-2.0
0010:         *
0011:         * Unless required by applicable law or agreed to in writing, software
0012:         * distributed under the License is distributed on an "AS IS" BASIS,
0013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014:         * See the License for the specific language governing permissions and
0015:         * limitations under the License.
0016:         */
0017:        package org.apache.wicket;
0018:
0019:        import java.io.Serializable;
0020:        import java.util.ArrayList;
0021:        import java.util.Collections;
0022:        import java.util.Iterator;
0023:        import java.util.List;
0024:        import java.util.Locale;
0025:
0026:        import org.apache.wicket.ajax.AjaxRequestTarget;
0027:        import org.apache.wicket.authorization.Action;
0028:        import org.apache.wicket.authorization.AuthorizationException;
0029:        import org.apache.wicket.authorization.IAuthorizationStrategy;
0030:        import org.apache.wicket.authorization.UnauthorizedActionException;
0031:        import org.apache.wicket.behavior.IBehavior;
0032:        import org.apache.wicket.feedback.FeedbackMessage;
0033:        import org.apache.wicket.markup.ComponentTag;
0034:        import org.apache.wicket.markup.MarkupException;
0035:        import org.apache.wicket.markup.MarkupStream;
0036:        import org.apache.wicket.markup.WicketTag;
0037:        import org.apache.wicket.markup.html.IHeaderContributor;
0038:        import org.apache.wicket.markup.html.internal.HtmlHeaderContainer;
0039:        import org.apache.wicket.model.IComponentAssignedModel;
0040:        import org.apache.wicket.model.IComponentInheritedModel;
0041:        import org.apache.wicket.model.IModel;
0042:        import org.apache.wicket.model.IModelComparator;
0043:        import org.apache.wicket.model.IWrapModel;
0044:        import org.apache.wicket.settings.IDebugSettings;
0045:        import org.apache.wicket.util.convert.IConverter;
0046:        import org.apache.wicket.util.lang.Classes;
0047:        import org.apache.wicket.util.lang.Objects;
0048:        import org.apache.wicket.util.string.PrependingStringBuffer;
0049:        import org.apache.wicket.util.string.Strings;
0050:        import org.apache.wicket.util.value.ValueMap;
0051:        import org.apache.wicket.version.undo.Change;
0052:        import org.slf4j.Logger;
0053:        import org.slf4j.LoggerFactory;
0054:
0055:        /**
0056:         * Component serves as the highest level abstract base class for all components.
0057:         * 
0058:         * <ul>
0059:         * <li><b>Identity </b>- All Components must have a non-null id which is
0060:         * retrieved by calling getId(). The id must be unique within the
0061:         * MarkupContainer that holds the Component, but does not have to be globally
0062:         * unique or unique within a Page's component hierarchy.
0063:         * 
0064:         * <li><b>Hierarchy </b>- A component has a parent which can be retrieved with
0065:         * {@link #getParent()}. If a component is an instance of MarkupContainer, it
0066:         * may have children. In this way it has a place in the hierarchy of components
0067:         * contained on a given page.
0068:         * 
0069:         * <li><b>Component Paths </b>- The path from the Page at the root of the
0070:         * component hierarchy to a given Component is simply the concatenation with dot
0071:         * separators of each id along the way. For example, the path "a.b.c" would
0072:         * refer to the component named "c" inside the MarkupContainer named "b" inside
0073:         * the container named "a". The path to a component can be retrieved by calling
0074:         * getPath(). This path is an absolute path beginning with the id of the Page at
0075:         * the root. Pages bear a PageMap/Session-relative identifier as their id, so
0076:         * each absolute path will begin with a number, such as "0.a.b.c". To get a
0077:         * Component path relative to the page that contains it, you can call
0078:         * getPageRelativePath().
0079:         * 
0080:         * <li><b>LifeCycle </b>- Components participate in the following lifecycle
0081:         * phases:
0082:         * <ul>
0083:         * <li><b>Construction </b>- A Component is constructed with the Java language
0084:         * new operator. Children may be added during construction if the Component is a
0085:         * MarkupContainer.
0086:         * 
0087:         * <li><b>Request Handling </b>- An incoming request is processed by a protocol
0088:         * request handler such as WicketServlet. An associated Application object
0089:         * creates Session, Request and Response objects for use by a given Component in
0090:         * updating its model and rendering a response. These objects are stored inside
0091:         * a container called {@link RequestCycle} which is accessible via
0092:         * {@link Component#getRequestCycle()}. The convenience methods
0093:         * {@link Component#getRequest()}, {@link Component#getResponse()} and
0094:         * {@link Component#getSession()} provide easy access to the contents of this
0095:         * container.
0096:         * 
0097:         * <li><b>Listener Invocation </b>- If the request references a listener on an
0098:         * existing Component, that listener is called, allowing arbitrary user code to
0099:         * handle events such as link clicks or form submits. Although arbitrary
0100:         * listeners are supported in Wicket, the need to implement a new class of
0101:         * listener is unlikely for a web application and even the need to implement a
0102:         * listener interface directly is highly discouraged. Instead, calls to
0103:         * listeners are routed through logic specific to the event, resulting in calls
0104:         * to user code through other overridable methods. For example, the
0105:         * {@link org.apache.wicket.markup.html.form.IFormSubmitListener#onFormSubmitted()}
0106:         * method implemented by the Form class is really a private implementation
0107:         * detail of the Form class that is not designed to be overridden (although
0108:         * unfortunately, it must be public since all interface methods in Java must be
0109:         * public). Instead, Form subclasses should override user-oriented methods such
0110:         * as onValidate(), onSubmit() and onError() (although only the latter two are
0111:         * likely to be overridden in practice).
0112:         * 
0113:         * <li><b>onBeginRequest </b>- The {@link Component#onBeginRequest()} method is
0114:         * called.
0115:         * 
0116:         * <li><b>Form Submit </b>- If a Form has been submitted and the Component is a
0117:         * FormComponent, the component's model is validated by a call to
0118:         * FormComponent.validate().
0119:         * 
0120:         * <li><b>Form Model Update </b>- If a valid Form has been submitted and the
0121:         * Component is a FormComponent, the component's model is updated by a call to
0122:         * FormComponent.updateModel().
0123:         * 
0124:         * <li><b>Rendering </b>- A markup response is generated by the Component via
0125:         * {@link Component#render()}, which calls subclass implementation code
0126:         * contained in {@link Component#onRender()}. Once this phase begins, a
0127:         * Component becomes immutable. Attempts to alter the Component will result in a
0128:         * WicketRuntimeException.
0129:         * 
0130:         * <li><b>onEndRequest </b>() - The {@link Component#onEndRequest()} method is
0131:         * called.
0132:         * </ul>
0133:         * 
0134:         * <li><b>Component Models </b>- The primary responsibility of a component is
0135:         * to use its model (an object that implements IModel), which can be set via
0136:         * {@link Component#setModel(IModel model)} and retrieved via
0137:         * {@link Component#getModel()}, to render a response in an appropriate markup
0138:         * language, such as HTML. In addition, form components know how to update their
0139:         * models based on request information. Since the IModel interface is a wrapper
0140:         * around an actual model object, a convenience method
0141:         * {@link Component#getModelObject()} is provided to retrieve the model Object
0142:         * from its IModel wrapper. A further convenience method,
0143:         * {@link Component#getModelObjectAsString()}, is provided for the very common
0144:         * operation of converting the wrapped model Object to a String.
0145:         * 
0146:         * <li><b>Visibility </b>- Components which have setVisible(false) will return
0147:         * false from isVisible() and will not render a response (nor will their
0148:         * children).
0149:         * 
0150:         * <li><b>Page </b>- The Page containing any given Component can be retrieved
0151:         * by calling {@link Component#getPage()}. If the Component is not attached to
0152:         * a Page, an IllegalStateException will be thrown. An equivalent method,
0153:         * {@link Component#findPage()} is available for special circumstances where it
0154:         * might be desirable to get a null reference back instead.
0155:         * 
0156:         * <li><b>Session </b>- The Page for a Component points back to the Session
0157:         * that contains the Page. The Session for a component can be accessed with the
0158:         * convenience method getSession(), which simply calls getPage().getSession().
0159:         * 
0160:         * <li><b>Locale </b>- The Locale for a Component is available through the
0161:         * convenience method getLocale(), which is equivalent to
0162:         * getSession().getLocale().
0163:         * 
0164:         * <li><b>String Resources </b>- Components can have associated String
0165:         * resources via the Application's Localizer, which is available through the
0166:         * method {@link Component#getLocalizer()}. The convenience methods
0167:         * {@link Component#getString(String key)} and
0168:         * {@link Component#getString(String key, IModel model)} wrap the identical
0169:         * methods on the Application Localizer for easy access in Components.
0170:         * 
0171:         * <li><b>Style </b>- The style ("skin") for a component is available through
0172:         * {@link Component#getStyle()}, which is equivalent to
0173:         * getSession().getStyle(). Styles are intended to give a particular look to a
0174:         * Component or Resource that is independent of its Locale. For example, a style
0175:         * might be a set of resources, including images and markup files, which gives
0176:         * the design look of "ocean" to the user. If the Session's style is set to
0177:         * "ocean" and these resources are given names suffixed with "_ocean", Wicket's
0178:         * resource management logic will prefer these resources to other resources,
0179:         * such as default resources, which are not as good of a match.
0180:         * 
0181:         * <li><b>Variation </b>- Whereas Styles are Session (user) specific,
0182:         * variations are component specific. E.g. if the Style is "ocean" and the
0183:         * Variation is "NorthSea", than the resources are given the names suffixed with
0184:         * "_ocean_NorthSea".
0185:         * 
0186:         * <li><b>AttributeModifiers </b>- You can add one or more
0187:         * {@link AttributeModifier}s to any component if you need to programmatically
0188:         * manipulate attributes of the markup tag to which a Component is attached.
0189:         * 
0190:         * <li><b>Application, ApplicationSettings and ApplicationPages </b>- The
0191:         * getApplication() method provides convenient access to the Application for a
0192:         * Component via getSession().getApplication(). The getApplicationSettings()
0193:         * method is equivalent to getApplication().getSettings(). The
0194:         * getApplicationPages is equivalent to getApplication().getPages().
0195:         * 
0196:         * <li><b>Feedback Messages </b>- The {@link Component#debug(String)},
0197:         * {@link Component#info(String)}, {@link Component#warn(String)},
0198:         * {@link Component#error(String)} and {@link Component#fatal(String)} methods
0199:         * associate feedback messages with a Component. It is generally not necessary
0200:         * to use these methods directly since Wicket validators automatically register
0201:         * feedback messages on Components. Any feedback message for a given Component
0202:         * can be retrieved with {@link Component#getFeedbackMessage}.
0203:         * 
0204:         * <li><b>Page Factory </b>- It is possible to change the way that Pages are
0205:         * constructed by overriding the {@link Component#getPageFactory()} method,
0206:         * returning your own implementation of {@link org.apache.wicket.IPageFactory}.
0207:         * 
0208:         * <li><b>Versioning </b>- Pages are the unit of versioning in Wicket, but
0209:         * fine-grained control of which Components should participate in versioning is
0210:         * possible via the {@link Component#setVersioned(boolean)} method. The
0211:         * versioning participation of a given Component can be retrieved with
0212:         * {@link Component#isVersioned()}.
0213:         * 
0214:         * <li><b>AJAX support</b>- Components can be re-rendered after the whole Page
0215:         * has been rendered at least once by calling doRender().
0216:         * 
0217:         * @author Jonathan Locke
0218:         * @author Chris Turner
0219:         * @author Eelco Hillenius
0220:         * @author Johan Compagner
0221:         * @author Juergen Donnerstag
0222:         * @author Igor Vaynberg (ivaynberg)
0223:         */
0224:        public abstract class Component implements  IClusterable,
0225:                IConverterLocator {
0226:            /**
0227:             * Change record of a model.
0228:             */
0229:            public class ComponentModelChange extends Change {
0230:                private static final long serialVersionUID = 1L;
0231:
0232:                /** Former model. */
0233:                private final IModel model;
0234:
0235:                /**
0236:                 * Construct.
0237:                 * 
0238:                 * @param model
0239:                 */
0240:                public ComponentModelChange(IModel model) {
0241:                    super ();
0242:                    this .model = model;
0243:                }
0244:
0245:                /**
0246:                 * @see java.lang.Object#toString()
0247:                 */
0248:                public String toString() {
0249:                    return "ComponentModelChange[component: " + getPath() + "]";
0250:                }
0251:
0252:                /**
0253:                 * @see org.apache.wicket.version.undo.Change#undo()
0254:                 */
0255:                public void undo() {
0256:                    setModel(model);
0257:                }
0258:            }
0259:
0260:            /**
0261:             * Generic component visitor interface for component traversals.
0262:             */
0263:            public static interface IVisitor {
0264:                /**
0265:                 * Value to return to continue a traversal.
0266:                 */
0267:                public static final Object CONTINUE_TRAVERSAL = null;
0268:
0269:                /**
0270:                 * A generic value to return to contiue a traversal, but if the
0271:                 * component is a container, don't visit its children.
0272:                 */
0273:                public static final Object CONTINUE_TRAVERSAL_BUT_DONT_GO_DEEPER = new Object();
0274:
0275:                /**
0276:                 * A generic value to return to stop a traversal.
0277:                 */
0278:                public static final Object STOP_TRAVERSAL = new Object();
0279:
0280:                /**
0281:                 * Called at each component in a traversal.
0282:                 * 
0283:                 * @param component
0284:                 *            The component
0285:                 * @return CONTINUE_TRAVERSAL (null) if the traversal should continue,
0286:                 *         or a non-null return value for the traversal method if it
0287:                 *         should stop. If no return value is useful, the generic
0288:                 *         non-null value STOP_TRAVERSAL can be used.
0289:                 */
0290:                public Object component(Component component);
0291:            }
0292:
0293:            /**
0294:             * Change object for undoing addition of behavior
0295:             * 
0296:             * @author Igor Vaynberg (ivaynberg)
0297:             */
0298:            private final class AddedBehaviorChange extends Change {
0299:
0300:                private static final long serialVersionUID = 1L;
0301:
0302:                private final IBehavior behavior;
0303:
0304:                /**
0305:                 * Construct.
0306:                 * 
0307:                 * @param behavior
0308:                 */
0309:                public AddedBehaviorChange(IBehavior behavior) {
0310:                    this .behavior = behavior;
0311:                }
0312:
0313:                public String toString() {
0314:                    return "[" + getClass().getName() + " behavior="
0315:                            + behavior.toString() + "]";
0316:                }
0317:
0318:                public void undo() {
0319:                    behaviors.remove(behavior);
0320:                    if (behaviors.size() == 0) {
0321:                        behaviors = null;
0322:                    }
0323:                }
0324:
0325:            }
0326:
0327:            /**
0328:             * Undo change for component border property
0329:             * 
0330:             * @author ivaynberg
0331:             */
0332:            private class ComponentBorderChange extends Change {
0333:                private static final long serialVersionUID = 1L;
0334:
0335:                private final IComponentBorder old = getComponentBorder();
0336:
0337:                public void undo() {
0338:                    setComponentBorder(old);
0339:                }
0340:
0341:            }
0342:
0343:            /**
0344:             * Change object for undoing removal of behavior
0345:             * 
0346:             * @author Igor Vaynberg (ivaynberg)
0347:             */
0348:            private final class RemovedBehaviorChange extends Change {
0349:
0350:                private static final long serialVersionUID = 1L;
0351:
0352:                private final IBehavior behavior;
0353:
0354:                /**
0355:                 * Construct.
0356:                 * 
0357:                 * @param behavior
0358:                 */
0359:                public RemovedBehaviorChange(IBehavior behavior) {
0360:                    this .behavior = behavior;
0361:                }
0362:
0363:                public String toString() {
0364:                    return "[" + getClass().getName() + " behavior="
0365:                            + behavior.toString() + "]";
0366:                }
0367:
0368:                public void undo() {
0369:                    if (behaviors == null) {
0370:                        behaviors = new ArrayList(1);
0371:                    }
0372:                    behaviors.add(behavior);
0373:                }
0374:
0375:            }
0376:
0377:            /**
0378:             * A enabled change operation.
0379:             */
0380:            protected final static class EnabledChange extends Change {
0381:                private static final long serialVersionUID = 1L;
0382:
0383:                /** Subject. */
0384:                private final Component component;
0385:
0386:                /** Former value. */
0387:                private final boolean enabled;
0388:
0389:                /**
0390:                 * Construct.
0391:                 * 
0392:                 * @param component
0393:                 */
0394:                EnabledChange(final Component component) {
0395:                    this .component = component;
0396:                    enabled = component.getFlag(FLAG_ENABLED);
0397:                }
0398:
0399:                /**
0400:                 * @see java.lang.Object#toString()
0401:                 */
0402:                public String toString() {
0403:                    return "EnabledChange[component: " + component.getPath()
0404:                            + ",enabled: " + enabled + "]";
0405:                }
0406:
0407:                /**
0408:                 * @see org.apache.wicket.version.undo.Change#undo()
0409:                 */
0410:                public void undo() {
0411:                    component.setEnabled(enabled);
0412:                }
0413:            }
0414:
0415:            /**
0416:             * A visibility change operation.
0417:             */
0418:            protected final static class VisibilityChange extends Change {
0419:                private static final long serialVersionUID = 1L;
0420:
0421:                /** Subject. */
0422:                private final Component component;
0423:
0424:                /** Former value. */
0425:                private final boolean visible;
0426:
0427:                /**
0428:                 * Construct.
0429:                 * 
0430:                 * @param component
0431:                 */
0432:                VisibilityChange(final Component component) {
0433:                    this .component = component;
0434:                    visible = component.getFlag(FLAG_VISIBLE);
0435:                }
0436:
0437:                /**
0438:                 * @see java.lang.Object#toString()
0439:                 */
0440:                public String toString() {
0441:                    return "VisibilityChange[component: " + component.getPath()
0442:                            + ", visible: " + visible + "]";
0443:                }
0444:
0445:                /**
0446:                 * @see org.apache.wicket.version.undo.Change#undo()
0447:                 */
0448:                public void undo() {
0449:                    component.setVisible(visible);
0450:                }
0451:            }
0452:
0453:            /**
0454:             * Action used with IAuthorizationStrategy to determine whether a component
0455:             * is allowed to be enabled.
0456:             * <p>
0457:             * If enabling is authorized, a component may decide by itself (typically
0458:             * using it's enabled property) whether it is enabled or not. If enabling is
0459:             * not authorized, the given component is marked disabled, regardless its
0460:             * enabled property.
0461:             * <p>
0462:             * When a component is not allowed to be enabled (in effect disabled through
0463:             * the implementation of this interface), Wicket will try to prevent model
0464:             * updates too. This is not completely fail safe, as constructs like:
0465:             * 
0466:             * <pre>
0467:             * User u = (User)getModelObject();
0468:             * u.setName(&quot;got you there!&quot;);
0469:             * </pre>
0470:             * 
0471:             * can't be prevented. Indeed it can be argued that any model protection is
0472:             * best dealt with in your model objects to be completely secured. Wicket
0473:             * will catch all normal framework-directed use though.
0474:             */
0475:            public static final Action ENABLE = new Action(Action.ENABLE);
0476:
0477:            /** Separator for component paths */
0478:            public static final char PATH_SEPARATOR = ':';
0479:
0480:            /**
0481:             * Action used with IAuthorizationStrategy to determine whether a component
0482:             * and its children are allowed to be rendered.
0483:             * <p>
0484:             * There are two uses for this method:
0485:             * <ul>
0486:             * <li>The 'normal' use is for controlling whether a component is rendered
0487:             * without having any effect on the rest of the processing. If a strategy
0488:             * lets this method return 'false', then the target component and its
0489:             * children will not be rendered, in the same fashion as if that component
0490:             * had visibility property 'false'.</li>
0491:             * <li>The other use is when a component should block the rendering of the
0492:             * whole page. So instead of 'hiding' a component, what we generally want to
0493:             * achieve here is that we force the user to logon/give-credentials for a
0494:             * higher level of authorization. For this functionality, the strategy
0495:             * implementation should throw a {@link AuthorizationException}, which will
0496:             * then be handled further by the framework.</li>
0497:             * </ul>
0498:             * </p>
0499:             */
0500:            public static final Action RENDER = new Action(Action.RENDER);
0501:
0502:            /** meta data key for missing body tags logging. */
0503:            private static final MetaDataKey BORDER_KEY = new MetaDataKey(
0504:                    IComponentBorder.class) {
0505:                private static final long serialVersionUID = 1L;
0506:            };
0507:
0508:            /** Basic model IModelComparator implementation for normal object models */
0509:            private static final IModelComparator defaultModelComparator = new IModelComparator() {
0510:                private static final long serialVersionUID = 1L;
0511:
0512:                public boolean compare(Component component, Object b) {
0513:                    final Object a = component.getModelObject();
0514:                    if (a == null && b == null) {
0515:                        return true;
0516:                    }
0517:                    if (a == null || b == null) {
0518:                        return false;
0519:                    }
0520:                    return a.equals(b);
0521:                }
0522:            };
0523:
0524:            private static final int FLAG_AFTER_RENDERING = 0x8000000;
0525:
0526:            /** True when a component is being auto-added */
0527:            private static final int FLAG_AUTO = 0x0001;
0528:
0529:            private static final int FLAG_BEFORE_RENDERING_SUPER_CALL_VERIFIED = 0x1000000;
0530:
0531:            private static final int FLAG_DETACHING = 0x80000000;
0532:
0533:            /** True when a component is enabled for model updates and is reachable. */
0534:            private static final int FLAG_ENABLED = 0x0080;
0535:
0536:            /** Flag for escaping HTML in model strings */
0537:            private static final int FLAG_ESCAPE_MODEL_STRINGS = 0x0002;
0538:
0539:            /**
0540:             * Boolean whether this component was rendered at least once for tracking
0541:             * changes.
0542:             */
0543:            private static final int FLAG_HAS_BEEN_RENDERED = 0x1000;
0544:
0545:            /** Ignore attribute modifiers */
0546:            private static final int FLAG_IGNORE_ATTRIBUTE_MODIFIER = 0x0040;
0547:
0548:            /** Flag for escaping HTML in model strings */
0549:            private static final int FLAG_INHERITABLE_MODEL = 0x0004;
0550:
0551:            /**
0552:             * Internal indicator of whether this component may be rendered given the
0553:             * current context's authorization. It overrides the visible flag in case
0554:             * this is false. Authorization is done before trying to render any
0555:             * component (otherwise we would end up with a half rendered page in the
0556:             * buffer)
0557:             */
0558:            private static final int FLAG_IS_RENDER_ALLOWED = 0x2000;
0559:
0560:            /**
0561:             * Whether or not the component should print out its markup id into the id
0562:             * attribute
0563:             */
0564:            private static final int FLAG_OUTPUT_MARKUP_ID = 0x4000;
0565:
0566:            /**
0567:             * Ouput a placeholder tag if the component is not visible. This is useful
0568:             * in ajax mode to go to visible(false) to visible(true) without the
0569:             * overhead of repaiting a visible parent container
0570:             */
0571:
0572:            private static final int FLAG_PLACEHOLDER = 0x8000;
0573:
0574:            /** Render tag boolean */
0575:            private static final int FLAG_RENDER_BODY_ONLY = 0x0020;
0576:
0577:            private static final int FLAG_RENDERING = 0x2000000;
0578:
0579:            /** Versioning boolean */
0580:            private static final int FLAG_VERSIONED = 0x0008;
0581:
0582:            /** Visibility boolean */
0583:            private static final int FLAG_VISIBLE = 0x0010;
0584:
0585:            /** Log. */
0586:            private static final Logger log = LoggerFactory
0587:                    .getLogger(Component.class);
0588:
0589:            /**
0590:             * The name of attribute that will hold markup id
0591:             */
0592:            private static final String MARKUP_ID_ATTR_NAME = "id";
0593:
0594:            /**
0595:             * Metadata key used to store/retrieve markup id
0596:             */
0597:            private static MetaDataKey MARKUP_ID_KEY = new MetaDataKey(
0598:                    String.class) {
0599:
0600:                private static final long serialVersionUID = 1L;
0601:
0602:            };
0603:            private static final long serialVersionUID = 1L;
0604:            /** Reserved subclass-definable flag bit */
0605:            protected static final int FLAG_RESERVED1 = 0x0100;
0606:            /** Reserved subclass-definable flag bit */
0607:            protected static final int FLAG_RESERVED2 = 0x0200;
0608:
0609:            /** Reserved subclass-definable flag bit */
0610:            protected static final int FLAG_RESERVED3 = 0x0400;
0611:            /** Reserved subclass-definable flag bit */
0612:            protected static final int FLAG_RESERVED4 = 0x0800;
0613:            /** Reserved subclass-definable flag bit */
0614:            protected static final int FLAG_RESERVED5 = 0x10000;
0615:
0616:            /** Reserved subclass-definable flag bit */
0617:            protected static final int FLAG_RESERVED6 = 0x20000;
0618:
0619:            /** Reserved subclass-definable flag bit */
0620:            protected static final int FLAG_RESERVED7 = 0x40000;
0621:
0622:            /** Reserved subclass-definable flag bit */
0623:            protected static final int FLAG_RESERVED8 = 0x80000;
0624:
0625:            /**
0626:             * Meta data key for line precise error logging for the moment of addition.
0627:             * Made package private for access in {@link MarkupContainer} and
0628:             * {@link Page}
0629:             */
0630:            static final MetaDataKey ADDED_AT_KEY = new MetaDataKey(
0631:                    String.class) {
0632:                private static final long serialVersionUID = 1L;
0633:            };
0634:
0635:            /**
0636:             * meta data key for line precise error logging for the moment of
0637:             * construction. Made package private for access in {@link Page}
0638:             */
0639:            static final MetaDataKey CONSTRUCTED_AT_KEY = new MetaDataKey(
0640:                    String.class) {
0641:                private static final long serialVersionUID = 1L;
0642:            };
0643:
0644:            static final int FLAG_ATTACH_SUPER_CALL_VERIFIED = 0x10000000;
0645:
0646:            static final int FLAG_ATTACHED = 0x20000000;
0647:
0648:            static final int FLAG_ATTACHING = 0x40000000;
0649:
0650:            /**
0651:             * Flag that makes we are in before-render callback phase Set after
0652:             * component.onBeforeRender is invoked (right before invoking beforeRender
0653:             * on children)
0654:             */
0655:            static final int FLAG_PREPARED_FOR_RENDER = 0x4000000;
0656:
0657:            /** List of behaviors to be applied for this Component */
0658:            private ArrayList behaviors = null;
0659:
0660:            /** Component flags. See FLAG_* for possible non-exclusive flag values. */
0661:            private int flags = FLAG_VISIBLE | FLAG_ESCAPE_MODEL_STRINGS
0662:                    | FLAG_VERSIONED | FLAG_ENABLED | FLAG_IS_RENDER_ALLOWED;
0663:
0664:            /** Component id. */
0665:            private String id;
0666:
0667:            /**
0668:             * MetaDataEntry array.
0669:             */
0670:            private MetaDataEntry[] metaData;
0671:
0672:            /** Any parent container. */
0673:            private MarkupContainer parent;
0674:
0675:            /**
0676:             * I really dislike it, but for now we need it. Reason: due to transparent
0677:             * containers and IComponentResolver there is guaranteed 1:1 mapping between
0678:             * component and markup
0679:             */
0680:            int markupIndex = -1;
0681:
0682:            /** The model for this component. */
0683:            IModel model;
0684:
0685:            /**
0686:             * Constructor. All components have names. A component's id cannot be null.
0687:             * This is the minimal constructor of component. It does not register a
0688:             * model.
0689:             * 
0690:             * @param id
0691:             *            The non-null id of this component
0692:             * @throws WicketRuntimeException
0693:             *             Thrown if the component has been given a null id.
0694:             */
0695:            public Component(final String id) {
0696:                setId(id);
0697:                getApplication().notifyComponentInstantiationListeners(this );
0698:
0699:                final IDebugSettings debugSettings = Application.get()
0700:                        .getDebugSettings();
0701:                if (debugSettings.isLinePreciseReportingOnNewComponentEnabled()) {
0702:                    setMetaData(CONSTRUCTED_AT_KEY, Strings.toString(this ,
0703:                            new MarkupException("constructed")));
0704:                }
0705:            }
0706:
0707:            /**
0708:             * Constructor. All components have names. A component's id cannot be null.
0709:             * This constructor includes a model.
0710:             * 
0711:             * @param id
0712:             *            The non-null id of this component
0713:             * @param model
0714:             *            The component's model
0715:             * 
0716:             * @throws WicketRuntimeException
0717:             *             Thrown if the component has been given a null id.
0718:             */
0719:            public Component(final String id, final IModel model) {
0720:                setId(id);
0721:                getApplication().notifyComponentInstantiationListeners(this );
0722:                this .model = wrap(model);
0723:
0724:                final IDebugSettings debugSettings = Application.get()
0725:                        .getDebugSettings();
0726:                if (debugSettings.isLinePreciseReportingOnNewComponentEnabled()) {
0727:                    setMetaData(CONSTRUCTED_AT_KEY, Strings.toString(this ,
0728:                            new MarkupException("constructed")));
0729:                }
0730:            }
0731:
0732:            /**
0733:             * Adds an behavior modifier to the component.
0734:             * 
0735:             * <p>
0736:             * Note: this method is override to enable users to do things like discussed
0737:             * in <a
0738:             * href="http://www.nabble.com/Why-add%28IBehavior%29-is-final--tf2598263.html#a7248198">this
0739:             * thread</a>.
0740:             * </p>
0741:             * 
0742:             * @param behavior
0743:             *            The behavior modifier to be added
0744:             * @return this (to allow method call chaining)
0745:             */
0746:            public Component add(final IBehavior behavior) {
0747:                if (behavior == null) {
0748:                    throw new IllegalArgumentException(
0749:                            "Argument may not be null");
0750:                }
0751:
0752:                // Lazy create
0753:                if (behaviors == null) {
0754:                    behaviors = new ArrayList(1);
0755:                }
0756:
0757:                behaviors.add(behavior);
0758:
0759:                if (!behavior.isTemporary()) {
0760:                    addStateChange(new AddedBehaviorChange(behavior));
0761:                }
0762:
0763:                // Give handler the opportunity to bind this component
0764:                behavior.bind(this );
0765:
0766:                return this ;
0767:            }
0768:
0769:            /**
0770:             * Called on very component after the page is renderd It will call
0771:             * onAfterRender for it self and its childeren.
0772:             */
0773:            public final void afterRender() {
0774:                // if the component has been previously attached via attach()
0775:                // detach it now
0776:                try {
0777:                    setFlag(FLAG_AFTER_RENDERING, true);
0778:                    onAfterRender();
0779:                    getApplication()
0780:                            .notifyComponentOnAfterRenderListeners(this );
0781:                    if (getFlag(FLAG_AFTER_RENDERING)) {
0782:                        throw new IllegalStateException(
0783:                                Component.class.getName()
0784:                                        + " has not been properly detached. Something in the hierarchy of "
0785:                                        + getClass().getName()
0786:                                        + " has not called super.onAfterRender() in the override of onAfterRender() method");
0787:                    }
0788:                    // always detach children because components can be attached
0789:                    // independently of their parents
0790:                    onAfterRenderChildren();
0791:                } finally {
0792:                    // this flag must always be set to false.
0793:                    setFlag(FLAG_RENDERING, false);
0794:                }
0795:            }
0796:
0797:            /**
0798:             * Attaches the component. This is called when the page is starting to be
0799:             * used for rendering or when a component listener call is executed on it.
0800:             */
0801:            public final void attach() {
0802:                internalAttach2();
0803:            }
0804:
0805:            /**
0806:             * Called for every component when the page is getting to be rendered. it
0807:             * will call onBeforeRender for this component and all the child components
0808:             */
0809:            public final void beforeRender() {
0810:                if (isVisible() && !getFlag(FLAG_RENDERING)
0811:                        && !getFlag(FLAG_PREPARED_FOR_RENDER)) {
0812:                    setFlag(FLAG_BEFORE_RENDERING_SUPER_CALL_VERIFIED, false);
0813:
0814:                    onBeforeRender();
0815:                    getApplication().notifyComponentOnBeforeRenderListeners(
0816:                            this );
0817:                    if (!getFlag(FLAG_BEFORE_RENDERING_SUPER_CALL_VERIFIED)) {
0818:                        throw new IllegalStateException(
0819:                                Component.class.getName()
0820:                                        + " has not been properly rendered. Something in the hierarchy of "
0821:                                        + getClass().getName()
0822:                                        + " has not called super.onBeforeRender() in the override of onBeforeRender() method");
0823:                    }
0824:                }
0825:            }
0826:
0827:            /**
0828:             * Redirects to any intercept page previously specified by a call to
0829:             * redirectToInterceptPage.
0830:             * 
0831:             * @return True if an original destination was redirected to
0832:             * @see Component#redirectToInterceptPage(Page)
0833:             */
0834:            public final boolean continueToOriginalDestination() {
0835:                return getPage().getPageMap().continueToOriginalDestination();
0836:            }
0837:
0838:            /**
0839:             * Registers a debug feedback message for this component
0840:             * 
0841:             * @param message
0842:             *            The feedback message
0843:             */
0844:            public final void debug(final String message) {
0845:                Session.get().getFeedbackMessages().debug(this , message);
0846:                Session.get().dirty();
0847:            }
0848:
0849:            /**
0850:             * Detaches the component. This is called at the end of the request for all
0851:             * the pages that are touched in that request.
0852:             */
0853:            public final void detach() {
0854:                // if the component has been previously attached via attach()
0855:                // detach it now
0856:                setFlag(FLAG_DETACHING, true);
0857:                onDetach();
0858:                if (getFlag(FLAG_DETACHING)) {
0859:                    throw new IllegalStateException(
0860:                            Component.class.getName()
0861:                                    + " has not been properly detached. Something in the hierarchy of "
0862:                                    + getClass().getName()
0863:                                    + " has not called super.onDetach() in the override of onDetach() method");
0864:                }
0865:                setFlag(FLAG_ATTACHED, false);
0866:
0867:                // always detach models because they can be attached without the
0868:                // component. eg component has a compoundpropertymodel and one of its
0869:                // children component's getmodelobject is called
0870:                detachModels();
0871:
0872:                // always detach children because components can be attached
0873:                // independently of their parents
0874:                detachChildren();
0875:
0876:                // reset the model to null when the current model is a IWrapModel and
0877:                // the model that created it/wrapped in it is a IComponentInheritedModel
0878:                // The model will be created next time.
0879:                if (getFlag(FLAG_INHERITABLE_MODEL)) {
0880:                    model = null;
0881:                    setFlag(FLAG_INHERITABLE_MODEL, false);
0882:                }
0883:            }
0884:
0885:            /**
0886:             * THIS IS WICKET INTERNAL ONLY. DO NOT USE IT.
0887:             * 
0888:             * Traverses all behaviors and calls detachModel() on them. This is needed
0889:             * to cleanup behavior after render. This method is necessary for
0890:             * {@link AjaxRequestTarget} to be able to cleanup component's behaviors
0891:             * after header contribution has been done (which is separated from
0892:             * component render).
0893:             */
0894:            public final void detachBehaviors() {
0895:                if (behaviors != null) {
0896:                    for (Iterator i = behaviors.iterator(); i.hasNext();) {
0897:                        IBehavior behavior = (IBehavior) i.next();
0898:
0899:                        // Always detach models, 'accepted' or not. Otherwise, if they
0900:                        // are accepted during render, but not here - something can go
0901:                        // undetached, and calling isEnabled can also lead to nasty side
0902:                        // effects. See for instance Timo's comment on
0903:                        // http://issues.apache.org/jira/browse/WICKET-673
0904:                        behavior.detach(this );
0905:
0906:                        if (behavior.isTemporary()) {
0907:                            i.remove();
0908:                        }
0909:                    }
0910:                }
0911:            }
0912:
0913:            /**
0914:             * Detaches all models
0915:             */
0916:            public void detachModels() {
0917:                // Detach any detachable model from this component
0918:                detachModel();
0919:
0920:                // detach any behaviors
0921:                detachBehaviors();
0922:            }
0923:
0924:            /**
0925:             * Registers an error feedback message for this component
0926:             * 
0927:             * @param message
0928:             *            The feedback message
0929:             */
0930:            public final void error(final Serializable message) {
0931:                Session.get().getFeedbackMessages().error(this , message);
0932:                Session.get().dirty();
0933:            }
0934:
0935:            /**
0936:             * Registers an fatal error feedback message for this component
0937:             * 
0938:             * @param message
0939:             *            The feedback message
0940:             */
0941:            public final void fatal(final String message) {
0942:                Session.get().getFeedbackMessages().fatal(this , message);
0943:                Session.get().dirty();
0944:            }
0945:
0946:            /**
0947:             * Finds the first container parent of this component of the given class.
0948:             * 
0949:             * @param c
0950:             *            MarkupContainer class to search for
0951:             * @return First container parent that is an instance of the given class, or
0952:             *         null if none can be found
0953:             */
0954:            public final MarkupContainer findParent(final Class c) {
0955:                // Start with immediate parent
0956:                MarkupContainer current = parent;
0957:
0958:                // Walk up containment hierarchy
0959:                while (current != null) {
0960:                    // Is current an instance of this class?
0961:                    if (c.isInstance(current)) {
0962:                        return current;
0963:                    }
0964:
0965:                    // Check parent
0966:                    current = current.getParent();
0967:                }
0968:
0969:                // Failed to find component
0970:                return null;
0971:            }
0972:
0973:            /**
0974:             * @return The nearest markup container with associated markup
0975:             */
0976:            public final MarkupContainer findParentWithAssociatedMarkup() {
0977:                MarkupContainer container = parent;
0978:                while (container != null) {
0979:                    if (container.hasAssociatedMarkup()) {
0980:                        return container;
0981:                    }
0982:                    container = container.getParent();
0983:                }
0984:
0985:                // This should never happen since Page always has associated markup
0986:                throw new WicketRuntimeException(
0987:                        "Unable to find parent with associated markup");
0988:            }
0989:
0990:            /**
0991:             * Gets interface to application that this component is a part of.
0992:             * 
0993:             * @return The application associated with the session that this component
0994:             *         is in.
0995:             * @see Application
0996:             */
0997:            public final Application getApplication() {
0998:                return Application.get();
0999:            }
1000:
1001:            /**
1002:             * Gets the currently coupled {@link IBehavior}s as a unmodifiable list.
1003:             * Returns an empty list rather than null if there are no behaviors coupled
1004:             * to this component.
1005:             * 
1006:             * @return The currently coupled behaviors as a unmodifiable list
1007:             */
1008:            public final List/* <IBehavior> */getBehaviors() {
1009:                return getBehaviors(null);
1010:            }
1011:
1012:            /**
1013:             * @return A path of the form [page-class-name].[page-relative-path]
1014:             * @see Component#getPageRelativePath()
1015:             */
1016:            public final String getClassRelativePath() {
1017:                return getClass().getName() + PATH_SEPARATOR
1018:                        + getPageRelativePath();
1019:            }
1020:
1021:            /**
1022:             * @return component border assigned to this component, or null if none
1023:             */
1024:            public final IComponentBorder getComponentBorder() {
1025:                return (IComponentBorder) getMetaData(BORDER_KEY);
1026:            }
1027:
1028:            /**
1029:             * @return nothing, will always throw an exception. Use
1030:             *         {@link #getConverter(Class)} instead.
1031:             * @deprecated To be removed. Please use/ override
1032:             *             {@link #getConverter(Class)} instead.
1033:             */
1034:            public final IConverter getConverter() {
1035:                throw new UnsupportedOperationException(
1036:                        "use #getConverter(Class) instead");
1037:            }
1038:
1039:            /**
1040:             * Gets the converter that should be used by this component.
1041:             * 
1042:             * @param type
1043:             *            The type to convert to
1044:             * 
1045:             * @return The converter that should be used by this component
1046:             */
1047:            public IConverter getConverter(Class/* <?> */type) {
1048:                return getApplication().getConverterLocator()
1049:                        .getConverter(type);
1050:            }
1051:
1052:            /**
1053:             * Gets whether model strings should be escaped.
1054:             * 
1055:             * @return Returns whether model strings should be escaped
1056:             */
1057:            public final boolean getEscapeModelStrings() {
1058:                return getFlag(FLAG_ESCAPE_MODEL_STRINGS);
1059:            }
1060:
1061:            /**
1062:             * @return Any feedback message for this component
1063:             */
1064:            public final FeedbackMessage getFeedbackMessage() {
1065:                return Session.get().getFeedbackMessages().messageForComponent(
1066:                        this );
1067:            }
1068:
1069:            /**
1070:             * Gets the id of this component.
1071:             * 
1072:             * @return The id of this component
1073:             */
1074:            public String getId() {
1075:                return id;
1076:            }
1077:
1078:            /**
1079:             * @return Innermost model for this component
1080:             */
1081:            public final IModel getInnermostModel() {
1082:                return getInnermostModel(getModel());
1083:            }
1084:
1085:            /**
1086:             * Gets the locale for this component. By default, it searches it parent for
1087:             * a locale. If no parents (it's a recursive search) returns a locale, it
1088:             * gets one from the session.
1089:             * 
1090:             * @return The locale to be used for this component
1091:             * @see Session#getLocale()
1092:             */
1093:            public Locale getLocale() {
1094:                Locale locale = null;
1095:                if (parent != null) {
1096:                    locale = parent.getLocale();
1097:                }
1098:                return (locale != null) ? locale : getSession().getLocale();
1099:            }
1100:
1101:            /**
1102:             * Convenience method to provide easy access to the localizer object within
1103:             * any component.
1104:             * 
1105:             * @return The localizer object
1106:             */
1107:            public final Localizer getLocalizer() {
1108:                return getApplication().getResourceSettings().getLocalizer();
1109:            }
1110:
1111:            /**
1112:             * THIS IS WICKET INTERNAL ONLY. DO NOT USE IT.
1113:             * 
1114:             * Get a copy of the markup's attributes which are associated with the
1115:             * component.
1116:             * <p>
1117:             * Modifications to the map returned don't change the tags attributes. It is
1118:             * just a copy.
1119:             * <p>
1120:             * Note: The component must have been added (directly or indirectly) to a
1121:             * container with an associated markup file (Page, Panel or Border).
1122:             * 
1123:             * @return markup attributes
1124:             */
1125:            public final ValueMap getMarkupAttributes() {
1126:                MarkupStream markupStream = locateMarkupStream();
1127:                ValueMap attrs = new ValueMap(markupStream.getTag()
1128:                        .getAttributes());
1129:                attrs.makeImmutable();
1130:                return attrs;
1131:            }
1132:
1133:            /**
1134:             * Retrieves id by which this component is represented within the markup.
1135:             * This is either the id attribute set explicitly via a call to
1136:             * {@link #setMarkupId(String)}, id attribute defined in the markup, or an
1137:             * automatically generated id - in that order.
1138:             * <p>
1139:             * If no explicit id is set this function will generate an id value that
1140:             * will be unique in the page. This is the preferred way as there is no
1141:             * chance of id collision.
1142:             * <p>
1143:             * Note: This method should only be called after the component or its parent
1144:             * have been added to the page.
1145:             * 
1146:             * @return markup id of the component
1147:             */
1148:            public String getMarkupId() {
1149:                String markupId = (String) getMetaData(MARKUP_ID_KEY);
1150:                if (markupId == null) {
1151:                    Page page = findPage();
1152:                    if (page == null) {
1153:                        throw new WicketRuntimeException(
1154:                                "This component is not (yet) coupled to a page. It has to be able "
1155:                                        + "to find the page it is supposed to operate in before you can call "
1156:                                        + "this method (Component#getMarkupId)");
1157:                    }
1158:                    // try to read from markup
1159:                    // TODO getting the id from markup doesn't work everywhere yet.
1160:                    // unfortunately, we have to drop this until we have a good solution
1161:                    // for issue http://issues.apache.org/jira/browse/WICKET-694
1162:                    // markupId = getMarkupAttributes().getString("id");
1163:
1164:                    // if (markupId == null)
1165:                    // {
1166:                    // if not in the markup, generate one
1167:
1168:                    markupId = getId() + page.getAutoIndex();
1169:                    // make sure id is compliant with w3c requirements (starts with a
1170:                    // letter)
1171:                    char c = markupId.charAt(0);
1172:                    if (!Character.isLetter(c)) {
1173:                        markupId = "id" + markupId;
1174:                    }
1175:
1176:                    // }
1177:                    setMetaData(MARKUP_ID_KEY, markupId);
1178:
1179:                }
1180:                return markupId;
1181:            }
1182:
1183:            /**
1184:             * Gets metadata for this component using the given key.
1185:             * 
1186:             * @param key
1187:             *            The key for the data
1188:             * @return The metadata or null of no metadata was found for the given key
1189:             * @see MetaDataKey
1190:             */
1191:            public final Serializable getMetaData(final MetaDataKey key) {
1192:                return key.get(metaData);
1193:            }
1194:
1195:            /**
1196:             * Gets the model. It returns the object that wraps the backing model.
1197:             * 
1198:             * @return The model
1199:             */
1200:            public final IModel getModel() {
1201:                // If model is null
1202:                if (model == null) {
1203:                    // give subclass a chance to lazy-init model
1204:                    model = initModel();
1205:                }
1206:
1207:                return model;
1208:            }
1209:
1210:            /**
1211:             * Gets the backing model object; this is shorthand for
1212:             * getModel().getObject().
1213:             * 
1214:             * @return The backing model object
1215:             */
1216:            public final Object getModelObject() {
1217:                final IModel model = getModel();
1218:                if (model != null) {
1219:                    // Get model value for this component.
1220:                    return model.getObject();
1221:                } else {
1222:                    return null;
1223:                }
1224:            }
1225:
1226:            /**
1227:             * Gets a model object as a string.
1228:             * 
1229:             * @return Model object for this component as a string
1230:             */
1231:            public final String getModelObjectAsString() {
1232:                return getModelObjectAsString(getModelObject());
1233:            }
1234:
1235:            /**
1236:             * @param modelObject
1237:             *            Model object to convert to string
1238:             * @return The string
1239:             */
1240:            public final String getModelObjectAsString(final Object modelObject) {
1241:                if (modelObject != null) {
1242:                    // Get converter
1243:                    final IConverter converter = getConverter(modelObject
1244:                            .getClass());
1245:
1246:                    // Model string from property
1247:                    final String modelString = converter.convertToString(
1248:                            modelObject, getLocale());
1249:
1250:                    if (modelString != null) {
1251:                        // If we should escape the markup
1252:                        if (getFlag(FLAG_ESCAPE_MODEL_STRINGS)) {
1253:                            // Escape it
1254:                            return Strings.escapeMarkup(modelString, false,
1255:                                    true).toString();
1256:                        }
1257:                        return modelString;
1258:                    }
1259:                }
1260:                return "";
1261:            }
1262:
1263:            /**
1264:             * Gets whether or not component will output id attribute into the markup.
1265:             * id attribute will be set to the value returned from
1266:             * {@link Component#getMarkupId()}.
1267:             * 
1268:             * @return whether or not component will output id attribute into the markup
1269:             */
1270:            public final boolean getOutputMarkupId() {
1271:                return getFlag(FLAG_OUTPUT_MARKUP_ID);
1272:            }
1273:
1274:            /**
1275:             * Gets the page holding this component.
1276:             * 
1277:             * @return The page holding this component
1278:             * @throws IllegalStateException
1279:             *             Thrown if component is not yet attached to a Page.
1280:             */
1281:            public final Page getPage() {
1282:                // Search for nearest Page
1283:                final Page page = findPage();
1284:
1285:                // If no Page was found
1286:                if (page == null) {
1287:                    // Give up with a nice exception
1288:                    throw new IllegalStateException(
1289:                            "No Page found for component " + this );
1290:                }
1291:
1292:                return page;
1293:            }
1294:
1295:            /**
1296:             * @return The page factory for the session that this component is in
1297:             */
1298:            public final IPageFactory getPageFactory() {
1299:                return getSession().getPageFactory();
1300:            }
1301:
1302:            /**
1303:             * Gets the path to this component relative to the page it is in.
1304:             * 
1305:             * @return The path to this component relative to the page it is in
1306:             */
1307:            public final String getPageRelativePath() {
1308:                return Strings.afterFirstPathComponent(getPath(),
1309:                        PATH_SEPARATOR);
1310:            }
1311:
1312:            /**
1313:             * Gets any parent container, or null if there is none.
1314:             * 
1315:             * @return Any parent container, or null if there is none
1316:             */
1317:            public final MarkupContainer getParent() {
1318:                return parent;
1319:            }
1320:
1321:            /**
1322:             * Gets this component's path.
1323:             * 
1324:             * @return Colon separated path to this component in the component hierarchy
1325:             */
1326:            public final String getPath() {
1327:                final PrependingStringBuffer buffer = new PrependingStringBuffer(
1328:                        32);
1329:                for (Component c = this ; c != null; c = c.getParent()) {
1330:                    if (buffer.length() > 0) {
1331:                        buffer.prepend(PATH_SEPARATOR);
1332:                    }
1333:                    buffer.prepend(c.getId());
1334:                }
1335:                return buffer.toString();
1336:            }
1337:
1338:            /**
1339:             * If false the component's tag will be printed as well as its body (which
1340:             * is default). If true only the body will be printed, but not the
1341:             * component's tag.
1342:             * 
1343:             * @return If true, the component tag will not be printed
1344:             */
1345:            public final boolean getRenderBodyOnly() {
1346:                return getFlag(FLAG_RENDER_BODY_ONLY);
1347:            }
1348:
1349:            /**
1350:             * @return The request for this component's active request cycle
1351:             */
1352:            public final Request getRequest() {
1353:                RequestCycle requestCycle = getRequestCycle();
1354:                if (requestCycle == null) {
1355:                    // Happens often with WicketTester when one forgets to call
1356:                    // createRequestCycle()
1357:                    throw new WicketRuntimeException(
1358:                            "No RequestCycle is currently set!");
1359:                }
1360:                return requestCycle.getRequest();
1361:            }
1362:
1363:            /**
1364:             * Gets the active request cycle for this component
1365:             * 
1366:             * @return The request cycle
1367:             */
1368:            public final RequestCycle getRequestCycle() {
1369:                return RequestCycle.get();
1370:            }
1371:
1372:            /**
1373:             * @return The response for this component's active request cycle
1374:             */
1375:            public final Response getResponse() {
1376:                return getRequestCycle().getResponse();
1377:            }
1378:
1379:            /**
1380:             * Gets the current Session object.
1381:             * 
1382:             * @return The Session that this component is in
1383:             */
1384:            public Session getSession() {
1385:                return Session.get();
1386:            }
1387:
1388:            /**
1389:             * @return Size of this Component in bytes
1390:             */
1391:            public long getSizeInBytes() {
1392:                final MarkupContainer originalParent = parent;
1393:                parent = null;
1394:                long size = -1;
1395:                try {
1396:                    size = Objects.sizeof(this );
1397:                } catch (Exception e) {
1398:                    log
1399:                            .error("Exception getting size for component "
1400:                                    + this , e);
1401:                }
1402:                parent = originalParent;
1403:                return size;
1404:            }
1405:
1406:            /**
1407:             * @param key
1408:             *            Key of string resource in property file
1409:             * @return The String
1410:             * @see Localizer
1411:             */
1412:            public final String getString(final String key) {
1413:                return getString(key, null);
1414:            }
1415:
1416:            /**
1417:             * @param key
1418:             *            The resource key
1419:             * @param model
1420:             *            The model
1421:             * @return The formatted string
1422:             * @see Localizer
1423:             */
1424:            public final String getString(final String key, final IModel model) {
1425:                return getLocalizer().getString(key, this , model);
1426:            }
1427:
1428:            /**
1429:             * @param key
1430:             *            The resource key
1431:             * @param model
1432:             *            The model
1433:             * @param defaultValue
1434:             *            A default value if the string cannot be found
1435:             * @return The formatted string
1436:             * @see Localizer
1437:             */
1438:            public final String getString(final String key, final IModel model,
1439:                    final String defaultValue) {
1440:                return getLocalizer().getString(key, this , model, defaultValue);
1441:            }
1442:
1443:            /**
1444:             * Gets the style of this component (see {@link org.apache.wicket.Session}).
1445:             * 
1446:             * @return The style of this component.
1447:             * 
1448:             * @see org.apache.wicket.Session
1449:             * @see org.apache.wicket.Session#getStyle()
1450:             */
1451:            public final String getStyle() {
1452:                String variation = getVariation();
1453:                String style = getSession().getStyle();
1454:                if (variation != null && !"".equals(variation)) {
1455:                    if (style != null && !"".equals(style)) {
1456:                        style = variation + "_" + style;
1457:                    } else {
1458:                        style = variation;
1459:                    }
1460:                }
1461:                return style;
1462:            }
1463:
1464:            /**
1465:             * Gets the variation string of this component that will be used to look up
1466:             * markup for this component. Subclasses can override this method to define
1467:             * by an instance what markup variation should be picked up. By default it
1468:             * will return null or the value of a parent.
1469:             * 
1470:             * @return The variation of this component.
1471:             */
1472:            public String getVariation() {
1473:                String variation = null;
1474:                if (parent != null) {
1475:                    variation = parent.getVariation();
1476:                }
1477:                return variation;
1478:            }
1479:
1480:            /**
1481:             * Gets whether this component was rendered at least once.
1482:             * 
1483:             * @return true if the component has been rendered before, false if it is
1484:             *         merely constructed
1485:             */
1486:            public final boolean hasBeenRendered() {
1487:                return getFlag(FLAG_HAS_BEEN_RENDERED);
1488:            }
1489:
1490:            /**
1491:             * @return True if this component has an error message
1492:             */
1493:            public final boolean hasErrorMessage() {
1494:                return Session.get().getFeedbackMessages().hasErrorMessageFor(
1495:                        this );
1496:            }
1497:
1498:            /**
1499:             * @return True if this component has some kind of feedback message
1500:             */
1501:            public final boolean hasFeedbackMessage() {
1502:                return Session.get().getFeedbackMessages().hasMessageFor(this );
1503:            }
1504:
1505:            /**
1506:             * Registers an informational feedback message for this component
1507:             * 
1508:             * @param message
1509:             *            The feedback message
1510:             */
1511:            public final void info(final String message) {
1512:                Session.get().getFeedbackMessages().info(this , message);
1513:                Session.get().dirty();
1514:            }
1515:
1516:            /**
1517:             * @deprecated
1518:             */
1519:            // TODO remove after deprecation release
1520:            public final void internalAttach() {
1521:                throw new UnsupportedOperationException();
1522:            }
1523:
1524:            /**
1525:             * @deprecated
1526:             */
1527:            // TODO remove after deprecation release
1528:            public final void internalDetach() {
1529:                throw new UnsupportedOperationException();
1530:            }
1531:
1532:            /**
1533:             * Authorizes an action for a component.
1534:             * 
1535:             * @param action
1536:             *            The action to authorize
1537:             * @return True if the action is allowed
1538:             * @throws AuthorizationException
1539:             *             Can be thrown by implementation if action is unauthorized
1540:             */
1541:            public final boolean isActionAuthorized(Action action) {
1542:                IAuthorizationStrategy authorizationStrategy = getSession()
1543:                        .getAuthorizationStrategy();
1544:                if (authorizationStrategy != null) {
1545:                    return authorizationStrategy.isActionAuthorized(this ,
1546:                            action);
1547:                }
1548:                return true;
1549:            }
1550:
1551:            /**
1552:             * Returns true if this component is an ancestor of the given component
1553:             * 
1554:             * @param component
1555:             *            The component to check
1556:             * @return True if the given component has this component as an ancestor
1557:             * @deprecated use getParent().contains(component, false)
1558:             */
1559:            public final boolean isAncestorOf(final Component component) {
1560:                return getParent().contains(component, false);
1561:                // // Walk up containment hierarchy
1562:                // for (MarkupContainer current = component.parent; current != null;
1563:                // current = current
1564:                // .getParent())
1565:                // {
1566:                // // Is this an ancestor?
1567:                // if (current == this)
1568:                // {
1569:                // return true;
1570:                // }
1571:                // }
1572:                //
1573:                // // This component is not an ancestor of the given component
1574:                // return false;
1575:            }
1576:
1577:            /**
1578:             * @return true if this component is authorized to be enabled, false
1579:             *         otherwise
1580:             */
1581:            public final boolean isEnableAllowed() {
1582:                return isActionAuthorized(ENABLE);
1583:            }
1584:
1585:            /**
1586:             * Gets whether this component is enabled. Specific components may decide to
1587:             * implement special behavior that uses this property, like web form
1588:             * components that add a disabled='disabled' attribute when enabled is
1589:             * false.
1590:             * 
1591:             * @return Whether this component is enabled.
1592:             */
1593:            public boolean isEnabled() {
1594:                return getFlag(FLAG_ENABLED);
1595:            }
1596:
1597:            /**
1598:             * Checks the security strategy if the {@link Component#RENDER} action is
1599:             * allowed on this component
1600:             * 
1601:             * @return ture if {@link Component#RENDER} action is allowed, false
1602:             *         otherwise
1603:             */
1604:            public final boolean isRenderAllowed() {
1605:                return getFlag(FLAG_IS_RENDER_ALLOWED);
1606:            }
1607:
1608:            /**
1609:             * Returns if the component is stateless or not. It checks the stateless
1610:             * hint if that is false it returns directly false. If that is still true it
1611:             * checks all its behaviours if they can be stateless.
1612:             * 
1613:             * @return whether the component is stateless.
1614:             */
1615:            public final boolean isStateless() {
1616:                if (!getStatelessHint()) {
1617:                    return false;
1618:                }
1619:
1620:                final Iterator behaviors = getBehaviors().iterator();
1621:
1622:                while (behaviors.hasNext()) {
1623:                    IBehavior behavior = (IBehavior) behaviors.next();
1624:                    if (!behavior.getStatelessHint(this )) {
1625:                        return false;
1626:                    }
1627:                }
1628:                return true;
1629:            }
1630:
1631:            /**
1632:             * @return True if this component is versioned
1633:             */
1634:            public boolean isVersioned() {
1635:                // Is the component itself versioned?
1636:                if (!getFlag(FLAG_VERSIONED)
1637:                        || !getFlag(FLAG_HAS_BEEN_RENDERED)) {
1638:                    return false;
1639:                } else {
1640:                    // If there's a parent and this component is versioned
1641:                    if (parent != null) {
1642:                        // Check if the parent is unversioned. If any parent
1643:                        // (recursively) is unversioned, then this component is too
1644:                        if (!parent.isVersioned()) {
1645:                            return false;
1646:                        }
1647:                    }
1648:                    return true;
1649:                }
1650:            }
1651:
1652:            /**
1653:             * Gets whether this component and any children are visible.
1654:             * <p>
1655:             * WARNING: this method can be called multiple times during a request. If
1656:             * you override this method, it is a good idea to keep it cheap in terms of
1657:             * processing. Alternatively, you can call {@link #setVisible(boolean)}.
1658:             * <p>
1659:             * 
1660:             * @return True if component and any children are visible
1661:             */
1662:            public boolean isVisible() {
1663:                return getFlag(FLAG_VISIBLE);
1664:            }
1665:
1666:            /**
1667:             * Checks if the component itself and all its parents are visible.
1668:             * 
1669:             * @return true if the component and all its parents are visible.
1670:             */
1671:            public final boolean isVisibleInHierarchy() {
1672:                Component component = this ;
1673:                while (component != null) {
1674:                    if (component.isRenderAllowed() && component.isVisible()) {
1675:                        component = component.getParent();
1676:                    } else {
1677:                        return false;
1678:                    }
1679:                }
1680:                return true;
1681:            }
1682:
1683:            /**
1684:             * Sets the RENDERING flag on component and it's children.
1685:             */
1686:            public final void markRendering() {
1687:                internalMarkRendering();
1688:            }
1689:
1690:            /**
1691:             * Called to indicate that the model content for this component has been
1692:             * changed
1693:             */
1694:            public final void modelChanged() {
1695:                // Call user code
1696:                internalOnModelChanged();
1697:                onModelChanged();
1698:            }
1699:
1700:            /**
1701:             * Called to indicate that the model content for this component is about to
1702:             * change
1703:             */
1704:            public final void modelChanging() {
1705:                checkHierarchyChange(this );
1706:
1707:                // Call user code
1708:                onModelChanging();
1709:
1710:                // Tell the page that our model changed
1711:                final Page page = findPage();
1712:                if (page != null) {
1713:                    page.componentModelChanging(this );
1714:                }
1715:            }
1716:
1717:            /**
1718:             * Creates a new page using the component's page factory
1719:             * 
1720:             * @param c
1721:             *            The class of page to create
1722:             * @return The new page
1723:             */
1724:            public final Page newPage(final Class c) {
1725:                return getPageFactory().newPage(c);
1726:            }
1727:
1728:            /**
1729:             * Creates a new page using the component's page factory
1730:             * 
1731:             * @param c
1732:             *            The class of page to create
1733:             * @param parameters
1734:             *            Any parameters to pass to the constructor
1735:             * @return The new page
1736:             */
1737:            public final Page newPage(final Class c,
1738:                    final PageParameters parameters) {
1739:                return getPageFactory().newPage(c, parameters);
1740:            }
1741:
1742:            /**
1743:             * Prepares the component and it's children for rendering. On whole page
1744:             * render this method must be called on the page. On AJAX request, this
1745:             * method must be called on updated component.
1746:             */
1747:            public void prepareForRender() {
1748:                beforeRender();
1749:                markRendering();
1750:            }
1751:
1752:            /**
1753:             * Redirects browser to an intermediate page such as a sign-in page. The
1754:             * current request's url is saved for future use by method
1755:             * continueToOriginalDestination(); Only use this method when you plan to
1756:             * continue to the current url at some later time; otherwise just use
1757:             * setResponsePage or - when you are in a constructor or checkAccessMethod,
1758:             * call redirectTo.
1759:             * 
1760:             * @param page
1761:             *            The sign in page
1762:             * 
1763:             * @see Component#continueToOriginalDestination()
1764:             */
1765:            public final void redirectToInterceptPage(final Page page) {
1766:                getPage().getPageMap().redirectToInterceptPage(page);
1767:            }
1768:
1769:            /**
1770:             * Removes this component from its parent. It's important to remember that a
1771:             * component that is removed cannot be referenced from the markup still.
1772:             */
1773:            public final void remove() {
1774:                if (parent == null) {
1775:                    throw new IllegalStateException("Cannot remove " + this 
1776:                            + " from null parent!");
1777:                }
1778:
1779:                parent.remove(this );
1780:            }
1781:
1782:            /**
1783:             * Removes behavior from component
1784:             * 
1785:             * @param behavior
1786:             *            behavior to remove
1787:             * 
1788:             * @return this (to allow method call chaining)
1789:             */
1790:            public Component remove(final IBehavior behavior) {
1791:                if (behavior == null) {
1792:                    throw new IllegalArgumentException(
1793:                            "Argument `behavior` cannot be null");
1794:                }
1795:                if (!behaviors.contains(behavior)) {
1796:                    throw new IllegalStateException(
1797:                            "Tried to remove a behavior that was not added to the component. Behavior: "
1798:                                    + behavior.toString());
1799:                }
1800:
1801:                if (!behavior.isTemporary()) {
1802:                    addStateChange(new RemovedBehaviorChange(behavior));
1803:                }
1804:                behaviors.remove(behavior);
1805:
1806:                if (behaviors.size() == 0) {
1807:                    behaviors = null;
1808:                }
1809:
1810:                return this ;
1811:            }
1812:
1813:            /**
1814:             * Performs a render of this component as part of a Page level render
1815:             * process.
1816:             * <p>
1817:             * For component level re-render (e.g. AJAX) please call
1818:             * {@link #renderComponent()}. Though render() does seem to work, it will
1819:             * fail for panel children.
1820:             */
1821:            public final void render() {
1822:                // Allow currently invisible components to be re-rendered as well
1823:                MarkupStream markupStream = null;
1824:                if (getParent() != null) {
1825:                    markupStream = findMarkupStream();
1826:                }
1827:
1828:                render(markupStream);
1829:            }
1830:
1831:            /**
1832:             * Performs a render of this component as part of a Page level render
1833:             * process.
1834:             * <p>
1835:             * For component level re-render (e.g. AJAX) please call
1836:             * {@link #renderComponent(MarkupStream)}. Though render() does seem to
1837:             * work, it will fail for panel children.
1838:             * 
1839:             * @param markupStream
1840:             */
1841:            public final void render(final MarkupStream markupStream) {
1842:                // We need to know the index before we do the visibility check.
1843:                // Otherwise
1844:                // we wouldn't know the markup index for invisible components
1845:                if (markupStream != null) {
1846:                    markupIndex = markupStream.getCurrentIndex();
1847:                }
1848:
1849:                markRendering();
1850:
1851:                setMarkupStream(markupStream);
1852:                setFlag(FLAG_HAS_BEEN_RENDERED, true);
1853:
1854:                // Determine if component is visible using it's authorization status
1855:                // and the isVisible property.
1856:                if (isRenderAllowed() && isVisible()) {
1857:                    // Rendering is beginning
1858:                    if (log.isDebugEnabled()) {
1859:                        log.debug("Begin render " + this );
1860:                    }
1861:
1862:                    try {
1863:                        // Call implementation to render component
1864:                        notifyBehaviorsComponentBeforeRender();
1865:                        final IComponentBorder border = getComponentBorder();
1866:                        if (border != null) {
1867:                            border.renderBefore(this );
1868:                        }
1869:                        onRender(markupStream);
1870:                        if (border != null) {
1871:                            border.renderAfter(this );
1872:                        }
1873:                        // Component has been rendered
1874:                        rendered();
1875:                    } catch (RuntimeException ex) {
1876:                        // Call each behaviors onException() to allow the
1877:                        // behavior to clean up
1878:                        if (behaviors != null) {
1879:                            for (Iterator i = behaviors.iterator(); i.hasNext();) {
1880:                                IBehavior behavior = (IBehavior) i.next();
1881:                                if (isBehaviorAccepted(behavior)) {
1882:                                    try {
1883:                                        behavior.exception(this , ex);
1884:                                    } catch (Throwable ex2) {
1885:                                        log
1886:                                                .error(
1887:                                                        "Error while cleaning up after exception",
1888:                                                        ex2);
1889:                                    }
1890:                                }
1891:                            }
1892:                        }
1893:
1894:                        // Re-throw the exception
1895:                        throw ex;
1896:                    }
1897:
1898:                    if (log.isDebugEnabled()) {
1899:                        log.debug("End render " + this );
1900:                    }
1901:                }
1902:                // markupStream is null when rendering a page
1903:                else if (markupStream != null) {
1904:                    if (getFlag(FLAG_PLACEHOLDER)) {
1905:                        // write out a placeholder tag into the markup
1906:                        final ComponentTag tag = markupStream.getTag();
1907:
1908:                        getResponse().write("<");
1909:                        getResponse().write(tag.getName());
1910:                        getResponse().write(" id=\"");
1911:                        getResponse().write(getMarkupId());
1912:                        getResponse().write("\" style=\"display:none\"></");
1913:                        getResponse().write(tag.getName());
1914:                        getResponse().write(">");
1915:                    }
1916:                    markupStream.skipComponent();
1917:                }
1918:            }
1919:
1920:            /**
1921:             * Page.renderPage() is used to render a whole page. With AJAX however it
1922:             * must be possible to render any one component contained in a page. That is
1923:             * what this method is for.
1924:             * <p>
1925:             * Note: it is not necessary that the page has previously been rendered. But
1926:             * the component must have been added (directly or indirectly) to a
1927:             * container with an associated markup file (Page, Panel or Border).
1928:             */
1929:            public final void renderComponent() {
1930:                // If this Component is a Page
1931:                if (this  instanceof  Page) {
1932:                    // Render as Page, with all the special logic that entails
1933:                    ((Page) this ).renderPage();
1934:                } else {
1935:                    // Save the parent's markup stream to re-assign it at the end
1936:                    MarkupContainer parent = getParent();
1937:                    MarkupStream originalMarkupStream = parent
1938:                            .getMarkupStream();
1939:                    MarkupStream markupStream = locateMarkupStream();
1940:
1941:                    try {
1942:                        // Make sure that while rendering the markup stream is found
1943:                        parent.setMarkupStream(markupStream);
1944:
1945:                        beforeRender();
1946:                        markRendering();
1947:                        // check authorization
1948:                        // first the component itself
1949:                        // (after attach as otherwise list views etc wont work)
1950:                        setRenderAllowed(isActionAuthorized(RENDER));
1951:                        // check children if this is a container
1952:                        if (this  instanceof  MarkupContainer) {
1953:                            MarkupContainer container = (MarkupContainer) this ;
1954:                            container.visitChildren(new IVisitor() {
1955:                                public Object component(
1956:                                        final Component component) {
1957:                                    // Find out if this component can be rendered
1958:                                    final boolean renderAllowed = component
1959:                                            .isActionAuthorized(RENDER);
1960:                                    // Authorize rendering
1961:                                    component.setRenderAllowed(renderAllowed);
1962:                                    return IVisitor.CONTINUE_TRAVERSAL;
1963:                                }
1964:                            });
1965:                        }
1966:
1967:                        // Render the component and all its children
1968:                        render(markupStream);
1969:                    } finally {
1970:                        // Make sure the original markup stream is back in place
1971:                        parent.setMarkupStream(originalMarkupStream);
1972:                        afterRender();
1973:                    }
1974:                }
1975:            }
1976:
1977:            /**
1978:             * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT USE IT.
1979:             * <p>
1980:             * Renders the component at the current position in the given markup stream.
1981:             * The method onComponentTag() is called to allow the component to mutate
1982:             * the start tag. The method onComponentTagBody() is then called to permit
1983:             * the component to render its body.
1984:             * 
1985:             * @param markupStream
1986:             *            The markup stream
1987:             */
1988:            public final void renderComponent(final MarkupStream markupStream) {
1989:                markupIndex = markupStream.getCurrentIndex();
1990:
1991:                // Get mutable copy of next tag
1992:                final ComponentTag openTag = markupStream.getTag();
1993:                final ComponentTag tag = openTag.mutable();
1994:
1995:                // Call any tag handler
1996:                onComponentTag(tag);
1997:
1998:                // If we're an openclose tag
1999:                if (!tag.isOpenClose() && !tag.isOpen()) {
2000:                    // We were something other than <tag> or <tag/>
2001:                    markupStream
2002:                            .throwMarkupException("Method renderComponent called on bad markup element: "
2003:                                    + tag);
2004:                }
2005:
2006:                if (tag.isOpenClose() && openTag.isOpen()) {
2007:                    markupStream
2008:                            .throwMarkupException("You can not modify a open tag to open-close: "
2009:                                    + tag);
2010:                }
2011:
2012:                try {
2013:                    // Render open tag
2014:                    if (getRenderBodyOnly() == false) {
2015:                        renderComponentTag(tag);
2016:                    }
2017:                    markupStream.next();
2018:
2019:                    // Render the body only if open-body-close. Do not render if
2020:                    // open-close.
2021:                    if (tag.isOpen()) {
2022:                        // Render the body
2023:                        onComponentTagBody(markupStream, tag);
2024:                    }
2025:
2026:                    // Render close tag
2027:                    if (tag.isOpen()) {
2028:                        if (openTag.isOpen()) {
2029:                            renderClosingComponentTag(markupStream, tag,
2030:                                    getRenderBodyOnly());
2031:                        } else {
2032:                            // If a open-close tag has been to modified to be
2033:                            // open-body-close than a synthetic close tag must be
2034:                            // rendered.
2035:                            if (getRenderBodyOnly() == false) {
2036:                                final boolean stripWicketTags = Application
2037:                                        .get().getMarkupSettings()
2038:                                        .getStripWicketTags();
2039:                                if (!(openTag instanceof  WicketTag)
2040:                                        || !stripWicketTags) {
2041:                                    // Close the manually opened panel tag.
2042:                                    getResponse().write(
2043:                                            openTag.syntheticCloseTagString());
2044:                                }
2045:                            }
2046:                        }
2047:                    }
2048:                } catch (RuntimeException re) {
2049:                    if (re instanceof  WicketRuntimeException
2050:                            || re instanceof  AbortException) {
2051:                        throw re;
2052:                    }
2053:                    throw new WicketRuntimeException(
2054:                            "Exception in rendering component: " + this , re);
2055:                }
2056:            }
2057:
2058:            /**
2059:             * Called to indicate that a component has been rendered. This method should
2060:             * only very rarely be called at all. One usage is in ImageMap, which
2061:             * renders its link children its own special way (without calling render()
2062:             * on them). If ImageMap did not call rendered() to indicate that its child
2063:             * components were actually rendered, the framework would think they had
2064:             * never been rendered, and in development mode this would result in a
2065:             * runtime exception.
2066:             */
2067:            public final void rendered() {
2068:                notifyBehaviorsComponentRendered();
2069:                // Tell the page that the component rendered
2070:                getPage().componentRendered(this );
2071:            }
2072:
2073:            /**
2074:             * Print to the web response what ever the component wants to contribute to
2075:             * the head section. Make sure that all attached behaviors are asked as
2076:             * well.
2077:             * <p>
2078:             * NOT intended for overriding by framework clients. Rather, use
2079:             * {@link IHeaderContributor#renderHead(org.apache.wicket.markup.html.IHeaderResponse)}
2080:             * </p>
2081:             * 
2082:             * @param container
2083:             *            The HtmlHeaderContainer
2084:             */
2085:            public void renderHead(final HtmlHeaderContainer container) {
2086:                if (isVisible()) {
2087:                    if (this  instanceof  IHeaderContributor) {
2088:                        ((IHeaderContributor) this ).renderHead(container
2089:                                .getHeaderResponse());
2090:                    }
2091:
2092:                    // Ask all behaviors if they have something to contribute to the
2093:                    // header or body onLoad tag.
2094:                    if (behaviors != null) {
2095:                        final Iterator iter = behaviors.iterator();
2096:                        while (iter.hasNext()) {
2097:                            IBehavior behavior = (IBehavior) iter.next();
2098:                            if (behavior instanceof  IHeaderContributor
2099:                                    && isBehaviorAccepted(behavior)) {
2100:                                ((IHeaderContributor) behavior)
2101:                                        .renderHead(container
2102:                                                .getHeaderResponse());
2103:                            }
2104:                        }
2105:                    }
2106:                }
2107:            }
2108:
2109:            /**
2110:             * Replaces this component with another. The replacing component must have
2111:             * the same component id as this component. This method serves as a shortcut
2112:             * to <code>this.getParent().replace(replacement)</code> and provides a
2113:             * better context for errors.
2114:             * 
2115:             * @since 1.2.1
2116:             * 
2117:             * @param replacement
2118:             *            component to replace this one
2119:             */
2120:            public void replaceWith(Component replacement) {
2121:                if (replacement == null) {
2122:                    throw new IllegalArgumentException(
2123:                            "Argument [[replacement]] cannot be null.");
2124:                }
2125:                if (!getId().equals(replacement.getId())) {
2126:                    throw new IllegalArgumentException(
2127:                            "Replacement component must have the same id as the component it will replace. Replacement id [["
2128:                                    + replacement.getId()
2129:                                    + "]], replaced id [[" + getId() + "]].");
2130:                }
2131:                if (parent == null) {
2132:                    throw new IllegalStateException(
2133:                            "This method can only be called on a component that has already been added to its parent.");
2134:                }
2135:                parent.replace(replacement);
2136:            }
2137:
2138:            /**
2139:             * @param component
2140:             *            The component to compare with
2141:             * @return True if the given component's model is the same as this
2142:             *         component's model.
2143:             */
2144:            public final boolean sameInnermostModel(final Component component) {
2145:                return sameInnermostModel(component.getModel());
2146:            }
2147:
2148:            /**
2149:             * @param model
2150:             *            The model to compare with
2151:             * @return True if the given component's model is the same as this
2152:             *         component's model.
2153:             */
2154:            public final boolean sameInnermostModel(final IModel model) {
2155:                // Get the two models
2156:                IModel this Model = getModel();
2157:                IModel thatModel = model;
2158:
2159:                // If both models are non-null they could be the same
2160:                if (this Model != null && thatModel != null) {
2161:                    return getInnermostModel(this Model) == getInnermostModel(thatModel);
2162:                }
2163:
2164:                return false;
2165:            }
2166:
2167:            /**
2168:             * Assigns a component border to this component. If called with
2169:             * <code>null</code> any previous border will be cleared.
2170:             * 
2171:             * @param border
2172:             *            componnet border to assign, or <code>null</code> to clear
2173:             *            any previous
2174:             * @return component for chaining
2175:             */
2176:            public final Component setComponentBorder(
2177:                    final IComponentBorder border) {
2178:                if (!Objects.equal(getComponentBorder(), border)) {
2179:                    addStateChange(new ComponentBorderChange());
2180:                }
2181:                setMetaData(BORDER_KEY, border);
2182:                return this ;
2183:            }
2184:
2185:            /**
2186:             * Sets whether this component is enabled. Specific components may decide to
2187:             * implement special behavior that uses this property, like web form
2188:             * components that add a disabled='disabled' attribute when enabled is
2189:             * false. If it is not enabled, it will not be allowed to call any listener
2190:             * method on it (e.g. Link.onClick) and the model object will be protected
2191:             * (for the common use cases, not for programmer's misuse)
2192:             * 
2193:             * @param enabled
2194:             *            whether this component is enabled
2195:             * @return This
2196:             */
2197:            public final Component setEnabled(final boolean enabled) {
2198:                // Is new enabled state a change?
2199:                if (enabled != getFlag(FLAG_ENABLED)) {
2200:                    // Tell the page that this component's enabled was changed
2201:                    if (isVersioned()) {
2202:                        final Page page = findPage();
2203:                        if (page != null) {
2204:                            addStateChange(new EnabledChange(this ));
2205:                        }
2206:                    }
2207:
2208:                    // Change visibility
2209:                    setFlag(FLAG_ENABLED, enabled);
2210:                }
2211:                return this ;
2212:            }
2213:
2214:            /**
2215:             * Sets whether model strings should be escaped.
2216:             * 
2217:             * @param escapeMarkup
2218:             *            True is model strings should be escaped
2219:             * @return This
2220:             */
2221:            public final Component setEscapeModelStrings(
2222:                    final boolean escapeMarkup) {
2223:                setFlag(FLAG_ESCAPE_MODEL_STRINGS, escapeMarkup);
2224:                return this ;
2225:            }
2226:
2227:            /**
2228:             * Sets this component's markup id to a user defined value. It is up to the
2229:             * user to ensure this value is unique.
2230:             * <p>
2231:             * The recommended way is to let wicket generate the value automatically,
2232:             * this method is here to serve as an override for that value in cases where
2233:             * a specific id must be used.
2234:             * <p>
2235:             * If null is passed in the user defined value is cleared and markup id
2236:             * value will fall back on automatically generated value
2237:             * 
2238:             * @see #getMarkupId()
2239:             * 
2240:             * @param markupId
2241:             *            markup id value or null to clear any previous user defined
2242:             *            value
2243:             */
2244:            public void setMarkupId(String markupId) {
2245:                if (markupId != null && Strings.isEmpty(markupId)) {
2246:                    throw new IllegalArgumentException(
2247:                            "Markup id cannot be an empty string");
2248:                }
2249:                setMetaData(MARKUP_ID_KEY, markupId);
2250:
2251:            }
2252:
2253:            /**
2254:             * Sets the metadata for this component using the given key. If the metadata
2255:             * object is not of the correct type for the metadata key, an
2256:             * IllegalArgumentException will be thrown. For information on creating
2257:             * MetaDataKeys, see {@link MetaDataKey}.
2258:             * 
2259:             * @param key
2260:             *            The singleton key for the metadata
2261:             * @param object
2262:             *            The metadata object
2263:             * @throws IllegalArgumentException
2264:             * @see MetaDataKey
2265:             */
2266:            public final void setMetaData(final MetaDataKey key,
2267:                    final Serializable object) {
2268:                metaData = key.set(metaData, object);
2269:            }
2270:
2271:            /**
2272:             * Sets the given model.
2273:             * <p>
2274:             * WARNING: DO NOT OVERRIDE THIS METHOD UNLESS YOU HAVE A VERY GOOD REASON
2275:             * FOR IT. OVERRIDING THIS MIGHT OPEN UP SECURITY LEAKS AND BREAK
2276:             * BACK-BUTTON SUPPORT.
2277:             * </p>
2278:             * 
2279:             * @param model
2280:             *            The model
2281:             * @return This
2282:             */
2283:            public Component setModel(final IModel model) {
2284:                // Detach current model
2285:                if (this .model != null) {
2286:                    this .model.detach();
2287:                }
2288:
2289:                IModel prevModel = this .model;
2290:                if (prevModel instanceof  IWrapModel) {
2291:                    prevModel = ((IWrapModel) prevModel).getWrappedModel();
2292:                }
2293:
2294:                // Change model
2295:                if (prevModel != model) {
2296:                    if (prevModel != null) {
2297:                        addStateChange(new ComponentModelChange(prevModel));
2298:                    }
2299:
2300:                    this .model = wrap(model);
2301:                }
2302:
2303:                modelChanged();
2304:                return this ;
2305:            }
2306:
2307:            /**
2308:             * Sets the backing model object; shorthand for
2309:             * getModel().setObject(object).
2310:             * 
2311:             * @param object
2312:             *            The object to set
2313:             * @return This
2314:             */
2315:            public final Component setModelObject(final Object object) {
2316:                final IModel model = getModel();
2317:
2318:                // Check whether anything can be set at all
2319:                if (model == null) {
2320:                    throw new IllegalStateException(
2321:                            "Attempt to set model object on null model of component: "
2322:                                    + getPageRelativePath());
2323:                }
2324:
2325:                // Check authorization
2326:                if (!isActionAuthorized(ENABLE)) {
2327:                    throw new UnauthorizedActionException(this , ENABLE);
2328:                }
2329:
2330:                // Check whether this will result in an actual change
2331:                if (!getModelComparator().compare(this , object)) {
2332:                    modelChanging();
2333:                    model.setObject(object);
2334:                    modelChanged();
2335:                }
2336:
2337:                return this ;
2338:            }
2339:
2340:            /**
2341:             * Sets whether or not component will output id attribute into the markup.
2342:             * id attribute will be set to the value returned from
2343:             * {@link Component#getMarkupId()}.
2344:             * 
2345:             * @param output
2346:             *            True if the component will out the id attribute into markup.
2347:             *            Please note that the default behavior is to use the same id as
2348:             *            the component. This means that your component must begin with
2349:             *            [a-zA-Z] in order to generate a valid markup id according to:
2350:             *            http://www.w3.org/TR/html401/types.html#type-name
2351:             * 
2352:             * @return this for chaining
2353:             */
2354:            public final Component setOutputMarkupId(final boolean output) {
2355:                setFlag(FLAG_OUTPUT_MARKUP_ID, output);
2356:                return this ;
2357:            }
2358:
2359:            /**
2360:             * Render a placeholder tag when the component is not visible. The tag is of
2361:             * form: &lt;componenttag style="display:none;" id="componentid"/&gt;. This
2362:             * method will also call <code>setOutputMarkupId(true)</code>.
2363:             * 
2364:             * This is useful, for example, in ajax situations where the component
2365:             * starts out invisible and then becomes visible through an ajax update.
2366:             * With a placeholder tag already in the markup you do not need to repaint
2367:             * this component's parent, instead you can repaint the component directly.
2368:             * 
2369:             * When this method is called with parameter <code>false</code> the
2370:             * outputmarkupid flag is not reverted to false.
2371:             * 
2372:             * @param outputTag
2373:             * @return this for chaining
2374:             */
2375:            public final Component setOutputMarkupPlaceholderTag(
2376:                    final boolean outputTag) {
2377:                if (outputTag != getFlag(FLAG_PLACEHOLDER)) {
2378:                    if (outputTag) {
2379:                        setOutputMarkupId(true);
2380:                        setFlag(FLAG_PLACEHOLDER, true);
2381:                    } else {
2382:                        setFlag(FLAG_PLACEHOLDER, false);
2383:                        // I think it's better to not setOutputMarkupId to false...
2384:                        // user can do it if we want
2385:                    }
2386:                }
2387:                return this ;
2388:            }
2389:
2390:            /**
2391:             * @param redirect
2392:             *            True if the response should be redirected to
2393:             * @see RequestCycle#setRedirect(boolean)
2394:             */
2395:            public final void setRedirect(final boolean redirect) {
2396:                getRequestCycle().setRedirect(redirect);
2397:            }
2398:
2399:            /**
2400:             * If false the component's tag will be printed as well as its body (which
2401:             * is default). If true only the body will be printed, but not the
2402:             * component's tag.
2403:             * 
2404:             * @param renderTag
2405:             *            If true, the component tag will not be printed
2406:             * @return This
2407:             */
2408:            public final Component setRenderBodyOnly(final boolean renderTag) {
2409:                this .setFlag(FLAG_RENDER_BODY_ONLY, renderTag);
2410:                return this ;
2411:            }
2412:
2413:            /**
2414:             * Sets the page that will respond to this request
2415:             * 
2416:             * @param cls
2417:             *            The response page class
2418:             * @see RequestCycle#setResponsePage(Class)
2419:             */
2420:            public final void setResponsePage(final Class cls) {
2421:                getRequestCycle().setResponsePage(cls);
2422:            }
2423:
2424:            /**
2425:             * Sets the page class and its parameters that will respond to this request
2426:             * 
2427:             * @param cls
2428:             *            The response page class
2429:             * @param parameters
2430:             *            The parameters for this bookmarkable page.
2431:             * @see RequestCycle#setResponsePage(Class, PageParameters)
2432:             */
2433:            public final void setResponsePage(final Class cls,
2434:                    PageParameters parameters) {
2435:                getRequestCycle().setResponsePage(cls, parameters);
2436:            }
2437:
2438:            /**
2439:             * Sets the page that will respond to this request
2440:             * 
2441:             * @param page
2442:             *            The response page
2443:             * @see RequestCycle#setResponsePage(Page)
2444:             */
2445:            public final void setResponsePage(final Page page) {
2446:                getRequestCycle().setResponsePage(page);
2447:            }
2448:
2449:            /**
2450:             * @param versioned
2451:             *            True to turn on versioning for this component, false to turn
2452:             *            it off for this component and any children.
2453:             * @return This
2454:             */
2455:            public Component setVersioned(boolean versioned) {
2456:                setFlag(FLAG_VERSIONED, versioned);
2457:                return this ;
2458:            }
2459:
2460:            /**
2461:             * Sets whether this component and any children are visible.
2462:             * 
2463:             * @param visible
2464:             *            True if this component and any children should be visible
2465:             * @return This
2466:             */
2467:            public final Component setVisible(final boolean visible) {
2468:                // Is new visibility state a change?
2469:                if (visible != getFlag(FLAG_VISIBLE)) {
2470:                    // record component's visibility change
2471:                    addStateChange(new VisibilityChange(this ));
2472:
2473:                    // Change visibility
2474:                    setFlag(FLAG_VISIBLE, visible);
2475:                }
2476:                return this ;
2477:            }
2478:
2479:            /**
2480:             * Gets the string representation of this component.
2481:             * 
2482:             * @return The path to this component
2483:             */
2484:            public String toString() {
2485:                return toString(true);
2486:            }
2487:
2488:            /**
2489:             * @param detailed
2490:             *            True if a detailed string is desired
2491:             * @return The string
2492:             */
2493:            public String toString(final boolean detailed) {
2494:                if (detailed) {
2495:                    final Page page = findPage();
2496:                    if (page == null) {
2497:                        return new StringBuffer("[Component id = ").append(
2498:                                getId()).append(", page = <No Page>, path = ")
2499:                                .append(getPath()).append(".").append(
2500:                                        Classes.simpleName(getClass())).append(
2501:                                        "]").toString();
2502:                    } else {
2503:                        return new StringBuffer("[Component id = ").append(
2504:                                getId()).append(", page = ").append(
2505:                                getPage().getClass().getName()).append(
2506:                                ", path = ").append(getPath()).append(".")
2507:                                .append(Classes.simpleName(getClass())).append(
2508:                                        ", isVisible = ").append(
2509:                                        (isRenderAllowed() && isVisible()))
2510:                                .append(", isVersioned = ").append(
2511:                                        isVersioned()).append("]").toString();
2512:                    }
2513:                } else {
2514:                    return "[Component id = " + getId() + "]";
2515:                }
2516:            }
2517:
2518:            /**
2519:             * Returns a bookmarkable URL that references a given page class using a
2520:             * given set of page parameters. Since the URL which is returned contains
2521:             * all information necessary to instantiate and render the page, it can be
2522:             * stored in a user's browser as a stable bookmark.
2523:             * 
2524:             * @see RequestCycle#urlFor(PageMap, Class, PageParameters)
2525:             * 
2526:             * @param pageClass
2527:             *            Class of page
2528:             * @param parameters
2529:             *            Parameters to page
2530:             * @return Bookmarkable URL to page
2531:             */
2532:            public final CharSequence urlFor(final Class pageClass,
2533:                    final PageParameters parameters) {
2534:                return getRequestCycle().urlFor(getPage().getPageMap(),
2535:                        pageClass, parameters);
2536:            }
2537:
2538:            /**
2539:             * Gets a URL for the listener interface on a behaviour (e.g.
2540:             * IBehaviorListener on AjaxPagingNavigationBehavior).
2541:             * 
2542:             * @param behaviour
2543:             *            The behaviour that the URL should point to
2544:             * @param listener
2545:             *            The listener interface that the URL should call
2546:             * @return The URL
2547:             */
2548:            public final CharSequence urlFor(final IBehavior behaviour,
2549:                    final RequestListenerInterface listener) {
2550:                return getRequestCycle().urlFor(this , behaviour, listener);
2551:            }
2552:
2553:            /**
2554:             * Returns a bookmarkable URL that references a given page class using a
2555:             * given set of page parameters. Since the URL which is returned contains
2556:             * all information necessary to instantiate and render the page, it can be
2557:             * stored in a user's browser as a stable bookmark.
2558:             * 
2559:             * @see RequestCycle#urlFor(PageMap, Class, PageParameters)
2560:             * 
2561:             * @param pageMap
2562:             *            Page map to use
2563:             * @param pageClass
2564:             *            Class of page
2565:             * @param parameters
2566:             *            Parameters to page
2567:             * 
2568:             * 
2569:             * @return Bookmarkable URL to page
2570:             */
2571:            public final CharSequence urlFor(final IPageMap pageMap,
2572:                    final Class pageClass, final PageParameters parameters) {
2573:                return getRequestCycle().urlFor(pageMap, pageClass, parameters);
2574:            }
2575:
2576:            /**
2577:             * Returns a URL that references the given request target.
2578:             * 
2579:             * @see RequestCycle#urlFor(IRequestTarget)
2580:             * 
2581:             * @param requestTarget
2582:             *            the request target to reference
2583:             * 
2584:             * @return a URL that references the given request target
2585:             */
2586:            public final CharSequence urlFor(final IRequestTarget requestTarget) {
2587:                return getRequestCycle().urlFor(requestTarget);
2588:            }
2589:
2590:            /**
2591:             * Gets a URL for the listener interface (e.g. ILinkListener).
2592:             * 
2593:             * @param listener
2594:             *            The listener interface that the URL should call
2595:             * @return The URL
2596:             */
2597:            public final CharSequence urlFor(
2598:                    final RequestListenerInterface listener) {
2599:                return getRequestCycle().urlFor(this , listener);
2600:            }
2601:
2602:            /**
2603:             * Returns a URL that references a shared resource through the provided
2604:             * resource reference.
2605:             * 
2606:             * @see RequestCycle#urlFor(ResourceReference)
2607:             * 
2608:             * @param resourceReference
2609:             *            The resource reference
2610:             * @return The url for the shared resource
2611:             */
2612:            public final CharSequence urlFor(
2613:                    final ResourceReference resourceReference) {
2614:                return getRequestCycle().urlFor(resourceReference);
2615:            }
2616:
2617:            /**
2618:             * Traverses all parent components of the given class in this container,
2619:             * calling the visitor's visit method at each one.
2620:             * 
2621:             * @param c
2622:             *            Class
2623:             * @param visitor
2624:             *            The visitor to call at each parent of the given type
2625:             * @return First non-null value returned by visitor callback
2626:             */
2627:            public final Object visitParents(final Class c,
2628:                    final IVisitor visitor) {
2629:                // Start here
2630:                Component current = this ;
2631:
2632:                // Walk up containment hierarchy
2633:                while (current != null) {
2634:                    // Is current an instance of this class?
2635:                    if (c.isInstance(current)) {
2636:                        final Object object = visitor.component(current);
2637:                        if (object != IVisitor.CONTINUE_TRAVERSAL) {
2638:                            return object;
2639:                        }
2640:                    }
2641:
2642:                    // Check parent
2643:                    current = current.getParent();
2644:                }
2645:                return null;
2646:            }
2647:
2648:            /**
2649:             * Registers a warning feedback message for this component.
2650:             * 
2651:             * @param message
2652:             *            The feedback message
2653:             */
2654:            public final void warn(final String message) {
2655:                Session.get().getFeedbackMessages().warn(this , message);
2656:                Session.get().dirty();
2657:            }
2658:
2659:            /**
2660:             * {@link IBehavior#beforeRender(Component)} Notify all behaviors that are
2661:             * assigned to this component that the component is about to be rendered.
2662:             */
2663:            private void notifyBehaviorsComponentBeforeRender() {
2664:                if (behaviors != null) {
2665:                    for (Iterator i = behaviors.iterator(); i.hasNext();) {
2666:                        IBehavior behavior = (IBehavior) i.next();
2667:                        if (isBehaviorAccepted(behavior)) {
2668:                            behavior.beforeRender(this );
2669:                        }
2670:                    }
2671:                }
2672:            }
2673:
2674:            /**
2675:             * {@link IBehavior#afterRender(Component)} Notify all behaviors that are
2676:             * assigned to this component that the component has rendered.
2677:             */
2678:            private void notifyBehaviorsComponentRendered() {
2679:                // notify the behaviors that component has been rendered
2680:                if (behaviors != null) {
2681:                    for (Iterator i = behaviors.iterator(); i.hasNext();) {
2682:                        IBehavior behavior = (IBehavior) i.next();
2683:                        if (isBehaviorAccepted(behavior)) {
2684:                            behavior.afterRender(this );
2685:                        }
2686:                    }
2687:                }
2688:            }
2689:
2690:            /**
2691:             * Adds state change to page.
2692:             * 
2693:             * @param change
2694:             *            The change
2695:             */
2696:            protected final void addStateChange(final Change change) {
2697:                checkHierarchyChange(this );
2698:                final Page page = findPage();
2699:                if (page != null) {
2700:                    page.componentStateChanging(this , change);
2701:                }
2702:            }
2703:
2704:            /**
2705:             * Checks whether the given type has the expected name.
2706:             * 
2707:             * @param tag
2708:             *            The tag to check
2709:             * @param name
2710:             *            The expected tag name
2711:             * @throws MarkupException
2712:             *             Thrown if the tag is not of the right name
2713:             */
2714:            protected final void checkComponentTag(final ComponentTag tag,
2715:                    final String name) {
2716:                if (!tag.getName().equalsIgnoreCase(name)) {
2717:                    findMarkupStream().throwMarkupException(
2718:                            "Component " + getId()
2719:                                    + " must be applied to a tag of type '"
2720:                                    + name + "', not "
2721:                                    + tag.toUserDebugString());
2722:                }
2723:            }
2724:
2725:            /**
2726:             * Checks that a given tag has a required attribute value.
2727:             * 
2728:             * @param tag
2729:             *            The tag
2730:             * @param key
2731:             *            The attribute key
2732:             * @param value
2733:             *            The required value for the attribute key
2734:             * @throws MarkupException
2735:             *             Thrown if the tag does not have the required attribute value
2736:             */
2737:            protected final void checkComponentTagAttribute(
2738:                    final ComponentTag tag, final String key, final String value) {
2739:                if (key != null) {
2740:                    final String tagAttributeValue = tag.getAttributes()
2741:                            .getString(key);
2742:                    if (tagAttributeValue == null
2743:                            || !value.equalsIgnoreCase(tagAttributeValue)) {
2744:                        findMarkupStream().throwMarkupException(
2745:                                "Component " + getId()
2746:                                        + " must be applied to a tag with '"
2747:                                        + key + "' attribute matching '"
2748:                                        + value + "', not '"
2749:                                        + tagAttributeValue + "'");
2750:                    }
2751:                }
2752:            }
2753:
2754:            /**
2755:             * Checks whether the hierarchy may be changed at all, and throws an
2756:             * exception if this is not the case.
2757:             * 
2758:             * @param component
2759:             *            the component which is about to be added or removed
2760:             */
2761:            protected void checkHierarchyChange(final Component component) {
2762:                // Throw exception if modification is attempted during rendering
2763:                if (!component.isAuto() && getFlag(FLAG_RENDERING)) {
2764:                    throw new WicketRuntimeException(
2765:                            "Cannot modify component hierarchy during render phase");
2766:                }
2767:
2768:                // Throw exception if modification is attempted during attach
2769:                if (getFlag(FLAG_ATTACHING)) {
2770:                    throw new WicketRuntimeException(
2771:                            "Cannot modify component hierarchy during attach phase");
2772:                }
2773:            }
2774:
2775:            /**
2776:             * Detaches the model for this component if it is detachable.
2777:             */
2778:            protected void detachModel() {
2779:                if (model != null) {
2780:                    model.detach();
2781:                }
2782:                // also detach the wrapped model of a component assignet wrap (not
2783:                // inherited)
2784:                if (model instanceof  IWrapModel
2785:                        && !getFlag(FLAG_INHERITABLE_MODEL)) {
2786:                    ((IWrapModel) model).getWrappedModel().detach();
2787:                }
2788:            }
2789:
2790:            /**
2791:             * Prefixes an exception message with useful information about this.
2792:             * component.
2793:             * 
2794:             * @param message
2795:             *            The message
2796:             * @return The modified message
2797:             */
2798:            protected final String exceptionMessage(final String message) {
2799:                return message + ":\n" + toString();
2800:            }
2801:
2802:            /**
2803:             * Finds the markup stream for this component.
2804:             * 
2805:             * @return The markup stream for this component. Since a Component cannot
2806:             *         have a markup stream, we ask this component's parent to search
2807:             *         for it.
2808:             */
2809:            protected MarkupStream findMarkupStream() {
2810:                if (parent == null) {
2811:                    throw new IllegalStateException(
2812:                            "Cannot find markupstream for " + this 
2813:                                    + " as there is no parent");
2814:                }
2815:
2816:                return parent.findMarkupStream();
2817:            }
2818:
2819:            /**
2820:             * If this Component is a Page, returns self. Otherwise, searches for the
2821:             * nearest Page parent in the component hierarchy. If no Page parent can be
2822:             * found, null is returned.
2823:             * 
2824:             * @return The Page or null if none can be found
2825:             */
2826:            protected final Page findPage() {
2827:                // Search for page
2828:                return (Page) (this  instanceof  Page ? this 
2829:                        : findParent(Page.class));
2830:            }
2831:
2832:            /**
2833:             * Gets the subset of the currently coupled {@link IBehavior}s that are of
2834:             * the provided type as a unmodifiable list or null if there are no
2835:             * behaviors attached. Returns an empty list rather than null if there are
2836:             * no behaviors coupled to this component.
2837:             * 
2838:             * @param type
2839:             *            The type or null for all
2840:             * 
2841:             * @return The subset of the currently coupled behaviors that are of the
2842:             *         provided type as a unmodifiable list or null
2843:             */
2844:            protected List/* <IBehavior> */getBehaviors(Class type) {
2845:                if (behaviors == null) {
2846:                    return Collections.EMPTY_LIST;
2847:                }
2848:
2849:                List subset = new ArrayList(behaviors.size()); // avoid growing
2850:                for (Iterator i = behaviors.iterator(); i.hasNext();) {
2851:                    Object behavior = i.next();
2852:                    if (type == null
2853:                            || type.isAssignableFrom(behavior.getClass())) {
2854:                        subset.add(behavior);
2855:                    }
2856:                }
2857:                return Collections.unmodifiableList(subset);
2858:            }
2859:
2860:            /**
2861:             * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT USE IT!
2862:             * 
2863:             * @param flag
2864:             *            The flag to test
2865:             * @return True if the flag is set
2866:             */
2867:            protected final boolean getFlag(final int flag) {
2868:                return (flags & flag) != 0;
2869:            }
2870:
2871:            /**
2872:             * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT USE IT!
2873:             * 
2874:             * @param flag
2875:             *            The flag to test
2876:             * @return True if the flag is set
2877:             */
2878:            protected final boolean getFlag(final short flag) {
2879:                return getFlag((int) flag);
2880:            }
2881:
2882:            /**
2883:             * Finds the innermost IModel object for an IModel that might contain nested
2884:             * IModel(s).
2885:             * 
2886:             * @param model
2887:             *            The model
2888:             * @return The innermost (most nested) model
2889:             */
2890:            protected final IModel getInnermostModel(final IModel model) {
2891:                IModel nested = model;
2892:                while (nested != null && nested instanceof  IWrapModel) {
2893:                    final IModel next = ((IWrapModel) nested).getWrappedModel();
2894:                    if (nested == next) {
2895:                        throw new WicketRuntimeException("Model for " + nested
2896:                                + " is self-referential");
2897:                    }
2898:                    nested = next;
2899:                }
2900:                return nested;
2901:            }
2902:
2903:            /**
2904:             * Gets the value defaultModelComparator. Implementations of this interface
2905:             * can be used in the Component.getComparator() for testing the current
2906:             * value of the components model data with the new value that is given.
2907:             * 
2908:             * @return the value defaultModelComparator
2909:             */
2910:            protected IModelComparator getModelComparator() {
2911:                return defaultModelComparator;
2912:            }
2913:
2914:            /**
2915:             * Returns whether the component can be stateless. Being able to be
2916:             * stateless doesn't necessary mean, that the component should be stateless.
2917:             * Whether the component should be stateless depends on
2918:             * 
2919:             * @return whether the component can be stateless
2920:             */
2921:            protected boolean getStatelessHint() {
2922:                return true;
2923:            }
2924:
2925:            /**
2926:             * Called when a null model is about to be retrieved in order to allow a
2927:             * subclass to provide an initial model. This gives FormComponent, for
2928:             * example, an opportunity to instantiate a model on the fly using the
2929:             * containing Form's model.
2930:             * 
2931:             * @return The model
2932:             */
2933:            protected IModel initModel() {
2934:                // Search parents for CompoundPropertyModel
2935:                for (Component current = getParent(); current != null; current = current
2936:                        .getParent()) {
2937:                    // Get model
2938:                    // Dont call the getModel() that could initialize many inbetween
2939:                    // completely useless models.
2940:                    // IModel model = current.getModel();
2941:                    IModel model = current.model;
2942:
2943:                    if (model instanceof  IWrapModel) {
2944:                        model = ((IWrapModel) model).getWrappedModel();
2945:                    }
2946:
2947:                    if (model instanceof  IComponentInheritedModel) {
2948:                        // we turn off versioning as we share the model with another
2949:                        // component that is the owner of the model (that component
2950:                        // has to decide whether to version or not
2951:                        // TODO can we really do this?? Model shouldn't versioned but
2952:                        // all other things?? (add/remove)
2953:                        setVersioned(false);
2954:
2955:                        // return the shared inherited
2956:                        model = ((IComponentInheritedModel) model)
2957:                                .wrapOnInheritance(this );
2958:                        setFlag(FLAG_INHERITABLE_MODEL, true);
2959:                        return model;
2960:                    }
2961:                }
2962:
2963:                // No model for this component!
2964:                return null;
2965:            }
2966:
2967:            /**
2968:             * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL OR
2969:             * OVERRIDE.
2970:             * 
2971:             * Called when a request begins.
2972:             * 
2973:             * @Deprecated use {@link #onBeforeRender()} instead
2974:             */
2975:            protected final void internalOnAttach() {
2976:            }
2977:
2978:            /**
2979:             * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL OR
2980:             * OVERRIDE.
2981:             * 
2982:             * Called when a request ends.
2983:             * 
2984:             * @Deprecated use {@link #onBeforeRender()} instead
2985:             * 
2986:             */
2987:            protected final void internalOnDetach() {
2988:            }
2989:
2990:            /**
2991:             * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL OR
2992:             * OVERRIDE.
2993:             * 
2994:             * Called anytime a model is changed via setModel or setModelObject.
2995:             */
2996:            protected void internalOnModelChanged() {
2997:            }
2998:
2999:            /**
3000:             * @return true if this component is attached
3001:             */
3002:            protected final boolean isAttached() {
3003:                return getFlag(FLAG_ATTACHED);
3004:            }
3005:
3006:            /**
3007:             * Components are allowed to reject behavior modifiers.
3008:             * 
3009:             * @param behavior
3010:             * @return False, if the component should not apply this behavior
3011:             */
3012:            protected boolean isBehaviorAccepted(final IBehavior behavior) {
3013:                // Ignore AttributeModifiers when FLAG_IGNORE_ATTRIBUTE_MODIFIER is set
3014:                if ((behavior instanceof  AttributeModifier)
3015:                        && (getFlag(FLAG_IGNORE_ATTRIBUTE_MODIFIER) != false)) {
3016:                    return false;
3017:                }
3018:
3019:                return behavior.isEnabled(this );
3020:            }
3021:
3022:            /**
3023:             * If true, all attribute modifiers will be ignored
3024:             * 
3025:             * @return True, if attribute modifiers are to be ignored
3026:             */
3027:            protected final boolean isIgnoreAttributeModifier() {
3028:                return this .getFlag(FLAG_IGNORE_ATTRIBUTE_MODIFIER);
3029:            }
3030:
3031:            /**
3032:             * @return Component's markup stream
3033:             */
3034:            protected MarkupStream locateMarkupStream() {
3035:                return new MarkupFragmentFinder().find(this );
3036:            }
3037:
3038:            /**
3039:             * Called just after a component is rendered.
3040:             */
3041:            protected void onAfterRender() {
3042:                setFlag(FLAG_AFTER_RENDERING, false);
3043:            }
3044:
3045:            /**
3046:             * Called to allow a component to attach resources for use.
3047:             * 
3048:             * Overrides of this method MUST call the super implementation, the most
3049:             * logical place to do this is the first line of the override method.
3050:             * 
3051:             */
3052:            protected void onAttach() {
3053:                setFlag(FLAG_ATTACH_SUPER_CALL_VERIFIED, true);
3054:            }
3055:
3056:            /**
3057:             * Called just before a component is rendered. If you override this, you
3058:             * *must* call super.onBeforeRender() within your implementation.
3059:             */
3060:            protected void onBeforeRender() {
3061:                setFlag(FLAG_PREPARED_FOR_RENDER, true);
3062:                onBeforeRenderChildren();
3063:                setFlag(FLAG_BEFORE_RENDERING_SUPER_CALL_VERIFIED, true);
3064:            }
3065:
3066:            /**
3067:             * @deprecated use onAttach() instead
3068:             */
3069:            // TODO remove after the deprecation release
3070:            protected final void onBeginRequest() {
3071:                throw new UnsupportedOperationException();
3072:            }
3073:
3074:            /**
3075:             * Processes the component tag.
3076:             * 
3077:             * @param tag
3078:             *            Tag to modify
3079:             */
3080:            protected void onComponentTag(final ComponentTag tag) {
3081:                // We can't try to get the ID from markup. This could be different than
3082:                // id returned from getMarkupId() prior first rendering the component
3083:                // (due to transparent resolvers and borders which break the 1:1
3084:                // component <-> markup relation)
3085:                if (getFlag(FLAG_OUTPUT_MARKUP_ID)) {
3086:                    tag.put(MARKUP_ID_ATTR_NAME, getMarkupId());
3087:                }
3088:            }
3089:
3090:            /**
3091:             * Processes the body.
3092:             * 
3093:             * @param markupStream
3094:             *            The markup stream
3095:             * @param openTag
3096:             *            The open tag for the body
3097:             */
3098:            protected void onComponentTagBody(final MarkupStream markupStream,
3099:                    final ComponentTag openTag) {
3100:            }
3101:
3102:            /**
3103:             * Called to allow a component to detach resources after use.
3104:             * 
3105:             * Overrides of this method MUST call the super implementation, the most
3106:             * logical place to do this is the last line of the override method.
3107:             * 
3108:             * 
3109:             */
3110:            protected void onDetach() {
3111:                if (behaviors != null) {
3112:                    behaviors.trimToSize();
3113:                }
3114:                setFlag(FLAG_DETACHING, false);
3115:
3116:            }
3117:
3118:            /**
3119:             * @deprecated use onDetach() instead
3120:             */
3121:            // TODO remove after the deprecation release
3122:            protected final void onEndRequest() {
3123:                throw new UnsupportedOperationException();
3124:            }
3125:
3126:            /**
3127:             * Called anytime a model is changed after the change has occurred
3128:             */
3129:            protected void onModelChanged() {
3130:            }
3131:
3132:            /**
3133:             * Called anytime a model is changed, but before the change actually occurs
3134:             */
3135:            protected void onModelChanging() {
3136:            }
3137:
3138:            /**
3139:             * Implementation that renders this component.
3140:             * 
3141:             * @since Wicket 1.2
3142:             * @param markupStream
3143:             */
3144:            protected abstract void onRender(final MarkupStream markupStream);
3145:
3146:            /**
3147:             * Writes a simple tag out to the response stream. Any components that might
3148:             * be referenced by the tag are ignored. Also undertakes any tag attribute
3149:             * modifications if they have been added to the component.
3150:             * 
3151:             * @param tag
3152:             *            The tag to write
3153:             */
3154:            protected final void renderComponentTag(ComponentTag tag) {
3155:                final boolean stripWicketTags = Application.get()
3156:                        .getMarkupSettings().getStripWicketTags();
3157:                if (!(tag instanceof  WicketTag) || !stripWicketTags) {
3158:                    // Apply behavior modifiers
3159:                    if ((behaviors != null) && !behaviors.isEmpty()
3160:                            && !tag.isClose()
3161:                            && (isIgnoreAttributeModifier() == false)) {
3162:                        tag = tag.mutable();
3163:
3164:                        for (Iterator i = behaviors.iterator(); i.hasNext();) {
3165:                            IBehavior behavior = (IBehavior) i.next();
3166:
3167:                            // Components may reject some behavior components
3168:                            if (isBehaviorAccepted(behavior)) {
3169:                                behavior.onComponentTag(this , tag);
3170:                            }
3171:                        }
3172:                    }
3173:
3174:                    // apply behaviors that are attached to the component tag.
3175:                    if (tag.hasBehaviors()) {
3176:                        Iterator behaviors = tag.getBehaviors();
3177:                        while (behaviors.hasNext()) {
3178:                            final IBehavior behavior = (IBehavior) behaviors
3179:                                    .next();
3180:                            behavior.onComponentTag(this , tag);
3181:                        }
3182:                    }
3183:
3184:                    // Write the tag
3185:                    tag.writeOutput(getResponse(), stripWicketTags,
3186:                            findMarkupStream().getWicketNamespace());
3187:                }
3188:            }
3189:
3190:            /**
3191:             * Replaces the body with the given one.
3192:             * 
3193:             * @param markupStream
3194:             *            The markup stream to replace the tag body in
3195:             * @param tag
3196:             *            The tag
3197:             * @param body
3198:             *            The new markup
3199:             */
3200:            protected final void replaceComponentTagBody(
3201:                    final MarkupStream markupStream, final ComponentTag tag,
3202:                    final CharSequence body) {
3203:                // The tag might have been changed from open-close to open. Hence
3204:                // we'll need what was in the markup itself
3205:                ComponentTag markupOpenTag = null;
3206:
3207:                // If tag has a body
3208:                if (tag.isOpen()) {
3209:                    // Get what tag was in the markup; not what the user it might
3210:                    // have changed it to.
3211:                    markupStream
3212:                            .setCurrentIndex(markupStream.getCurrentIndex() - 1);
3213:                    markupOpenTag = markupStream.getTag();
3214:                    markupStream.next();
3215:
3216:                    // If it was an open tag in the markup as well, than ...
3217:                    if (markupOpenTag.isOpen()) {
3218:                        // skip any raw markup in the body
3219:                        markupStream.skipRawMarkup();
3220:                    }
3221:                }
3222:
3223:                if (body != null) {
3224:                    // Write the new body
3225:                    getResponse().write(body);
3226:                }
3227:
3228:                // If we had an open tag (and not an openclose tag) and we found a
3229:                // close tag, we're good
3230:                if (tag.isOpen()) {
3231:                    // If it was an open tag in the markup, than there must be
3232:                    // a close tag as well.
3233:                    if ((markupOpenTag != null) && markupOpenTag.isOpen()
3234:                            && !markupStream.atCloseTag()) {
3235:                        // There must be a component in this discarded body
3236:                        markupStream
3237:                                .throwMarkupException("Expected close tag for '"
3238:                                        + markupOpenTag
3239:                                        + "' Possible attempt to embed component(s) '"
3240:                                        + markupStream.get()
3241:                                        + "' in the body of this component which discards its body");
3242:                    }
3243:                }
3244:            }
3245:
3246:            /**
3247:             * @param auto
3248:             *            True to put component into auto-add mode
3249:             */
3250:            protected final void setAuto(final boolean auto) {
3251:                setFlag(FLAG_AUTO, auto);
3252:            }
3253:
3254:            /**
3255:             * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT USE IT!
3256:             * 
3257:             * @param flag
3258:             *            The flag to set
3259:             * @param set
3260:             *            True to turn the flag on, false to turn it off
3261:             */
3262:            protected final void setFlag(final int flag, final boolean set) {
3263:                if (set) {
3264:                    flags |= flag;
3265:                } else {
3266:                    flags &= ~flag;
3267:                }
3268:            }
3269:
3270:            /**
3271:             * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT USE IT!
3272:             * 
3273:             * @param flag
3274:             *            The flag to set
3275:             * @param set
3276:             *            True to turn the flag on, false to turn it off
3277:             */
3278:            protected final void setFlag(final short flag, final boolean set) {
3279:                setFlag((int) flag, set);
3280:            }
3281:
3282:            /**
3283:             * If true, all attribute modifiers will be ignored
3284:             * 
3285:             * @param ignore
3286:             *            If true, all attribute modifiers will be ignored
3287:             * @return This
3288:             */
3289:            protected final Component setIgnoreAttributeModifier(
3290:                    final boolean ignore) {
3291:                this .setFlag(FLAG_IGNORE_ATTRIBUTE_MODIFIER, ignore);
3292:                return this ;
3293:            }
3294:
3295:            /**
3296:             * The markup stream will be assigned to the component at the beginning of
3297:             * the component render phase. It is temporary working variable only.
3298:             * 
3299:             * @see #findMarkupStream()
3300:             * @see MarkupContainer#getMarkupStream()
3301:             * 
3302:             * @param markupStream
3303:             *            The current markup stream which should be applied by the
3304:             *            component to render itself
3305:             */
3306:            protected void setMarkupStream(final MarkupStream markupStream) {
3307:            }
3308:
3309:            /**
3310:             * @param model
3311:             *            The model to wrap if need be
3312:             * @return The wrapped model
3313:             */
3314:            protected final IModel wrap(final IModel model) {
3315:                if (model instanceof  IComponentAssignedModel) {
3316:                    return ((IComponentAssignedModel) model)
3317:                            .wrapOnAssignment(this );
3318:                } else {
3319:                    return model;
3320:                }
3321:            }
3322:
3323:            /**
3324:             * Detaches any child components
3325:             * 
3326:             * @see {@link #attachChildren()}
3327:             */
3328:            void detachChildren() {
3329:            }
3330:
3331:            /**
3332:             * Gets the component at the given path.
3333:             * 
3334:             * @param path
3335:             *            Path to component
3336:             * @return The component at the path
3337:             */
3338:            Component get(final String path) {
3339:                // Path to this component is an empty path
3340:                if (path.equals("")) {
3341:                    return this ;
3342:                }
3343:                throw new IllegalArgumentException(
3344:                        exceptionMessage("Component is not a container and so does "
3345:                                + "not contain the path " + path));
3346:            }
3347:
3348:            /**
3349:             * Checks whether or not this component has a markup id value generated,
3350:             * whether it is automatic or user defined
3351:             * 
3352:             * @return true if this component has a markup id value generated
3353:             */
3354:            final boolean hasMarkupIdMetaData() {
3355:                return getMetaData(MARKUP_ID_KEY) != null;
3356:            }
3357:
3358:            /**
3359:             * Attaches any child components
3360:             * 
3361:             * This method is here only for {@link MarkupContainer}. It is broken out
3362:             * of {@link #onBeforeRender()} so we can guarantee that it executes as the
3363:             * last in onAttach() chain no matter where user places the
3364:             * <code>super.onAttach()</code> call
3365:             */
3366:            void internalAttach2() {
3367:                if (!getFlag(FLAG_ATTACHED)) {
3368:                    setFlag(FLAG_ATTACHING, true);
3369:                    setFlag(FLAG_ATTACH_SUPER_CALL_VERIFIED, false);
3370:                    onAttach();
3371:                    if (!getFlag(FLAG_ATTACH_SUPER_CALL_VERIFIED)) {
3372:                        throw new IllegalStateException(
3373:                                "Component "
3374:                                        + this 
3375:                                        + " of type "
3376:                                        + getClass().getName()
3377:                                        + " has not been properly attached.  "
3378:                                        + "Something in its class hierarchy has failed to call super.onAttach() in an override of onAttach() method");
3379:                    }
3380:                    setFlag(FLAG_ATTACHING, false);
3381:                    setFlag(FLAG_ATTACHED, true);
3382:                }
3383:            }
3384:
3385:            void internalMarkRendering() {
3386:                setFlag(FLAG_PREPARED_FOR_RENDER, false);
3387:                setFlag(FLAG_RENDERING, true);
3388:            }
3389:
3390:            /**
3391:             * @return True if this component or any of its parents is in auto-add mode
3392:             */
3393:            final boolean isAuto() {
3394:                // Search up hierarchy for FLAG_AUTO
3395:                for (Component current = this ; current != null; current = current
3396:                        .getParent()) {
3397:                    if (current.getFlag(FLAG_AUTO)) {
3398:                        return true;
3399:                    }
3400:                }
3401:                return false;
3402:            }
3403:
3404:            boolean isPreparedForRender() {
3405:                return getFlag(FLAG_PREPARED_FOR_RENDER);
3406:            }
3407:
3408:            void onAfterRenderChildren() {
3409:            }
3410:
3411:            /**
3412:             * This method is here for {@link MarkupContainer}. It is broken out of
3413:             * {@link #onBeforeRender()} so we can guarantee that it executes as the
3414:             * last in onBeforeRender() chain no matter where user places the
3415:             * <code>super.onBeforeRender()</code> call.
3416:             */
3417:            void onBeforeRenderChildren() {
3418:            }
3419:
3420:            /**
3421:             * Renders the close tag at the current position in the markup stream.
3422:             * 
3423:             * @param markupStream
3424:             *            the markup stream
3425:             * @param openTag
3426:             *            the tag to render
3427:             * @param renderTagOnly
3428:             *            if true, the tag will not be written to the output
3429:             */
3430:            final void renderClosingComponentTag(
3431:                    final MarkupStream markupStream,
3432:                    final ComponentTag openTag, final boolean renderTagOnly) {
3433:                // Tag should be open tag and not openclose tag
3434:                if (openTag.isOpen()) {
3435:                    // If we found a close tag and it closes the open tag, we're good
3436:                    if (markupStream.atCloseTag()
3437:                            && markupStream.getTag().closes(openTag)) {
3438:                        // Get the close tag from the stream
3439:                        ComponentTag closeTag = markupStream.getTag();
3440:
3441:                        // If the open tag had its id changed
3442:                        if (openTag.getNameChanged()) {
3443:                            // change the id of the close tag
3444:                            closeTag = closeTag.mutable();
3445:                            closeTag.setName(openTag.getName());
3446:                        }
3447:
3448:                        // Render the close tag
3449:                        if (renderTagOnly == false) {
3450:                            renderComponentTag(closeTag);
3451:                        }
3452:                        markupStream.next();
3453:                    } else {
3454:                        if (openTag.requiresCloseTag()) {
3455:                            // Missing close tag
3456:                            markupStream
3457:                                    .throwMarkupException("Expected close tag for "
3458:                                            + openTag);
3459:                        }
3460:                    }
3461:                }
3462:            }
3463:
3464:            /**
3465:             * Sets the id of this component. This method is private because the only
3466:             * time a component's id can be set is in its constructor.
3467:             * 
3468:             * @param id
3469:             *            The non-null id of this component
3470:             */
3471:            final void setId(final String id) {
3472:                if (id == null && !(this  instanceof  Page)) {
3473:                    throw new WicketRuntimeException(
3474:                            "Null component id is not allowed.");
3475:                }
3476:                this .id = id;
3477:            }
3478:
3479:            /**
3480:             * Sets the parent of a component.
3481:             * 
3482:             * @param parent
3483:             *            The parent container
3484:             */
3485:            final void setParent(final MarkupContainer parent) {
3486:                if (this .parent != null && log.isDebugEnabled()) {
3487:                    log.debug("Replacing parent " + this .parent + " with "
3488:                            + parent);
3489:                }
3490:                this .parent = parent;
3491:            }
3492:
3493:            /**
3494:             * Sets the render allowed flag.
3495:             * 
3496:             * @param renderAllowed
3497:             */
3498:            final void setRenderAllowed(boolean renderAllowed) {
3499:                setFlag(FLAG_IS_RENDER_ALLOWED, renderAllowed);
3500:            }
3501:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.