Something that’s very desirable to do in Apache Wicket is create HTML emails using Wicket’s brilliant component-oriented markup.
I’ve been working on this problem on and off for ages — it’s tricky because of teh way that markup rendering is so deeply tied to the requestcycle, which in turn is deeply dependent on the httpservletrequest — with good reason, too. That’s where Wicket gets its autoconfiguring magic from!
So in order to use Wicket to create HTML emails, we need to fake the request/response cycle. I wrote this convenient method that renders a bookmarkable page (pageclass + pageparameters) to a string:
protected String renderPage(Class<? extends Page> pageClass, PageParameters pageParameters) { //get the servlet context WebApplication application = (WebApplication) WebApplication.get(); ServletContext context = application.getServletContext(); //fake a request/response cycle MockHttpSession servletSession = new MockHttpSession(context); servletSession.setTemporary(true); MockHttpServletRequest servletRequest = new MockHttpServletRequest( application, servletSession, context); MockHttpServletResponse servletResponse = new MockHttpServletResponse( servletRequest); //initialize request and response servletRequest.initialize(); servletResponse.initialize(); WebRequest webRequest = new WebRequest(servletRequest); BufferedWebResponse webResponse = new BufferedWebResponse(servletResponse); webResponse.setAjax(true); WebRequestCycle requestCycle = new WebRequestCycle( application, webRequest, webResponse); requestCycle.setRequestTarget(new BookmarkablePageRequestTarget(pageClass, pageParameters)); try { requestCycle.request(); log.warn("Response after request: "+webResponse.toString()); if (requestCycle.wasHandled() == false) { requestCycle.setRequestTarget(new WebErrorCodeResponseTarget( HttpServletResponse.SC_NOT_FOUND)); } requestCycle.detach(); } finally { requestCycle.getResponse().close(); } return webResponse.toString(); }
One other thing that’s desirable to do is change all relative links in the email to absolute URLs — something that Wicket makes super-easy, if you know how. That will be the subject of my next post.
Hi Dan,
thanks for the post, that seems to be exactly what I’m looking for.
Copying the code into my app, I got a compiler error on the line where the WebRequest is created. Using the constructor to ServletWebRequest helped.
Nonetheless, I get only an empty string back, no clue whats going wrong.
I’m using Wicket 1.3.5.
We are also using Wicket in combination with Spring. Wouldn’t it be easier to use Spring + Velocity to generate HTML Emails?
http://www.theserverside.com/tt/blogs/showblog.tss?id=SpringVelocityEmail
Although I would prefer a solution that is more tied to Wicket, the Spring solution seems to be easier to grab and thus more maintainable IMHO.
I never tried it any of the above, but will have to in the next couple of months.
Got it working by replacing requestCycle.request() with requestCycle.getProcessor().respond(requestCycle);
Thanks for sharing!
and by changing
new WebRequest(servletRequest);
to
new ServletWebRequest(servletRequest);
I have a similar problem – something that should be easy to do, and may already be available from the API (I am still usin 1.3.5).
How can one duplicate rendered strings? In other words, I am trying to render once but copy a number of times for better performance – e.g., putting a page navigator both at the top and bottom of the list (the bottom is simply a label generated from copying the rendered top one). I tried using onRendered to copy getResponse.toString() for later reuse, but renderComponent() throws IllegalStateException: page not found – even though I am adding the component to a panel as instructed by Component.renderComponent() – any ideas? Thx
Hey guys – use wicket-test this is the framework for testing but can render panels or entire pages to a string. It does use a fake web application so you might need to hack some things if you require funky web application setups
I have some BookmarkablePageLink in the page I want to render. They are rendering just a part of the url, for instance
http://www.miapp.com/asd/asd/asd
it renders only
/asd/asd/asd
which its wrong because users read it in their email program. How can I instruct BookmarkablePageLink to render the whole url?
thanks in advance
Dan,
I have to send emails from another servlet. In this case, I need a mock application to get it working. I try to build my own without success. Dummy Application says it has not attached a ServletContext. I got it from WicketTester. Any idea how to build mails from a servlet that is not a WicketFilter or wicket servlet?
Hi,
is there a possibility to use this code snippet for components (i.e. MarkupContainer) instead of bookmarkable pages? I didn’t find a way to change this. Maybe someone can help me?
Thanks Andrew Williams for mentioning WicketTester! It’s way easier, shorter and you don’t need any web app context at all. Just do this:
WicketTester tester = new WicketTester();
tester.startPage(YourPage.class);
String s = tester.getServletResponse().getDocument();
regards,
Tim
for 1.5 version ( seen it on wicket forum )
BufferedWebResponse bufferedWebResponse = new BufferedWebResponse(null);
webPage.getRequestCycle().setResponse(bufferedWebResponse);
webPage.render();
return bufferedWebResponse.getText().toString();