Gerger Blog

An ADF Faces ProgressIndicator Example for File Upload

This post demonstrates how an ADF Faces ProgressIndicator can be used to display the progress of a file upload.

The sample application is built in JDeveloper 10.1.3.2. You can download the sample workspace from here. The workspace does not need a database connection to run.
Sample Application

The sample application consists of one page that allows the user to upload files to the server. When the upload starts, a progress indicator displays the current status of the upload operation. The uploaded files are not stored anywhere.
Controlling the progressIndicator

<f:view>
<afh:html>
<afh:head title="FileUpload">
<meta http-equiv="Content-Type"
content="text/html; charset=windows-1252"/>
<afh:script source="progressIndicator.js"/>
</afh:head>
<afh:body onload="deactivateProgressIndicators();">
<af:messages/>
<af:form usesUpload="true">
<af:inputHidden id="fileUploadStatus" value="#{MyFileUploadBean.fileUploadStatus}"/>
<af:panelBox>
<af:inputFile valueChangeListener="#{MyFileUploadBean.fileUploaded}"/>
<af:commandButton text="start upload"
id="startButton"
actionListener="#{MyFileUploadBean.doUpload}"
onclick="reactivateProgressIndicators();"/>
</af:panelBox>
<af:panelBox id="panelBox" inlineStyle="display:none">
<af:panelHeader text="File is being uploaded"/>
<af:progressIndicator id="progressIndicator"
value="#{MyProgressRangeModel}"
partialTriggers="pollid">
<af:outputFormatted styleUsage="instruction"
value="Task status not known"
rendered="#{MyProgressRangeModel.value == -1}"/>
<af:outputFormatted styleUsage="instruction"
value="#{MyProgressRangeModel.value} of #{MyProgressRangeModel.maximum} Completed"
rendered="#{MyProgressRangeModel.value > -1}"/>
</af:progressIndicator>
<af:poll id="pollid" interval="1000"/>
</af:panelBox>
</af:form>
</afh:body>
</afh:html>
</f:view>

The fileUpload.jsp page contains a <af:progressIndicator/> tag and a <af:poll/> tag. The poll tag is used as a timer by the progressIndicator to check the status of the file upload periodically using partial page rendering (PPR). However, this operation is not necessary if the user is not uploading any files. If the polling is not deactivated, the progressIndicator is going to perform PPR even if there is no file being uploaded. This constant PPR creates an undesired effect on the page.

At client side, a PollManager object is used to regulate the poll objects on the page. The PollManager provides two methods to activate and deactivate the poll objects; reactivateAll() and deactivateAll(). Using these two methods the PPR can be started when file upload begins and stopped when it ends. Below is the JavaScript code that accomplishes these tasks;

function deactivateProgressIndicators()
{
if (self._pollManager)
{
if (document.getElementById('fileUploadStatus').value=='noUpload')
{
_pollManager.deactivateAll();
}
}
}

function reactivateProgressIndicators()
{
if (self._pollManager)
{
document.getElementById('panelBox').style.display='';
document.getElementById('fileUploadStatus').value='uploading';
_pollManager.reactivateAll();
}
}

Server Side Code

The MyFileUploadBean and MyProgressRangeModel beans handle the file upload and progressIndicator server side operations respectively.

You can find a detailed explanation of the ProgressRangeModel and how it is used with the progressIndicator at Duncan Mills blog.

Below is the source code for the MyFileUploadBean and the MyProgressRangeModel classes in the sample application.

public class MyFileUploadBean
{
private UploadedFile file;
private long sizeOfFile;
private int availableBytes;
private String fileUploadStatus = "noUpload";

public MyFileUploadBean() {
}

public void fileUploaded(ValueChangeEvent valueChangeEvent)
{
file = (UploadedFile)valueChangeEvent.getNewValue();
if(file != null)
{
sizeOfFile = file.getLength();
}
}

public void doUpload(ActionEvent actionEvent)
{
if(file != null)
{
InputStream is;
OutputStream os;
FacesContext fctx = FacesContext.getCurrentInstance();
FacesMessage message = new FacesMessage("succesfully uploaded file" +
" " + file.getFilename() + " (" +
file.getLength() + " bytes)");
fctx.addMessage(actionEvent.getComponent().getClientId(fctx),
message);

try
{
is = file.getInputStream();
int data;
getMyRangeModel().setMaximumBytes(sizeOfFile);
while((data = is.read()) != -1)
{
availableBytes = is.available();
getMyRangeModel().setAvailableBytes(availableBytes);
if(availableBytes == 0)
{
setFileUploadStatus("noUpload");
}
}
is.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}

private MyProgressRangeModel getMyRangeModel()
{
FacesContext fctx = FacesContext.getCurrentInstance();
MyProgressRangeModel rangeModel = (MyProgressRangeModel) fctx.getApplication()
.createValueBinding("#{MyProgressRangeModel}").getValue(fctx);
return rangeModel;
}

public void setFileUploadStatus(String fileUploadStatus) {
this.fileUploadStatus = fileUploadStatus;
}

public String getFileUploadStatus() {
return fileUploadStatus;
}
}
public class MyProgressRangeModel extends oracle.adf.view.faces.model.BoundedRangeModel
{
private long availableBytes;
private long maximumBytes;

public MyProgressRangeModel()
{
}

public long getMaximum()
{
long result;
long maxByte = getMaximumBytes();
if(maxByte==0)
result=-1;
else
result = maxByte;
return result;
}

public long getValue()
{
long result;
long availableByte = getMaximumBytes() - getAvailableBytes();
if(availableByte == 0 || availableByte==getMaximumBytes())
result=-1;
else
result = availableByte;
return result;
}

public void setAvailableBytes(long availableBytes)
{
this.availableBytes = availableBytes;
}

public long getAvailableBytes()
{
return availableBytes;
}

public void setMaximumBytes(long maximumBytes)
{
this.maximumBytes = maximumBytes;
}

public long getMaximumBytes()
{
return maximumBytes;
}
}

Yalım K. Gerger