Follow by Email

Monday, 15 February 2016

Show live progress of a long running task using af:progressIndicator in Oracle ADF

This post is about using af:progressIndicator to show live status of a particular task
af:progressIndicator state is tracked and maintained by it's value property that supports org.apache.myfaces.trinidad.model.BoundedRangeModel
This class has two methods

public abstract long getMaximum() { }
returns Maximum value for Model

public abstract long getValue() { }
returns value for Model (current state)

Now to see live progress on page we have to refresh progressIndicator component periodically and this can be achieved using af:poll component , poll component delivers poll events to server periodically and we can ppr (refresh) progress indicator after a particular interval


So I have created a page and dropped these ADF Faces components
af:button- to start processing (start a thread that loop up to 100 and sleeps for 100 milliseconds to make it long)
af:progressIndicator- to show live progress
af:outputText- to show text percentage completed
af:poll- to refresh progressIndicator after a fixed time interval


Next i have created a bean class that extends BoundedRangeModel and implements Runnable (For thread purpose)
See Managed Bean -

import javax.faces.event.ActionEvent;

import oracle.adf.view.rich.context.AdfFacesContext;

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

public class ProgressIndicatorBean extends BoundedRangeModel implements Runnable {


    public ProgressIndicatorBean() {
    }
    // An Integer value that presents current state of progress
    int procVal = 0;
    //To set poll interval, on start button click it will start polling
    private int pollInterval = -1;

    //Variable accessors to be used by ADF Faces Components on page
    public void setPollInterval(int pollInterval) {
        this.pollInterval = pollInterval;
    }

    public int getPollInterval() {
        return pollInterval;
    }

    public int getProcVal() {
        return procVal;
    }

    public void setProcVal(int procVal) {
        this.procVal = procVal;
    }

    @Override
    public long getMaximum() {
        return 100;
    }

    @Override
    public long getValue() {
        return procVal;
    }

    @Override
    public void run() {
        // Loop up to Maximum value of Progress Model
        while (procVal < getMaximum()) {
            try {
                //Sleeps for 100ms to make it long
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //Increase current status of progress model
            procVal++;
        }
    }

    /**Method to process Action Event, starts polling and a thread that makes processing long
     * @param actionEvent
     */
    public void processValueAction(ActionEvent actionEvent) {
        //Set poll interval to postive value to start polling
        pollInterval = 100;
        //Set initial progrss to zero
        procVal = 0;
        //Start a thread
        Thread t = new Thread(this);
        t.start();
    }


    /**Poll Listener to stop poll (set poll interval to -1) once task is done
     * @param pollEvent
     */
    public void pollListnerEvt(PollEvent pollEvent) {
        //Check if processing is complete
        if (procVal == getMaximum()) {
            //Setting poll interval to negative value to stop polling
            pollInterval = -1;
            //Refresh poll component
            AdfFacesContext.getCurrentInstance().addPartialTarget(pollEvent.getComponent());
        }
    }
}

Now see page XML source - (How this bean is mapped on page)


<af:panelGroupLayout id="pgl1" layout="vertical" halign="center">
                    <af:button text="Start" id="b1"
                               actionListener="#{viewScope.ProgressIndicatorBean.processValueAction}"/>
                    <af:spacer width="10" height="10" id="s1"/>
                    <af:poll id="p1" interval="#{viewScope.ProgressIndicatorBean.pollInterval}" partialTriggers="b1"
                             clientComponent="true" timeout="10000"
                             pollListener="#{viewScope.ProgressIndicatorBean.pollListnerEvt}"/>
                    <af:progressIndicator id="pi1" value="#{viewScope.ProgressIndicatorBean}" partialTriggers="p1"/>
                    <af:outputText value="Proceesing.. #{viewScope.ProgressIndicatorBean.procVal}% Done" id="ot1"
                                   partialTriggers="p1" inlineStyle="color:blue;font-weight:bold;"/>
                </af:panelGroupLayout>


All done :) Page looks like this

 Run and check application, Click on start button

Sample ADF Application (Jdeveloper 12.1.3) -Download
Cheers :) Happy Learning

2 comments :

  1. Good work , but how can i use it for upload process like uploading file to the server , where and how can i use loop to change progress indicator

    ReplyDelete