Reusing components and models If I understand correctly, currently Wicket creates a new Page instance, if I request a BookmarkablePage. Take SignIn example: * from examples list click on "signin" * because user is not logged in, he is redirected from Home to SignIn * new SignIn page is created and form is displayed * If username is wrong, _same_ page is redisplayed with error message (I turned versioning off) * If I go back to the example list, and then forward, I will see the same form. Good. * But if i go back to the example list, and click on the "signin" link, I will get a new instance of SignIn Page with empty model. This is what I actively dislike.
My main grief is that I want to retain model if I click the "signin" link again. Also, reusing the Page object makes sense as well, it decreases the load on the session. On the other hand, if the Page instance is preserved, and its model is preserved, how do I clean the form fields? I need some kind of reset request parameter for that. Here is what I have done just as a sketch, it works, but I am sure it can be implemented more cleanly. (1) Initialization request parameter ------------------------------------ The init parameter can be sent to a Page instance to signal that Page's model should be cleaned. This parameter produces the same effect as current Wicket behavior, when a new and clean instance is created each time I click a link. Only in case of parameter, the instance can be reused. Apparently, I have to create a custom Link type, which will be rendered as url with init parameter. I have not done that, for now I pass the parameter directly. I use "wicket-init" as parameter. I also set it to 1 just because sometimes it is easier to search a request parameter which has value. So, the request looks like: http://localhost:8080/wicket-examples/signin?wicket-reset=1 In WebRequestCycle.parseRequest() I check if parameter is passed. If yes, I call responsePage.setMustReset(true). Methods setMustReset() and reset() are defined in Page class. I have to set reset flag instead of calling reset() directly, because I might be addressing to one page like Home, but in the end be redirected to another, like SignIn. So, I set a flag, which is then set again on the "real" page. (2) Reusing page instance ------------------------- I am reusing instance of SignIn page, because originally it is created in AuthenticatedWebPage.checkAccess() method, so it is easy to plug in my own code. But the instance of the Home page itself seems to be recreated each time, and I don't know yet how to reuse its instance. The newPage() methods are not called from anywhere but AuthenticatedWebPage, so I don't know yet how Wicket creates new instance internally. Anyway, here is what I do to reuse SignIn instance. I defined AuthenticatedWebPage.myNewPage() method which creates a new page. Actually, I wanted to override Page.newPage() but it is final. In myNewPage() method I check if the page to be created should have a single instance. I created a static field: static protected boolean singleton; which I set to true for Page classes which are supposed to have a single instance. So, the myNewPage() method looks like this: public Page myNewPage(final Class c) { Page page = null; Field isSingletonField = c.getDeclaredField("singleton"); boolean isSingleton = isSingletonField.getBoolean(null); if (isSingleton) { // This map is defined in SignInSession class Map recentPages = getSignInSession().getRecentPages(); if (recentPages != null) { page = (Page) recentPages.get(SignIn.class.getName()); } // Reset existing page, this is what we are after if (page != null && page.isMustReset()) { page.reset(); } // Singleton page not found, create and store if (page == null) { page = newPage(c); recentPages.put(c.getName(), page); } // Page is not singleton, create unconditionally } else { page = newPage(c); } return page; } SignInSession class contains page map: protected Map recentPages = new HashMap(); public Map getRecentPages() { return recentPages; } (3) How it works ---------------- I define all pages in SignIn example as nonversioned. SignIn page is defined as singleton. When I access Home page using http://localhost:8080/wicket-examples/signin link, the checkAccess() method creates a new instance of SignIn page if it was not created yet, or just reuses existing one. Therefore, I see the same data I entered before. If I click http://localhost:8080/wicket-examples/signin?wicket-reset=1 link and SignIn instance exists, then Home.mustReset is set, then SignIn.mustReset is set, then myNewPage is called and in the end it calls SignIn.reset(), which has the following code: public void reset() { // This check is here because I think maybe // I want to call reset() from outside unconditionally if (isMustReset()) { MarkupContainer form = null; if (formId != null) { form = (MarkupContainer) get(formId); } // Resetting form model by removing // the corresponding objects altogether if (form != null) { properties.remove("username"); properties.remove("password"); } } } So, the fields are cleared and a user sees an empty form. (4) TO-DO --------- Now I need to find out how to reuse Home page, and I need to wrap reset parameter into a ResetLink class or something. I would like this functionality to be included in Wicket. I can clean up and submit the code patches if this would be considered worthwhile. Michael. ------------------------------------------------------- SF.Net email is Sponsored by the Better Software Conference & EXPO September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf _______________________________________________ Wicket-develop mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/wicket-develop
