GWT's RPC services are only able to send java objects back to the client. To send a file back to the user you'll need to use a non-GWT java servlet. Here's some code I've used before for serving up jpeg images from a repository.
public class ImageServlet extends HttpServlet {
private final String repository = "/var/images/";
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String filename = request.getParameter("file");
// Security: '..' in the filename will let sneaky users access files
// not in your repository.
filename = filename.replace("..", "");
File file = new File(repository + filename);
if (!file.exists())
throw new FileNotFoundException(file.getAbsolutePath());
response.setHeader("Content-Type", "image/jpeg");
response.setHeader("Content-Length", String.valueOf(file.length()));
response.setHeader("Content-disposition", "attachment;filename=\"" + filename + "\"");
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
byte[] buf = new byte[1024];
while (true) {
int length = bis.read(buf);
if (length == -1)
break;
bos.write(buf, 0, length);
}
bos.flush();
bos.close();
bis.close();
}
}
"Content-disposition: attachment" should cause most browsers to download the file instead of displaying it, with the filename defaulting to whatever you provide. The way you would use this servlet is to have the user call the RPCService that you already have, which saves the file to the repository folder. Then, you link or redirect them to this servlet with a url such as http://your.domain.com/fileServlet?file=myFile.jpg. Obviously with this setup you have a security risk where users can download other people's files if they can guess the filenames.
What you might like to do is merge the database code from your RPC service into this servlet. There's no need to save the file anywhere on the server, you can take your database results and write them into response.getOutputStream() or response.getWriter() in exactly the same way you would write them to file, except that the result goes straight to the user. As long as you set your content headers correctly the user won't notice the difference.
You can't call this method from another servlet, the only way to make a browser to download it as a file is to access it through a normal HTTP request. First you declare the servlet in your web.xml file like you would a GWT RPC service:
<servlet>
<servlet-name>ImageServlet</servlet-name>
<servlet-class>
com.package.ImageServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ImageServlet</servlet-name>
<url-pattern>/imageServlet</url-pattern>
</servlet-mapping>
Now any HTTP GET requests going to http://your.tomcat.server/webapp/imageServlet will get picked up by ImageServlet.doGet(). Then on the client side you can either make a normal html link to the file:
new HTML("<a href='" + GWT.getHostPageBaseURL() + "imageServlet?file=" + filename + "'>download</a>");
...or, you should be able to put this in a ClickHandler (I haven't tested it):
Window.Location.assign(GWT.getHostPageBaseURL() + "imageServlet?file=" + filename);