Tuesday 11 August 2009

Accessing WebDAV from Java on OSX

I'm currently working on an extension for an existing project. The project consists of a Canon MEAP application that enables users of multifunctionals to scan documents in a quick and simple way to a SMB share or to an email address. The extension that I have to build involves adding a third transfer method, WebDAV, so that scanned documents can be sent to our Atlassian Confluence wiki.

Since the Canon MEAP platform is Java based, I started looking a Java WebDAV libraries. I found 2 good ones: Slide and Jackrabbit. The Slide project has been retired due to lack of active maintenance. This leaves us with Jackrabbit, a JCR (JSR 170) implementation, that also contains a nice WebDAV implementation that is based on Commons HttpClient.

After this I decided to do a small proof of concept to test the the 2 use cases that I needed for my extension: get a file listing and put a file on a WebDAV server. For this I needed a WebDAV capable server off course, normally I could have just used our actual wiki, but after a recent upgrade it seems that something had changed in the WebDAV integration and I couldn't access anything from the normal URL (later got to know that the new/current WebDAV URL of Confluence is https://myserver.com/confluence/plugins/servlet/confluence/default).

So I needed an alternative solution: setting up my own WebDAV server. After looking around a bit I found out that Jackrabbit also has a simple WebDAV enabled server included and does this via a WAR file that you can simply drop into a default Tomcat installation (I used jackrabbit-webapp-1.5.7.war). Another possibility would have been to configure the Apache server that is bundled with OSX to enable WebDAV, but since I've already got Jackrabbit and Tomcat is closer to my Java background I favored that approach.

Since I was already trying a lot of new stuff, I also decided to use that latest Tomcat version and download a 6.0.20 Core version. After doing this I unpacked the downloaded file into a directory, cd'ed to the bin directory of the Tomcat installation and ran ./catalina.sh start and encountered my first problems:
  • -bash: ./catalina.sh: Permission denied: solved by chmod +x catalina.sh
  • The BASEDIR environment variable is not defined correctly: again the cause seems to be some kind of permission problem and was solved by this post.
After this I dropped the download WAR, jackrabbit-webapp-1.5.7.war, into the webapps directory and watched the application deploy. If everything deployed correctly you should now be able to access the web interface at http://localhost:8080/jackrabbit-webapp-1.5.7. The home page displayed fine, but every other menu item I clicked threw errors. After a restart of Tomcat I traced the problem down to a missing JCR jar. This was solved by downloading one and placing it in the lib directory of Tomcat and restarting it. After this you'll need to go to the home page again and click the Create Content Repository button to initialize the WebDAV correctly. Once the initialization is done you'll be able to access your local WebDAV instance at http://localhost:8080/jackrabbit-webapp-1.5.7/repository/default/ (any username/password combination will work by default).

Now we have a working WebDAV server we can concentrate on creating a client that can do a listing of the WebDAV root directory and place a new file in it. Using a set of different sources I was able to put together the following code:


import java.io.FileInputStream;
import java.io.IOException;

import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpConnectionManager;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.jackrabbit.webdav.DavConstants;
import org.apache.jackrabbit.webdav.DavException;
import org.apache.jackrabbit.webdav.MultiStatusResponse;
import org.apache.jackrabbit.webdav.client.methods.DavMethod;
import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;

public class WebdavTest {

public static void main(String[] args) throws IOException, DavException {
HostConfiguration hostConfig = new HostConfiguration();
hostConfig.setHost("127.0.0.1", 8080);
HttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
HttpClient client = new HttpClient(connectionManager);
Credentials creds = new UsernamePasswordCredentials("userId", "pw");
client.getState().setCredentials(AuthScope.ANY, creds);
client.setHostConfiguration(hostConfig);

PutMethod put = new PutMethod("http://127.0.0.1:8080/jackrabbit-webapp-1.5.7/repository/default/test.txt");
RequestEntity requestEntity = new InputStreamRequestEntity(new FileInputStream("/path/to/file/test.txt"));
put.setRequestEntity(requestEntity);
client.executeMethod(put);

DavMethod pFind = new PropFindMethod("http://127.0.0.1:8080/jackrabbit-webapp-1.5.7/repository/default", DavConstants.PROPFIND_ALL_PROP, DavConstants.DEPTH_1);
client.executeMethod(pFind);

MultiStatusResponse[] responses = pFind.getResponseBodyAsMultiStatus().getResponses();
System.out.println("Folders and files: ");
for (int i = 0; i < responses.length; i++) {
System.out.println(responses[i].getHref());
}
}
}

You'll need the following libraries to make the code compile and run: commons-codec, commons-httpclient, commons-logging, jackrabbit-jcr-commons, jackrabbit-webdav, slf4j-api and slf4j-nop.

No comments:

Post a Comment