The following XSnippet (of an XAgent) gives you a bit of an idea of what to do.
https://openntf.org/XSnippets.nsf/snippet.xsp?id=download-all-attachments
In the XSnippet above, all the attachments in a Document are being zipped and then sent to the browser as a zip file.
The url has some parameters e.g. documentID which the XAgent uses to determine which document to zip through.
The XAgent gets a handle to the HttpServletResponse, and configures it so that, instead of sending back an XPage, it specifies it is sending an 'application/zip' file.
It then finds the document using documentId and zips it up, writes the contents to the response and then tells the facesContext that the response is complete (don't do anymore rendering).
In your case, you would put a parameter which identifies the file that you want download. And you could link to this XAgent using a url e.g.
Download.xsp?fileId=somefileid
Your XAgent would then setup the response similar to above but the content type might not be an 'application/zip'. If you don't know the file type you can use 'application/octet-sream' but if you know it is a pdf of something you can use the appropriate Mime Type
Retrieve the file using whatever code you have written to access your webservice, decode it, and write it to the response's output stream
Example Implementing in Java as a Managed bean
The following example outputs some plain text that was originally in a base64 byte array. It is decoded and then written to the response.
All you would do is change the content type to 'application/octet-stream'
Create the managed bean in the Java Design Element.
package com.example;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletResponse;
import com.sun.faces.util.Base64;
public class DownloadBean implements Serializable {
private static final long serialVersionUID = 1L;
public DownloadBean() {
};
public void downloadFile() throws IOException {
FacesContext fc = FacesContext.getCurrentInstance();
ExternalContext context = fc.getExternalContext();
String myFileName = "SomeFile.txt";
HttpServletResponse resp = (HttpServletResponse) context.getResponse();
resp.setHeader("Cache-Control", "no-cache");
resp.setDateHeader("Expires", -1);
resp.setContentType("text/plain");
resp.setHeader("Content-Disposition", "attachment; filename="
+ myFileName);
OutputStream os = resp.getOutputStream();
byte[] base64bytes = "SGVsbG8gTWFyY3Vz".getBytes();
ByteArrayInputStream bais = new ByteArrayInputStream(base64bytes);
sun.misc.BASE64Decoder dec = new sun.misc.BASE64Decoder();
dec.decodeBuffer(bais, os);
os.flush();
os.close();
fc.responseComplete();
}
}
Register it in faces-config.xml. Request Scope should be enough. so for example if you called it 'downloadBean', and it was of class com.example.DownloadBean, put this entry in faces-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<faces-config>
<managed-bean>
<managed-bean-name>downloadBean</managed-bean-name>
<managed-bean-class>com.example.DownloadBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
</faces-config>
How to use
You can then call this from a button:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:button value="Download" id="buttonDownload">
<xp:eventHandler event="onclick" submit="true"
refreshMode="complete" action="#{downloadBean.downloadFile}">
</xp:eventHandler>
</xp:button>
</xp:view>
Or you can create an XPage like an XAgent that just downloads the file, and link to this Xpage in new window.
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core"
rendered="false" beforePageLoad="#{downloadBean.downloadFile}">
</xp:view>
You could access url parameters if needed using something like
https://openntf.org/XSnippets.nsf/snippet.xsp?id=get-url-parameter-using-java