Wicket: how to render page programmatically and get result as string? - java

I'm in the process of converting an app to use i18n/l10n on all its pages. I'm very happy with Wicket's support for this, and it's going well so far. The one tricky part I've run into is the following:
We have a text file that is used as an HTML template to send email when users perform a certain operation on the site. When the user clicks a particular link, I read in this template manually, do some text substitutions like "Dear $USERNAME", and send the result as an HTML email to the user.
In order to support the 10 or so languages we're targeting, I'll either have to maintain 10 copies of this template file, or figure out a way to render this "page" using Wicket's built-in i18n support, grab the result as a string, and then send it.
Hence my question: how can I "render" a Wicket page programmatically and get the result as a string?
I'd prefer to avoid hacks like using HttpClient if at all possible; HttpClient won't have the user's Locale, won't be automatically logged in as the user, etc., so that doesn't seem like a good solution to me.

Two article regarding to this:
Render a Wicket page to a string for HTML email
Rendering Panel to a String
Currently the only other approach was using WicketTester for that, but I do not remember details how to do that.

If you just want the raw code, here it is: (This is practically the same as the solution described in the article.)
//I assumed that you want to use the current user's session for rendering. If this isn't the case, you'll have to use a mock session
MockHttpServletRequest mockReq = new MockHttpServletRequest( WebApplication.get(), ((WebRequest)getRequest()).getHttpServletRequest().getSession(), WebApplication.get().getServletContext() );
MockHttpServletResponse mockRes = new MockHttpServletResponse( mockReq );
WebResponse res = new WebResponse(mockRes);
ServletWebRequest req = new ServletWebRequest( mockReq );
RequestCycle cycle = new WebRequestCycle( WebApplication.get(), req, res );
PageParameters pp = new PageParameters();
//add page parameters here
//Your email page should really be a bookmarkable page, but if it isn't, you can replace the request target with something that better suits your case
cycle.request( new BookmarkablePageRequestTarget( EmailPage.class, pp ));
System.out.println( mockRes.getDocument() );

For newer Wicket versions: 6.7.0 came with a new ComponentRenderer precisely for this purpose!

Related

Is there any method to create radio button in com.ibm.cics.server

The java API for CICS is here. Does anyone know if there any method to put a couple of radio buttons to a web form using this API?
Here's my code to create radio button
HttpRequest req = HttpRequest.getHttpRequestInstance();
String msg = "ZEUSBANK ANTI-FRAUD CHECK BY SHE0008.<br> "
+ "When investigation is complete. Tick the check box and submit.<br>";
String template = "<form><input type=\"radio\"> YES<br><input type=\"radio\"> NO<br></form>";
HttpResponse resp = new HttpResponse();
Document doc = new Document();
doc.createText(msg);
doc.appendFromTemplate(template);
resp.setMediaType("text/plain");
resp.sendDocument(doc, (short)200, "OK", ASCII);
But when I run it on a browser, it print plain text and doesn't convert html tag.
Fixed it, I just change media type from text/plain to text/html and it works.
As you've already discovered, you needed to send the request with the text/html content type.
If you're planning to do more Java web-based work through CICS Java, you might want to investigate the embedded WebSphere Liberty. It adds support for Java EE features, which includes JSF, JSP and Servlets, which can make web development in Java a lot easier.
Tri,
I haven't used CICS for 15 years, so I doubt I'm an expert anymore. But looking quickly at the API, it seems like all the presentation logic would be in your regular Java code. You would then format appropriate messages and invoke the CICS API to update the server & get a response.
There doesn't seem to be any 'BMS-related' methods at all (which is a good thing).
The only 'field' method I see is com.ibm.cics.server.FormField but that only has get() methods, not set().
Are you just starting with Java CICS, or are you just stuck on this particular issue? If you have some sample code of what you are trying, post it so we can see if anyone has any ideas.
HTH, Jim

CommandExecuteIn Background throws a "Not an (encodable) value" error

