diff --git a/pom.xml b/pom.xml index 413a21f4..cbfe106e 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ com.github.lookfirst sardine jar - 5.13-SNAPSHOT + 5.14-SNAPSHOT An easy to use WebDAV client for Java Sardine WebDAV client https://github.com/lookfirst/sardine @@ -53,6 +53,18 @@ + + org.apache.maven.plugins + maven-enforcer-plugin + 3.3.0 + + + org.codehaus.mojo + extra-enforcer-rules + 1.7.0 + + + org.apache.maven.plugins maven-jar-plugin @@ -121,6 +133,29 @@ + + org.apache.maven.plugins + maven-enforcer-plugin + + + enforce-bytecode-version + + enforce + + + + + ${maven.compiler.target} + + test + + + + true + + + + org.apache.maven.plugins maven-jar-plugin @@ -260,8 +295,8 @@ - 8 - 8 + 11 + 11 false 4.5.14 diff --git a/src/main/java/com/github/sardine/DavResource.java b/src/main/java/com/github/sardine/DavResource.java index cb104681..ddc955aa 100644 --- a/src/main/java/com/github/sardine/DavResource.java +++ b/src/main/java/com/github/sardine/DavResource.java @@ -147,6 +147,18 @@ public DavResource(Response response) throws URISyntaxException */ private int getStatusCode(Response response) { + List list = response.getPropstat(); + for(Propstat propstat : list) { + if(propstat.getStatus() != null) { + try { + return BasicLineParser.parseStatusLine(propstat.getStatus(), null).getStatusCode(); + } + catch(ParseException e) { + log.warning(String.format("Failed to parse status line: %s", propstat.getStatus())); + return -1; + } + } + } String status = response.getStatus(); if (status == null || status.isEmpty()) { diff --git a/src/main/java/com/github/sardine/Sardine.java b/src/main/java/com/github/sardine/Sardine.java index d8ef72b3..d00731ee 100644 --- a/src/main/java/com/github/sardine/Sardine.java +++ b/src/main/java/com/github/sardine/Sardine.java @@ -86,6 +86,37 @@ public interface Sardine */ List list(String url, int depth, boolean allProp) throws IOException; + /** + * Gets versions listing of resource. + * + * @param url Path to the resource including protocol and hostname + * @throws IOException I/O error or HTTP response validation failure + */ + List versionsList(String url) throws IOException; + + /** + * Gets versions listing of resource. + * + * @param url Path to the resource including protocol and hostname + * @param depth The depth to look at (use 0 for single resource, 1 for directory listing, + * -1 for infinite recursion) + * @throws IOException I/O error or HTTP response validation failure + * + */ + List versionsList(String url, int depth) throws IOException; + + /** + * Gets versions listing of resource. + * + * @param url Path to the resource including protocol and hostname + * @param depth The depth to look at (use 0 for single resource, 1 for directory listing, + * -1 for infinite recursion) + * @param props Set of properties to be requested + * @throws IOException I/O error or HTTP response validation failure + * + */ + List versionsList(String url, int depth, Set props) throws IOException; + /** * Fetches a resource using WebDAV PROPFIND. Only the specified properties * are retrieved. @@ -180,6 +211,17 @@ public interface Sardine */ InputStream get(String url) throws IOException; + /** + * Uses HTTP GET to download specific version of data from a server. + * The stream must be closed after reading. + * + * @param url Path to the resource including protocol and hostname + * @param version version of resource + * @return Data stream to read from + * @throws IOException I/O error or HTTP response validation failure + */ + InputStream get(String url, String version) throws IOException; + /** * Uses HTTP GET to download data from a server. The stream must be closed after reading. * @@ -432,6 +474,33 @@ public interface Sardine */ void unlock(String url, String token) throws IOException; + /** + * Put the resource under version control. + * + * @param url Path to the resource including protocol and hostname + * @throws IOException I/O error or HTTP response validation failure + */ + void addToVersionControl(String url) throws IOException; + + /** + * CHECKOUT request can be applied only to a checked-in version-controlled resource + * to allow modifications to the content and properties of that version-controlled resource. + * + * @param url Path to the checked-in, version-controlled resource including protocol and hostname + * @throws IOException I/O error or HTTP response validation failure + */ + void checkout(String url) throws IOException; + + /** + * CHECKIN request can be applied to a checked-out version-controlled + * resource to produce a new version whose content and properties + * are copied from the checked-out resource. + * + * @param url Path to the checked-out, version-controlled resource including protocol and hostname + * @throws IOException I/O error or HTTP response validation failure + */ + void checkin(String url) throws IOException; + /** * Read access control list for resource * diff --git a/src/main/java/com/github/sardine/impl/SardineImpl.java b/src/main/java/com/github/sardine/impl/SardineImpl.java index f057640b..9decb0fa 100644 --- a/src/main/java/com/github/sardine/impl/SardineImpl.java +++ b/src/main/java/com/github/sardine/impl/SardineImpl.java @@ -16,64 +16,19 @@ package com.github.sardine.impl; -import com.github.sardine.DavAce; -import com.github.sardine.DavAcl; -import com.github.sardine.DavPrincipal; -import com.github.sardine.DavQuota; -import com.github.sardine.DavResource; -import com.github.sardine.Sardine; -import com.github.sardine.Version; +import com.github.sardine.*; import com.github.sardine.impl.handler.ExistsResponseHandler; import com.github.sardine.impl.handler.LockResponseHandler; import com.github.sardine.impl.handler.MultiStatusResponseHandler; import com.github.sardine.impl.handler.VoidResponseHandler; import com.github.sardine.impl.io.ContentLengthInputStream; import com.github.sardine.impl.io.HttpMethodReleaseInputStream; -import com.github.sardine.impl.methods.HttpAcl; -import com.github.sardine.impl.methods.HttpCopy; -import com.github.sardine.impl.methods.HttpLock; -import com.github.sardine.impl.methods.HttpMkCol; -import com.github.sardine.impl.methods.HttpMove; -import com.github.sardine.impl.methods.HttpPropFind; -import com.github.sardine.impl.methods.HttpPropPatch; -import com.github.sardine.impl.methods.HttpReport; -import com.github.sardine.impl.methods.HttpSearch; -import com.github.sardine.impl.methods.HttpUnlock; -import com.github.sardine.model.Ace; -import com.github.sardine.model.Acl; -import com.github.sardine.model.Allprop; -import com.github.sardine.model.Displayname; -import com.github.sardine.model.Exclusive; -import com.github.sardine.model.Group; -import com.github.sardine.model.Lockinfo; -import com.github.sardine.model.Lockscope; -import com.github.sardine.model.Locktype; -import com.github.sardine.model.Multistatus; -import com.github.sardine.model.ObjectFactory; -import com.github.sardine.model.Owner; -import com.github.sardine.model.PrincipalCollectionSet; -import com.github.sardine.model.PrincipalURL; -import com.github.sardine.model.Prop; -import com.github.sardine.model.Propertyupdate; -import com.github.sardine.model.Propfind; -import com.github.sardine.model.Propstat; -import com.github.sardine.model.QuotaAvailableBytes; -import com.github.sardine.model.QuotaUsedBytes; -import com.github.sardine.model.Remove; -import com.github.sardine.model.Resourcetype; -import com.github.sardine.model.Response; -import com.github.sardine.model.SearchRequest; -import com.github.sardine.model.Set; -import com.github.sardine.model.Write; +import com.github.sardine.impl.methods.*; +import com.github.sardine.model.*; import com.github.sardine.report.SardineReport; +import com.github.sardine.report.VersionTreeReport; import com.github.sardine.util.SardineUtil; -import org.apache.http.Consts; -import org.apache.http.Header; -import org.apache.http.HttpEntity; -import org.apache.http.HttpHeaders; -import org.apache.http.HttpHost; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; +import org.apache.http.*; import org.apache.http.auth.AuthScope; import org.apache.http.auth.AuthState; import org.apache.http.auth.NTCredentials; @@ -84,12 +39,7 @@ import org.apache.http.client.ResponseHandler; import org.apache.http.client.config.AuthSchemes; import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.HttpDelete; -import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpHead; -import org.apache.http.client.methods.HttpPut; -import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.client.methods.*; import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.client.protocol.RequestAcceptEncoding; import org.apache.http.client.protocol.ResponseContentEncoding; @@ -108,11 +58,7 @@ import org.apache.http.entity.InputStreamEntity; import org.apache.http.entity.StringEntity; import org.apache.http.impl.auth.BasicScheme; -import org.apache.http.impl.client.BasicAuthCache; -import org.apache.http.impl.client.BasicCredentialsProvider; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.client.*; import org.apache.http.impl.conn.DefaultSchemePortResolver; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.impl.conn.SystemDefaultRoutePlanner; @@ -139,6 +85,8 @@ import java.util.Map.Entry; import java.util.logging.Logger; +import static com.github.sardine.util.SardineUtil.createQNameWithDefaultNamespace; + /** * Implementation of the Sardine interface. This is where the meat of the Sardine library lives. * @@ -414,6 +362,21 @@ public List list(String url, int depth, boolean allProp) throws IOE } } + @Override + public List versionsList(String url) throws IOException { + return versionsList(url, 0); + } + + @Override + public List versionsList(String url, int depth) throws IOException { + return versionsList(url, depth, Collections.emptySet()); + } + + @Override + public List versionsList(String url, int depth, java.util.Set props) throws IOException { + return report(url, depth, new VersionTreeReport(props)); + } + @Override public List list(String url, int depth, java.util.Set props) throws IOException { @@ -643,6 +606,21 @@ public void unlock(String url, String token) throws IOException this.execute(entity, new VoidResponseHandler()); } + @Override + public void addToVersionControl(String url) throws IOException { + this.execute(new HttpVersionControl(url), new VoidResponseHandler()); + } + + @Override + public void checkout(String url) throws IOException { + this.execute(new HttpCheckout(url), new VoidResponseHandler()); + } + + @Override + public void checkin(String url) throws IOException { + this.execute(new HttpCheckin(url), new VoidResponseHandler()); + } + @Override public void setAcl(String url, List aces) throws IOException { @@ -806,6 +784,13 @@ public ContentLengthInputStream get(String url) throws IOException return this.get(url, Collections.emptyMap()); } + @Override + public ContentLengthInputStream get(String url, String version) throws IOException { + List versionHistory = propfind(url, 0, Collections.singleton(createQNameWithDefaultNamespace("version-history"))); + String storageUrl = versionHistory.get(0).getCustomProps().get("version-history"); + return this.get(storageUrl + version); + } + @Override public ContentLengthInputStream get(String url, Map headers) throws IOException { diff --git a/src/main/java/com/github/sardine/impl/methods/HttpCheckin.java b/src/main/java/com/github/sardine/impl/methods/HttpCheckin.java new file mode 100644 index 00000000..afba8f99 --- /dev/null +++ b/src/main/java/com/github/sardine/impl/methods/HttpCheckin.java @@ -0,0 +1,26 @@ +package com.github.sardine.impl.methods; + +import org.apache.http.client.methods.HttpRequestBase; + +import java.net.URI; + +/** + * Simple class for making WebDAV CHECKIN requests. + */ +public class HttpCheckin extends HttpRequestBase { + + public static final String METHOD_NAME = "CHECKIN"; + + public HttpCheckin(String uri) { + this(URI.create(uri)); + } + + public HttpCheckin(URI uri) { + this.setURI(uri); + } + + @Override + public String getMethod() { + return METHOD_NAME; + } +} diff --git a/src/main/java/com/github/sardine/impl/methods/HttpCheckout.java b/src/main/java/com/github/sardine/impl/methods/HttpCheckout.java new file mode 100644 index 00000000..47b5d668 --- /dev/null +++ b/src/main/java/com/github/sardine/impl/methods/HttpCheckout.java @@ -0,0 +1,26 @@ +package com.github.sardine.impl.methods; + +import org.apache.http.client.methods.HttpRequestBase; + +import java.net.URI; + +/** + * Simple class for making WebDAV CHECKOUT requests. + */ +public class HttpCheckout extends HttpRequestBase { + + public static final String METHOD_NAME = "CHECKOUT"; + + public HttpCheckout(String uri) { + this(URI.create(uri)); + } + + public HttpCheckout(URI uri) { + this.setURI(uri); + } + + @Override + public String getMethod() { + return METHOD_NAME; + } +} diff --git a/src/main/java/com/github/sardine/impl/methods/HttpVersionControl.java b/src/main/java/com/github/sardine/impl/methods/HttpVersionControl.java new file mode 100644 index 00000000..d41e8fd5 --- /dev/null +++ b/src/main/java/com/github/sardine/impl/methods/HttpVersionControl.java @@ -0,0 +1,26 @@ +package com.github.sardine.impl.methods; + +import org.apache.http.client.methods.HttpRequestBase; + +import java.net.URI; + +/** + * Simple class for making WebDAV VERSION-CONTROL requests. + */ +public class HttpVersionControl extends HttpRequestBase { + + public static final String METHOD_NAME = "VERSION-CONTROL"; + + public HttpVersionControl(String uri) { + this(URI.create(uri)); + } + + public HttpVersionControl(URI uri) { + this.setURI(uri); + } + + @Override + public String getMethod() { + return METHOD_NAME; + } +} diff --git a/src/main/java/com/github/sardine/model/ObjectFactory.java b/src/main/java/com/github/sardine/model/ObjectFactory.java index cdca00a6..1fb04008 100644 --- a/src/main/java/com/github/sardine/model/ObjectFactory.java +++ b/src/main/java/com/github/sardine/model/ObjectFactory.java @@ -282,6 +282,10 @@ public SyncCollection createSyncCollection() { return new SyncCollection(); } + public VersionTree createVersionTree() { + return new VersionTree(); + } + /** * Create an instance of {@link Limit } * diff --git a/src/main/java/com/github/sardine/model/VersionTree.java b/src/main/java/com/github/sardine/model/VersionTree.java new file mode 100644 index 00000000..a7cdf7b4 --- /dev/null +++ b/src/main/java/com/github/sardine/model/VersionTree.java @@ -0,0 +1,38 @@ +package com.github.sardine.model; + +import javax.xml.bind.annotation.*; + +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "", propOrder = { + "prop" +}) +@XmlRootElement(name = "version-tree") +public class VersionTree { + + @XmlElement + protected Prop prop; + + /** + * Gets the value of the prop property. + * + * @return + * possible object is + * {@link Prop } + * + */ + public Prop getProp() { + return prop; + } + + /** + * Sets the value of the prop property. + * + * @param value + * allowed object is + * {@link Prop } + * + */ + public void setProp(Prop value) { + this.prop = value; + } +} diff --git a/src/main/java/com/github/sardine/report/VersionTreeReport.java b/src/main/java/com/github/sardine/report/VersionTreeReport.java new file mode 100644 index 00000000..04b66870 --- /dev/null +++ b/src/main/java/com/github/sardine/report/VersionTreeReport.java @@ -0,0 +1,59 @@ +package com.github.sardine.report; + +import com.github.sardine.DavResource; +import com.github.sardine.model.*; +import com.github.sardine.util.SardineUtil; +import org.w3c.dom.Element; + +import javax.xml.namespace.QName; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.logging.Logger; + +public class VersionTreeReport extends SardineReport> +{ + + private static final Logger log = Logger.getLogger(SardineReport.class.getName()); + + private final Set properties; + + public VersionTreeReport(Set properties) + { + this.properties = properties; + } + + @Override + public Object toJaxb() + { + Prop prop = new Prop(); + List any = prop.getAny(); + for (QName entry : properties) + { + any.add(SardineUtil.createElement(entry)); + } + + VersionTree versionTree = new VersionTree(); + versionTree.setProp(prop); + return versionTree; + } + + @Override + public List fromMultistatus(Multistatus multistatus) + { + List responses = multistatus.getResponse(); + List resources = new ArrayList(responses.size()); + for (Response response : responses) { + try + { + resources.add(new DavResource(response)); + } + catch (URISyntaxException e) + { + log.warning(String.format("Ignore resource with invalid URI %s", response.getHref().get(0))); + } + } + return resources; + } +} diff --git a/src/test/java/com/github/sardine/FunctionalSardineTest.java b/src/test/java/com/github/sardine/FunctionalSardineTest.java index fae24e45..f1a66822 100644 --- a/src/test/java/com/github/sardine/FunctionalSardineTest.java +++ b/src/test/java/com/github/sardine/FunctionalSardineTest.java @@ -222,8 +222,7 @@ public void getDavQuota() throws IOException Sardine sardine = SardineFactory.begin(); sardine.createDirectory(url); DavQuota davQuota = sardine.getQuota(url); - assertTrue(davQuota.getQuotaAvailableBytes() > 0); - assertEquals(0, davQuota.getQuotaUsedBytes()); + assertNull(davQuota); } @Test(expected = SardineException.class) diff --git a/webdav.xsd b/webdav.xsd index e7443f71..e9c3c8cf 100644 --- a/webdav.xsd +++ b/webdav.xsd @@ -400,6 +400,14 @@ + + + + + + + +