Friday, April 13, 2007

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

12 comments:

Brenden Anstey said...

This is excellent, thanks and well done.

Kishore said...

That was really good .
Learnt more from that.
But can u also let me know how do u put text(html) in between the ADF tags?
or how do u write a paragraph in b/n the ADf tags? Thnk u in advance.

jGaL said...

Congrats.
Very well documented example.
Thanks

Anonymous said...

Hi , thanks for good example. can you help with this question. i have selectinputdate on my page and every time i use this component the poller gets activated , is there anyway to control this to activate poller only on submit button

Thanks

Anonymous said...

Hi

i was wondering if you ran into the issue discussed at this otn forum link and if you have any suggestions,

http://forums.oracle.com/forums/thread.jspa?threadID=558016&tstart=15

OnlinePharmacy said...

t8bYQs Your blog is great. Articles is interesting!

Klaas said...

Hi, the example looks nice. Worked but when I put the code in my project the polling is starting after I click a selectInputText or a selectInputFile, and not after I click the upload button.

What could this be?

Asked my question also on OTN forum:
http://forums.oracle.com/forums/thread.jspa?messageID=2178310�

Anonymous said...

Good example - can anyone tell me if htere is an equally simple way to get the files uploaded into a UploadedFile out again?

I would realy like to be able to click on a button and open/save the file.

Thanks!

LVL

Aldrino said...

Thanks.

Anonymous said...

The link for downloading the sample workspace is not working. Can you fix it please.
Thank you.

Gerger said...

Oh Gosh, It has been a while since we stopped using that domain. I will update all the download links if I can find a copy of the application workspaces. It has been a while since we used these workspaces.

Anonymous said...

Can you please update the link as I am working on similar use case and your sample will definately help me.