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.

StatelessDataView<Photo> dv;
add(dv = new StatelessDataView<Photo>("pics", getPhotoProvider(), amount, pageParams) {
                        private static final long serialVersionUID = 1L;

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

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

The dataview

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<T> extends DataView<T> {
        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)));
                        }
                }
        }

}

The paging navigator

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<Object> lnk = new BookmarkablePageLink<Object>(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<Object> 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<Object>(id, clazz, pp) {
                        private static final long serialVersionUID = 1L;

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

        protected Link<Object> 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<Object>(id, clazz, pp) {
                        private static final long serialVersionUID = 1L;

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

        @Override
        protected Link<Object> 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);
        }

}

Which inherits from

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;
        }

}

<wicket:panel>
        <a wicket:id="prev">Previous</a>
    <span wicket:id="navigation">
                  <a wicket:id="pageLink" href="#"><span wicket:id="pageNumber">5</span></a>
    </span>
    <a wicket:id="next">Next</a>
  </wicket:panel>