Jochen,

If you are refering to streaming a file- I have struggled with the same thing. 
For some reason this breaks the JSF lifecycle. I have however come up with a 
solution that uses a hidden iframe. This approach allows JSF to finish its 
lifecycle without being affected by the file being streamed for download.

This is how it works...

In your request scoped bean (ReportBean.java) where we want to download a file 
from (in my case it was a report) I have a method that invokes the download. It 
sets the temporary session attribute that holds the report/file by calling the 
static method "FileDownloadBean.setFileForDownload(report);" and sets an 
property of the bean that holds the url to the "fileDownload.jsp" using 
"setReportDownloadUrl("fileDownload.jsp");" (by default this propertys getter 
method returns "about:blank" to the iframe src). When these two methods are 
called in your bean the "reportDownloadUrl" getter method will return the 
proper url to the "fileDownload.jsp" page invoking the "FileDownloadBean.java" 
constructor that invokes the file download process to the iframe. I also added 
an error message in case things go wrong. Because we are using a hidden iframe 
that has no knowledge of the page that invoked it we can't use the regular 
faces messages. However, we can use a simple JavaScript alert that uses a 
message resource bundle message.

The source code:

reportResult.jsp (the page we want to download a file from insert the 
following- css class "file-download" just sets 
"visibility:hidden;display:none;"):
...
        <t:panelGroup id="fileDownloadPanel"
                binding="#{report.fileDownloadPanel}">
                <f:verbatim>
                        <iframe id="fileDownloadFrame" frameborder="0" 
scrolling="0"
                                src="</f:verbatim><tr:outputText 
value="#{report.reportDownloadUrl}" /><f:verbatim>"
                                class="file-download"></iframe>
                </f:verbatim>
        </t:panelGroup>
...

fileDownload.jsp (I use myfaces base form and command button, but tr should 
work as well):

<f:view>
        <f:loadBundle basename="WEB-INF.resources.message" var="labels" />
        <t:panelGroup rendered="#{!fileDownload.isComplete}">
                <trh:html>
                <trh:body onload="#{fileDownload.clientScriptError}">
                        <h:form id="fFileDownload">
                                <h:commandButton id="downloadFileBtn" 
styleClass="form-inp-button"
                                        
binding="#{fileDownload.downloadFileActionSrc}"
                                        
value="#{labels.lbl_filedownload_download}"
                                        action="#{fileDownload.downloadFile}"
                                        
title="#{labels.lbl_filedownload_download}">
                                </h:commandButton>
                        </h:form>
                </trh:body>
                </trh:html>
        </t:panelGroup>
</f:view>


/**
 * File download bean used to stream ad hoc files to the client without
 * encountering <code>java.lang.IllegalStateException</code>. This still
 * occures even when calling
 * <code>FacesContext.getCurrentInstance().responseComplete()</code>.
 */
public class FileDownloadBean extends BaseBean {

        /**
         * Default constructor that downloads a file that has been temporarily
         * stored in the session.
         */
        public FileDownloadBean() {
                downloadFile();
        }

        /**
         * Gets the file for download and passes it to file download method that
         * takes an object. This method can be used in a faces page for a file
         * download action.
         *
         * @see FileDownloadBean#downloadFile(Object)
         * @return the faces action
         */
        public final String downloadFile() {
                try {
                        downloadFile(getFileForDownload());
                } catch (Throwable e) {
                        log.fatal("Unable to call file download", e);
                }
                return null;
        }

        /**
         * Processes file download
         *
         * @param file
         * @return the faces action
         */
        @SuppressWarnings("unchecked")
        protected String downloadFile(Object file) {
                String errorMessage = null;
                try {
                        if (file == null) {
                                log.warn("File cannot be null. Ensure that the "
                                                + "session attribute with key: 
" + PARAM_FILE_KEY
                                                + " is set with a valid file or 
init object");
                                errorMessage = getMessageResourceString(
                                                
"bean_filedownload_error_notfound", null, false);
                        } else if (file instanceof File) {
                                downloadFile((File) file, true);
                        } else {
                                log.error("Invalid file: " + file);
                        }
                } catch (Throwable e) {
                        log.error("Unable to download the file", e);
                        errorMessage = getMessageResourceString(
                                        "bean_filedownload_error_unknown", 
null, false);
                } finally {
                        completeFileDownload(errorMessage);
                }
                return null;
        }

        /**
         * Completes the file download process. If the error message is not 
null a
         * client alert will be initiated to notify the client of the error. If 
the
         * error message is null the response will be marked as complete.
         *
         * @param errorMessage
         */
        protected final void completeFileDownload(String errorMessage) {
                try {
                        if (errorMessage != null) {
                                setDownloadErrorScript(errorMessage);
                                setIsComplete(false);
                        } else {
                                responseComplete();
                                // renderResponse();
                                setIsComplete(true);
                        }
                        setFileDownloadValue(null);
                } catch (Throwable e) {
                        log.error("Unable to complete file download", e);
                }
        }

        /**
         * Sets the client download script error text.
         *
         * @param errorMessage
         */
        protected final void setDownloadErrorScript(String errorMessage) {
                try {
                        StringBuffer err = new StringBuffer();
                        err.append("javascript:");
                        err.append("alert('");
                        err.append(isValid(errorMessage) ? errorMessage : 
"unknown");
                        err.append("');");
                        setClientScriptError(err.toString());
                } catch (Throwable e) {
                        if (log.isWarnEnabled())
                                log.warn("Unable to set the download error 
script: "
                                                + errorMessage);
                }
        }

        /*------- File Session Methods -------*/

        /**
         * Sets the temporary session attribute that holds the file to be 
streamed
         * to the client.
         *
         * @see FileDownloadBean#setFileDownloadValue(Object)
         * @param file
         */
        public static final void setFileForDownload(File file) {
                setFileDownloadValue(file);
        }

        /**
         * Sets the temporary session attribute that holds the report used to
         * generate a streamed report file for downloading.
         *
         * @see FileDownloadBean#setFileDownloadValue(Object)
         * @param report
         */
        public static final void setFileForDownload(
                        IExtendedReport<Report, String, IReportParam> report) {
                setFileDownloadValue(report);
        }

        /*------- Accessor Properties -------*/

        /**
         * This is the button or link binding that inits the file download
         */
        private ActionSource downloadFileActionSrc;

        /**
         * This is used for checking if the download process is complete
         */
        private boolean isComplete;

        /**
         * Client script error returned when a file download error occurs
         */
        private String clientScriptError;

        /*------- Accessor Methods -------*/

        /**
         * @return the clientScriptError
         */
        public String getClientScriptError() {
                if (clientScriptError == null) {
                        clientScriptError = "";
                }
                return clientScriptError;
        }

        /**
         * @param clientScriptError
         *            the clientScriptError to set
         */
        public void setClientScriptError(String clientScriptError) {
                this.clientScriptError = clientScriptError;
        }

        /**
         * @return the isComplete
         */
        public boolean getIsComplete() {
                return isComplete;
        }

        /**
         * @param isComplete
         *            the isComplete to set
         */
        public void setIsComplete(boolean isComplete) {
                this.isComplete = isComplete;
        }

        /**
         * @return the downloadFileActionSrc
         */
        public ActionSource getDownloadFileActionSrc() {
                return downloadFileActionSrc;
        }

        /**
         * @param downloadFileActionSrc
         *            the downloadFileActionSrc to set
         */
        public void setDownloadFileActionSrc(ActionSource 
downloadFileActionSrc) {
                this.downloadFileActionSrc = downloadFileActionSrc;
        }

        /*------- Constants -------*/

        /**
         * log4j
         */
        private static final Log log = 
LogFactory.getLog(FileDownloadBean.class);

        /**
         * serialVersionUID
         */
        private static final long serialVersionUID = -5803068483496878170L;

}



In a "FacesWebUtil.java" I have the following methods:

