Here's a proof of concept I just wipped up. It seems to work just
fine. The only problem is that turning everything into a post may be a
bit tricky and is probably where all the work is.
-Phil
On 6/30/05, Phil Kulak <[EMAIL PROTECTED]> wrote:
> There has been some mention of this, but I've never heard of the
> details. Is this something that's planned? I've been thinking about
> it, and it may not actually be that bad. All you'd have to do is
> serialize all the models under a page into a base64 string (or
> equivelent), then plunk them all back into a fresh component tree on
> the next request: pretty much how .NET and JSF do it. That would solve
> all the back-button issues, you could get a totally stateless
> webserver AND have the killer wicket component model. Anyway, just
> some thoughs. I'm going to play around with it and probably figure out
> that it's a lot more complicated then that in the process. :)
>
package com.apropobenefits.wicket;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import org.apache.commons.codec.binary.Base64;
import wicket.Component;
import wicket.Page;
import wicket.WicketRuntimeException;
import wicket.Component.IVisitor;
import wicket.model.IModel;
public class PageState {
private Map<String, IModel> models;
/**
* Creates a new PageState from the given page.
*/
public PageState(Page page) {
models = new HashMap<String, IModel>();
// Add the page model.
IModel pageModel = page.getModel();
if (pageModel != null) {
models.put("", pageModel);
}
page.visitChildren(new IVisitor() {
public Object component(Component component) {
IModel model = component.getModel();
if (model != null) {
models.put(component.getPageRelativePath(), model);
}
return CONTINUE_TRAVERSAL;
}
});
}
/**
* Creates a new PageState from a string.
*/
public PageState(String serializedString) {
ByteArrayInputStream bais = null;
GZIPInputStream unzipper = null;
ObjectInputStream in = null;
try {
bais = new ByteArrayInputStream(
Base64.decodeBase64(serializedString.getBytes()));
unzipper = new GZIPInputStream(bais);
in = new ObjectInputStream(unzipper);
models = (Map<String, IModel>) in.readObject();
in.close();
} catch (Exception e) {
throw new WicketRuntimeException(e.getMessage());
}
}
/**
* Returns a base64 string that can be used to store the page state
* on the client.
*/
public String getString() {
ByteArrayOutputStream baos = null;
GZIPOutputStream zipper = null;
ObjectOutputStream out = null;
// Detach all the models.
for (IModel model: models.values()) {
model.detach();
}
try {
baos = new ByteArrayOutputStream();
zipper = new GZIPOutputStream(baos);
out = new ObjectOutputStream(zipper);
out.writeObject(models);
out.close();
} catch (Exception e) {
throw new WicketRuntimeException(e.getMessage());
}
return new String(Base64.encodeBase64Chunked(baos.toByteArray()));
}
/**
* Returns the page to the state represented by this page state.
*/
public void populatePage(Page page) {
if (models.containsKey("")) {
page.setModel(models.get(""));
}
page.visitChildren(new IVisitor() {
public Object component(Component component) {
String path = component.getPageRelativePath();
if (models.containsKey(path)) {
component.setModel(models.get(path));
}
return CONTINUE_TRAVERSAL;
}
});
}
}