Source Code Cross Referenced for Page.java in  » J2EE » wicket » 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 » wicket 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * $Id: Page.java 508111 2007-02-15 19:50:42Z ivaynberg $ $Revision: 508111 $ $Date:
0003:         * 2006-03-16 11:34:01 -0800 (Thu, 16 Mar 2006) $
0004:         * 
0005:         * ==============================================================================
0006:         * Licensed under the Apache License, Version 2.0 (the "License"); you may not
0007:         * use this file except in compliance with the License. You may obtain a copy of
0008:         * the License at
0009:         * 
0010:         * http://www.apache.org/licenses/LICENSE-2.0
0011:         * 
0012:         * Unless required by applicable law or agreed to in writing, software
0013:         * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
0014:         * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
0015:         * License for the specific language governing permissions and limitations under
0016:         * the License.
0017:         */
0018:        package wicket;
0019:
0020:        import java.util.ArrayList;
0021:        import java.util.HashSet;
0022:        import java.util.List;
0023:        import java.util.Set;
0024:
0025:        import org.apache.commons.logging.Log;
0026:        import org.apache.commons.logging.LogFactory;
0027:
0028:        import wicket.authorization.UnauthorizedActionException;
0029:        import wicket.feedback.FeedbackMessages;
0030:        import wicket.feedback.IFeedback;
0031:        import wicket.markup.MarkupException;
0032:        import wicket.markup.MarkupStream;
0033:        import wicket.markup.html.WebPage;
0034:        import wicket.markup.html.form.Form;
0035:        import wicket.model.IModel;
0036:        import wicket.request.RequestParameters;
0037:        import wicket.session.pagemap.IPageMapEntry;
0038:        import wicket.settings.IDebugSettings;
0039:        import wicket.settings.IPageSettings;
0040:        import wicket.util.lang.Classes;
0041:        import wicket.util.lang.Objects;
0042:        import wicket.util.string.StringValue;
0043:        import wicket.util.value.Count;
0044:        import wicket.version.IPageVersionManager;
0045:        import wicket.version.undo.Change;
0046:        import wicket.version.undo.UndoPageVersionManager;
0047:
0048:        /**
0049:         * Abstract base class for pages. As a MarkupContainer subclass, a Page can
0050:         * contain a component hierarchy and markup in some markup language such as
0051:         * HTML. Users of the framework should not attempt to subclass Page directly.
0052:         * Instead they should subclass a subclass of Page that is appropriate to the
0053:         * markup type they are using, such as WebPage (for HTML markup).
0054:         * <ul>
0055:         * <li><b>Construction </b>- When a page is constructed, it is automatically
0056:         * added to the current PageMap in the Session. When a Page is added to the
0057:         * Session's PageMap, the PageMap assigns the Page an id. A PageMap is roughly
0058:         * equivalent to a browser window and encapsulates a set of pages accessible
0059:         * through that window. When a popup window is created, a new PageMap is created
0060:         * for the popup.
0061:         * 
0062:         * <li><b>Identity </b>- The Session that a Page is contained in can be
0063:         * retrieved by calling Page.getSession(). Page identifiers start at 0 for each
0064:         * PageMap in the Session and increment as new pages are added to the map. The
0065:         * PageMap-(and Session)-unique identifier assigned to a given Page can be
0066:         * retrieved by calling getId(). So, the first Page added to a new user Session
0067:         * will always be named "0".
0068:         * 
0069:         * <li><b>LifeCycle </b>- Subclasses of Page which are interested in lifecycle
0070:         * events can override onBeginRequest, onEndRequest() and onModelChanged(). The
0071:         * onBeginRequest() method is inherited from Component. A call to
0072:         * onBeginRequest() is made for every Component on a Page before page rendering
0073:         * begins. At the end of a request (when rendering has completed) to a Page, the
0074:         * onEndRequest() method is called for every Component on the Page.
0075:         * 
0076:         * <li><b>Nested Component Hierarchy </b>- The Page class is a subclass of
0077:         * MarkupContainer. All MarkupContainers can have "associated markup", which
0078:         * resides alongside the Java code by default. All MarkupContainers are also
0079:         * Component containers. Through nesting, of containers, a Page can contain any
0080:         * arbitrary tree of Components. For more details on MarkupContainers, see
0081:         * {@link wicket.MarkupContainer}.
0082:         * 
0083:         * <li><b>Bookmarkable Pages </b>- Pages can be constructed with any
0084:         * constructor when they are being used in a Wicket session, but if you wish to
0085:         * link to a Page using a URL that is "bookmarkable" (which implies that the URL
0086:         * will not have any session information encoded in it, and that you can call
0087:         * this page directly without having a session first directly from your
0088:         * browser), you need to implement your Page with a no-arg constructor or with a
0089:         * constructor that accepts a PageParameters argument (which wraps any query
0090:         * string parameters for a request). In case the page has both constructors, the
0091:         * constructor with PageParameters will be used.
0092:         * 
0093:         * <li><b>Models </b>- Pages, like other Components, can have models (see
0094:         * {@link IModel}). A Page can be assigned a model by passing one to the Page's
0095:         * constructor, by overriding initModel() or with an explicit invocation of
0096:         * setModel(). If the model is a {@link wicket.model.CompoundPropertyModel},
0097:         * Components on the Page can use the Page's model implicitly via container
0098:         * inheritance. If a Component is not assigned a model, the initModel() override
0099:         * in Component will cause that Component to use the nearest CompoundModel in
0100:         * the parent chain, in this case, the Page's model. For basic CompoundModels,
0101:         * the name of the Component determines which property of the implicit page
0102:         * model the component is bound to. If more control is desired over the binding
0103:         * of Components to the page model (for example, if you want to specify some
0104:         * property expression other than the component's name for retrieving the model
0105:         * object), BoundCompoundPropertyModel can be used.
0106:         * 
0107:         * <li><b>Back Button </b>- Pages can support the back button by enabling
0108:         * versioning with a call to setVersioned(boolean). If a Page is versioned and
0109:         * changes occur to it which need to be tracked, a verison manager will be
0110:         * installed using the overridable factory method newVersionManager(). The
0111:         * default version manager returned by the base implementation of this method is
0112:         * an instance of UndoPageVersionManager, which manages versions of a page by
0113:         * keeping change records that can be reversed at a later time.
0114:         * 
0115:         * <li><b>Security </b>- Pages can be secured by overriding checkAccess(). If
0116:         * checkAccess() returns ACCESS_ALLOWED (true), then onRender() will render the
0117:         * page. If it returns false (ACCESS_DENIED), then onRender() will not render
0118:         * the page. Besides returning true or false, an implementation of checkAccess()
0119:         * may also choose to send the user to another page with
0120:         * Component.setResponsePage() or Component.redirectToInterceptPage(). This can
0121:         * be used to allow a user to authenticate themselves if they were denied
0122:         * access.
0123:         * 
0124:         * @see wicket.markup.html.WebPage
0125:         * @see wicket.MarkupContainer
0126:         * @see wicket.model.CompoundPropertyModel
0127:         * @see wicket.model.BoundCompoundPropertyModel
0128:         * @see wicket.Component
0129:         * @see wicket.version.IPageVersionManager
0130:         * @see wicket.version.undo.UndoPageVersionManager
0131:         * 
0132:         * @author Jonathan Locke
0133:         * @author Chris Turner
0134:         * @author Eelco Hillenius
0135:         * @author Johan Compagner
0136:         */
0137:        public abstract class Page extends MarkupContainer implements 
0138:                IRedirectListener, IPageMapEntry {
0139:            private static final long serialVersionUID = 1L;
0140:
0141:            /**
0142:             * When passed to {@link Page#getVersion(int)} the latest page version is
0143:             * returned.
0144:             */
0145:            public static final int LATEST_VERSION = -1;
0146:
0147:            /** True if this page is currently rendering. */
0148:            private static final short FLAG_IS_RENDERING = FLAG_RESERVED2;
0149:
0150:            /** True if a new version was created for this request. */
0151:            private static final short FLAG_NEW_VERSION = FLAG_RESERVED3;
0152:
0153:            /** True if component changes are being tracked. */
0154:            private static final short FLAG_TRACK_CHANGES = FLAG_RESERVED4;
0155:
0156:            /** Log. */
0157:            private static final Log log = LogFactory.getLog(Page.class);
0158:
0159:            /** Used to create page-unique numbers */
0160:            private short autoIndex;
0161:
0162:            /** Feedback messages for this page */
0163:            private FeedbackMessages feedbackMessages;
0164:
0165:            /** Numeric version of this page's id */
0166:            private short numericId;
0167:
0168:            /** The PageMap within the session that this page is stored in */
0169:            private transient PageMap pageMap;
0170:
0171:            /** Name of PageMap that this page is stored in */
0172:            private String pageMapName;
0173:
0174:            /** Set of components that rendered if component use checking is enabled */
0175:            private transient Set renderedComponents;
0176:
0177:            /**
0178:             * Boolean if the page is stateless, so it doesn't have to be in the page
0179:             * map, will be set in urlFor
0180:             */
0181:            private transient boolean stateless = true;
0182:
0183:            /** Version manager for this page */
0184:            private IPageVersionManager versionManager;
0185:
0186:            /**
0187:             * Constructor.
0188:             */
0189:            protected Page() {
0190:                // A Page's id is not determined until setId is called when the Page is
0191:                // added to a PageMap in the Session.
0192:                super (null);
0193:                init();
0194:            }
0195:
0196:            /**
0197:             * Constructor.
0198:             * 
0199:             * @param model
0200:             *            See Component
0201:             * @see Component#Component(String, IModel)
0202:             */
0203:            protected Page(final IModel model) {
0204:                // A Page's id is not determined until setId is called when the Page is
0205:                // added to a PageMap in the Session.
0206:                super (null, model);
0207:                init();
0208:            }
0209:
0210:            /**
0211:             * Constructor.
0212:             * 
0213:             * @param pageMap
0214:             *            The page map to put this page in
0215:             */
0216:            protected Page(final PageMap pageMap) {
0217:                // A Page's id is not determined until setId is called when the Page is
0218:                // added to a PageMap in the Session.
0219:                super (null);
0220:                init(pageMap);
0221:            }
0222:
0223:            /**
0224:             * Constructor.
0225:             * 
0226:             * @param pageMap
0227:             *            the name of the page map to put this page in
0228:             * @param model
0229:             *            See Component
0230:             * @see Component#Component(String, IModel)
0231:             */
0232:            protected Page(final PageMap pageMap, final IModel model) {
0233:                // A Page's id is not determined until setId is called when the Page is
0234:                // added to a PageMap in the Session.
0235:                super (null, model);
0236:                init(pageMap);
0237:            }
0238:
0239:            /**
0240:             * Called right after a component's listener method (the provided method
0241:             * argument) was called. This method may be used to clean up dependencies,
0242:             * do logging, etc. NOTE: this method will also be called when
0243:             * {@link WebPage#beforeCallComponent(Component, RequestListenerInterface)}
0244:             * or the method invocation itself failed.
0245:             * 
0246:             * @param component
0247:             *            the component that is to be called
0248:             * @param listener
0249:             *            the listener of that component that is to be called
0250:             */
0251:            public void afterCallComponent(final Component component,
0252:                    final RequestListenerInterface listener) {
0253:            }
0254:
0255:            /**
0256:             * Called just before a component's listener method (the provided method
0257:             * argument) is called. This method may be used to set up dependencies,
0258:             * enforce authorization, etc. NOTE: if this method fails, the method will
0259:             * not be excuted. Method
0260:             * {@link WebPage#afterCallComponent(Component, RequestListenerInterface)}
0261:             * will always be called.
0262:             * 
0263:             * @param component
0264:             *            the component that is to be called
0265:             * @param listener
0266:             *            the listener of that component that is to be called
0267:             */
0268:            public void beforeCallComponent(final Component component,
0269:                    final RequestListenerInterface listener) {
0270:            }
0271:
0272:            /**
0273:             * @return fixed true;
0274:             * 
0275:             * @deprecated this method is to be removed in future version in favor of
0276:             *             instances of
0277:             *             {@link wicket.authorization.IAuthorizationStrategy} such as
0278:             *             {@link wicket.authorization.strategies.page.AbstractPageAuthorizationStrategy}.
0279:             *             It isn't called anymore and made final so that people see
0280:             *             what must be changed.
0281:             */
0282:            public final boolean checkAccess() {
0283:                return true;
0284:            }
0285:
0286:            /**
0287:             * @see wicket.MarkupContainer#internalDetach()
0288:             */
0289:            public void internalDetach() {
0290:                super .internalDetach();
0291:            }
0292:
0293:            /**
0294:             * Detaches any attached models referenced by this page.
0295:             */
0296:            public void detachModels() {
0297:                // visit all this page's children to detach the models
0298:                visitChildren(new IVisitor() {
0299:                    public Object component(Component component) {
0300:                        try {
0301:                            // detach any models of the component
0302:                            component.detachModels();
0303:                        } catch (Exception e) // catch anything; we MUST detach all models
0304:                        {
0305:                            log.error("detaching models of component "
0306:                                    + component + " failed:", e);
0307:                        }
0308:                        return IVisitor.CONTINUE_TRAVERSAL;
0309:                    }
0310:                });
0311:
0312:                super .detachModels();
0313:            }
0314:
0315:            /**
0316:             * Mark this page as dirty in the session
0317:             */
0318:            public final void dirty() {
0319:                Session.get().dirtyPage(this );
0320:            }
0321:
0322:            /**
0323:             * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL IT.
0324:             */
0325:            public final void renderPage() {
0326:                // first try to check if the page can be rendered:
0327:                if (!isActionAuthorized(RENDER)) {
0328:                    if (log.isDebugEnabled()) {
0329:                        log.debug("Page not allowed to render: " + this );
0330:                    }
0331:                    throw new UnauthorizedActionException(this ,
0332:                            Component.RENDER);
0333:                }
0334:
0335:                // Make sure it is really empty
0336:                renderedComponents = null;
0337:
0338:                // Reset it to stateless so that it can be tested again
0339:                this .stateless = true;
0340:
0341:                // Set form component values from cookies
0342:                setFormComponentValuesFromCookies();
0343:
0344:                // First, give priority to IFeedback instances, as they have to
0345:                // collect their messages before components like ListViews
0346:                // remove any child components
0347:                visitChildren(IFeedback.class, new IVisitor() {
0348:                    public Object component(Component component) {
0349:                        ((IFeedback) component).updateFeedback();
0350:                        component.internalAttach();
0351:                        return IVisitor.CONTINUE_TRAVERSAL;
0352:                    }
0353:                });
0354:
0355:                if (this  instanceof  IFeedback) {
0356:                    ((IFeedback) this ).updateFeedback();
0357:                }
0358:
0359:                // Now, do the initialization for the other components
0360:                internalAttach();
0361:
0362:                // Call reset head rendered on the page
0363:                resetHeadRendered();
0364:
0365:                // Visit all this page's children to reset markup streams and check
0366:                // rendering authorization, as appropriate. We set any result; positive
0367:                // or negative as a temporary boolean in the components, and when a
0368:                // authorization exception is thrown it will block the rendering of this
0369:                // page
0370:
0371:                // first the page itself
0372:                setRenderAllowed(isActionAuthorized(RENDER));
0373:                // children of the page
0374:                visitChildren(new IVisitor() {
0375:                    public Object component(final Component component) {
0376:                        component.resetHeadRendered();
0377:
0378:                        // Find out if this component can be rendered
0379:                        final boolean renderAllowed = component
0380:                                .isActionAuthorized(RENDER);
0381:
0382:                        // Authorize rendering
0383:                        component.setRenderAllowed(renderAllowed);
0384:                        return IVisitor.CONTINUE_TRAVERSAL;
0385:                    }
0386:                });
0387:
0388:                // Handle request by rendering page
0389:                render(null);
0390:
0391:                // Check rendering if it happened fully
0392:                checkRendering(this );
0393:
0394:                // Add/touch the response page in the session (its pagemap).
0395:                getSession().touch(this );
0396:            }
0397:
0398:            /**
0399:             * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL.
0400:             * 
0401:             * This method is called when a component was rendered standalone. If it is
0402:             * a markupcontainer then the rendering for that container is checked.
0403:             * 
0404:             * @param component
0405:             * 
0406:             */
0407:            public final void endComponentRender(Component component) {
0408:                if (component instanceof  MarkupContainer) {
0409:                    checkRendering((MarkupContainer) component);
0410:                } else {
0411:                    renderedComponents = null;
0412:                }
0413:            }
0414:
0415:            /**
0416:             * Expire the oldest version of this page
0417:             */
0418:            public final void expireOldestVersion() {
0419:                if (versionManager != null) {
0420:                    versionManager.expireOldestVersion();
0421:                }
0422:            }
0423:
0424:            /**
0425:             * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL IT.
0426:             * 
0427:             * Get a page unique number, which will be increased with each call.
0428:             * 
0429:             * @return A page unique number
0430:             */
0431:            public final short getAutoIndex() {
0432:                return this .autoIndex++;
0433:            }
0434:
0435:            /**
0436:             * @return The current version number of this page. If the page has been
0437:             *         changed once, the return value will be 1. If the page has not yet
0438:             *         been revised, the version returned will be 0, indicating that the
0439:             *         page is still in its original state.
0440:             */
0441:            public final int getCurrentVersionNumber() {
0442:                return versionManager == null ? 0 : versionManager
0443:                        .getCurrentVersionNumber();
0444:            }
0445:
0446:            /**
0447:             * @return Returns feedback messages from all components in this page
0448:             *         (including the page itself).
0449:             */
0450:            public final FeedbackMessages getFeedbackMessages() {
0451:                if (feedbackMessages == null) {
0452:                    feedbackMessages = new FeedbackMessages();
0453:                }
0454:                return feedbackMessages;
0455:            }
0456:
0457:            /**
0458:             * @see wicket.Component#getId()
0459:             */
0460:            public final String getId() {
0461:                return Integer.toString(numericId);
0462:            }
0463:
0464:            /**
0465:             * @see wicket.session.pagemap.IPageMapEntry#getNumericId()
0466:             */
0467:            public int getNumericId() {
0468:                return numericId;
0469:            }
0470:
0471:            /**
0472:             * @see wicket.session.pagemap.IPageMapEntry#getPageClass()
0473:             */
0474:            public final Class getPageClass() {
0475:                return getClass();
0476:            }
0477:
0478:            /**
0479:             * @return Returns the PageMap that this Page is stored in.
0480:             */
0481:            public final PageMap getPageMap() {
0482:                // If the transient needs to be restored
0483:                if (pageMap == null) {
0484:                    // Look the page map up in the session
0485:                    pageMap = PageMap.forName(pageMapName);
0486:                }
0487:                return pageMap;
0488:            }
0489:
0490:            /**
0491:             * @return Get a page map entry for this page. By default, this is the page
0492:             *         itself. But if you know of some way to compress the state for the
0493:             *         page, you can return a custom implementation that produces the
0494:             *         page on-the-fly.
0495:             */
0496:            public IPageMapEntry getPageMapEntry() {
0497:                return this ;
0498:            }
0499:
0500:            /**
0501:             * @return Size of this page in bytes
0502:             */
0503:            public final long getSizeInBytes() {
0504:                this .pageMap = null;
0505:                return Objects.sizeof(this );
0506:            }
0507:
0508:            /**
0509:             * Override this method to implement a custom way of producing a version of
0510:             * a Page when it cannot be found in the Session.
0511:             * 
0512:             * @param versionNumber
0513:             *            The version desired
0514:             * @return A Page object with the component/model hierarchy that was
0515:             *         attached to this page at the time represented by the requested
0516:             *         version.
0517:             */
0518:            public Page getVersion(final int versionNumber) {
0519:                // If we're still the original Page and that's what's desired
0520:                if (versionManager == null) {
0521:                    if (versionNumber == 0 || versionNumber == LATEST_VERSION) {
0522:                        return this ;
0523:                    } else {
0524:                        log
0525:                                .info("No version manager available to retrieve requested versionNumber "
0526:                                        + versionNumber);
0527:                        return null;
0528:                    }
0529:                } else {
0530:                    // Save original change tracking state
0531:                    final boolean originalTrackChanges = getFlag(FLAG_TRACK_CHANGES);
0532:
0533:                    try {
0534:                        // While the version manager is potentially playing around with
0535:                        // the Page, it may change the page in order to undo changes and
0536:                        // we don't want change tracking going on while its doing this.
0537:                        setFlag(FLAG_TRACK_CHANGES, false);
0538:
0539:                        // Get page of desired version
0540:                        final Page page;
0541:                        if (versionNumber != LATEST_VERSION) {
0542:                            page = versionManager.getVersion(versionNumber);
0543:                        } else {
0544:                            page = versionManager
0545:                                    .getVersion(getCurrentVersionNumber());
0546:                        }
0547:
0548:                        // If we went all the way back to the original page
0549:                        if (page != null && page.getCurrentVersionNumber() == 0) {
0550:                            // remove version info
0551:                            page.versionManager = null;
0552:                        }
0553:
0554:                        return page;
0555:                    } finally {
0556:                        // Restore change tracking state
0557:                        setFlag(FLAG_TRACK_CHANGES, originalTrackChanges);
0558:                    }
0559:                }
0560:            }
0561:
0562:            /**
0563:             * @return Number of versions of this page
0564:             */
0565:            public final int getVersions() {
0566:                return versionManager == null ? 1 : versionManager
0567:                        .getVersions() + 1;
0568:            }
0569:
0570:            /**
0571:             * @return This page's component hierarchy as a string
0572:             */
0573:            public final String hierarchyAsString() {
0574:                final StringBuffer buffer = new StringBuffer();
0575:                buffer.append("Page " + getId() + " (version "
0576:                        + getCurrentVersionNumber() + ")");
0577:                visitChildren(new IVisitor() {
0578:                    public Object component(Component component) {
0579:                        int levels = 0;
0580:                        for (Component current = component; current != null; current = current
0581:                                .getParent()) {
0582:                            levels++;
0583:                        }
0584:                        buffer.append(StringValue.repeat(levels, "	")
0585:                                + component.getPageRelativePath() + ":"
0586:                                + Classes.simpleName(component.getClass()));
0587:                        return null;
0588:                    }
0589:                });
0590:                return buffer.toString();
0591:            }
0592:
0593:            /**
0594:             * Override this method and return true if your page is used to display
0595:             * Wicket errors. This can help the framework prevent infinite failure
0596:             * loops.
0597:             * 
0598:             * @return True if this page is intended to display an error to the end
0599:             *         user.
0600:             */
0601:            public boolean isErrorPage() {
0602:                return false;
0603:            }
0604:
0605:            /**
0606:             * Redirect to this page.
0607:             * 
0608:             * @see wicket.IRedirectListener#onRedirect()
0609:             */
0610:            public final void onRedirect() {
0611:            }
0612:
0613:            /**
0614:             * Convenience method. Search for children of type fromClass and invoke
0615:             * their respective removePersistedFormData() methods.
0616:             * 
0617:             * @see Form#removePersistentFormComponentValues(boolean)
0618:             * 
0619:             * @param formClass
0620:             *            Form to be selected. Pages may have more than one Form.
0621:             * @param disablePersistence
0622:             *            if true, disable persistence for all FormComponents on that
0623:             *            page. If false, it will remain unchanged.
0624:             */
0625:            public final void removePersistedFormData(final Class formClass,
0626:                    final boolean disablePersistence) {
0627:                // Check that formClass is an instanceof Form
0628:                if (!Form.class.isAssignableFrom(formClass)) {
0629:                    throw new WicketRuntimeException("Form class "
0630:                            + formClass.getName()
0631:                            + " is not a subclass of Form");
0632:                }
0633:
0634:                // Visit all children which are an instance of formClass
0635:                visitChildren(formClass, new IVisitor() {
0636:                    public Object component(final Component component) {
0637:                        // They must be of type Form as well
0638:                        if (component instanceof  Form) {
0639:                            // Delete persistet FormComponent data and disable
0640:                            // persistence
0641:                            ((Form) component)
0642:                                    .removePersistentFormComponentValues(disablePersistence);
0643:                        }
0644:                        return CONTINUE_TRAVERSAL;
0645:                    }
0646:                });
0647:            }
0648:
0649:            /**
0650:             * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL.
0651:             * 
0652:             * Set the id for this Page. This method is called by PageMap when a Page is
0653:             * added because the id, which is assigned by PageMap, is not known until
0654:             * this time.
0655:             * 
0656:             * @param id
0657:             *            The id
0658:             */
0659:            public final void setNumericId(final int id) {
0660:                this .numericId = (short) id;
0661:            }
0662:
0663:            /**
0664:             * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL.
0665:             * 
0666:             * This method is called when a component will be rendered standalone.
0667:             * 
0668:             * @param component
0669:             * 
0670:             */
0671:            public final void startComponentRender(Component component) {
0672:                renderedComponents = null;
0673:            }
0674:
0675:            /**
0676:             * Get the string representation of this container.
0677:             * 
0678:             * @return String representation of this container
0679:             */
0680:            public String toString() {
0681:                return "[Page class = " + getClass().getName() + ", id = "
0682:                        + getId() + "]";
0683:            }
0684:
0685:            /**
0686:             * Set-up response with appropriate content type, locale and encoding. The
0687:             * locale is set equal to the session's locale. The content type header
0688:             * contains information about the markup type (@see #getMarkupType()) and
0689:             * the encoding. The response (and request) encoding is determined by an
0690:             * application setting (@see
0691:             * ApplicationSettings#getResponseRequestEncoding()). In addition, if the
0692:             * page's markup contains a xml declaration like &lt?xml ... ?&gt; an xml
0693:             * declaration with proper encoding information is written to the output as
0694:             * well, provided it is not disabled by an applicaton setting (@see
0695:             * ApplicationSettings#getStripXmlDeclarationFromOutput()).
0696:             * <p>
0697:             * Note: Prior to Wicket 1.1 the output encoding was determined by the
0698:             * page's markup encoding. Because this caused uncertainties about the
0699:             * /request/ encoding, it has been changed in favour of the new, much safer,
0700:             * approach. Please see the Wiki for more details.
0701:             */
0702:            protected void configureResponse() {
0703:                // Get the response and application
0704:                final RequestCycle cycle = getRequestCycle();
0705:                final Application application = cycle.getApplication();
0706:                final Response response = cycle.getResponse();
0707:
0708:                // Determine encoding
0709:                final String encoding = application.getRequestCycleSettings()
0710:                        .getResponseRequestEncoding();
0711:
0712:                // Set content type based on markup type for page
0713:                response.setContentType("text/" + getMarkupType()
0714:                        + "; charset=" + encoding);
0715:
0716:                // Write out an xml declaration if the markup stream and settings allow
0717:                final MarkupStream markupStream = findMarkupStream();
0718:                if ((markupStream != null)
0719:                        && (markupStream.getXmlDeclaration() != null)
0720:                        && (application.getMarkupSettings()
0721:                                .getStripXmlDeclarationFromOutput() == false)) {
0722:                    response.write("<?xml version='1.0' encoding='");
0723:                    response.write(encoding);
0724:                    response.write("'?>");
0725:                }
0726:
0727:                // Set response locale from session locale
0728:                response.setLocale(getSession().getLocale());
0729:            }
0730:
0731:            /**
0732:             * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL OR
0733:             * OVERRIDE.
0734:             * 
0735:             * @see wicket.Component#internalOnDetach()
0736:             */
0737:            protected final void internalOnDetach() {
0738:                if (log.isDebugEnabled()) {
0739:                    log.debug("ending request for page " + this  + ", request "
0740:                            + getRequest());
0741:                }
0742:
0743:                detachModels();
0744:
0745:                if (isVersioned()) {
0746:                    // Any changes to the page after this point will be tracked by the
0747:                    // page's version manager. Since trackChanges is never set to false,
0748:                    // this effectively means that change tracking begins after the
0749:                    // first request to a page completes.
0750:                    setFlag(FLAG_TRACK_CHANGES, true);
0751:
0752:                    endVersion();
0753:                }
0754:            }
0755:
0756:            /**
0757:             * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL OR
0758:             * OVERRIDE.
0759:             * 
0760:             * @see wicket.Component#internalOnModelChanged()
0761:             */
0762:            protected final void internalOnModelChanged() {
0763:                visitChildren(new Component.IVisitor() {
0764:                    public Object component(final Component component) {
0765:                        // If form component is using form model
0766:                        if (component.sameRootModel(Page.this )) {
0767:                            component.modelChanged();
0768:                        }
0769:                        return IVisitor.CONTINUE_TRAVERSAL;
0770:                    }
0771:                });
0772:            }
0773:
0774:            /**
0775:             * @return Factory method that creates a version manager for this Page
0776:             */
0777:            protected IPageVersionManager newVersionManager() {
0778:                final IPageSettings settings = getSession().getApplication()
0779:                        .getPageSettings();
0780:                return new UndoPageVersionManager(this , settings
0781:                        .getMaxPageVersions());
0782:            }
0783:
0784:            /**
0785:             * Renders this container to the given response object.
0786:             * 
0787:             * @param markupStream
0788:             */
0789:            protected void onRender(final MarkupStream markupStream) {
0790:                // Set page's associated markup stream
0791:                final MarkupStream associatedMarkupStream = getAssociatedMarkupStream(true);
0792:                setMarkupStream(associatedMarkupStream);
0793:
0794:                // Configure response object with locale and content type
0795:                configureResponse();
0796:
0797:                // Render all the page's markup
0798:                setFlag(FLAG_IS_RENDERING, true);
0799:                try {
0800:                    renderAll(associatedMarkupStream);
0801:                } finally {
0802:                    setFlag(FLAG_IS_RENDERING, false);
0803:                }
0804:            }
0805:
0806:            /**
0807:             * A component was added.
0808:             * 
0809:             * @param component
0810:             *            The component that was added
0811:             */
0812:            final void componentAdded(final Component component) {
0813:                checkHierarchyChange(component);
0814:
0815:                dirty();
0816:                if (mayTrackChangesFor(component, component.getParent())) {
0817:                    versionManager.componentAdded(component);
0818:                }
0819:            }
0820:
0821:            /**
0822:             * A component's model changed.
0823:             * 
0824:             * @param component
0825:             *            The component whose model is about to change
0826:             */
0827:            final void componentModelChanging(final Component component) {
0828:                checkHierarchyChange(component);
0829:
0830:                dirty();
0831:                if (mayTrackChangesFor(component, null)) {
0832:                    versionManager.componentModelChanging(component);
0833:                }
0834:            }
0835:
0836:            /**
0837:             * A component was removed.
0838:             * 
0839:             * @param component
0840:             *            The component that was removed
0841:             */
0842:            final void componentRemoved(final Component component) {
0843:                checkHierarchyChange(component);
0844:
0845:                dirty();
0846:                if (mayTrackChangesFor(component, component.getParent())) {
0847:                    versionManager.componentRemoved(component);
0848:                }
0849:            }
0850:
0851:            /**
0852:             * Adds a component to the set of rendered components.
0853:             * 
0854:             * @param component
0855:             *            The component that was rendered
0856:             */
0857:            final void componentRendered(final Component component) {
0858:                // Inform the page that this component rendered
0859:                if (Application.get().getDebugSettings().getComponentUseCheck()) {
0860:                    if (renderedComponents == null) {
0861:                        renderedComponents = new HashSet();
0862:                    }
0863:                    if (renderedComponents.add(component) == false) {
0864:                        throw new MarkupException(
0865:                                "The component "
0866:                                        + component
0867:                                        + " has the same wicket:id as another component already added at the same level");
0868:                    }
0869:                    if (log.isDebugEnabled()) {
0870:                        log.debug("Rendered " + component);
0871:                    }
0872:                }
0873:            }
0874:
0875:            final void componentStateChanging(final Component component,
0876:                    Change change) {
0877:                checkHierarchyChange(component);
0878:
0879:                dirty();
0880:                if (mayTrackChangesFor(component, null)) {
0881:                    versionManager.componentStateChanging(change);
0882:                }
0883:            }
0884:
0885:            /**
0886:             * @return Return true from this method if you want to keep a page out of
0887:             *         the session.
0888:             */
0889:            final boolean isStateless() {
0890:                return stateless;
0891:            }
0892:
0893:            final void setStateless(boolean stateless) {
0894:                this .stateless = stateless;
0895:            }
0896:
0897:            /**
0898:             * Sets values for form components based on cookie values in the request.
0899:             * 
0900:             */
0901:            final void setFormComponentValuesFromCookies() {
0902:                // Visit all Forms contained in the page
0903:                visitChildren(Form.class, new Component.IVisitor() {
0904:                    // For each FormComponent found on the Page (not Form)
0905:                    public Object component(final Component component) {
0906:                        ((Form) component).loadPersistentFormComponentValues();
0907:                        return CONTINUE_TRAVERSAL;
0908:                    }
0909:                });
0910:            }
0911:
0912:            /**
0913:             * @param pageMap
0914:             *            Sets this page into the page map with the given name. If the
0915:             *            page map does not yet exist, it is automatically created.
0916:             */
0917:            final void setPageMap(final PageMap pageMap) {
0918:                // Save transient reference to pagemap
0919:                this .pageMap = pageMap;
0920:
0921:                // Save name for restoring transient
0922:                this .pageMapName = pageMap.getName();
0923:            }
0924:
0925:            /**
0926:             * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL OR
0927:             * OVERRIDE.
0928:             * 
0929:             * @param map
0930:             */
0931:            protected final void moveToPageMap(PageMap map) {
0932:                // TODO post 1.2 shouldn't we remove this page from the pagemap/session
0933:                // if it would be in there?
0934:                // This should be done if the page was not cloned first, but shouldn't
0935:                // be done if it was cloned..
0936:                setPageMap(map);
0937:                numericId = (short) map.nextId();
0938:            }
0939:
0940:            /**
0941:             * Checks whether the hierarchy may be changed at all, and throws an
0942:             * exception if this is not the case.
0943:             * 
0944:             * @param component
0945:             *            the component which is about to be added or removed
0946:             */
0947:            private void checkHierarchyChange(Component component) {
0948:                // Throw exception if modification is attempted during rendering
0949:                if ((!component.isAuto()) && getFlag(FLAG_IS_RENDERING)) {
0950:                    throw new WicketRuntimeException(
0951:                            "Cannot modify component hierarchy during render phase");
0952:                }
0953:            }
0954:
0955:            /**
0956:             * Throw an exception if not all components rendered.
0957:             * 
0958:             * @param renderedContainer
0959:             *            The page itself if it was a full page render or the container
0960:             *            that was rendered standalone
0961:             */
0962:            private final void checkRendering(
0963:                    final MarkupContainer renderedContainer) {
0964:                // If the application wants component uses checked and
0965:                // the response is not a redirect
0966:                final IDebugSettings debugSettings = Application.get()
0967:                        .getDebugSettings();
0968:                if (debugSettings.getComponentUseCheck()
0969:                        && !getResponse().isRedirect()) {
0970:                    final Count unrenderedComponents = new Count();
0971:                    final List unrenderedAutoComponents = new ArrayList();
0972:                    final StringBuffer buffer = new StringBuffer();
0973:                    renderedContainer.visitChildren(new IVisitor() {
0974:                        public Object component(final Component component) {
0975:                            // If component never rendered
0976:                            if (renderedComponents == null
0977:                                    || !renderedComponents.contains(component)) {
0978:                                // If auto component ...
0979:                                if (component.isAuto()) {
0980:                                    // Add to list of unrendered auto components to
0981:                                    // delete below
0982:                                    unrenderedAutoComponents.add(component);
0983:                                } else if (component.isVisibleInHierarchy()) {
0984:                                    // Increase number of unrendered components
0985:                                    unrenderedComponents.increment();
0986:
0987:                                    // Add to explanatory string to buffer
0988:                                    buffer.append(Integer
0989:                                            .toString(unrenderedComponents
0990:                                                    .getCount())
0991:                                            + ". " + component + "\n");
0992:                                } else {
0993:                                    // if the component is not visible in hierarchy we
0994:                                    // should not visit its children since they are also
0995:                                    // not visible
0996:                                    return CONTINUE_TRAVERSAL_BUT_DONT_GO_DEEPER;
0997:                                }
0998:                            }
0999:                            return CONTINUE_TRAVERSAL;
1000:                        }
1001:                    });
1002:
1003:                    // Remove any unrendered auto components since versioning couldn't
1004:                    // do it. We can't remove the component in the above visitChildren
1005:                    // callback because we're traversing the list at that time.
1006:                    for (int i = 0; i < unrenderedAutoComponents.size(); i++) {
1007:                        ((Component) unrenderedAutoComponents.get(i)).remove();
1008:                    }
1009:
1010:                    // Throw exception if any errors were found
1011:                    if (unrenderedComponents.getCount() > 0) {
1012:                        // Get rid of set
1013:                        renderedComponents = null;
1014:
1015:                        // Throw exception
1016:                        throw new WicketRuntimeException(
1017:                                "The component(s) below failed to render. A common problem is that you have added a component in code but forgot to reference it in the markup (thus the component will never be rendered).\n\n"
1018:                                        + buffer.toString());
1019:                    }
1020:                }
1021:
1022:                // Get rid of set
1023:                renderedComponents = null;
1024:            }
1025:
1026:            /**
1027:             * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL OR
1028:             * OVERRIDE.
1029:             * 
1030:             */
1031:            private final void endVersion() {
1032:                // If a new version was created
1033:                if (getFlag(FLAG_NEW_VERSION)) {
1034:                    // We're done with this version
1035:                    if (versionManager != null) {
1036:                        versionManager.endVersion();
1037:                    }
1038:
1039:                    // Evict any page version(s) as need be
1040:                    getApplication().getSessionSettings()
1041:                            .getPageMapEvictionStrategy().evict(getPageMap());
1042:
1043:                    // Reset boolean for next request
1044:                    setFlag(FLAG_NEW_VERSION, false);
1045:                }
1046:            }
1047:
1048:            /**
1049:             * Initializes Page by adding it to the Session and initializing it.
1050:             */
1051:            private final void init() {
1052:                final RequestCycle cycle = getRequestCycle();
1053:                String pageMapName = null;
1054:                if (cycle != null) {
1055:                    RequestParameters parameters = getRequest()
1056:                            .getRequestParameters();
1057:                    pageMapName = parameters.getPageMapName();
1058:                }
1059:                final PageMap pageMap = PageMap.forName(pageMapName);
1060:                init(pageMap);
1061:            }
1062:
1063:            /**
1064:             * Initializes Page by adding it to the Session and initializing it.
1065:             * 
1066:             * @param pageMap
1067:             *            The page map to put this page in.
1068:             */
1069:            private final void init(final PageMap pageMap) {
1070:                // Set the page map
1071:                if (pageMap != null) {
1072:                    setPageMap(pageMap);
1073:                } else {
1074:                    throw new IllegalStateException("PageMap cannot be null");
1075:                }
1076:
1077:                // Set the numeric id on this page
1078:                setNumericId(getPageMap().nextId());
1079:
1080:                // Set versioning of page based on default
1081:                setVersioned(Application.get().getPageSettings()
1082:                        .getVersionPagesByDefault());
1083:
1084:                // All Pages are born dirty so they get clustered right away
1085:                dirty();
1086:            }
1087:
1088:            /**
1089:             * For the given component, whether we may record changes.
1090:             * 
1091:             * @param component
1092:             *            The component which is affected
1093:             * @param parent
1094:             * @return True if the change is okay to report
1095:             */
1096:            private final boolean mayTrackChangesFor(final Component component,
1097:                    MarkupContainer parent) {
1098:                // Auto components do not participate in versioning since they are
1099:                // added during the rendering phase (which is normally illegal).
1100:                if (component.isAuto()
1101:                        || (parent == null && !component.isVersioned())
1102:                        || (parent != null && !parent.isVersioned())) {
1103:                    return false;
1104:                } else {
1105:                    // the component is versioned... are we tracking changes at all?
1106:                    if (getFlag(FLAG_TRACK_CHANGES)) {
1107:                        // we are tracking changes... do we need to start new version?
1108:                        if (!getFlag(FLAG_NEW_VERSION)) {
1109:                            // if we have no version manager
1110:                            if (versionManager == null) {
1111:                                // then install a new version manager
1112:                                versionManager = newVersionManager();
1113:                            }
1114:
1115:                            // start a new version
1116:                            versionManager.beginVersion();
1117:                            setFlag(FLAG_NEW_VERSION, true);
1118:                        }
1119:
1120:                        // return true as we are ready for versioning
1121:                        return true;
1122:                    }
1123:
1124:                    // we are not tracking changes or the component not versioned
1125:                    return false;
1126:                }
1127:            }
1128:
1129:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.