One of the first few things I have tackled while creating fabulously40 was stateless pagination. I wanted to keep all the public facing pages stateless to avoid session overhead. Wicket makes pagination brain dead simple at the cost of session use. I wanted to keep the simple programming model yet be completely stateless. Here is my solution to the problem.

Wicket a stateful framework, is actually really good at being stateless.

Example code on how to use it.

update: I would suggest using MixedParamHybridCodingStrategy with the stateless paging navigation to keep links clean.

[code lang=”java”]

StatelessDataView dv;
add(dv = new StatelessDataView(“pics”, getPhotoProvider(), amount, pageParams) {
private static final long serialVersionUID = 1L;

@Override
protected void populateItem(final Item arg0) {
}
});

// call back page class, page paramaters passed, the dataview and 12 pagination links.
add(new StatelessSimplePagingNavigator(“nav”, PhotosPage.class, pageParams, dataView, 12));

[/code]

The dataview

[code lang=”java”]

package com.base.components;

import org.apache.wicket.PageParameters;
import org.apache.wicket.markup.repeater.data.DataView;
import org.apache.wicket.markup.repeater.data.IDataProvider;

public abstract class StatelessDataView extends DataView {
private static final long serialVersionUID = 1L;
private PageParameters pp;

@Override
protected boolean getStatelessHint() {
return true;
}

protected int getPageNumber(final String param) {
String numResult = param;
if(numResult.contains(“.wicket-“)) {
numResult = numResult.substring(0,numResult.indexOf(“.wicket-“));
}
return Integer.valueOf(numResult);
}

public StatelessDataView(final String id, final IDataProvider dataProvider, final PageParameters pp) {
super(id, dataProvider);
this.pp = pp;
if (pp.getString(id) != null) {
int pageNum = getPageNumber(pp.getString(id));
if(pageNum != -1 && pageNum >= 0 && pageNum <= getPageCount()) { setCurrentPage(getPageNumber(pp.getString(id))); } } } public StatelessDataView(final String id, final IDataProvider dataProvider, final int itemsPerPage, final PageParameters pp) { super(id, dataProvider, itemsPerPage); this.pp = pp; if (pp.getString(id) != null) { int pageNum = getPageNumber(pp.getString(id)); if(pageNum != -1 && pageNum >= 0 && pageNum <= getPageCount()) { setCurrentPage(getPageNumber(pp.getString(id))); } } } } [/code] The paging navigator [code lang="java"] package com.base.components; import org.apache.wicket.Component; import org.apache.wicket.PageParameters; import org.apache.wicket.markup.ComponentTag; import org.apache.wicket.markup.html.link.BookmarkablePageLink; import org.apache.wicket.markup.html.link.Link; import org.apache.wicket.markup.html.navigation.paging.IPageable; import org.apache.wicket.markup.html.navigation.paging.IPagingLabelProvider; import org.apache.wicket.markup.html.navigation.paging.PagingNavigation; public class StatelessSimplePagingNavigator extends SimplePagingNavigator { private static final long serialVersionUID = 1L; private Class clazz; private PageParameters pp; private int current_page; private int page_count; private String pageable_id; private String anchor = null; @Override protected boolean getStatelessHint() { return true; } public StatelessSimplePagingNavigator(final String id, final Class clazz, final PageParameters pp, final IPageable pageable, final int viewsize) { this(id, clazz, pp, pageable, viewsize, false); } public StatelessSimplePagingNavigator(final String id, final Class clazz, final PageParameters pp, final IPageable pageable, final int viewsize, final boolean anchorSelf) { super(id, pageable, viewsize, anchorSelf); this.clazz = clazz; this.pp = pp; this.current_page = pageable.getCurrentPage(); this.page_count = pageable.getPageCount(); this.pageable_id = ((Component) pageable).getId(); } public StatelessSimplePagingNavigator(final String id, final Class clazz, final PageParameters pp, final IPageable pageable, final int viewsize, final String anchor) { super(id, pageable, viewsize, false); this.clazz = clazz; this.pp = pp; this.current_page = pageable.getCurrentPage(); this.page_count = pageable.getPageCount(); this.pageable_id = ((Component) pageable).getId(); this.anchor = anchor; } @Override protected void onBeforeRender() { super.onBeforeRender(); addOrReplace(newStatelessPagingNavigationLink("next", pageable_id, current_page, 1)); addOrReplace(newStatelessPagingNavigationLink("prev", pageable_id, current_page, -1)); } @Override protected PagingNavigation newNavigation(final IPageable pageable, final IPagingLabelProvider labelProvider) { PagingNavigation pg = new PagingNavigation("navigation", pageable, labelProvider) { private static final long serialVersionUID = 1L; @Override protected Link newPagingNavigationLink(final String id, final IPageable pageable, final int pageIndex) { Component c = (Component) pageable; // PageParameters p1 = new PageParameters(); // p1.putAll(pp); pp.put(c.getId(), String.valueOf(pageIndex)); BookmarkablePageLink lnk = new BookmarkablePageLink(id, clazz, pp) {
private static final long serialVersionUID = 1L;

@Override
protected void onComponentTag(final ComponentTag arg0) {
super.onComponentTag(arg0);
if (anchor != null) {
if(arg0.getString(“href”) != null) {
String href = arg0.getString(“href”).toString();
String atag = anchor.contains(“#”) ? anchor : “#” + anchor;
arg0.put(“href”, href + atag);
}
}
}

@Override
public boolean isEnabled() {
return (current_page != pageIndex);
}
};
if (isAnchorSelf()) {
lnk.setAnchor(StatelessSimplePagingNavigator.this);
}
return lnk;
}
};
pg.setViewSize(getViewsize());
return pg;
}

@Override
protected Link newPagingNavigationIncrementLink(final String id, final IPageable pageable, final int increment) {
Component c = (Component) pageable;
final int page = Integer.valueOf(pp.getString(c.getId()));
pp.put(c.getId(), String.valueOf(page + increment));
return new BookmarkablePageLink(id, clazz, pp) {
private static final long serialVersionUID = 1L;

@Override
public boolean isVisible() {
return (page + increment) >= 0;
}
};
}

protected Link newStatelessPagingNavigationLink(final String id, final String pageableId, final int currentPage,
final int increment) {
// PageParameters p1 = new PageParameters();
// p1.putAll(pp);
pp.put(pageableId, String.valueOf(currentPage + increment));
return new BookmarkablePageLink(id, clazz, pp) {
private static final long serialVersionUID = 1L;

@Override
public boolean isVisible() {
return (currentPage + increment) < page_count && (currentPage + increment) >= 0;
}
};
}

@Override
protected Link newPagingNavigationLink(final String id, final IPageable pageable, final int pageNumber) {
Component c = (Component) pageable;
// PageParameters p1 = new PageParameters();
// p1.putAll(pp);
pp.put(c.getId(), String.valueOf(pageNumber));
return new BookmarkablePageLink(id, clazz, pp);
}

}

