I'm working on upgrading our existing Wicket webapp to 1.5 and have hit a snag in our renderPage function that we use to render our HTML emails.
Previously we used the code referenced/listed in this StackOverflow question and this (currently broken but maybe fixed later) link but that code no longer works as a lot of those classes don't exist in 1.5.
I also found this email thread but it is light on the details and I don't know how to create the WebPage from my pageClass and parameters.
http://apache-wicket.1842946.n4.nabble.com/Render-WebPage-to-String-in-Wicket-1-5-td3622130.html
Here is my code:
// Renders a page under a temporary request cycle in order to get the rendered markup
public static 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 ServletWebRequest(servletRequest);
BufferedWebResponse webResponse = new BufferedWebResponse(servletResponse);
webResponse.setAjax(true);
WebRequestCycle requestCycle = new WebRequestCycle(application, webRequest, webResponse);
requestCycle.setRequestTarget(new BookmarkablePageRequestTarget(pageClass, pageParameters));
try
{
requestCycle.getProcessor().respond(requestCycle);
if (requestCycle.wasHandled() == false)
{
requestCycle.setRequestTarget(new WebErrorCodeResponseTarget(HttpServletResponse.SC_NOT_FOUND));
}
}
finally
{
requestCycle.detach();
requestCycle.getResponse().close();
}
return webResponse.toString();
}
Specifically, the code breaks because the WebRequestCycle and BookmarkablePageRequestTarget classes no longer exist. I feel like I should be able to use the StringResponse class some how but I'm missing the link that would help me trigger a render on that response.
Any help would be appreciated. Thanks.
My Final Solution
Using the example that I was directed to by the answer below I ended up with the following code. I'm pasting it here as well so that if that link disappears or is changed with a future version of Wicket then people from the future will still be able to get the answer they need.
I ended up passing in a PageProvider because in some cases I needed to pass in an instantiated Page and in others a pageClass + parameters.
public static String renderPage(final PageProvider pageProvider)
{
final RenderPageRequestHandler handler = new RenderPageRequestHandler(pageProvider, RedirectPolicy.NEVER_REDIRECT);
final PageRenderer pageRenderer = Application.get().getPageRendererProvider().get(handler);
RequestCycle requestCycle = RequestCycle.get();
final Response oldResponse = requestCycle.getResponse();
BufferedWebResponse tempResponse = new BufferedWebResponse(null);
try
{
requestCycle.setResponse(tempResponse);
pageRenderer.respond(requestCycle);
}
finally
{
requestCycle.setResponse(oldResponse);
}
return tempResponse.getText().toString();
}
Check the source code of http://www.wicket-library.com/wicket-examples/mailtemplate/ example.
Related
I am building a JAVA HTTP Adapter, I am authenticating the user in UserAuthenticationSecurityCheck class using the following method
#Override
protected AuthenticatedUser createUser() {
return new AuthenticatedUser(userId, logonId, this.getName(), attributes);
}
#Override
protected boolean validateCredentials(Map<String, Object> credentials) {
return false;
}
After this control goes to android app then they call the REST API called /updateClientRegistrtion which will update the ClientRegistrationData
#GET
public Response updateClientRegistartion(#Context HttpServletRequest request) {
AuthenticatedUser authUser = securityContext.getAuthenticatedUser();
Map<String, Object> attributes = authUser.getAttributes();
ClientData clientData = securityContext.getClientRegistrationData();
clientData.getProtectedAttributes().put(some parameter);
if (clientData.getClientId() != null) {
securityContext.storeClientRegistrationData(clientData);
}
But this code is giving me error like
Exception Message :
409; headers=[ MFP-Conflict=Concurrency failure]; body={}
Is there any solution to this problem? Can someone please help me with this.
Tutorial followed : http://mobilefirstplatform.ibmcloud.com/tutorials/en/foundation/8.0/authentication-and-security/user-authentication/security-check/
409; headers=[ MFP-Conflict=Concurrency failure]; body={}
results when concurrent requests try to store attributes into the same row or the data in the row being modified by another request before it was updated.
This could be from the request being fired more than once ( in close proximity).Another possibility is that while one request was working on the data in memory, another had already modified and updated it.
The code should still work without the line:
securityContext.storeClientRegistrationData(clientData);
Try that out.
Alternatively, put a try-catch around the
storeClientRegistrationData(clientData)
and retry in the catch block.
I am upgrading tapestry from 5.2.4 to 5.3.8 and am stuck at re-implementing the URL re-writing part.
In my application a user account can have multiple data stores. User can have same page of different stores active at the same time. Hence I need to put the storeId in page links and event links URLs. So What is done is as follows.
I register MyLinkTransformerClass in AppModule as follows.
#Contribute(PageRenderLinkTransformer.class)
#Primary
public static void provideURLRewriting( OrderedConfiguration<PageRenderLinkTransformer> configuration){
configuration.addInstance(
"Faces", MyLinkTransformer.class);
}
Following is the MyLinkTransformer class which implements PageRenderLinkTransformer
public PageRenderRequestParameters decodePageRenderRequest(
Request request) {
// for incoming requests - remove the store id from URL and
// save into Request as an attribute
String path = request.getPath();
if (path.equals("/")) {
// Redirect to accounts page
return new PageRenderRequestParameters("account", new EmptyEventContext(), false);
}
else {
String start = path.split("/")[1];
if (!ignoredRewriteSet.contains(start) && !start.startsWith("account")) {
String storePath = path.substring(1).substring(path.indexOf("/"));
int idx = storePath.indexOf("/");
if (idx < 0) idx = storePath.length();
String storeId = storePath.substring(0, idx).trim();
RequestHelper.setStoreId(request, storeId);
EventContext urlEventContext = new URLEventContext(contextValueEncoder, new String[]{storeId});
EventContext arrayEventContext = new ArrayEventContext(typeCoercer, "foo");
return new PageRenderRequestParameters(storePath.substring(idx), arrayEventContext, false);
//return new PageRenderRequestParameters(storePath.substring(idx), new EmptyEventContext(), false);
}
}
return null;
}
public Link transformPageRenderLink(
Link defaultLink,
PageRenderRequestParameters parameters) {
// for outgoing requests- This is where I want to access the store Id
// which is stored in Request class of Tapestry as an attribute and
// add it to the URL
return null;
}
So, the idea is to remove storeId from URL in decodePageRenderRequest method and save it in the Request class of Tapestry as an attribute. And while creating outgoing URLs of page link and event link, I want to access the storeId which was saved in Request and inject it to the URL which will be rendered in method transformPageRenderLink.
But I don't know how to pass parameters to transformPageRenderLink method or access Request instance there.
I am following http://blog.tapestry5.de/index.php/2010/09/06/new-url-rewriting-api/ example.
I am new to URL Rewriting, any help with this will be appreciated.
You will probably be interested in the ModeComponentEventLinkEncoder here. It removes a "mode" from the URL and puts it onto the Environment before passing it on to the normal tapestry URL processing.
It's a two way process so the "mode" is included in any links generated on the page.
Note: This is applied as a decorator here
I try my best to describe my situation.
My wicket site contains list wicket component, where every list element has another list. Each element in lowest level list has ajax wicket link to download some file. All this works fine. I used to this AjaxBehaviour. Method startDownload of this behaviour is invoked within link onClick method.
public void startDownload(AjaxRequestTarget target) {
target.appendJavaScript("window.location.href='" + getCallbackUrl() +"'");
}
Method onRequest of this behaviour is:
#Override
public void onRequest() {
IRequestHandler fileTarget = new IRequestHandler() {
#Override
public void respond(IRequestCycle requestCycle) {
if (null != file) {
try {
FileInputStream inputStream = new FileInputStream(file);
WebResponse resp = (WebResponse) requestCycle.getResponse();
resp.setAttachmentHeader(fileName);
String contentType = FileUtils.getFileType(fileName);
if (contentType != null) {
resp.setContentType(contentType);
}
resp.setHeader("Pragma", "anytextexeptno-cache");
resp.setHeader("Cache-Control", "max-age=0");
Streams.copy(inputStream, requestCycle.getResponse().getOutputStream());
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
}
Now i need to reload model and refresh some components in the page after download file action. I tried to add entire page to the AjaxRequestTarget in method onclick, after code invoked startDownload method. Reload page works fine but window with file to download doesn`t show.
I think that i have to do reload page in other, separate request (maybe i'm mistaken? ), because in this request i call 'window.location.href=....', but i don`t know how i can to enforce second request to reload page.
Does have someone some ideas what I do wrong ? And how can I resolve my problem ?
Seems you need something like this:
https://cwiki.apache.org/confluence/display/WICKET/AJAX+update+and+file+download+in+one+blow
It seems that my implementation is simmilar to this from cwiki.apache.org website. In onRequest method i used getComponent().getRequestCycle().scheduleRequestHandlerAfterCurrent(handler), and despite of this doesn`t work.
Is possible that reason of this is component, which cause request is added to target (because i add to target entire page and component - ajaxLink in this example, is child of this page)
I am developing my first project with Tapestry and I am about to finish, except for the images..
What do I want? I just need to display an image outside my application, example: /home/app/images/image.jpg
What did I try? I have been "googling" and reading Tapestry5 forums, I found this: http://wiki.apache.org/tapestry/Tapestry5HowToStreamAnExistingBinaryFile
I followed the steps, creating classes but I need to display the image embed on another page (so I can't use ImagePage), I tried this:
On page java class
public StreamResponse getImage() {
InputStream input = DetallesMultimedia.class
.getResourceAsStream("/home/santi/Escritorio/evolution-of-mario.jpg"); //On application, i will retrieve this from DB
return new JPEGInline(input,"hellow");
}
On page template
...
<img src="${image}" alt:image/>
...
or
...
${image}
...
Obviusly, this didn't work and I really don't know how can I do it. I read about loading the image on an event (returning the OutputStream on that event, as it's said in the HowTo linked above) but my english is so bad (I am sure you already noticed) and I don't understand well how can I do that.
Could you help me please?
Thanks you all.
I've never seen the examples as on the wiki page. Below some code on how to load an image on the classpath though using a StreamResponse.
#Inject
private ComponentResources resources;
#OnEvent(value = "GET_IMAGE_STREAM_EVENT")
private Object getProfilePic() throws Exception {
InputStream openStream = DetallesMultimedia.class.getResourceAsStream("/home/santi/Escritorio/evolution-of-mario.jpg");
byte[] imageBytes = IOUtils.toByteArray(openStream);
final ByteArrayInputStream output = new ByteArrayInputStream(imageBytes);
final StreamResponse response = new StreamResponse() {
public String getContentType() {
"image/jpegOrPngOrGif";
}
public InputStream getStream() throws IOException {
return output;
}
public void prepareResponse(Response response) {
// add response headers if you need to here
}
};
return response;
}
public String getPicUrl() throws Exception {
return resources.createFormEventLink("GET_IMAGE_STREAM_EVENT");
}
In your template:
<img src="${picUrl}"/>
I have a GWT based page that I would like to create an HTML snapshot for it using HtmlUnit.
The page loads using Ajax/JavaScript information on a product, so for about 1 second there is a Loading... message and then the content appears.
The problem is that HtmlUnit doesn't seem to capture the information and all I'm getting is the "Loading..." span.
Below is an experimental code with HtmlUnit where I try to give it enough time to wait for the loading of the data but it doesn't seem to change anything and I am still unable to capture the data loaded by the GWT javascript.
WebClient webClient = new WebClient();
webClient.setJavaScriptEnabled(true);
webClient.setThrowExceptionOnScriptError(false);
webClient.setAjaxController(new NicelyResynchronizingAjaxController());
WebRequest request = new WebRequest(new URL("<my_url>"));
HtmlPage page = webClient.getPage(request);
int i = webClient.waitForBackgroundJavaScript(1000);
while (i > 0)
{
i = webClient.waitForBackgroundJavaScript(1000);
if (i == 0)
{
break;
}
synchronized (page)
{
System.out.println("wait");
page.wait(500);
}
}
webClient.getAjaxController().processSynchron(page, request, false);
System.out.println(page.asXml());
Any ideas...?
Thank you for responding.
I actually should have reported this sooner that I have found the solution myself.
Apparently when initialising WebClient with FF:
WebClient webClient = new WebClient(BrowserVersion.FIREFOX_3_6);
It seem to be working.
When initialising WebClient with the default constructor it uses IE7 by default and I guess FF has better support for Ajax and is the recommended emulator to use.
I believe by default NicelyResynchronizingAjaxController will only resynchronize AJAX calls that were caused by a user action, by tracking which thread it originated from. Perhaps the GWT generated JavaScript is being called by some other thread which NicelyResynchronizingAjaxController does not want to wait for.
Try declaring your own AjaxController to synchronize with everything regardless of originating thread:
webClient.setAjaxController(new AjaxController(){
#Override
public boolean processSynchron(HtmlPage page, WebRequest request, boolean async)
{
return true;
}
});
As documentation states, waitForBackgroundJavaScript is experimental:
Experimental API: May be changed in next release and may not yet work perfectly!
The next approach has always worked for me, regardless of the BrowserVersion used:
int tries = 5; // Amount of tries to avoid infinite loop
while (tries > 0 && aCondition) {
tries--;
synchronized(page) {
page.wait(2000); // How often to check
}
}
Note aCondition is whatever you're checking for. EG:
page.getElementById("loading-text-element").asText().equals("Loading...")
None of the so far provided solutions worked for me. I ended up with Dan Alvizu's solution + my own hack:
private WebClient webClient = new WebClient();
public void scrapPage() {
makeWebClientWaitThroughJavaScriptLoadings();
HtmlPage page = login();
//do something that causes JavaScript loading
waitOutLoading(page);
}
private void makeWebClientWaitThroughJavaScriptLoadings() {
webClient.setAjaxController(new AjaxController(){
#Override
public boolean processSynchron(HtmlPage page, WebRequest request, boolean async)
{
return true;
}
});
}
private void waitOutLoading(HtmlPage page) {
while(page.asText().contains("Please wait while loading!")){
webClient.waitForBackgroundJavaScript(100);
}
}
Needless to say, "Please wait while loading!" should be replaced with whatever text is shown while your page is loading. If there is no text, maybe there is a way to check for existence of some gif (if that is used). Of course, you could simply provide a big enough milliseconds value if you're feeling adventurous.