How to show file in GWT client side, instead of Downloading: - gwt

I need little help to achieve this, in my app user can upload files to server and its stored as blob object, and now i need to show them to user up on there request.
What I am up to is show in below code,
On server side I put content to response:
(This code is implemented based on this blog post WaterTalks)
resp.setContentType("text/plain");
resp.setHeader("Content-Disposition", "attachment; filename=output.txt");
PrintWriter out = resp.getWriter();
out.println("This is the output content");
out.println("Probably something dynamic should go in here:::::");
PersistenceManager pm = null;
try {
pm = PMF.get().getPersistenceManager();
javax.jdo.Transaction transaction = pm.currentTransaction();
Extent e = pm.getExtent(WaterTalkFiles.class, true);
Iterator iter = e.iterator();
String returns = "";
WaterTalkFiles file = (WaterTalkFiles)iter.next();
Blob blob = file.getData();
byte[] buffer = blob.getBytes();
String s = new String(buffer);
out.println(s);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != pm)
pm.close();
}
Now in client side when user click show button i want to show the file content in browser, not to download it.
My client side code is:
showfilecontentButton.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
String link = "/FileUploadByWaterTalks";
container.add(new HTML("ShowFile"));
}
});
The code above (Client side code) not showing content of file its just downloading the file.
But I don't want user to download it, I want show them the content of it.
And, do I have to configure something over here to work it out.
resp.setContentType("text/plain");
resp.setHeader("Content-Disposition", "attachment; filename=output.txt");
Hope you got what my problem is. Please be free to share your thoughts and solutions to achieve this.
Thanks.
UPDATED
Up on the bases of first answer here, I changed some portion of my code:
updated code sections are:
resp.setHeader("Pragma", "no-cache");
final String url = "http://127.0.0.1:8888/FileUploadByWaterTalks";
String name = "output.txt";
Anchor link1 = new Anchor(name);
RootPanel.get().add(link1);
link1.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
Frame f = new Frame(url);
f.setSize("600px", "400px");
f.getElement().getStyle().setBorderWidth(0, Unit.PX);
RootPanel.get().add(f);
}
});
But still the browser asking me to save the file instead of showing it in the browser itself.

First remove the 'Content-Disposition' in your servlet.
Second, use a GWT Anchor in your code and when the user clicks open the link in a new window or an iframe.
Here you have a example using new window, and another using iframe:
final String url = "http://gwtquery.googlecode.com/git/README.txt";
String name = "README.txt";
Anchor link1 = new Anchor(name);
RootPanel.get().add(link1);
link1.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
Window.open(url, "_blank", "");
}
});
Anchor link2 = new Anchor(name);
RootPanel.get().add(link2);
link2.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
Frame f = new Frame(url);
f.setSize("600px", "400px");
f.getElement().getStyle().setBorderWidth(0, Unit.PX);
RootPanel.get().add(f);
}
});
This approach works for any file which the browser is capable to display, but be sure that you send the appropriate Content-Type header (text/plain, text/html, image/png etc.)

Related

wicket 9: how to test downloading a resource

I have a component which allows a user to download an excel file after clicking a link.
It works and everything is fine, but I don't know how to write a test for this component.
I want to write a test to check if after pressing a link a file is sent to a client.
And so, my component looks like this
Link<Void> calculationsLink = new Link<>("calculationsLink") {
#Override
public void onClick() {
AbstractResourceStreamWriter rStream =
new AbstractResourceStreamWriter() {
#Override
public void write(OutputStream output)
throws IOException {
output.write(MyApp.class
.getResourceAsStream(pathToCalculations)
.readAllBytes());
}
};
ResourceStreamRequestHandler handler =
new ResourceStreamRequestHandler(rStream, "calculations.xslx");
getRequestCycle().scheduleRequestHandlerAfterCurrent(handler);
}
};
My test is
#Test
public void calculations_file_downloaded_Successfully() {
// then start and render the base page
tester.startPage(HomePage.class); <-- link is located in a HomePage
tester.clickLink("navBar:calculations", false); <-- link is clickable
tester.getResponse();//????
tester.assert???(?????); <-- how to assert and what to assert?
}
You should use tester.getLastResponse() and assert on its properties.
tester.getResponse() is the MockHttpServletResponse that will be used for the next HTTP call.
Some dummy examples:
assertEquals("application/octet-stream", tester.getLastResponse().getContentType());
assertEquals(3, tester.getLastResponse().getBinaryContent().length);
assertArrayEquals(new byte[] {1, 2, 3}, tester.getLastResponse().getBinaryContent());

