Generate a download or show an error message in Wicket - java

I'm using the following code to dynamically generate a download in Wicket, using the ResourceLink approach (since the download is not a static file, it needs to be generated on the fly, and I was told this was the correct approach):
IResource res = new AbstractResource() {
#Override
protected ResourceResponse newResourceResponse(Attributes attributes) {
ResourceResponse resourceResponse = new ResourceResponse();
resourceResponse.setContentType("application/pdf");
resourceResponse.setFileName("output.pdf");
resourceResponse.setContentDisposition(ContentDisposition.ATTACHMENT);
resourceResponse.setWriteCallback(new WriteCallback() {
#Override
public void writeData(Attributes attributes) throws IOException {
OutputStream outputStream = attributes.getResponse().getOutputStream();
try {
outputStream.write(generateDocument());
} catch (Exception e) {
//Generation failed... Here I'd like to either show a popup message or alter the current page to show an error somewhere in the page
}
}
});
return resourceResponse;
}
};
ResourceLink<Void> resLink = new ResourceLink<Void>("resLink", res);
myForm.add(resLink);
The comment in the code above shows where I'm having trouble. If the generation of the download fails (which can happen, if certain conditions are not met) I'd like to show an error message, either by showing a popup or altering the page to show some error text (but in either case I want to avoid leaving/reloading the entire page)
Is this possible?

Here's the link with the answer:
https://cwiki.apache.org/confluence/display/WICKET/AJAX+update+and+file+download+in+one+blow
Don't forger to use a try/catch with an error(e.getMessage()) inside the catch and a target.add(feedbackPanel) after catching the error.

I am not sure this is possible because you need to use non-Ajax request to be able to download as ATTACHMENT. But since it is non-Ajax request you will need to either reload the current page or redirect to another page in case of an error.

Related

Wicket trigger request after another request

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)

RequestDispatcher.include is working only once

I am trying to output the rendering of a JSP page using RequestDispatcher.include() in the following method:
public static String readTemplate(HttpServletRequest request, HttpServletResponse response, String template) {
HttpServletResponseWrapper responseWrapper = new HttpServletResponseWrapper(response) {
private final StringWriter sw = new StringWriter();
#Override
public PrintWriter getWriter() throws IOException {
return new PrintWriter(sw);
}
#Override
public String toString() {
return sw.toString();
}
};
String templateFile = "/templates/" + template + ".jsp";
logger.log(Level.INFO, "Reading template {0} ...", templateFile);
try {
request.getRequestDispatcher(templateFile).include(request, responseWrapper);
} catch (ServletException | IOException | IllegalStateException e) {
logger.log(Level.SEVERE, e.getMessage());
}
logger.log(Level.INFO, "Completed reading template {0}", templateFile);
// retrieve HTML from response
return responseWrapper.toString();
}
The method is part of a servlet I am running with Tomcat8. This works perfectly the first time, but hangs at the include call the second run (i.e. if I click refresh on the browser).
I have already verified the dispatcher is not null.
This is what I can see from the catalina.log (cleaned for your review)
First run:
26-Feb-2015 17:41:17.921 INFO [http-nio-8081-exec-2] ism.Reports.readTemplate Reading template /templates/INCIDENT_REPORT.jsp ...
26-Feb-2015 17:41:18.046 INFO [http-nio-8081-exec-2] ism.Reports.readTemplate Completed reading template /templates/INCIDENT_REPORT.jsp
Second run (response never returns, i.e. browser always loading page):
26-Feb-2015 17:41:26.327 INFO [http-nio-8081-exec-8] ism.Reports.readTemplate Reading template /templates/INCIDENT_REPORT.jsp ...
This does not change until I reboot Tomcat.
Can someone explain what am I doing wrong or at least how to debug this? Thanks!
EDIT 1: Forgot to say the method is static, but I also tried making it not static didn't make any difference
The code above is working, I realized where the issue was. The included JSP page was opening many MySQL connections but only one was closed. Hence the second request was waiting for the MYSQL resources to be freed before performing the task. I am very sorry I didn't notice this until now, and I didn't even mention MySQL connections in the first place. I guess not receiving replies here lead me to find the solution on the JSP file itself.

Accessing uploaded file in Apache Tapestry page

