Sunday, February 24, 2008

Implementing File download feature in Struts 2 & Struts

Although file upload is a common feature that many struts application developers implement , it is less common to implement file download , in this post we will see how to provide file download feature in your struts 2 application.

Before we see how to implement this feature, let us first understand the requirement

1) A web page contains a link , which upon clicking it responds with a browser's file save dialog with a default name
2) User can choose the save location to save the file (as with any file save dialog)

This example uses a simple ActionClass with name DownloadAction and a jsp to show the link for downloading an arbitrary file



Let us start with the JSP , this is the simplest thing with a link pointing to the action class


Click to download


The action class which provides the download of file just needs to implement the getInputStream() method returning the InputStream of the required file to dowload !! Simple ...isn't ?

DownloadAction.java

public class DownloadAction {
private String fileName="YOUR FILE PATH";
public InputStream getInputStream(){
try{
return new FileInputStream(new File(fileName));
}catch(Exception e){}
}
public String execute(){
return "success"
}
}


Now the final thing is to wire these up in struts.xml , NOTE... there is something that is different from other regular configurations!! ... unlike other cases the control need not be passed to the JSP , instead we want the content to be handled by the browser itself (to bring up required download dialog), hence the result type is specified as "stream", which by default looks for getInputStream method (it can be configured) and sends it back as response














Easy !! isn't ? Then how about the implementation in Struts 1.xx ?

We can achieve this with the following steps

1) In the Action Class obtain the servlet response object
2) get the OutputStream from the response object
3) Get the InputStream of the target file (which we want to send to the browser)
4) Write the contents of the file to the Outputstream of step #2.
5) Don't forward the request by returning null to terminate the action.

Now, let us take a look at the code snippet of the DownloadAction.


...
...
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
File f = new File("C:\\myTestFile.xml");
response.setContentType("application/octet");
byte[] buffer = new byte[2048];
FileInputStream inputStream=new FileInputStream(f);
int bytesRead = inputStream.read(buffer);
ServletOutputStream outputStream=response.getOutputStream();
while (bytesRead >= 0) {
if (bytesRead > 0) {
outputStream.write(buffer, 0, bytesRead);
}
bytesRead = inputStream.read(buffer);
}
outputStream.flush();
//no need to forward ..
return null;
}


Here for the sake of brevity I have hardcoded the file name you will get the file name Or file Object probably from your models or from the form ..(Or any other way)

Thats it!! Hope it helps

Monday, January 21, 2008

List of Values in Web Apps



I recall the days where we used to develop using Developer 2000 , and many applications (Desktop apps) used to feature a List of Values functionality (LOVs) where users click on a button to select from a set of options which can be better displayed in separate screen providing search/filter capabilities and an ID is returned to the Original Window's control. Although not common in websites , many web applications require this functionality ..Here is how they do it...

Let us consider a sample web application in which
1) User has to select a part ID from a list of available parts ,
2) This cannot be modled as a select(Combo) box as we need to show some extra info in a table
3) We just need part ID from popup where user can search based on part name or description

now..Look at the above figure, Page1 requires Part ID from Popup, and we are using Struts . The best way (In my opinion) is :
1) Create a JSP (Popup.jsp) with a table showing the information of Parts (array of Part Objects)
2) Create a mapping in struts-config.xml






As you know ...PartsForm is the FormBean,

1) LovParts is the Action name which will be invoked by Page1 (refer to figure above)
2) Popup.jsp is the popup that displays Parts information in a HTML table
3) PartsAction Contains(or calls) required business methods to get the list of Parts

We are almost done with this.. inorder to bring up the popup there are many methods but all involve using javascript's window.open, for our example let us assume that we just have one field in the Page 1 that can be sumbitted (using POST) to determine what to show in the Popup initially (Like pre-fetching values for a already existing Part ID)

Write a function in your JSP (or your js file) which does the following

1) but the target page shall not replace the existing one
2) Submits the contents of the form to a different window so that the resulting page will not replace the current one (we want the existing page and the Popup)


  1. function postToPopup(winName){
  2. var winProps = 'Width='+20+', Height='+30+', top='+10+', left='+50; //ADJUST THESE VALUES..
  3. var hndWin = window.open("", winName, winProps); //OPEN A BLANK POPUP
  4. document.forms[0].target=winName;
  5. document.forms[0].submit(); //submit the form and open the content in popup identified by winName
  6. }

now Just call this function on the button press :
postToPopup("partsIdPopup")


Congrats!! We have just completed the first part , ie., Opening the popup, Now after user selects the Required Part and clicks OK , the Popup should close and the PartID should be returned to the Page1. Doing this is also easy , we just need to use window.opener property to get the parent window which opened this Popup and use DOM to access the field we want to set the PartID

For example: the name of the field we want to set is partID then the code in the Popup.jsp will have this in the Button click event of OK


 
function okClicked(){
window.opener.document.forms[0].partsId=partID;
//NOw cose the Popup Window
window.close();
}


Thats it..

Hope it helped you

How to try/test/learn Objective C without a Mac

At last I am convinced that I should now move to Mac platform. Although Java is my primary dev platform , I know(or heard) that the real fun will be developing using Cocoa for Mac. Now.. I never even looked at a Objective C program and was curious to learn it before buying my MacBook Pro, used my friend Mr. Google for resources but few point to Objective C on Windows, to make it easy for others..here is how .....

Basically there are two options to compile /run Objective C programs

1) Use a Linux distro like Ubuntu on Virtual PC and start compiling your programs using gcc (Yes ..it compiles Objective C)
2) Download GNUStep for Windows from http://www.gnustep.org/ ,to write Objective C in your favorite old Windows Box

Option 1 is fairly simple , but if you are a Linux hater Option #2 is also an easier one

1) On Installing GNUstep on your windows box, it will provide you with developer tools like gcc
2) You can use command line provided by Gnustep if you are familiar with *nix by writing programs in vi and compiling manually using gcc
3) You can even use your favorite editor like EditPlus or TextPad to write programs easily (I prefer this..for sake of keeping it simple)

To Compile and Run your programs, configure you editor to invoke the following on your source files


gcc *.m -lobjc -lm

Execute the resulting a.out file

There is good information in http://en.wikibooks.org/wiki/Programming:Objective-C

I am still learning Objective C , please let me know if there are better ways to do all this :-)