        /*------- File Download Methods -------*/

        /**
         * @see FacesWebUtil#downloadFile(FacesContext, File, boolean)
         */
        public static final void downloadFile(FacesContext context,
                        String filePath, String fileName, boolean isAttachment)
                        throws NullPointerException, 
UnsupportedEncodingException,
                        FileNotFoundException, IOException {
                if (log.isDebugEnabled())
                        log.debug("downloadFile(" + context + ',' + filePath + 
','
                                        + fileName + ',' + isAttachment + ')');
                downloadFile(context, new File(filePath, fileName), 
isAttachment);
        }

        /**
         * @see FacesWebUtil#downloadFile(FacesContext, BufferedInputStream, 
String,
         *      boolean)
         */
        public static final void downloadFile(FacesContext context, File file,
                        boolean isAttachment) throws 
UnsupportedEncodingException,
                        IOException, FileNotFoundException {
                if (log.isDebugEnabled())
                        log.debug("downloadFile(" + context + ',' + file + ','
                                        + isAttachment + ')');
                downloadFile(context,
                                new BufferedInputStream(new 
FileInputStream(file)), file
                                                .getName(), isAttachment);
        }

        /**
         * Streams a binary input stream to the faces response
         *
         * @param context
         * @param input
         * @param isAttachment
         * @param fileName
         */
        public static final void downloadFile(FacesContext context,
                        BufferedInputStream input, String fileName, boolean 
isAttachment)
                        throws UnsupportedEncodingException, IOException {
                if (log.isDebugEnabled())
                        log.debug("downloadFile(" + context + ',' + input + ',' 
+ fileName
                                        + ',' + isAttachment + ')');
                if (input != null) {
                        BufferedOutputStream output = null;
                        try {
                                if (context == null) {
                                        context = 
FacesContext.getCurrentInstance();
                                }
                                String disposition = isAttachment ? 
"attachment" : "inline";
                                int contentLength = input.available();

                                // Init servlet response
                                HttpServletResponse response = 
(HttpServletResponse) context
                                                
.getExternalContext().getResponse();
                                
response.setContentType("application/octet-stream");
                                response.setContentLength(contentLength);
                                response.setHeader("Content-disposition", 
disposition
                                                + "; filename=\"" + fileName + 
"\"");

                                // Write file contents to the response
                                output = new 
BufferedOutputStream(response.getOutputStream());
                                while (contentLength-- > 0) {
                                        output.write(input.read());
                                }

                                output.flush();
                                context.responseComplete();
                                // context.renderResponse();
                        } catch (UnsupportedEncodingException e) {
                                log.error("Invalid file download encoding");
                                throw e;
                        } catch (IOException e) {
                                log.error("File download i/o exception");
                                throw e;
                        } finally {
                                try {
                                        if (input != null) {
                                                input.close();
                                        }
                                        if (output != null) {
                                                output.close();
                                        }
                                } catch (Throwable e) {
                                }
                        }
                } else {
                        log.error("Input stream cannot be null");
                }
        }

-----Original Message-----
From: Jochen Traunecker [mailto:[EMAIL PROTECTED]
Sent: Tuesday, March 27, 2007 4:27 AM
To: adffaces-user@incubator.apache.org
Subject: Providing Files / Streams as download-link with trinidad?


Hello everybody,

I'm just wondering if there is some Trinidad-specific / Faces-specific way to 
serve binary downloads, like PDFs stored in a database. Or do I have to provide 
some link to a non managed servlet?

Thanks,
Jochen




               
___________________________________________________________
Telefonate ohne weitere Kosten vom PC zum PC: http://messenger.yahoo.de

Reply via email to