GWT FileUpload - Servlet options and handling response

I am new to GWT and am trying to implement a file upload functionality.
Found some implementation help over the internet and used that as reference.
But have some questions related to that:
The actual upload or writing the contents of file on server(or disk) will be done by a servlet.
Is it necessary that this servlet (say MyFileUploadServlet) extends HttpServlet? OR
I can use RemoteServiceServlet or implement any other interface? If yes, which method do I need to implement/override?
In my servlet, after everything is done, I need to return back the response back to the client.
I think form.addSubmitCompleteHandler() can be used to achieve that. From servlet, I could return text/html (or String type object) and then use SubmitCompleteEvent.getResults() to get the result.
Question is that can I use my custom object instead of String (lets say MyFileUploadResult), populate the results in it and then pass it back to client?
or can I get back JSON object?
Currently, after getting back the response and using SubmitCompleteEvent.getResults(), I am getting some HTML tags added to the actual response such as :
pre> Image upload successfully /pre> .
Is there a way to get rid of that?
Thanks a lot in advance!
Regards,
Ashish
To upload files, I have extended HttpServlet in the past. I used it together with Commons-FileUpload.
I made a general widget for form-based uploads. That was to accommodate uploads for different file types (plain text and Base64). If you just need to upload plain text files, you could combine the following two classes into one.
public class UploadFile extends Composite {
#UiField FormPanel uploadForm;
#UiField FileUpload fileUpload;
#UiField Button uploadButton;
interface Binder extends UiBinder<Widget, UploadFile> {}
public UploadFile() {
initWidget(GWT.<Binder> create(Binder.class).createAndBindUi(this));
fileUpload.setName("fileUpload");
uploadForm.setEncoding(FormPanel.ENCODING_MULTIPART);
uploadForm.setMethod(FormPanel.METHOD_POST);
uploadForm.addSubmitHandler(new SubmitHandler() {
#Override
public void onSubmit(SubmitEvent event) {
if ("".equals(fileUpload.getFilename())) {
Window.alert("No file selected");
event.cancel();
}
}
});
uploadButton.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
uploadForm.submit();
}
});
}
public HandlerRegistration addCompletedCallback(
final AsyncCallback<String> callback) {
return uploadForm.addSubmitCompleteHandler(new SubmitCompleteHandler() {
#Override
public void onSubmitComplete(SubmitCompleteEvent event) {
callback.onSuccess(event.getResults());
}
});
}
}
The UiBinder part is pretty straighforward.
<g:HTMLPanel>
<g:HorizontalPanel>
<g:FormPanel ui:field="uploadForm">
<g:FileUpload ui:field="fileUpload"></g:FileUpload>
</g:FormPanel>
<g:Button ui:field="uploadButton">Upload File</g:Button>
</g:HorizontalPanel>
</g:HTMLPanel>
Now you can extend this class for plain text files. Just make sure your web.xml serves the HttpServlet at /textupload.
public class UploadFileAsText extends UploadFile {
public UploadFileAsText() {
uploadForm.setAction(GWT.getModuleBaseURL() + "textupload");
}
}
The servlet for plain text files goes on the server side. It returns the contents of the uploaded file to the client. Make sure to install the jar for FileUpload from Apache Commons somewhere on your classpath.
public class TextFileUploadServiceImpl extends HttpServlet {
private static final long serialVersionUID = 1L;
#Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
if (! ServletFileUpload.isMultipartContent(request)) {
response.sendError(HttpServletResponse.SC_BAD_REQUEST,
"Not a multipart request");
return;
}
ServletFileUpload upload = new ServletFileUpload(); // from Commons
try {
FileItemIterator iter = upload.getItemIterator(request);
if (iter.hasNext()) {
FileItemStream fileItem = iter.next();
// String name = fileItem.getFieldName(); // file name, if you need it
ServletOutputStream out = response.getOutputStream();
response.setBufferSize(32768);
int bufSize = response.getBufferSize();
byte[] buffer = new byte[bufSize];
InputStream in = fileItem.openStream();
BufferedInputStream bis = new BufferedInputStream(in, bufSize);
long length = 0;
int bytes;
while ((bytes = bis.read(buffer, 0, bufSize)) >= 0) {
out.write(buffer, 0, bytes);
length += bytes;
}
response.setContentType("text/html");
response.setContentLength(
(length > 0 && length <= Integer.MAX_VALUE) ? (int) length : 0);
bis.close();
in.close();
out.flush();
out.close();
}
} catch(Exception caught) {
throw new RuntimeException(caught);
}
}
}
I cannot recall how I got around the <pre></pre> tag problem. You may have to filter the tags on the client. The topic is also addressed here.

