📄 page.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.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.ObjectStreamException;import java.util.ArrayList;import java.util.HashSet;import java.util.Iterator;import java.util.List;import java.util.Set;import org.apache.wicket.authorization.IAuthorizationStrategy;import org.apache.wicket.authorization.UnauthorizedActionException;import org.apache.wicket.authorization.strategies.page.SimplePageAuthorizationStrategy;import org.apache.wicket.markup.MarkupException;import org.apache.wicket.markup.MarkupStream;import org.apache.wicket.markup.html.WebPage;import org.apache.wicket.markup.html.form.Form;import org.apache.wicket.markup.resolver.IComponentResolver;import org.apache.wicket.model.IModel;import org.apache.wicket.request.RequestParameters;import org.apache.wicket.session.ISessionStore;import org.apache.wicket.session.pagemap.IPageMapEntry;import org.apache.wicket.settings.IDebugSettings;import org.apache.wicket.util.concurrent.ConcurrentHashMap;import org.apache.wicket.util.lang.Classes;import org.apache.wicket.util.lang.Objects;import org.apache.wicket.util.string.StringValue;import org.apache.wicket.version.IPageVersionManager;import org.apache.wicket.version.undo.Change;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/** * Abstract base class for pages. As a MarkupContainer subclass, a Page can contain a component * hierarchy and markup in some markup language such as HTML. Users of the framework should not * attempt to subclass Page directly. Instead they should subclass a subclass of Page that is * appropriate to the markup type they are using, such as WebPage (for HTML markup). * <ul> * <li><b>Construction </b>- When a page is constructed, it is automatically added to the current * PageMap in the Session. When a Page is added to the Session's PageMap, the PageMap assigns the * Page an id. A PageMap is roughly equivalent to a browser window and encapsulates a set of pages * accessible through that window. When a popup window is created, a new PageMap is created for the * popup. * * <li><b>Identity </b>- The Session that a Page is contained in can be retrieved by calling * Page.getSession(). Page identifiers start at 0 for each PageMap in the Session and increment as * new pages are added to the map. The PageMap-(and Session)-unique identifier assigned to a given * Page can be retrieved by calling getId(). So, the first Page added to a new user Session will * always be named "0". * * <li><b>LifeCycle </b>- Subclasses of Page which are interested in lifecycle events can override * onBeginRequest, onEndRequest() and onModelChanged(). The onBeginRequest() method is inherited * from Component. A call to onBeginRequest() is made for every Component on a Page before page * rendering begins. At the end of a request (when rendering has completed) to a Page, the * onEndRequest() method is called for every Component on the Page. * * <li><b>Nested Component Hierarchy </b>- The Page class is a subclass of MarkupContainer. All * MarkupContainers can have "associated markup", which resides alongside the Java code by default. * All MarkupContainers are also Component containers. Through nesting, of containers, a Page can * contain any arbitrary tree of Components. For more details on MarkupContainers, see * {@link org.apache.wicket.MarkupContainer}. * * <li><b>Bookmarkable Pages </b>- Pages can be constructed with any constructor when they are * being used in a Wicket session, but if you wish to link to a Page using a URL that is * "bookmarkable" (which implies that the URL will not have any session information encoded in it, * and that you can call this page directly without having a session first directly from your * browser), you need to implement your Page with a no-arg constructor or with a constructor that * accepts a PageParameters argument (which wraps any query string parameters for a request). In * case the page has both constructors, the constructor with PageParameters will be used. * * <li><b>Models </b>- Pages, like other Components, can have models (see {@link IModel}). A Page * can be assigned a model by passing one to the Page's constructor, by overriding initModel() or * with an explicit invocation of setModel(). If the model is a * {@link org.apache.wicket.model.CompoundPropertyModel}, Components on the Page can use the Page's * model implicitly via container inheritance. If a Component is not assigned a model, the * initModel() override in Component will cause that Component to use the nearest CompoundModel in * the parent chain, in this case, the Page's model. For basic CompoundModels, the name of the * Component determines which property of the implicit page model the component is bound to. If more * control is desired over the binding of Components to the page model (for example, if you want to * specify some property expression other than the component's name for retrieving the model * object), BoundCompoundPropertyModel can be used. * * <li><b>Back Button </b>- Pages can support the back button by enabling versioning with a call to * setVersioned(boolean). If a Page is versioned and changes occur to it which need to be tracked, a * version manager will be installed using the {@link ISessionStore}'s factory method * newVersionManager(). * * <li><b>Security </b>- See {@link IAuthorizationStrategy}, * {@link SimplePageAuthorizationStrategy} * * @see org.apache.wicket.markup.html.WebPage * @see org.apache.wicket.MarkupContainer * @see org.apache.wicket.model.CompoundPropertyModel * @see org.apache.wicket.model.BoundCompoundPropertyModel * @see org.apache.wicket.Component * @see org.apache.wicket.version.IPageVersionManager * @see org.apache.wicket.version.undo.UndoPageVersionManager * * @author Jonathan Locke * @author Chris Turner * @author Eelco Hillenius * @author Johan Compagner */public abstract class Page extends MarkupContainer implements IRedirectListener, IPageMapEntry{ /** * You can set implementation of the interface in the {@link Page#serializer} then that * implementation will handle the serialization of this page. The serializePage method is called * from the writeObject method then the implementation override the default serialization. * * @author jcompagner */ public static interface IPageSerializer { /** * Called when page is being deserialized * * @param id * TODO * @param name * TODO * @param page * @param stream * @return New instance to replace page instance being deserialized * @throws IOException * @throws ClassNotFoundException * */ public Page deserializePage(int id, String name, Page page, ObjectInputStream stream) throws IOException, ClassNotFoundException; /** * Called from the {@link Page#writeObject(java.io.ObjectOutputStream)} method. * * @param page * The page that must be serialized. * @param stream * ObjectOutputStream * @throws IOException */ public void serializePage(Page page, ObjectOutputStream stream) throws IOException; } /** * When passed to {@link Page#getVersion(int)} the latest page version is returned. */ public static final int LATEST_VERSION = -1; /** * This is a thread local that is used for serializing page references in this page.It stores a * {@link IPageSerializer} which can be set by the outside world to do the serialization of this * page. */ public static final ThreadLocal serializer = new ThreadLocal(); /** True if a new version was created for this request. */ private static final short FLAG_NEW_VERSION = FLAG_RESERVED3; /** True if the page should try to be stateless */ private static final int FLAG_STATELESS_HINT = FLAG_RESERVED5; /** True if component changes are being tracked. */ private static final short FLAG_TRACK_CHANGES = FLAG_RESERVED4; /** Log. */ private static final Logger log = LoggerFactory.getLogger(Page.class); /** * {@link #isBookmarkable()} is expensive, we cache the result here */ private static final ConcurrentHashMap pageClassToBookmarkableCache = new ConcurrentHashMap(); private static final long serialVersionUID = 1L; /** Used to create page-unique numbers */ private short autoIndex; /** Numeric version of this page's id */ private int numericId; /** The PageMap within the session that this page is stored in */ private transient IPageMap pageMap; /** Name of PageMap that this page is stored in */ private String pageMapName; // temporary variable to pass page instance from readObject to readResolve private transient Page pageToResolve = null; /** Set of components that rendered if component use checking is enabled */ private transient Set renderedComponents; /** * Boolean if the page is stateless, so it doesn't have to be in the page map, will be set in * urlFor */ private transient Boolean stateless = null; /** Version manager for this page */ private IPageVersionManager versionManager; /** The page parameters object hat constructed this page */ private PageParameters parameters; /** * Constructor. */ protected Page() { // A Page's id is not determined until setId is called when the Page is // added to a PageMap in the Session. super(null); init(); } /** * Constructor. * * @param model * See Component * @see Component#Component(String, IModel) */ protected Page(final IModel model) { // A Page's id is not determined until setId is called when the Page is // added to a PageMap in the Session. super(null, model); init(); } /** * Constructor. * * @param pageMap * The page map to put this page in */ protected Page(final IPageMap pageMap) { // A Page's id is not determined until setId is called when the Page is // added to a PageMap in the Session. super(null); init(pageMap); } /** * Constructor. * * @param pageMap * the page map to put this page in * @param model * See Component * @see Component#Component(String, IModel) */ protected Page(final IPageMap pageMap, final IModel model) { // A Page's id is not determined until setId is called when the Page is // added to a PageMap in the Session. super(null, model); init(pageMap); } /** * The {@link PageParameters} parameter will be stored in this page and then those parameters * will be used to create stateless links to this bookmarkable page. * * @param parameters * externally passed parameters * @see PageParameters */ protected Page(final PageParameters parameters) { super(null); this.parameters = parameters; init(); } /** * The {@link PageParameters} parameter will be stored in this page and then those parameters * will be used to create stateless links to this bookmarkable page. * * @param pageMap * the page map to put this page in * @param parameters * externally passed parameters * @see PageParameters */ protected Page(final IPageMap pageMap, final PageParameters parameters) { super(null); this.parameters = parameters; init(pageMap); } /** * The {@link PageParameters} object that was used to construct this page. This will be used in * creating stateless/bookmarkable links to this page * * @return {@link PageParameters} The construction page parameter */ public PageParameters getPageParameters() { return parameters; } /** * Called right after a component's listener method (the provided method argument) was called. * This method may be used to clean up dependencies, do logging, etc. NOTE: this method will * also be called when {@link WebPage#beforeCallComponent(Component, RequestListenerInterface)} * or the method invocation itself failed. * * @param component * the component that is to be called * @param listener * the listener of that component that is to be called */ // TODO Post-1.3: We should create a listener on Application like // IComponentInstantiationListener // that forwards to IAuthorizationStrategy for RequestListenerInterface // invocations. public void afterCallComponent(final Component component, final RequestListenerInterface listener) { } /** * Called just before a component's listener method (the provided method argument) is called. * This method may be used to set up dependencies, enforce authorization, etc. NOTE: if this * method fails, the method will not be executed. Method * {@link WebPage#afterCallComponent(Component, RequestListenerInterface)} will always be * called. * * @param component * the component that is to be called * @param listener * the listener of that component that is to be called */ // TODO Post-1.3: We should create a listener on Application like // IComponentInstantiationListener // that forwards to IAuthorizationStrategy for RequestListenerInterface // invocations. public void beforeCallComponent(final Component component, final RequestListenerInterface listener) { } /** * Adds a component to the set of rendered components. * * @param component * The component that was rendered */ public final void componentRendered(final Component component) { // Inform the page that this component rendered if (Application.get().getDebugSettings().getComponentUseCheck()) { if (renderedComponents == null) { renderedComponents = new HashSet(); } if (renderedComponents.add(component) == false) { throw new MarkupException("The component " + component + " has the same wicket:id as another component already added at the same level"); } if (log.isDebugEnabled()) { log.debug("Rendered " + component); } } } /** * Detaches any attached models referenced by this page. */ public void detachModels() { // // visit all this page's children to detach the models // visitChildren(new IVisitor() // { // public Object component(Component component) // { // try // { // // detach any models of the component // component.detachModels(); // } // catch (Exception e) // catch anything; we MUST detach all models // { // log.error("detaching models of component " + component + " failed:", // e); // } // return IVisitor.CONTINUE_TRAVERSAL; // } // }); super.detachModels(); } /** * Mark this page as dirty in the session */ public final void dirty() { Session.get().dirtyPage(this); } /** * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL. * * This method is called when a component was rendered standalone. If it is a * <code>MarkupContainer</code> then the rendering for that container is checked. * * @param component * */ public final void endComponentRender(Component component) { if (component instanceof MarkupContainer) { checkRendering((MarkupContainer)component); } else { renderedComponents = null; } } /** * Expire the oldest version of this page */ public final void expireOldestVersion() { if (versionManager != null) { versionManager.expireOldestVersion(); } } /** * @return The current ajax version number of this page. */ public final int getAjaxVersionNumber() { return versionManager == null ? 0 : versionManager.getAjaxVersionNumber(); } /** * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL IT. * * Get a page unique number, which will be increased with each call. * * @return A page unique number */ public final short getAutoIndex() { return autoIndex++; } /** * @return The current version number of this page. If the page has been changed once, the * return value will be 1. If the page has not yet been revised, the version returned * will be 0, indicating that the page is still in its original state. */ public final int getCurrentVersionNumber() { return versionManager == null ? 0 : versionManager.getCurrentVersionNumber(); } /** * @see org.apache.wicket.Component#getId() */ public final String getId() { return Integer.toString(numericId); } /** * @see org.apache.wicket.session.pagemap.IPageMapEntry#getNumericId() */ public int getNumericId() { return numericId; } /** * @see org.apache.wicket.session.pagemap.IPageMapEntry#getPageClass() */ public final Class getPageClass() { return getClass(); } /** * @return Returns the PageMap that this Page is stored in. */ public final IPageMap getPageMap() { // If the transient needs to be restored if (pageMap == null)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -