Dear Wiki user, You have subscribed to a wiki page or wiki category on "Tapestry Wiki" for change notification.
The following page has been changed by GregWoolsey: http://wiki.apache.org/tapestry/SessionPagePersistence New page: Tapestry's session persistence is great, but some times you just want a value to work like a "session page instance variable" - only around while the user is working within a page (calling listener methods on that page, but not rendering any other page). This strategy avoids all the problems of using real instance variables in a page object. Values are discarded if the last page rendered was not the same as the current page being rendered. You'll need a Persistence strategy, some hivemodule magic, and a Page End Render Listener. Once it's done, just use @Persist("session:page") to use. The strategy: {{{ package com.fireapps.tapestry.infrastructure; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import org.apache.hivemind.util.Defense; import org.apache.tapestry.engine.ServiceEncoding; import org.apache.tapestry.record.PropertyChange; import org.apache.tapestry.record.PropertyPersistenceStrategy; import org.apache.tapestry.record.RecordUtils; import org.apache.tapestry.record.WebSessionAttributeCallback; import org.apache.tapestry.web.WebRequest; import org.apache.tapestry.web.WebSession; /** * Derivative of SessionPropertyPersistenceScope * - only stores properties while the given page is the most recently rendered page. */ public class SessionPagePropertyPersistenceStrategy implements PropertyPersistenceStrategy { /** * unique persistence name */ public static final String STRATEGY_ID = "session:page"; /** * Session key for the last rendered page name */ public static final String LAST_RENDERED_PAGE_ID = "lastPage"; // Really, the name of the servlet; used as a prefix on all HttpSessionAttribute keys // to keep things straight if multiple Tapestry apps are deployed // in the same WAR. private String _applicationId; private WebRequest _request; public void store(String pageName, String idPath, String propertyName, Object newValue) { Defense.notNull(pageName, "pageName"); Defense.notNull(propertyName, "propertyName"); WebSession session = _request.getSession(true); String attributeName = RecordUtils.buildChangeKey(STRATEGY_ID, _applicationId, pageName, idPath, propertyName); session.setAttribute(attributeName, newValue); } public Collection getStoredChanges(String pageName) { Defense.notNull(pageName, "pageName"); WebSession session = _request.getSession(false); if (session == null) return Collections.EMPTY_LIST; /* * Single largest difference between this and Session persistence: * If the last rendered page is not this page (or is null) then don't return any * property values, and set any values found to null. */ String lastPage = (String) session.getAttribute(getLastPageKey(_applicationId)); if (lastPage == null || ! lastPage.equals(pageName)) { // discard values and return empty list discardStoredChanges(pageName); return Collections.EMPTY_LIST; } final Collection result = new ArrayList(); WebSessionAttributeCallback callback = new WebSessionAttributeCallback() { @SuppressWarnings("unchecked") public void handleAttribute(WebSession ws, String name) { PropertyChange change = RecordUtils.buildChange(name, ws.getAttribute(name)); result.add(change); } }; RecordUtils.iterateOverMatchingAttributes(STRATEGY_ID, _applicationId, pageName, session, callback); return result; } public void discardStoredChanges(String pageName) { WebSession session = _request.getSession(false); if (session == null) return; WebSessionAttributeCallback callback = new WebSessionAttributeCallback() { public void handleAttribute(WebSession ws, String name) { ws.setAttribute(name, null); } }; RecordUtils.iterateOverMatchingAttributes(STRATEGY_ID, _applicationId, pageName, session, callback); } public void addParametersForPersistentProperties(ServiceEncoding encoding, boolean post) { // nothing to do - we don't use query parameters for sessions } /** * @param applicationName (injected by HiveMind) for uniqueness of session attribute names */ public void setApplicationId(String applicationName) { _applicationId = applicationName; } /** * @param request (injected by HiveMind) */ public void setRequest(WebRequest request) { _request = request; } /** * @param appId * @return application specific session key name for the last rendered page * static so the PageEndRenderListener can also use it - there may be a better way for this */ public static String getLastPageKey(String appId) { return new StringBuilder().append(STRATEGY_ID).append(",").append(appId).append(",").toString(); } } }}} The hivemodule config: {{{ <service-point id="SessionPagePropertyPersistenceStrategy" interface="org.apache.tapestry.record.PropertyPersistenceStrategy"> Stores properties in the session, but only until the next useage of the page. Mapped to the name "session:page". <invoke-factory> <construct class="com.fireapps.tapestry.infrastructure.SessionPagePropertyPersistenceStrategy"> <set-object property="request" value="infrastructure:request"/> <set-object property="applicationId" value="infrastructure:applicationId"/> </construct> </invoke-factory> </service-point> <contribution configuration-id="tapestry.persist.PersistenceStrategy"> <strategy name="session:page" object="service:SessionPagePropertyPersistenceStrategy"/> </contribution> }}} The Page End Render Lister (example shows the definition of an annonymous inner class) {{{ new PageEndRenderListener() { /** * After rendering, store the page name in the session so the "session:page" persistence strategy can use it. * @see org.apache.tapestry.event.PageEndRenderListener#pageEndRender(org.apache.tapestry.event.PageEvent) */ public void pageEndRender(PageEvent e) { final String pageKey = SessionPagePropertyPersistenceStrategy .getLastPageKey(e.getRequestCycle().getInfrastructure().getApplicationId()); e.getRequestCycle() .getInfrastructure() .getRequest() .getSession(true) .setAttribute(pageKey, e.getPage().getPageName()); } } }}} You need to add this PageEndRenderListener to all your pages, unless someone has a neat trick for injecting it that I haven't figured out yet (improvements highly encouraged!). What we did was add this pageAttached() method to our base page class (extends AppPage, ancestor for all our pages): {{{ public void pageAttached(PageEvent event) { addPageEndRenderListener([above listener code, to create an anonymous inner class]); } }}} --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