How to handle the drag & drop of a hyperlink in GWT

I want to handle the drag & drop of hyperlinks in my app. The hyperlink could be from any where, therefore I cannot make it setDragable(true) and setData("link", "the URL") to mark it.
A very similar scenario would be Google Image search by image, where you can drag & drop a link of image to the search box.
The sample code,
Label lblDropLink = new Label("Drop a link here");
lblDropLink.addDragOverHandler(new DragOverHandler() {
#Override
public void onDragOver(DragOverEvent event) {
lblDropLink.setText("Drop here to add the link.");
lblDropLink.setStyleName("dragOverFade");
}
});
lblDropLink.addDropHandler(new DropHandler() {
#Override
public void onDrop(DropEvent event) {
event.preventDefault();
// QUESTION: how to get the link, and even its text?
}
});
Thanks!
The only thing you can get when dropping a link is the URL!
You can get it by calling the event.getData(format) method.
format can either be "text" or "url" (see dom-datatransfer-getdata). When testing it "text" and "url" always deliverd the same result.
So the code you need in "// QUESTION: how to get the link, and even its text?" is one of the two
event.getData("text")
event.getData("url")
Here is a little sample prgramm:
final Label lblDropLink = new Label(defaultText);
lblDropLink.addDragOverHandler(new DragOverHandler() {
#Override
public void onDragOver(DragOverEvent event) {
lblDropLink.setText(dragOverText);
}
});
lblDropLink.addDropHandler(new DropHandler() {
#Override
public void onDrop(DropEvent event) {
event.preventDefault();
RootPanel.get().add(new Label("Dropped source formated with \"text\": " + event.getData("text")));
RootPanel.get().add(new Label("Dropped source formated with \"url\": " + event.getData("url")));
}
});
RootPanel.get().add(lblDropLink);
}
That should be all...
There is a function called getSource(). Use it to cast the source of the dragged object and get the link property of the source object in the onDrop event.
Example:
public void onDrop(DropEvent event) {
event.preventDefault();
Link link = (Link)event.getSource();
}
Link is the object being dragged. Then you can call Link.getLink() or whatever you use to get the value of the link.
Hpope you get the concept :)

confusion in running small history GWT application