I am currently trying to implement file exports in background so that the user can do some actions while the file is downloading.
I used the apache isis CommandExexuteIn:Background action attribute. However, I got an error
"Not an (encodable) value", this is an error thrown by the ScalarValueRenderer class.
This is how my method looks like:
#Action(semantics = SemanticsOf.SAFE,
command = CommandReification.ENABLED)
commandExecuteIn = CommandExecuteIn.BACKGROUND)
public Blob exportViewAsPdf() {
final Contact contact = this;
final String filename = this.businessName + " Contact Details";
final Map<String, Object> parameters = new HashMap<>();
parameters.put("contact", contact);
final String template = templateLoader.buildFromTemplate(Contact.class, "ContactViewTemplate", parameters);
return pdfExporter.exportAsPdf(filename, template);
}
I think the error has something to do with the command not actually invoking the action but returns the persisted background command.
This implementation actually worked on the method where there is no return type. Did I miss something? Or is there a way to implement background command and get the expected results?
interesting use case, but it's not one I anticipated when that part of the framework was implemented, so I'm not surprised it doesn't work. Obviously the error message you are getting here is pretty obscure, so I've raised a
JIRA ticket to see if we could at least improve that.
I'm interested to know in what user experience you think the framework should provide here?
In the Estatio application that we work on (that has driven out many of the features added to the framework over the last few years) we have a somewhat similar requirement to obtain PDFs from a reporting server (which takes 5 to 10 seconds) and then download them. This is for all the tenants in a shopping centre, so there could be 5 to 50 of these to generate in a single go. The design we went with was to move the rendering into a background command (similar to the templateLoader.buildFromTemplate(...) and pdfExporter.exportAsPdf(...) method calls in your code fragment, and to capture the output as a Document, via the document module. We then use the pdfbox addon to stitch all the document PDFs together as a single downloadable PDF for printing.
Hopefully that gives you some ideas of a different way to support your use case
Thx
Dan

Passing server side data to JavaScript - Scriplet or AJAX call - which is better?

In a property file at server side I'm maintaining a comma separated list of words.
words.for.js=some,comma,separated,words
I want to create a JavaScript array out of these words.
var words = [some,comma,separated,words];
I thought of two options
1.Using a JSP scriplet, create a global variable
<%
out.print("<script> var words = [");
out.print( PropertyLoader.getAsCommaSeparated("words.for.js") );
out.print(" ] </script>");
%>
2.Expose a service/ action (i.e. /getWords.do ) and call this using AJAX and construct the array.
I'm not sure which is better of the two and appreciate your thoughts here.
Or is there any better way to do this?
Thanks.
EDIT:
This is also a comparison of global JS variable (in case of option 1) vs additional http request (in case of option 2) - which one is worse. I would like to know your thoughts from this perspective as well.
I prefer embedding the server-side data within your JSP's markup - #1. It is faster and doesn't require a callback.
For me, it is all about the nature of the data. In your case, the data in that properties file seems unlikely to change without a server reboot. So, saving an additional network callback and embedding it into the markup feels appropriate for a global variable.
If you were dealing with some sort of dynamic data, an ajax callback onload would be better.
Exposing through an http request would be the most elegant option and would allow for refreshes. You are already counting on the browser having javascript, anyway.
Also, if the value is not dynamic, why not just serve a static javascript file with the array in the first place?
Why don't you use JSON? since all you need is to send some string to front end. Something like this:
String [] s = {"test","test1"};
JSONArray array = new JSONArray();
array.put(s);
request.setAttribute("test", array);
JSP
<script>
var array='${test}'
</script>
Update
You should place your configurations in servlet context as it's accessed throughout your web application including in jsp files & also will not change until you restart your application.
ServletContext context = getServletContext();
Properties prop= new Properties();
prop.load(context.getResourceAsStream("/WEB-INF/filename.properties"));
String[]configArray= prop.get("words.for.js").toString().split(",");
context.setAttribute("configArray", myConfigArray);
or if your using ServletContextListener
ServletContext ctx = servletContextEvent.getServletContext();
ctx.setAttribute("configArray", myConfigArray);

Make gwt website crawlable without hash symbol?

In GWT we need to use # in a URL to navigate from one page to another i.e for creating history for eg. www.abc.com/#questions/10245857 but due to which I am facing a problem in sharing the url. Google scrappers are reading the url only before # i.e. www.abc.com.
Now I want to remove # from my url and want to keep it straight as www.abc.com/question/10245857.
I am unable to do so. How can I do this?
When user navigates the app I use the hash urls and History object (as
to not reload the pages). However sometimes it's nice/needed to have a
pretty URL (e.g. for sharing, showing in public, etc..) so I would like to know how to
provide the pretty URL of the same page.
Note:
We have to do this to make our webpages url crawlable and to link the website with outside world.
There are 3 issues here, and each can be solved:
The URL should appear prettier to the user
Going directly to the pretty URL should work.
WebCrawlers should be able to get the content
These may all seem like the same issue, but they are quite distinct in this context.
Display Pretty URLs
Can be done with a small javascript file which uses HTML5 state methods. You can see a simple demo here, with source here. This makes all changes to "#" appear without the "#" (on modern browsers).
Relevent code from fiddle:
var stateObj = {locationHash: hash};
history.replaceState(stateObj, "Page Title", baseURL + hash.substring(1));
Repsond to Pretty URLs
This is relatively simple, as long as you have a listener in GWT to load based on the "#" at page load already. You can just throw up a simple re-direct servlet which reinserts the "#" mark where it belongs when requests come in.
For a servlet, listening for the pretty URL:
if(request.getPathInfo()!=null && request.getPathInfo().length()>1){
response.sendRedirect("#" + request.getPathInfo());
return;
}
Alternatively, you can serve up your GWT app directly from this servlet, and initialize it with parameters from the URL, but there's a bit of relative-path bookkeeping to be aware of.
WebCrawlers
This is the trickiest one. Basically you can't get around having static(ish) pages here. That's not too hard if there are a finite set of simple states that you're indexing. One simple scheme is to have a separate servlet which returns the raw content you normally fetch with GWT, in minimal formatted HTML. This servlet can have a different URL pattern like "/indexing/". These wouldn't be meant for humans, just for the webcrawlers. You can attach a simple javascript in the <head> to redirect users to the pretty url once the page loads.
Here's an example for the doGet method of such a servlet:
response.setContentType("text/html;charset=UTF-8");
response.setStatus(200);
pw = response.getWriter();
pw.println("<html>");
pw.println("<head><script>");
pw.println("window.location.href='http://www.example.com/#"
+ request.getPathInfo() + "';");
pw.println("</script></head>");
pw.println("<body>");
pw.println(getRawPageContent(request.getPathInfo()));
pw.println("</body>");
pw.println("</html>");
pw.flush();
pw.close();
return;
You should then just have some links to these indexing pages hidden somewhere on your main app URL (or behind a link on your main app URL).

HtmlUnit to take snapshot of Ajax applications

I create a basic GWT (Google Web Toolkit) Ajax application, and now I'm trying to create snapshots to the crawlers read the page.
I create a Servlet to response the crawlers, using HtmlUnit.
My application runs perfectly when I'm on a browser. But when in HtmlUnit, it throws a lot of errors about the special chars I have in the HTML. But these chars are content, and I wouldn't like to replace it with the special codes, once it's currently working, just because of the HtmlUnit. (at least I should check before if I'm using HtmlUnit correctly )
I think HtmlUnit should read the charset information of the page and render it as a browser, once it's the objective of the project I think.
I haven't found good information about this problem. Is this an HtmlUnit limitation? Do I need to change all the content of my website to use this java library to take snapshots?
Here's my code:
if ((queryString != null) && (queryString.contains("_escaped_fragment_"))) {
// ok its the crawler
// rewrite the URL back to the original #! version
// remember to unescape any %XX characters
url = URLDecoder.decode(url, "UTF-8");
String ajaxURL = url.replace("?_escaped_fragment_=", "#!");
final WebClient webClient = new WebClient(BrowserVersion.FIREFOX_24);
HtmlPage page = webClient.getPage(ajaxURL);
// important! Give the headless browser enough time to execute JavaScript
// The exact time to wait may depend on your application.
webClient.waitForBackgroundJavaScript(3000);
// return the snapshot
response.getWriter().write(page.asXml());
The problem was XML confliting with the HTML. #ColinAlworth comments helped me.
I followed Google example, and there was not working.
To it work, you need to remove XML tags and let just the HTML be responded, changing the line:
// return the snapshot
response.getWriter().write(page.asXml());
to
response.getWriter().write(page.asXml().replaceFirst("<\\?.*>",""));
Now it's rendering.
But although it is being rendered, the CSS is ot working, and the DOM is not updated (GWT updates page title when page opens). HTMLUnit throwed a lot of errors about CSS, and I'm using twitter bootstrap without any changes. Apparently, HtmlUnit project have a lot of bugs, good for small tests, but not to parse complex (or even simple) HTMLs.

Categories

Resources