Wednesday 24 September 2014

ADF : Show Pop Up while af:fileDownloadActionListener is taking long time to complete.

Following example shows how to show a Pop-up and block the user from doing anything on the page until the fileDownloadActionListener Completes its process.


Steps to Implement the above Scenario:

1: Create a new Fusion Web Application(ADF) in Jdeveloper.

2: Create a Jsp Page(FileDownload.jspx). While Creating select Create as XML Documnet(*.jspx) option.

3.Drag and Drop a PanelGroupLayout in the pageand then drag and drop two Command Buttons inside the PanelGroupLayout.Then Drag and Drop Poll component from Operations tab in Component pallete.

Add ClientListener to first CommandButton.


 <af:commandButton text="Click Me Download !" id="cb1">

      <af:clientListener method="launchDownloadProcess" type="action"/>

 </af:commandButton> 

For second Command Button  set ClientComponent attribute to true and visible attribute to false.Add FileDownloadActionListener to second Command Button. Create a Bean class (in view Scope) and add the method to handle filedownload. Set the filename,contentType and charset attribute as shown below.


    <af:commandButton text="Invisible" id="cb2" clientComponent="true"
                      visible="false">
      <af:fileDownloadActionListener method="#{viewScope.FileDownloadBean.downloadFile}" filename="download.txt"
                                        contentType="text/plain; charset=utf-8"/>
    </af:commandButton>

Add the poll Listener For the Poll component, Set the interval as "-1". Also add binding for the poll Component.We will add the method content later.


 <af:poll id="pol1" pollListener="#{viewScope.FileDownloadBean.pollListener}"
             binding="#{viewScope.FileDownloadBean.poll}" interval='-1'
             clientComponent="true"/>


4. Add Pop Up to the PanalGroupLayout. And design the popup accoring to your requirement.
But autoCancel attribute should be disabled and dialog components closeIconVisible attribute should be false . Below is sample how i have designed my popup.


<af:popup childCreation="deferred" autoCancel="disabled" id="busyStatePopup"
              contentDelivery="immediate" binding="#{viewScope.FileDownloadBean.popup}">
      <af:dialog id="d2" closeIconVisible="false" type="none"
                 title="Information">
        <af:outputText value="Please wait while the report is generated ..."
                       id="ot1"/>
      </af:dialog>
    </af:popup>

5. Add the below javascript source in the document.


      function launchDownloadProcess(evt) {
           // find and Show the popup
           var popup = evt.getSource().findComponent('longRunningPopup');
            if (popup != null) {
               popup.show();
            }
            // find and set the interval for the poll so the polling starts
            var poll = evt.getSource().findComponent('pol1');
            if (poll!= null) {
               poll.setInterval(2000);
            }
            // Find and queue the event associated with the invisible button 
            var invisibleButton = evt.getSource().findComponent('cb2');
            AdfActionEvent.queue(invisibleButton, true); 
 }

And the Complete page will look like.

FileDownload.jspx