When I am running a small login application consisting of history management, it works fine at my home where im using latest chrome and firefox versions and GWT 2.4
The same application when I run at my office works wild. I have used a Global static boolean variable which has correct value in the debug mode while it has wrong value when I run it normally. In Office Im using IE 7 and GWT 2.2
Also, onModuleLoad() is called only once at my home environment whereas it is called everytime when I type someURL#sometoken and press enter to change the internal page. When is onModuleLoad() called. Only once per session or evrytime user loads some page (or even token)?
Can anyone tell is this some problem due to IE 7 or GWT 2.2 or some other issue.
EDIT - Its very small app. Code ---
TestHistory.java
public class TestHistory implements EntryPoint, ValueChangeHandler<String> {
static boolean isLoggedIn = false;
static final String PAGENAME = "mainscreen";
public void onModuleLoad()
{
History.addValueChangeHandler(this);
String startToken = History.getToken();
System.out.println("onModuleLoad Called..... start token= -------"+startToken+"--------");
if(startToken.isEmpty())
History.newItem("login");
else
History.fireCurrentHistoryState(); //to execute onValueChange 1st time since 1st time history is not setup
}
#Override
public void onValueChange(ValueChangeEvent<String> event) {
String token = event.getValue();
System.out.println("onValueChange called with token = ***"+token+"***");
String args = "";
int question = token.indexOf("?");
if (question != -1) {
args = token.substring(question + 1);
token = token.substring(0, question);
}
if(!isLoggedIn)
{
if(token.isEmpty() || "login".equals(token)) //1st time opened the site normally
new Login().display(false, RootPanel.get());
else {
new Login().display(true, RootPanel.get());
}
}
else //User has logged in
{
if(token.isEmpty() || "login".equals(token))
{
if(isLoggedIn)
Window.alert("Ur already logged in!!!");
else
new Login().display(false, RootPanel.get());
}
else if("withdraw".equals(token))
new Withdraw().display(RootPanel.get(), args);
else if("deposit".equals(token))
new Deposit().display(RootPanel.get(), args);
else //token not clear
Window.alert("Unrecognized token=" + token);
}
}
}
Login.java
public class Login {
static final String PAGENAME = "login";
void display(final boolean hasTypedSomeToken,final Panel myPanel) //Process login
{
System.out.println("login display called");
Label displayLabel = new Label("This is the Login Page");
Label enterName = new Label("Enter ur name");
final TextBox txtName = new TextBox();
Label enterPasswd = new Label("Enter ur Passwd");
final TextBox txtPasswd = new TextBox();
Button btnLogIn = new Button("Login", new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
/* Real app will check DB. Here we r jst chckng d txt fields hv value */
if(txtName.getValue().length()>0 && txtPasswd.getValue().length()>0)
{
TestHistory.isLoggedIn = true;
if(hasTypedSomeToken) {
System.out.println("adsljasdlfjljkfsd");
History.fireCurrentHistoryState();
System.out.println("hoolala "+History.getToken());
}
else
{
myPanel.clear();
Label displayLabel = new Label("Thank U for logging. U can now access the application.");
myPanel.add(displayLabel);
}
}
}
});
myPanel.clear();
myPanel.add(displayLabel);
myPanel.add(enterName);
myPanel.add(txtName);
myPanel.add(enterPasswd);
myPanel.add(txtPasswd);
myPanel.add(btnLogIn);
}
}
Deposit.java
public class Deposit {
static final String PAGENAME = "deposit";
void display(Panel myPanel, String param)
{
System.out.println("deposit display called");
myPanel.clear();
Label displayLabel = new Label("This is the Deposit Page & ur parameter = "+param+")");
myPanel.add(displayLabel);
}
}
Class Withdraw is same as Deposit.
The problem Im facing is that once Im logged in I should be able to open all the internal pages which works perfectly at my home (and onModuleLoad() is called just once) whereas I have to log in everytime to open a internal page at my office (and onModuleLoad() is called evrytime)
onModuleLoad is called when the page is loaded, but:
pressing the enter key while in the address bar can reload the page in some browsers
changing the hash in the URL from outside the application (typing in the address bar, or using a bookmark) can confuse IE6/7; when GWT detects it, it reloads the page (have a look inside the HistoryImplIE6 class). Note that it does not happen when navigating in the history (this is what the hidden iframe is for)
Did you included the hidden iframe for history support in gwt in your html host page?
See http://code.google.com/intl/de-DE/webtoolkit/doc/latest/DevGuideCodingBasicsHistory.html#mechanism

wicket download csv "Page expired" error

I am trying to download a csv file on click of a button. I have the following implementation, but the moment I click the button, I get a page expired message
WebResource export = new WebResource() {
#Override
public IResourceStream getResourceStream() {
StringBuffer result = new StringBuffer();
for(Person person: tmpList){
result.append(person.toCSV()).append("\n");
}
return new StringResourceStream(result, "text/plain");
}
#Override
protected void setHeaders(WebResponse response) {
super.setHeaders(response);
response.setAttachmentHeader("person.csv");
}
};
export.setCacheable(false);
form.add(new ResourceLink("exportLink", export));
my html markup is as follows
<a wicket:id="exportLink"><button class="button">Export</button></a>
The error was because of serialization. one of the classes were not serialized