You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by Apache Wiki <wi...@apache.org> on 2006/07/12 19:27:33 UTC
[Tapestry Wiki] Update of "SessionPagePersistence" by GregWoolsey
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: dev-unsubscribe@tapestry.apache.org
For additional commands, e-mail: dev-help@tapestry.apache.org