Thursday, March 25, 2010

Strange behavior with a4j:form & s:fileUpload

Last time, I wrote about how you can use s:fileUpload for uploading files. It seemed straightforward and easy. But when I started implementing the whole code, I couldn't proceed.

I have a page where users can upload files and also can change properties of the file. A file can belong to Folder A, Folder B or Folder C. So, I needed to specify the files properties so that I can retrieve appropriate one. So, I had an a4j:form tag with enctype set to handle s:fileupload and other components(two drop downs and one button). But I was having trouble uploading the files. It was just not uploading.

So, in the end, I ended up taking other components out from the form and have a separate a4j:form. And that works. I don't have explanation for such behaviors. All I can say is that if you put too many components and s:fileUpload into an a4j:form with enctype set to handle s:fileUpload, it just might not work for you.

Tuesday, March 16, 2010

Upload Files with JSF, JAVA & Seam

About 4-5 years ago, I learned in Java about how to make a File dialog box appears. I haven't used it about file dialog boxes in my projects. So, I was excited when I had the idea to allow users to upload simple PDFs file without them having to ask me to do it. I know it is going to be a bit extensive work for me on top of what I have to accomplish before the next deployment. But I'm sure that procrastination is the habit of almost all the programmers.

So, I'm going to use Seam's s:fileUpload to allow users to upload a file. s:fileUpload comes with a browse button which allows you to browse through the files in your local disk. The first step for me was to learn how to use that fileUpload tag.

In order to use s:fileUpload, it is mandatory that it's inside either a4j:form or h:form which has enctype="multipart/form-data". In my case, it's like this :

a4j:form id="uploadTA" enctype="multipart/form-data"

Then in the backing bean or POJO, I need to specify either an inputstream or byte array to hold the file's data. The way Seam passes the file information is inside data attribute of s:fileupload. So, it'll be like :

s:fileupload data="#{fileUpload.file}" accept="application/pdf"

fileUpload is my backing POJO and file is a byte[] array. I can't use an injection and outjection attribute for my byte[] array. You will need to use getters and setters otherwise you will get an exception.

If you are up to this part, then all you are left with was how to save the file data on the server hard disk. s:fileUpload only allows you to hold the file's data into a byte array. If you want to have a file, then you need to do a little more work. You will need a button that will call an action method to do the work. So, I have the following on my jsf page :

h:commandbutton action="#{fileUpload.upload()}" value="Upload"

The upload() method looks like this :

public void upload() throws IOException{
if(file.length != 0){
//you can specify the name you want and the path inside File() object's constructor
OutputStream out = new FileOutputStream(new File("file.pdf"));
out.write(file);
out.close();
log.info("Successfully created file");

}else{
log.info("file size is either null or 0");
}
}

Wednesday, March 10, 2010

AJAX & Seam's Conversation Time Out

I've been struggling so much with Seam's conversation time out error that I began to abhor to use anything that is AJAX. Maybe my problem does not entirely lie on AJAX. Maybe it can also be caused by the fact that I used the properties of AJAX a lot on my web design without realizing the side effects.

One should have a strict control of AJAX events if one wants to incorporate AJAX functionality into the web pages. That is, you should clearly planned and set out about how the updates and re-rendering should happen. If you did not, what could possibly happen is that multiple ajax events can simultaneously happen and create a deadlock situation for conversations if you use Seam and AJAX together. I have a big web page with a lot of events and AJAX functions. Now, it's hard for me to trace back what is causing the problem. One way to solve it is to rewrite the whole page, piece by piece, by putting strict control over AJAX events. But at this point in my project, it'll be too much to handle.

A piece of advice that I want to give to those who plan on or have been using AJAX supports is that make sure you use eventQueues attribute of AJAX to organize your AJAX calls. This does not solve the problems at times, but it definitely helps. Also manually re-render the portion of the page instead of using auto re-render offered by . If you have a small page, using 's auto re-render property might be harmless, but it can cause you big problems if you use it a lot on a complicated page.