I'm using Apache Tapestry v5.3.7 and I already use the normal Tapestry upload component in a form. For a better user experience I try now to integrate Dropzone.js in a normal Tapestry page without any form. The JavaScript integration works fine. The uploaded file data are transferred to my server with a post request and I can access the request with all of its parameters.
My question is now how can I access the binary data of the uploaded file (maybe as InputStream) to save them in my system? I already injected the http request but getInputStream returns a empty stream.
Thanks for any suggestions
/** Code snippet of page java part */
...
#Inject
protected HttpServletRequest _request;
public void onActivate (String rowId) {
String fileName=_request.getParameter("file");
try {
InputStream is=_request.getInputStream();
// if I do read from is it returns -1
// :-(
doSomeSaveStuff(is); // dummy code
}
catch(Exception e) {
e.printStackTrace();
}
}
...
Here's one way to do it:
In template:
<t:form t:id="testForm" class="dropzone">
</t:form>
In page.java
#Inject
MultipartDecoder multipartDecoder;
#Component(id = "testForm")
private Form testForm;
#Inject
RequestGlobals requestGlobals;
void onSubmitFromTestForm() throws ManagerException {
System.out.println("test form invoked");
HttpServletRequest r = requestGlobals.getHTTPServletRequest();
UploadedFile u = multipartDecoder.getFileUpload("file");
The uploaded file contains what you uploaded and you can work with it the way you want.
Note: the HttpServletRequest::getParameterMap() , told me that the handle to to the file is called file which is how I know that passing file to getFileUpload makes the decoder correctly parse the multipart/post

One API to handle adding and updating files

I'm using SVNKIT 1.8 with SVN 1.8.5 and the SVN protocol to attempt to add files in bulk to my SVN repository. I would like to have one method for adding and updating files and the below code successfully handles both when using the FILE protocol since the editor.addFile(file, null, -1) throws an SVNException. When I switch to the SVN protocol (desired protocol), the editor.addFile(file, null, -1); doesn't throw an exception. Instead the editor.closeEdit(); throws an exception which is not desired. Any ideas on how to use one API for both adding and updating files?
public void addFiles(Map<String, String> data) throws Exception {
TreeSet<String> filesToCreate = new TreeSet<String>(data.keySet());
SVNRepository repo = null;
ISVNEditor editor = null;
try {
repo = openSession();
editor = repo.getCommitEditor("Adding files.", null);
editor.openRoot(-1);
for (String file : filesToCreate) {
try {
editor.addFile(file, null, -1);
} catch (SVNException e) {
editor.openFile(file, -1);
}
editor.applyTextDelta(file, null);
SVNDeltaGenerator gen = new SVNDeltaGenerator();
String checksum = gen.sendDelta(file, new ByteArrayInputStream(data.get(file).getBytes()), editor, true);
editor.closeFile(file, checksum);
}
editor.closeEdit();
} catch (Exception ex) {
abort(editor);
throw new Exception(ex.toString(), ex);
} finally {
closeSession(repo);
}
}
This is a side effect of an optimization in the svn:// protocol. During an editor drive the server does not send any response unless there is an error and as such the client can't tell that a specific action succeeded. I haven't looked at SVNKit's code but I'd bet that you could potentially get the exception from any of the editor methods since the error will be detected in the next editor drive call after the server responds. In this case your changes are so small that the editor drive sending happens before the response from the server can be detected and so you end up seeing the error when you do closeEdit().
The svnmucc command in Subversion has a similar problem as what you're trying to solve. It has a put operation that adds or updates a file. It uses the same technique that Dmitry advised you to use on the svnkit-users mailing list (link1, link2). Specifically running a check_path before determining to add or create the file.
You're not going to be able to do anything better than this because of the way the protocol works.

Window.open in GWT not open correctly with in a call back function

I have a situation where i need to download a excel file. So i user Window.open for that. The problem is i need to check whether the file is exsist in the server location before call the Window.open. So when user click the download buton below call happens,
public void onClick(Button button, EventObject e) {
final String url = GWT.getModuleBaseURL() + "fileupload/dailyLogReport?param1=param1
openFileDownloadWindow(url,fileName);
}
public void openFileDownloadWindow(final String url,String fileName){
CommonServiceAsync serviceAsyn = CommonService.Util.getInstance();
final AsyncCallback callback = new AsyncCallback() {
public void onSuccess(Object result)
{
isFileExsist = (Boolean)result;
if(isFileExsist){
Window.open( url, "_blank", "status=0,toolbar=0,menubar=0,location=0");
}else{
Window.alert("File not found.");
}
}
public void onFailure(Throwable caught)
{
MessageBox.alert("Error", "Error while getting data"
+ caught.getMessage());
}
};
// calling of the action
serviceAsyn.isDailyLogFileExsists(fileName, callback);
}
But the problem is if i put the Window.open inside the success it just open a Window and getting it close quickly with out download the file. But if i put the Window.open directly in onClick method it successfully open the window pop up and download the file successfully. But Since i have to download the file conditionally by checking whether the file is exists or not I can not put the Window.open inside onClick.
What is the reason Window.open not working properly inside the call back success function?
The problem is popup blocker.
When you click on a element you can open a new window since the browser considers it is a deliberate user action to open the window.
Otherwise, the browser blocks any window.open in asynchronous blocks, because it considers that it could be malicious code run out of the user control.
The best solution, is to open the file in an iframe, but you have to set the appropriate content-disposition header in server side which causes the browser to show the "Save" dialog.
Client Code:
// Create a new iframe
final Frame f = new Frame();
f.setUrl(url_to_my_excel_file");
// Set a size of 0px unless you want the file be displayed in it
// For .html images .pdf, etc. you must configure your servlet
// to send the Content-Disposition header
f.setSize("0px", "0px");
RootPanel.get().add(f);
// Configure a timer to remove the element from the DOM
new Timer() {
public void run() {
f.removeFromParent();
}
}.schedule(10000);
Server Code:
protected void doGet( HttpServletRequest req, HttpServletResponse resp ) throws ServletException, IOException {
[...]
// Set the appropriate type for your file
resp.setContentType("application/vnd.ms-excel");
// Mandatory if you want the browser open the save dialog
resp.setHeader("Content-Disposition:", "attachment;filename='my_excel_file.xls'");
[...]
}

Categories