📄 component.java
字号:
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.apache.wicket;import java.io.Serializable;import java.util.ArrayList;import java.util.Collections;import java.util.Iterator;import java.util.List;import java.util.Locale;import org.apache.wicket.ajax.AjaxRequestTarget;import org.apache.wicket.authorization.Action;import org.apache.wicket.authorization.AuthorizationException;import org.apache.wicket.authorization.IAuthorizationStrategy;import org.apache.wicket.authorization.UnauthorizedActionException;import org.apache.wicket.behavior.IBehavior;import org.apache.wicket.feedback.FeedbackMessage;import org.apache.wicket.feedback.IFeedback;import org.apache.wicket.markup.ComponentTag;import org.apache.wicket.markup.MarkupException;import org.apache.wicket.markup.MarkupStream;import org.apache.wicket.markup.WicketTag;import org.apache.wicket.markup.html.IHeaderContributor;import org.apache.wicket.markup.html.internal.HtmlHeaderContainer;import org.apache.wicket.model.IComponentAssignedModel;import org.apache.wicket.model.IComponentInheritedModel;import org.apache.wicket.model.IModel;import org.apache.wicket.model.IModelComparator;import org.apache.wicket.model.IWrapModel;import org.apache.wicket.model.LoadableDetachableModel;import org.apache.wicket.protocol.http.WebRequest;import org.apache.wicket.settings.IDebugSettings;import org.apache.wicket.util.convert.IConverter;import org.apache.wicket.util.lang.Classes;import org.apache.wicket.util.lang.Objects;import org.apache.wicket.util.string.PrependingStringBuffer;import org.apache.wicket.util.string.Strings;import org.apache.wicket.util.value.ValueMap;import org.apache.wicket.version.undo.Change;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/** * Component serves as the highest level abstract base class for all components. * * <ul> * <li><b>Identity </b>- All Components must have a non-null id which is retrieved by calling * getId(). The id must be unique within the MarkupContainer that holds the Component, but does not * have to be globally unique or unique within a Page's component hierarchy. * * <li><b>Hierarchy </b>- A component has a parent which can be retrieved with {@link #getParent()}. * If a component is an instance of MarkupContainer, it may have children. In this way it has a * place in the hierarchy of components contained on a given page. * * <li><b>Component Paths </b>- The path from the Page at the root of the component hierarchy to a * given Component is simply the concatenation with dot separators of each id along the way. For * example, the path "a.b.c" would refer to the component named "c" inside the MarkupContainer named * "b" inside the container named "a". The path to a component can be retrieved by calling * getPath(). This path is an absolute path beginning with the id of the Page at the root. Pages * bear a PageMap/Session-relative identifier as their id, so each absolute path will begin with a * number, such as "0.a.b.c". To get a Component path relative to the page that contains it, you can * call getPageRelativePath(). * * <li><b>LifeCycle </b>- Components participate in the following lifecycle phases: * <ul> * <li><b>Construction </b>- A Component is constructed with the Java language new operator. * Children may be added during construction if the Component is a MarkupContainer. * * <li><b>Request Handling </b>- An incoming request is processed by a protocol request handler * such as WicketServlet. An associated Application object creates Session, Request and Response * objects for use by a given Component in updating its model and rendering a response. These * objects are stored inside a container called {@link RequestCycle} which is accessible via * {@link Component#getRequestCycle()}. The convenience methods {@link Component#getRequest()}, * {@link Component#getResponse()} and {@link Component#getSession()} provide easy access to the * contents of this container. * * <li><b>Listener Invocation </b>- If the request references a listener on an existing Component, * that listener is called, allowing arbitrary user code to handle events such as link clicks or * form submits. Although arbitrary listeners are supported in Wicket, the need to implement a new * class of listener is unlikely for a web application and even the need to implement a listener * interface directly is highly discouraged. Instead, calls to listeners are routed through logic * specific to the event, resulting in calls to user code through other overridable methods. For * example, the {@link org.apache.wicket.markup.html.form.IFormSubmitListener#onFormSubmitted()} * method implemented by the Form class is really a private implementation detail of the Form class * that is not designed to be overridden (although unfortunately, it must be public since all * interface methods in Java must be public). Instead, Form subclasses should override user-oriented * methods such as onValidate(), onSubmit() and onError() (although only the latter two are likely * to be overridden in practice). * * <li><b>onBeginRequest </b>- The {@link Component#onBeginRequest()} method is called. * * <li><b>Form Submit </b>- If a Form has been submitted and the Component is a FormComponent, the * component's model is validated by a call to FormComponent.validate(). * * <li><b>Form Model Update </b>- If a valid Form has been submitted and the Component is a * FormComponent, the component's model is updated by a call to FormComponent.updateModel(). * * <li><b>Rendering </b>- A markup response is generated by the Component via * {@link Component#render()}, which calls subclass implementation code contained in * {@link Component#onRender(org.apache.wicket.markup.MarkupStream)}. Once this phase begins, a * Component becomes immutable. Attempts to alter the Component will result in a * WicketRuntimeException. * * <li><b>onEndRequest </b>() - The {@link Component#onEndRequest()} method is called. * </ul> * * <li><b>Component Models </b>- The primary responsibility of a component is to use its model (an * object that implements IModel), which can be set via {@link Component#setModel(IModel model)} and * retrieved via {@link Component#getModel()}, to render a response in an appropriate markup * language, such as HTML. In addition, form components know how to update their models based on * request information. Since the IModel interface is a wrapper around an actual model object, a * convenience method {@link Component#getModelObject()} is provided to retrieve the model Object * from its IModel wrapper. A further convenience method, {@link Component#getModelObjectAsString()}, * is provided for the very common operation of converting the wrapped model Object to a String. * * <li><b>Visibility </b>- Components which have setVisible(false) will return false from * isVisible() and will not render a response (nor will their children). * * <li><b>Page </b>- The Page containing any given Component can be retrieved by calling * {@link Component#getPage()}. If the Component is not attached to a Page, an * IllegalStateException will be thrown. An equivalent method, {@link Component#findPage()} is * available for special circumstances where it might be desirable to get a null reference back * instead. * * <li><b>Session </b>- The Page for a Component points back to the Session that contains the Page. * The Session for a component can be accessed with the convenience method getSession(), which * simply calls getPage().getSession(). * * <li><b>Locale </b>- The Locale for a Component is available through the convenience method * getLocale(), which is equivalent to getSession().getLocale(). * * <li><b>String Resources </b>- Components can have associated String resources via the * Application's Localizer, which is available through the method {@link Component#getLocalizer()}. * The convenience methods {@link Component#getString(String key)} and * {@link Component#getString(String key, IModel model)} wrap the identical methods on the * Application Localizer for easy access in Components. * * <li><b>Style </b>- The style ("skin") for a component is available through * {@link Component#getStyle()}, which is equivalent to getSession().getStyle(). Styles are * intended to give a particular look to a Component or Resource that is independent of its Locale. * For example, a style might be a set of resources, including images and markup files, which gives * the design look of "ocean" to the user. If the Session's style is set to "ocean" and these * resources are given names suffixed with "_ocean", Wicket's resource management logic will prefer * these resources to other resources, such as default resources, which are not as good of a match. * * <li><b>Variation </b>- Whereas Styles are Session (user) specific, variations are component * specific. E.g. if the Style is "ocean" and the Variation is "NorthSea", than the resources are * given the names suffixed with "_ocean_NorthSea". * * <li><b>AttributeModifiers </b>- You can add one or more {@link AttributeModifier}s to any * component if you need to programmatically manipulate attributes of the markup tag to which a * Component is attached. * * <li><b>Application, ApplicationSettings and ApplicationPages </b>- The getApplication() method * provides convenient access to the Application for a Component via getSession().getApplication(). * The getApplicationSettings() method is equivalent to getApplication().getSettings(). The * getApplicationPages is equivalent to getApplication().getPages(). * * <li><b>Feedback Messages </b>- The {@link Component#debug(String)}, * {@link Component#info(String)}, {@link Component#warn(String)}, * {@link Component#error(java.io.Serializable)} and {@link Component#fatal(String)} methods * associate feedback messages with a Component. It is generally not necessary to use these methods * directly since Wicket validators automatically register feedback messages on Components. Any * feedback message for a given Component can be retrieved with {@link Component#getFeedbackMessage}. * * <li><b>Page Factory </b>- It is possible to change the way that Pages are constructed by * overriding the {@link Component#getPageFactory()} method, returning your own implementation of * {@link org.apache.wicket.IPageFactory}. * * <li><b>Versioning </b>- Pages are the unit of versioning in Wicket, but fine-grained control of * which Components should participate in versioning is possible via the * {@link Component#setVersioned(boolean)} method. The versioning participation of a given Component * can be retrieved with {@link Component#isVersioned()}. * * <li><b>AJAX support</b>- Components can be re-rendered after the whole Page has been rendered * at least once by calling doRender(). * * @author Jonathan Locke * @author Chris Turner * @author Eelco Hillenius * @author Johan Compagner * @author Juergen Donnerstag * @author Igor Vaynberg (ivaynberg) */public abstract class Component implements IClusterable, IConverterLocator{ /** * Change record of a model. */ public class ComponentModelChange extends Change { private static final long serialVersionUID = 1L; /** Former model. */ private final IModel model; /** * Construct. * * @param model */ public ComponentModelChange(IModel model) { super(); this.model = model; } /** * @see java.lang.Object#toString() */ public String toString() { return "ComponentModelChange[component: " + getPath() + "]"; } /** * @see org.apache.wicket.version.undo.Change#undo() */ public void undo() { setModel(model); } } /** * Generic component visitor interface for component traversals. */ public static interface IVisitor { /** * Value to return to continue a traversal. */ public static final Object CONTINUE_TRAVERSAL = null; /** * A generic value to return to continue a traversal, but if the component is a container, * don't visit its children. */ public static final Object CONTINUE_TRAVERSAL_BUT_DONT_GO_DEEPER = new Object(); /** * A generic value to return to stop a traversal. */ public static final Object STOP_TRAVERSAL = new Object(); /** * Called at each component in a traversal. * * @param component * The component * @return CONTINUE_TRAVERSAL (null) if the traversal should continue, or a non-null return * value for the traversal method if it should stop. If no return value is useful, * the generic non-null value STOP_TRAVERSAL can be used. */ public Object component(Component component); } /** * Change object for undoing addition of behavior * * @author Igor Vaynberg (ivaynberg) */ private final class AddedBehaviorChange extends Change { private static final long serialVersionUID = 1L; private final IBehavior behavior; /** * Construct. * * @param behavior */ public AddedBehaviorChange(IBehavior behavior) { this.behavior = behavior; } public String toString() { return "[" + getClass().getName() + " behavior=" + behavior.toString() + "]"; } public void undo() { removeBehavior(behavior); } } /** * Undo change for component border property * * @author ivaynberg */ private class ComponentBorderChange extends Change { private static final long serialVersionUID = 1L; private final IComponentBorder old = getComponentBorder(); public void undo() { setComponentBorder(old); } } /** * Change object for undoing removal of behavior * * @author Igor Vaynberg (ivaynberg) */ private final class RemovedBehaviorChange extends Change { private static final long serialVersionUID = 1L; private final IBehavior behavior; /** * Construct. * * @param behavior */ public RemovedBehaviorChange(IBehavior behavior) { this.behavior = behavior; } public String toString() { return "[" + getClass().getName() + " behavior=" + behavior.toString() + "]"; } public void undo() { addBehavior(behavior); } } /** * A enabled change operation. */ protected final static class EnabledChange extends Change { private static final long serialVersionUID = 1L; /** Subject. */ private final Component component; /** Former value. */ private final boolean enabled; /** * Construct. * * @param component */ EnabledChange(final Component component) { this.component = component; enabled = component.getFlag(FLAG_ENABLED); } /** * @see java.lang.Object#toString() */ public String toString() { return "EnabledChange[component: " + component.getPath() + ",enabled: " + enabled + "]"; } /** * @see org.apache.wicket.version.undo.Change#undo() */ public void undo() { component.setEnabled(enabled); } } /** * A visibility change operation. */ protected final static class VisibilityChange extends Change { private static final long serialVersionUID = 1L; /** Subject. */ private final Component component; /** Former value. */ private final boolean visible; /** * Construct. * * @param component */ VisibilityChange(final Component component) { this.component = component; visible = component.getFlag(FLAG_VISIBLE); } /** * @see java.lang.Object#toString() */ public String toString() { return "VisibilityChange[component: " + component.getPath() + ", visible: " + visible + "]"; } /** * @see org.apache.wicket.version.undo.Change#undo() */ public void undo() { component.setVisible(visible); } } /** * Action used with IAuthorizationStrategy to determine whether a component is allowed to be * enabled. * <p> * If enabling is authorized, a component may decide by itself (typically using it's enabled * property) whether it is enabled or not. If enabling is not authorized, the given component is * marked disabled, regardless its enabled property. * <p> * When a component is not allowed to be enabled (in effect disabled through the implementation * of this interface), Wicket will try to prevent model updates too. This is not completely fail * safe, as constructs like: * * <pre>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -