Getting the Lock Token for an item in Jackrabbit

Share

I’ve seen this problem around from the first versions of Apache Jackrabbit. The problem is straightforward and just. If you perform a WebDAV Lock command on an item in Jackrabbit the resulting lock token is available only in that command’s session. In other words, if you do not save the lock token that is provided as the result of the WebDAV Lock command then you cannot retrieve it in any way later and the item remains locked.

I’m not sure what the JCR specifications are (probably it is meant do be like this) but there are lots of practical examples where you need to be able to retrieve that token even if you did not save it. Of course, if a different user tries to get it, he/she should not be allowed, but I’m talking about the case when the same user that locks the file, tries to get the lock token.

For example, if you open a file from MS Word through WebDAV. In this case MS Word asks you for your username/password, opens the file and locks it. Upon closing MS Word, it releases that lock. But in the case that it is terminated inappropriately (end task, crash etc) the file remains locked and it would be normal that the same user to be able to use another WebDAV tool (or execute commands “manually”) in order to find that lock token and unlock the file.

All the examples rely on this idea. You lock a file form one application and then you try to unlock it (or refresh the lock) from another app which cannot be supplied with the lock token (that is supposed you saved from the first lock command). In each case we assume that the same user needs this. If it is another then is normal not to be allowed to do it.

There is a solution !
… but it is a bit complicated to implement.

The main problem relies in the org.apache.jackrabbit.core.lock.LockImpl class. Its getLockToken method looks like this:

public String getLockToken() {
if (!info.isSessionScoped() && info.isLockHolder(node.getSession())) {
return info.getLockToken();
} else {
return null;
}
}

It is obvious that the token is provided only if it is in the same session.
That if line is actually wired because it asks that the lock token NOT to be session scoped but its locking session to be the same as the current session (node.getSession() is the current session)

I did not manage to create a session scoped lock until now, the sessionScope attribute is always false no matter what parameters I use in the LockInfo object of the WebDAV LockMethod. Furthermore, by locking an item with MS Word (and I think that any application that know how to handle WebDAV does the same), the sessionScope attribute is always false. So the problem is obvious in that code.

In order to fix this, the code must be modified as follows:
public String getLockToken() {
if(info.isSessionScoped())
return null;
if (info.isLockHolder(node.getSession()) || info.getLockOwner().equals(node.getSession().getUserID())) {
return info.getLockToken();
} else {
return null;
}
}

The first if is to preserve the original behavior about the sessionScope attribute (whatever that may be).
The second if fixes the problem.

The easiest way to replace the code is to take the org.apache.jackrabbit.core.lock.LockImpl.java file from Jackrabbit source distribution, modify it, compile it and replace it into the jar file.

But the problem is still not fixed ! Because there you will get another one now.
If you fix this then the lock token and the lock owner should be present in the lockdiscovery property of an item when
peforming a PropFind command. I started Jackrabbit in debug mode and saw that an ActiveLock object is set as a child node of the lockdiscovery property and should be present on the client side but it is not ! It is null !!

So after wasting a few hours with this I decided modify Jackrabbit to return the lock token and lock owner as separate item properties. So this is what you should do:

You need to overwrite the org.apache.jackrabbit.webdav.server.AbstractWebdavServlet.doPropFind() method:

protected void doPropFind(WebdavRequest request, WebdavResponse response,
DavResource resource) throws IOException, DavException {
if (!resource.exists()) {
response.sendError(DavServletResponse.SC_NOT_FOUND);
return;
}

int depth = request.getDepth(DEPTH_INFINITY);
DavPropertyNameSet requestProperties = request.getPropFindProperties();
int propfindType = request.getPropFindType();
/* Copy from original code above */

/* Hack to set the lock token and owner as separate properties */
ActiveLock aLock = resource.getLock(Type.WRITE, Scope.EXCLUSIVE);

if ((aLock != null) && (aLock.getOwner() != null)) {
properties.add(new DefaultDavProperty("lockowner", aLock.getOwner(), DavConstants.NAMESPACE));
}
if ((aLock != null) && (aLock.getToken() != null)) {
properties.add(new DefaultDavProperty("locktoken", aLock.getToken(), DavConstants.NAMESPACE));
}

/* The rest of the original code */
MultiStatus mstatus = new MultiStatus();
mstatus.addResourceProperties(resource, requestProperties, propfindType, depth);
response.sendMultiStatus(mstatus);
}

The first property is the lock owner which should be visible for any user. You can remove it if you don’t like.
The second property is the lock token. This will be not null only if the PropFind command is issued by the same user that locked the file. See the second code sample. (The modified LockImpl class). So if it is another user then the property is not set.

All you have to do now is put this code into Jackrabbit. How do you actually overwrite the AbstractWebdavServlet class ? Well you actually need to overwrite the org.apache.jackrabbit.j2ee.SimpleWebdavServlet class that you find in the classes folder of Jackrabbit. This is a subclass of AbstractWebdavServlet and is specified in the the Jackrabbit’s web.xml file. So you overwrite this class (SimpleWebdavServlet) and you specify replace it in the web.xml as the servlet class of the WebDAV servlet (look it up in the web.xml and you will find it).

This is all you have to do. Now start Jackrabbit and you will see that you when you execute a PropPatch command your returning item will have 2 new properties that contain the lock token and lock owner (in case you are the same user that performed the lock).
Of course if an item is not locked then these properties will not be present.

And don’t worry about overwriting and replacing that webdav class. It doesn’t modify Jackrabbit behavior in any other way. (Just what is written in this blog).

Live long and prosper !

Finally, there’s another very important peculiarity of what does Cialis that brings it so high above its alternatives. It is the only med that is available in two versions – one intended for use on as-needed basis and one intended for daily use. As you might know, Viagra and Levitra only come in the latter of these two forms and should be consumed shortly before expected sexual activity to ensure best effect. Daily Cialis, in its turn, contains low doses of Tadalafil, which allows to build its concentration up in your system gradually over time and maintain it on acceptable levels, which, consequently, makes it possible for you to enjoy sex at any moment without having to time it.

By continuing to use the site, you agree to the use of cookies. More information

The cookie settings on this website are set to "allow cookies" to give you the best browsing experience possible. If you continue to use this website without changing your cookie settings or you click "Accept" below then you are consenting to this.

Close