Tuesday, May 10, 2011

Using JackRabbit as a WebDAV client for Android

I have been looking for a WebDAV client to work on Android. Some of the WebDAV clients that are available are Jakarata Slide (which is now retired), JackRabbit (Apache open source) and Sardine (from Google code). I zeroed in on JackRabbit2.2.5 as Sardine was not working and did not want to spend time on debugging. But then JackRabbit did not work as well on Android. My first mistake was to download the jackrabbit-standalone.jar from the net, and trying to make it work. This was a 30+ MB file and hence not suitable for Android platform. Then I tried debugging the jackrabbit-webdav code. It internally uses some of the packages which Android does not support. After making all the "Android-happy" changes in the code, I built the jackrabbit-webdav-2.2.5.jar again using their pom.xml(maven). The files size was around 288 KB. I believe this can be optimized further, even though I did not spend much time in doing so later. :)
Here is a code snippet to upload a file to the WebDAV server using the  jar:

 File file = new File(filePath);
/*PutMethod is a class in the jackrabbit-webdav for uploading files in the server*/
        PutMethod putMethod = new PutMethod(baseURI+ uploadPath+file.getName());
        
RequestEntity requestEntity = new InputStreamRequestEntity(new FileInputStream(file));
        
putMethod.setRequestEntity(requestEntity);
//HttpClient httpClient  
httpClient.executeMethod(putMethod);

Same way, the MoveMethod, CopyMethod, DeleteMethod, MkColMethod (create), PropFindMethod (list the directory contents) can be used.
You can download the jar file ! :).


Edited:
The above file do not contain the org.apache.commons.httpclient. You may want to dowload the same from the apache site and add to your project class path  OR .....


As one of the readers had requested to provide a jar file which includes the "org.apache.commons.httpclient", I have rebuilt my library to accommodate this change. This library is heavier than the previous one.


Previously the commons-httpclient version 3.0 was used in my jackrabbit jar. As one of the readers of this post has pointed out, FileRequestEntity (for content chunking) was not being supported, I rebuilt my jar to include the same. This includes commons-httpclient version 3.1.

So those of you who would like to use FileRequestEntity API for larger file upload, you can download the latest version of my jar. Here you go:  jackrabbit-webdav-2.2.6-jar-with-dependencies.jar (size:  919 KB)

The older version (without FileRequestEntity) i.e. 2.2.5-jar, support only InputStreamRequestEntity and not FileRequestEntity. So those of you who would upload file of smaller size around 2 KB, can use the older version of my library:  jackrabbit-webdav-2.2.5-jar-with-dependencies (size 892 KB).

I would appreciate your feedback or acknowledgement in the form of comments or a g+ rating if my library has helped you. Thanks. :)

Monday, May 2, 2011

Using Java File Handler API vs Android File handler API

I had an application App1 whose package name was "com.sample".

I decided to create a directory called "testdirectory" under "data/data/com.sample" so that it's path would be "data/data/com.sample/testdirectory".

So, I wrote a code like this:

File dir = getDir("testdirectory", Context.MODE_WORLD_WRITEABLE);


But what I got was :
data/data/com.sample/app_testdirectory
getDir() is Android API.

So I decided to try out java File handler:

File dir = new File("data/data/com.sample/testdirectory").mkdir();

This created "data/data/com.sample/directory" without prefixing with the word "app_".
So while Android's getDir() always prepends the word to the "app_" to the directory name, Java file handlers allows to create a directory without prefixing anything !

Using SharedUserId in Android App

I had this requirement where App1 needs to access(read,write) the file system of App2. That does not seem very easy and surely there is no straight forward way to do this. I stumbled upon the concept of using SharedUserId that Android allows. Both the apps should have the same shared user Id in their manifest file. I must admit that this is not a very ideal solution. One needs to be extremely cautious. For e.g. if App1 did not use Shared Id at the time of launch, but decides to go for it at the time of upgrade, the new application might crash in the sense that it's data package might become inaccessible. Otherwise if it already had a shared Id but decides to go for a different one during upgrade, it will meet with the same fate.
So while opting for shared User Id, it should be taken in to consideration, that it will not allow any modification later and also it should be one time activity at the beginning. Once used, it tells you "Please leave me alone". :) 
There is already a bug raised for this, as I came to know from one of the LinkedIn members of Google Android forum.

Plugging in the DropBox API to android application

DropBox, as we all know is an online storage and it provides file browsing, synchronization, backup and share. They have support for mobile App development.
Their SDK encapsulate, the RESTful calls that they make over HTTP to interact with DropBox service. I was expecting a good online documentation, which would have made the developer's work easier, but sadly enough there was none, at least at the time of writing this post. So, I downloaded their sample application in Java (there were Python and Ruby versions as well). What helped me in understanding the usage, was the JUnit Testcases in the client code that is available for download. The sample app is only instantiating the client API (the one that makes the RESTful calls) and listing the contents of a directory. But if one goes through the JUnit Test cases, one can clearly understand the usages of the API.
Another important thing that I would like to mention here is that, while the DropBox api gives all meta data related information of a directory (account name, available storage, directory children etc.), if one wants to perform copy,move,delete operations on the user file System on the DropBox, one must instantiate the DropBox client:
Dropboxclient mClient = new DropboxClient(Map configMap, Authenticator auth);
IMHO, this could have been avoided if the DropBox guys provided CRUD implementation in the DropboxAPI itself.
DropboxAPI mApi = new DropboxAPI();
The DropboxAPI class already instantiates Dropboxclient. But then why to force the developers to instantiate it again just to get access to the CRUD operations?
But I guess it is still in evolving stage, as they have admitted their code is well tested in Python, Java and Ruby...in that order. :)
All in all, a very useful API if one wants to integrate the DropBox service for their Android app.