<?xml version='1.0' encoding='UTF-8'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1"
          xmlns:f="http://java.sun.com/jsf/core"
          xmlns:h="http://java.sun.com/jsf/html"
          xmlns:af="http://xmlns.oracle.com/adf/faces/rich">
  <jsp:directive.page contentType="text/html;charset=UTF-8"/>
  <f:view>
    <af:document id="d1">
      <af:resource type="javascript">
      function launchDownloadProcess(evt) {
        // find and Show the popup var popup =
        evt.getSource().findComponent('longRunningPopup');
        if (popup != null) {
            popup.show();
        }
        //find and set the interval for the poll so the polling starts
        var poll = evt.getSource().findComponent('pol1');
        if (poll != null) {
            poll.setInterval(2000);
        }
        // Find and queue the event associated with the invisible button
        var invisibleButton = evt.getSource().findComponent('cb2');
        AdfActionEvent.queue(invisibleButton, true);
      }    
      </af:resource>
      <af:form id="f1">
        <af:panelGroupLayout id="pgl1" layout="scroll">
          <af:commandButton text="Click Me Download !" id="cb1">
            <af:clientListener method="launchDownloadProcess" type="action"/>
            <!--<af:fileDownloadActionListener method="#{FileDownloadBean.downloadFile}" filename="download.txt"
                                        contentType="text/plain; charset=utf-8"/>-->
          </af:commandButton>
          <af:commandButton text="Invisible" id="cb2" clientComponent="true"
                            visible="false">
            <af:fileDownloadActionListener method="#{viewScope.FileDownloadBean.downloadFile}"
                                           filename="download.txt"
                                           contentType="text/plain; charset=utf-8"/>
          </af:commandButton>
          <af:poll id="pol1"
                   pollListener="#{viewScope.FileDownloadBean.pollListener}"
                   binding="#{viewScope.FileDownloadBean.poll}" interval='-1'
                   clientComponent="true"/>
          <af:popup childCreation="deferred" autoCancel="disabled"
                    id="busyStatePopup" contentDelivery="immediate"
                    binding="#{viewScope.FileDownloadBean.popup}">
            <af:dialog id="d2" closeIconVisible="false" type="none"
                       title="Information">
              <af:outputText value="Please wait while the report is generated ..."
                             id="ot1"/>
            </af:dialog>
          </af:popup>
        </af:panelGroupLayout>
      </af:form>
    </af:document>
  </f:view>
</jsp:root>

6. Add the below code in the FileDownloadBean's downloadFile method. 

        isProcessing = true;
        isPopUpVisible = true;
        //Added Sleep just to illustrate the use case
        Thread.currentThread().sleep(5000);
        OutputStreamWriter w = new OutputStreamWriter(outputStream, "UTF-8");
        w.write("File Generated by FileDownloadActionListener");
        // The stream is automatically closed, but since we wrapped it,
        // we'd better flush our writer
        w.flush();
        isProcessing = false;

7. Add the below Code in th Poll listener method body


        if (!isProcessing && isPopUpVisible) {
            popup.hide();
            isPopUpVisible = false;
            //Set the poll interval to -1 so that further polling doesn't happen
            poll.setInterval(-1);
            AdfFacesContext.getCurrentInstance().addPartialTarget(poll);
        }

Complete FileDownloadBean.java files.
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;

import javax.faces.context.FacesContext;

import oracle.adf.view.rich.component.rich.RichPoll;
import oracle.adf.view.rich.component.rich.RichPopup;
import oracle.adf.view.rich.context.AdfFacesContext;

import org.apache.myfaces.trinidad.event.PollEvent;


public class FileDownloadBean {
    private RichPopup popup;

    private boolean isProcessing = false;
    private boolean isPopUpVisible = false;
    private RichPoll poll;

    public FileDownloadBean() {
    }

    public void downloadFile(FacesContext facesContext,
                             OutputStream outputStream) throws InterruptedException,
                                                               UnsupportedEncodingException,
                                                               IOException {
        isProcessing = true;
        isPopUpVisible = true;
        //Added Sleep just to illustrate the use case
        Thread.currentThread().sleep(5000);
        OutputStreamWriter w = new OutputStreamWriter(outputStream, "UTF-8");
        w.write("File Generated by FileDownloadActionListener");
        // The stream is automatically closed, but since we wrapped it,
        // we'd better flush our writer
        w.flush();
        isProcessing = false;
    }

    public void pollListener(PollEvent pollEvent) {
        if (!isProcessing && isPopUpVisible) {
            popup.hide();
            isPopUpVisible = false;
            //Set the poll interval to -1 so that further polling doesn't happen
            poll.setInterval(-1);
            AdfFacesContext.getCurrentInstance().addPartialTarget(poll);
        }
    }

    public void setPopup(RichPopup popup) {
        this.popup = popup;
    }

    public RichPopup getPopup() {
        return popup;
    }

    public void setPoll(RichPoll poll) {
        this.poll = poll;
    }

    public RichPoll getPoll() {
        return poll;
    }
}


8. All the done changes are done. Run the FileDownload.jspx. When we click the Click to Download File button the Popup will open and prevent user from doing any activity in the page. Once the file is ready for download the popup will close.



2 comments: