Skip to content

Commit

Permalink
Add basic lock handling. Should be extended to include If header in P…
Browse files Browse the repository at this point in the history
…UT, POST, PROPPATCH, MOVE, DELETE, or MKCOL on the locked resource.
  • Loading branch information
dkocher@sudo.ch committed May 30, 2011
1 parent 40fa969 commit c3acbdd
Show file tree
Hide file tree
Showing 6 changed files with 362 additions and 0 deletions.
33 changes: 33 additions & 0 deletions src/com/googlecode/sardine/Sardine.java
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,39 @@ public interface Sardine
*/
boolean exists(String url) throws IOException;

/**
* Put an exclusive write lock on this resource. A write lock must prevent a principal without
* the lock from successfully executing a PUT, POST, PROPPATCH, LOCK, UNLOCK, MOVE, DELETE, or MKCOL
* on the locked resource. All other current methods, GET in particular, function
* independently of the lock.
* <p/>
* A WebDAV compliant server is not required to support locking in any form. If the server does support
* locking it may choose to support any combination of exclusive and shared locks for any access types.
*
* @param url Path to the resource including protocol and hostname
* @return The lock token to unlock this resource. A lock token is a type of state token, represented
* as a URI, which identifies a particular lock. A lock token is returned by every successful
* <code>LOCK</code> operation in the lockdiscovery property in the response body, and can also be found through
* lock discovery on a resource.
* @throws IOException
*/
public String lock(String url) throws IOException;

/**
* Unlock the resource.
* <p/>
* A WebDAV compliant server is not required to support locking in any form. If the server does support
* locking it may choose to support any combination of exclusive and shared locks for any access types.
*
* @param url Path to the resource including protocol and hostname
* @return The lock token to unlock this resource. A lock token is a type of state token, represented
* as a URI, which identifies a particular lock. A lock token is returned by every successful
* <code>LOCK</code> operation in the lockdiscovery property in the response body, and can also be found through
* lock discovery on a resource.
* @throws IOException
*/
public void unlock(String url, String token) throws IOException;

/**
* Enables HTTP GZIP compression. If enabled, requests originating from Sardine
* will include "gzip" as an "Accept-Encoding" header.
Expand Down
40 changes: 40 additions & 0 deletions src/com/googlecode/sardine/impl/SardineImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,30 @@
import com.googlecode.sardine.Sardine;
import com.googlecode.sardine.Version;
import com.googlecode.sardine.impl.handler.ExistsResponseHandler;
import com.googlecode.sardine.impl.handler.LockResponseHandler;
import com.googlecode.sardine.impl.handler.MultiStatusResponseHandler;
import com.googlecode.sardine.impl.handler.VoidResponseHandler;
import com.googlecode.sardine.impl.io.ConsumingInputStream;
import com.googlecode.sardine.impl.methods.HttpCopy;
import com.googlecode.sardine.impl.methods.HttpLock;
import com.googlecode.sardine.impl.methods.HttpMkCol;
import com.googlecode.sardine.impl.methods.HttpMove;
import com.googlecode.sardine.impl.methods.HttpPropFind;
import com.googlecode.sardine.impl.methods.HttpPropPatch;
import com.googlecode.sardine.impl.methods.HttpUnlock;
import com.googlecode.sardine.model.Allprop;
import com.googlecode.sardine.model.Exclusive;
import com.googlecode.sardine.model.Lockinfo;
import com.googlecode.sardine.model.Lockscope;
import com.googlecode.sardine.model.Locktype;
import com.googlecode.sardine.model.Multistatus;
import com.googlecode.sardine.model.Prop;
import com.googlecode.sardine.model.Propertyupdate;
import com.googlecode.sardine.model.Propfind;
import com.googlecode.sardine.model.Remove;
import com.googlecode.sardine.model.Response;
import com.googlecode.sardine.model.Set;
import com.googlecode.sardine.model.Write;
import com.googlecode.sardine.util.SardineUtil;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
Expand Down Expand Up @@ -207,6 +215,10 @@ public HttpUriRequest getRedirect(HttpRequest request, HttpResponse response, Ht
{
return new HttpPropFind(uri);
}
if (method.equalsIgnoreCase(HttpLock.METHOD_NAME))
{
return new HttpLock(uri);
}
return new HttpGet(uri);
}
});
Expand Down Expand Up @@ -368,6 +380,34 @@ public void setCustomProps(String url, Map<String, String> setProps, List<String
this.execute(entity, new VoidResponseHandler());
}

public String lock(String url) throws IOException
{
HttpLock entity = new HttpLock(url);
Lockinfo body = new Lockinfo();
Lockscope scopeType = new Lockscope();
scopeType.setExclusive(new Exclusive());
body.setLockscope(scopeType);
final Locktype lockType = new Locktype();
lockType.setWrite(new Write());
body.setLocktype(lockType);
entity.setEntity(new StringEntity(SardineUtil.toXml(body), "UTF-8"));
// Return the lock token
return this.execute(entity, new LockResponseHandler());
}

public void unlock(String url, String token) throws IOException
{
HttpUnlock entity = new HttpUnlock(url, token);
Lockinfo body = new Lockinfo();
Lockscope scopeType = new Lockscope();
scopeType.setExclusive(new Exclusive());
body.setLockscope(scopeType);
final Locktype lockType = new Locktype();
lockType.setWrite(new Write());
body.setLocktype(lockType);
this.execute(entity, new VoidResponseHandler());
}

/**
* (non-Javadoc)
*
Expand Down
73 changes: 73 additions & 0 deletions src/com/googlecode/sardine/impl/handler/LockResponseHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright 2009-2011 Jon Stevens et al.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.googlecode.sardine.impl.handler;

import com.googlecode.sardine.impl.SardineException;
import com.googlecode.sardine.model.Prop;
import com.googlecode.sardine.util.SardineUtil;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;

import javax.xml.bind.JAXBException;
import java.io.IOException;
import java.io.InputStream;

/**
* @version $Id$
*/
public final class LockResponseHandler extends ValidatingResponseHandler<String>
{
public String handleResponse(HttpResponse response) throws IOException
{
super.validateResponse(response);

// Process the response from the server.
HttpEntity entity = response.getEntity();
if (entity == null)
{
StatusLine statusLine = response.getStatusLine();
throw new SardineException("No entity found in response", statusLine.getStatusCode(),
statusLine.getReasonPhrase());
}
return this.getToken(entity.getContent());
}

/**
* Helper method for getting the Multistatus response processor.
*
* @param stream The input to read the status
* @return Multistatus element parsed from the stream
* @throws java.io.IOException When there is a JAXB error
*/
protected String getToken(InputStream stream)
throws IOException
{
try
{
final Prop prop = (Prop) SardineUtil.createUnmarshaller().unmarshal(stream);
return prop.getLockdiscovery().getActivelock().iterator().next().getLocktoken().getHref().iterator().next();
}
catch (JAXBException e)
{
IOException failure = new IOException(e.getMessage());
// Backward compatibility
failure.initCause(e);
throw failure;
}
}
}
79 changes: 79 additions & 0 deletions src/com/googlecode/sardine/impl/methods/HttpLock.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright 2009-2011 Jon Stevens et al.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.googlecode.sardine.impl.methods;

import org.apache.http.HttpHeaders;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;

import java.net.URI;

/**
* @version $Id:$
*/
public class HttpLock extends HttpEntityEnclosingRequestBase
{
public static final String METHOD_NAME = "LOCK";

public HttpLock(String url)
{
this(URI.create(url));
}

public HttpLock(URI url)
{
this.setURI(url);
this.setHeader(HttpHeaders.CONTENT_TYPE, "text/xml");
}

@Override
public String getMethod()
{
return METHOD_NAME;
}

/**
* The Depth header may be used with the <code>LOCK</code> method. Values other than <code>0</code> or <code>infinity</code> must not
* be used with the Depth header on a <code>LOCK</code> method. All resources that support the <code>LOCK</code>
* method must support the Depth header.
* <p/>
* If no Depth header is submitted on a <code>LOCK</code> request then the request must act as if
* a <code>Depth:infinity</code> had been submitted.
*
* @param depth <code>"0"</code> or <code>"infinity"</code>.
*/
public void setDepth(String depth)
{
this.setHeader("Depth", depth);
}

/**
* Clients may include Timeout headers in their LOCK requests. However, the server is not required to honor
* or even consider these requests.
*/
public void setTimeout(int seconds)
{
this.setHeader("Timeout", "Second-" + seconds);
}

/**
* Desires an infinite length lock.
*/
public void setInfinite()
{
this.setHeader("Timeout", "Infinite");
}
}
60 changes: 60 additions & 0 deletions src/com/googlecode/sardine/impl/methods/HttpUnlock.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright 2009-2011 Jon Stevens et al.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.googlecode.sardine.impl.methods;

import org.apache.http.HttpHeaders;
import org.apache.http.client.methods.HttpRequestBase;

import java.net.URI;

/**
* @version $Id:$
*/
public class HttpUnlock extends HttpRequestBase
{
public static final String METHOD_NAME = "UNLOCK";

/**
* @param url
* @param token The Lock-Token request header is used with the UNLOCK method to identify the lock to be removed.
* The lock token in the Lock-Token request header must identify a lock that contains the resource
* identified by Request-URI as a member.
*/
public HttpUnlock(String url, String token)
{
this(URI.create(url), token);
}

/**
* @param url
* @param token The Lock-Token request header is used with the UNLOCK method to identify the lock to be removed.
* The lock token in the Lock-Token request header must identify a lock that contains the resource
* identified by Request-URI as a member.
*/
public HttpUnlock(URI url, String token)
{
this.setURI(url);
this.setHeader(HttpHeaders.CONTENT_TYPE, "text/xml");
this.setHeader("Lock-Token", "<" + token + ">");
}

@Override
public String getMethod()
{
return METHOD_NAME;
}
}
Loading

0 comments on commit c3acbdd

Please sign in to comment.