Monday, February 26, 2007

Appfuse and Servlets

I needed to use a servlet, in my appfuse based application, to handle the download of certain files to the web client. Basically users will upload files, and users satisfying certain conditions will be able to download those files. I need to use a servlet because I want to avoid users linking to the file directly, and user based authentication is not appropriate in this case.

So I set about implementing a servlet to do the job. The download action establishes whether the user should be given the file and which file to give them, then stores the name of the file and the path to the file, in the request object. I set a global forward mapping to the servlet in metadata\web\global-forwards.xml. So I just forward my action to that forward mapping to send control over to the servlet. The servlet reads 4 Kb blocks from file and posts them out to the servletoutput stream.

The code in the servlet for reading and posting file data looks like this:
String fileName = (String) request.getAttribute("fileName");
String filePath = (String) request.getAttribute("filePath");


//new method
if (filePath != null)
{
//Get handle on file
File file = new File(filePath);
FileInputStream fileIn = new FileInputStream(file);

//Get and set content type
String contentType = getServletContext().getMimeType( filePath );
if ( contentType != null ){
response.setContentType ( contentType ) ;
}else{
response.setContentType ( "application/octet-stream" ) ;
}
response.addHeader( "Content-Disposition", "attachment; filename=" + fileName) ;



//Gets servlet output stream
ServletOutputStream outStream = response.getOutputStream();

//4kbuffer
byte[] buffer = new byte[4 * 1024];

//Read file bytes into buffer and send to client
int readCount =0;
while ((readCount=fileIn.read(buffer))!=-1){
//outStream.write(buffer,sent,file.length());
outStream.write(buffer,0,readCount);
}
//Clean up
outStream.flush();
outStream.close();
}



Integrating the servlet into appfuse, meant bypassing the documented way of doing things. I had to set up serlet mappings in web.xml directly, because the webdoclet tags didn't work and neither did putting settings in the appfuses documented servlets config file. shrug.

Monday, February 19, 2007

I spent the better part of this afternoon putting together a new appfuse application (version 1.9) for authorised downloads. I used appfuse when making a previous project and so was able to get up and running relatively quickly.

Some of the things I noticed that were different to the appfuse 1.8 were that the passwords for users are no longer stored in the db as clear text, but are hashed. This affects the passwords seen in the sample-data.xml used to put data into the db when building/testing the app.

Also the equals and hashcode shori doesn't seem to work the way it used to. In fact, after using appgen to generate the code from some POJOs, the code didn't work out of the box. I had to tweak it a bit.

I never really used the tests much last time, but this time I will be. The build process hung on the test phase on a number of places. Firstly I needed to add required fields information manually to the dao tests and the web action tests. (I use struts). Secondly the web tests wouldn't run. I think my tomcat setup is not matched in the appfuse test configuration. I changed the port number from 8080 to 80 in properties.xml, but still the tests putted out on the starting tomcat stage. Hmmm.

Anyway the app itself is running in its current form, though it isn't finished yet.