[/code]

Which inherits from

[code lang=”java”]

package com.base.components;

import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.markup.html.navigation.paging.IPageable;
import org.apache.wicket.markup.html.navigation.paging.IPagingLabelProvider;
import org.apache.wicket.markup.html.navigation.paging.PagingNavigation;
import org.apache.wicket.markup.html.navigation.paging.PagingNavigator;

public class SimplePagingNavigator extends PagingNavigator {
private static final long serialVersionUID = 1L;

private int viewsize = 0;
private boolean anchorSelf = false;

public SimplePagingNavigator(final String id, final IPageable pageable, final int viewsize) {
this(id, pageable, viewsize, false);
}

public SimplePagingNavigator(final String id, final IPageable pageable, final int viewsize, final boolean anchorSelf) {
super(id, pageable);
setOutputMarkupId(true);
this.setViewsize(viewsize);
this.setAnchorSelf(anchorSelf);
}

@Override
protected void onBeforeRender() {
if (get(“navigation”) != null) {
remove(“navigation”);
}
if (get(“prev”) != null) {
remove(“prev”);
}
if (get(“next”) != null) {
remove(“next”);
}
super.onBeforeRender();
if (get(“first”) != null) {
remove(“first”);
}
if (get(“last”) != null) {
remove(“last”);
}
if (getViewsize() != 0) {
getPagingNavigation().setViewSize(getViewsize());
}
}

@Override
protected PagingNavigation newNavigation(final IPageable pageable, final IPagingLabelProvider labelProvider) {
PagingNavigation pg = new PagingNavigation(“navigation”, pageable, labelProvider) {
private static final long serialVersionUID = 1L;

@Override
protected Link newPagingNavigationLink(final String id, final IPageable pageable, final int pageIndex) {
Link lnk = (Link) super.newPagingNavigationLink(id, pageable, pageIndex);
if (isAnchorSelf()) {
lnk.setAnchor(SimplePagingNavigator.this);
}
return lnk;
}
};
pg.setViewSize(getViewsize());
return pg;
}

@Override
public boolean isVisible() {
if (getPageable() != null) {
return (getPageable().getPageCount() > 1);
}
return true;
}

public void setAnchorSelf(final boolean anchorSelf) {
this.anchorSelf = anchorSelf;
}

public boolean isAnchorSelf() {
return anchorSelf;
}

public void setViewsize(final int viewsize) {
this.viewsize = viewsize;
}

public int getViewsize() {
return viewsize;
}

}

[/code]

[code lang=”html”]


Previous

5

Next

[/code]

3 comments so far

  1. Roman says:

    This is great, I’ll use it as base for my stateless naviagtion.

    Btw, as of Wicket 1.4.0 “super.onBeforeRender();” should move to the bottom of onBeforeRender(). Else it will throw an exception.

  2. victori says:

    I am still on 1.4.0-beta7 and it works correctly as is.

  3. decebal says:

    Can I use a GridView instead DataView?

Leave a Reply