incubator-adffaces-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "William Hoover" <whoo...@nemours.org>
Subject RE: Providing Files / Streams as download-link with trinidad?
Date Tue, 27 Mar 2007 11:47:43 GMT
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:madnecker@yahoo.com]
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


Mime
View raw message