This is an automated email from the ASF dual-hosted git repository.
ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-vfs.git
The following commit(s) were added to refs/heads/master by this push:
new 4434be76 Use for-each loop
4434be76 is described below
commit 4434be760962847d554db7f850b59132706619a5
Author: Gary Gregory <[email protected]>
AuthorDate: Sat Jul 9 09:42:14 2022 -0400
Use for-each loop
---
.../vfs2/provider/webdav4/Webdav4FileObject.java | 1263 ++++++++++----------
1 file changed, 629 insertions(+), 634 deletions(-)
diff --git
a/commons-vfs2-jackrabbit2/src/main/java/org/apache/commons/vfs2/provider/webdav4/Webdav4FileObject.java
b/commons-vfs2-jackrabbit2/src/main/java/org/apache/commons/vfs2/provider/webdav4/Webdav4FileObject.java
index acc33516..094d0756 100644
---
a/commons-vfs2-jackrabbit2/src/main/java/org/apache/commons/vfs2/provider/webdav4/Webdav4FileObject.java
+++
b/commons-vfs2-jackrabbit2/src/main/java/org/apache/commons/vfs2/provider/webdav4/Webdav4FileObject.java
@@ -1,634 +1,629 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.commons.vfs2.provider.webdav4;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.net.HttpURLConnection;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.commons.vfs2.FileContentInfoFactory;
-import org.apache.commons.vfs2.FileNotFolderException;
-import org.apache.commons.vfs2.FileNotFoundException;
-import org.apache.commons.vfs2.FileObject;
-import org.apache.commons.vfs2.FileSystemException;
-import org.apache.commons.vfs2.FileType;
-import org.apache.commons.vfs2.NameScope;
-import org.apache.commons.vfs2.provider.AbstractFileName;
-import org.apache.commons.vfs2.provider.DefaultFileContent;
-import org.apache.commons.vfs2.provider.GenericURLFileName;
-import org.apache.commons.vfs2.provider.http4.Http4FileObject;
-import org.apache.commons.vfs2.util.FileObjectUtils;
-import org.apache.commons.vfs2.util.MonitorOutputStream;
-import org.apache.commons.vfs2.util.URIUtils;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.HttpStatus;
-import org.apache.http.client.methods.HttpPut;
-import org.apache.http.client.methods.HttpRequestBase;
-import org.apache.http.client.methods.HttpUriRequest;
-import org.apache.http.client.utils.DateUtils;
-import org.apache.http.entity.ByteArrayEntity;
-import org.apache.http.entity.ContentType;
-import org.apache.jackrabbit.webdav.DavConstants;
-import org.apache.jackrabbit.webdav.DavException;
-import org.apache.jackrabbit.webdav.MultiStatus;
-import org.apache.jackrabbit.webdav.MultiStatusResponse;
-import org.apache.jackrabbit.webdav.client.methods.BaseDavRequest;
-import org.apache.jackrabbit.webdav.client.methods.HttpCheckin;
-import org.apache.jackrabbit.webdav.client.methods.HttpCheckout;
-import org.apache.jackrabbit.webdav.client.methods.HttpDelete;
-import org.apache.jackrabbit.webdav.client.methods.HttpMkcol;
-import org.apache.jackrabbit.webdav.client.methods.HttpMove;
-import org.apache.jackrabbit.webdav.client.methods.HttpPropfind;
-import org.apache.jackrabbit.webdav.client.methods.HttpProppatch;
-import org.apache.jackrabbit.webdav.client.methods.HttpVersionControl;
-import org.apache.jackrabbit.webdav.property.DavProperty;
-import org.apache.jackrabbit.webdav.property.DavPropertyIterator;
-import org.apache.jackrabbit.webdav.property.DavPropertyName;
-import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
-import org.apache.jackrabbit.webdav.property.DavPropertySet;
-import org.apache.jackrabbit.webdav.property.DefaultDavProperty;
-import org.apache.jackrabbit.webdav.version.DeltaVConstants;
-import org.apache.jackrabbit.webdav.version.VersionControlledResource;
-import org.apache.jackrabbit.webdav.xml.Namespace;
-import org.w3c.dom.Node;
-
-/**
- * A WebDAV file.
- *
- * @since 2.5.0
- */
-public class Webdav4FileObject extends Http4FileObject<Webdav4FileSystem> {
-
- /**
- * An OutputStream that writes to a Webdav resource.
- * <p>
- * TODO - Use piped stream to avoid temporary file.
- */
- private class WebdavOutputStream extends MonitorOutputStream {
- private final Webdav4FileObject file;
-
- WebdavOutputStream(final Webdav4FileObject file) {
- super(new ByteArrayOutputStream());
- this.file = file;
- }
-
- private boolean createVersion(final String urlStr) {
- try {
- final HttpVersionControl request = new
HttpVersionControl(urlStr);
- setupRequest(request);
- executeRequest(request);
- return true;
- } catch (final Exception ex) {
- return false;
- }
- }
-
- /**
- * Called after this stream is closed.
- */
- @Override
- protected void onClose() throws IOException {
- final HttpEntity entity = new
ByteArrayEntity(((ByteArrayOutputStream) out).toByteArray());
- final GenericURLFileName fileName = (GenericURLFileName) getName();
- final String urlStr = toUrlString(fileName);
- if (builder.isVersioning(getFileSystem().getFileSystemOptions())) {
- DavPropertySet set = null;
- boolean fileExists = true;
- boolean isCheckedIn = true;
- try {
- set = getPropertyNames(fileName);
- } catch (final FileNotFoundException fnfe) {
- fileExists = false;
- }
- if (fileExists && set != null) {
- if (set.contains(VersionControlledResource.CHECKED_OUT)) {
- isCheckedIn = false;
- } else if
(!set.contains(VersionControlledResource.CHECKED_IN)) {
- DavProperty<?> prop =
set.get(VersionControlledResource.AUTO_VERSION);
- if (prop != null) {
- prop = getProperty(fileName,
VersionControlledResource.AUTO_VERSION);
- if
(DeltaVConstants.XML_CHECKOUT_CHECKIN.equals(prop.getValue())) {
- createVersion(urlStr);
- }
- }
- }
- }
- if (fileExists && isCheckedIn) {
- try {
- final HttpCheckout request = new HttpCheckout(urlStr);
- setupRequest(request);
- executeRequest(request);
- isCheckedIn = false;
- } catch (final FileSystemException ex) {
- log(ex);
- }
- }
-
- try {
- final HttpPut request = new HttpPut(urlStr);
- request.setEntity(entity);
- setupRequest(request);
- executeRequest(request);
- setUserName(fileName, urlStr);
- } catch (final FileSystemException ex) {
- if (!isCheckedIn) {
- try {
- final HttpCheckin request = new
HttpCheckin(urlStr);
- setupRequest(request);
- executeRequest(request);
- isCheckedIn = true;
- } catch (final Exception e) {
- // Going to throw original.
- log(e);
- }
- throw ex;
- }
- }
- if (!fileExists) {
- createVersion(urlStr);
- try {
- final DavPropertySet props =
getPropertyNames(fileName);
- isCheckedIn =
!props.contains(VersionControlledResource.CHECKED_OUT);
- } catch (final FileNotFoundException fnfe) {
- log(fnfe);
- }
- }
- if (!isCheckedIn) {
- final HttpCheckin request = new HttpCheckin(urlStr);
- setupRequest(request);
- executeRequest(request);
- }
- } else {
- final HttpPut request = new HttpPut(urlStr);
- request.setEntity(entity);
- setupRequest(request);
- executeRequest(request);
- try {
- setUserName(fileName, urlStr);
- } catch (final IOException e) {
- // Unable to set the user name.
- log(e);
- }
- }
- ((DefaultFileContent) this.file.getContent()).resetAttributes();
- }
-
- private void setUserName(final GenericURLFileName fileName, final
String urlStr) throws IOException {
- final DavPropertySet setProperties = new DavPropertySet();
- final DavPropertyNameSet removeProperties = new
DavPropertyNameSet();
- String name =
builder.getCreatorName(getFileSystem().getFileSystemOptions());
- final String userName = fileName.getUserName();
- if (name == null) {
- name = userName;
- } else if (userName != null) {
- final String comment = "Modified by user " + userName;
- setProperties.add(new
DefaultDavProperty<>(DeltaVConstants.COMMENT, comment));
- }
- setProperties.add(new
DefaultDavProperty<>(DeltaVConstants.CREATOR_DISPLAYNAME, name));
- final HttpProppatch request = new HttpProppatch(urlStr,
setProperties, removeProperties);
- setupRequest(request);
- executeRequest(request);
- }
- }
-
- /** The character set property name. */
- public static final DavPropertyName RESPONSE_CHARSET =
DavPropertyName.create("response-charset");
-
- /**
- * An empty immutable {@code Webdav4FileObject} array.
- */
- private static final Webdav4FileObject[] EMPTY_ARRAY = {};
-
- /** The FileSystemConfigBuilder */
- private final Webdav4FileSystemConfigBuilder builder;
-
-
- protected Webdav4FileObject(final AbstractFileName name, final
Webdav4FileSystem fileSystem)
- throws FileSystemException {
- this(name, fileSystem, Webdav4FileSystemConfigBuilder.getInstance());
- }
-
- protected Webdav4FileObject(final AbstractFileName name, final
Webdav4FileSystem fileSystem,
- final Webdav4FileSystemConfigBuilder builder) throws
FileSystemException {
- super(name, fileSystem, builder);
- this.builder = builder;
- }
-
- /**
- * Creates this file as a folder.
- */
- @Override
- protected void doCreateFolder() throws Exception {
- final HttpMkcol request = new
HttpMkcol(toUrlString((GenericURLFileName) getName()));
- setupRequest(request);
- try {
- executeRequest(request);
- } catch (final FileSystemException fse) {
- throw new
FileSystemException("vfs.provider.webdav/create-collection.error", getName(),
fse);
- }
- }
-
- /**
- * Deletes the file.
- */
- @Override
- protected void doDelete() throws Exception {
- final HttpDelete request = new
HttpDelete(toUrlString((GenericURLFileName) getName()));
- setupRequest(request);
- executeRequest(request);
- }
-
- /**
- * Returns the properties of the Webdav resource.
- */
- @Override
- protected Map<String, Object> doGetAttributes() throws Exception {
- final Map<String, Object> attributes = new HashMap<>();
- try {
- final GenericURLFileName fileName = (GenericURLFileName) getName();
- DavPropertySet properties = getProperties(fileName,
DavConstants.PROPFIND_ALL_PROP,
- new DavPropertyNameSet(), false);
- final DavPropertyIterator iter = properties.iterator();
- while (iter.hasNext()) {
- final DavProperty<?> property = iter.nextProperty();
- attributes.put(property.getName().toString(),
property.getValue());
- }
- properties = getPropertyNames(fileName);
- final DavPropertyIterator iter2 = properties.iterator();
- while (iter2.hasNext()) {
- DavProperty<?> property = iter2.nextProperty();
- if (!attributes.containsKey(property.getName().getName())) {
- property = getProperty(fileName, property.getName());
- if (property != null) {
- final Object name = property.getName();
- final Object value = property.getValue();
- if (name != null && value != null) {
- attributes.put(name.toString(), value);
- }
- }
- }
- }
- return attributes;
- } catch (final Exception e) {
- throw new
FileSystemException("vfs.provider.webdav/get-attributes.error", getName(), e);
- }
- }
-
- /**
- * Returns the size of the file content (in bytes).
- */
- @Override
- protected long doGetContentSize() throws Exception {
- final DavProperty<?> property = getProperty((GenericURLFileName)
getName(), DavConstants.PROPERTY_GETCONTENTLENGTH);
- if (property != null) {
- final String value = (String) property.getValue();
- return Long.parseLong(value);
- }
- return 0;
- }
-
- /**
- * Returns the last modified time of this file. Is only called if {@link
#doGetType} does not return
- * {@link FileType#IMAGINARY}.
- */
- @Override
- protected long doGetLastModifiedTime() throws Exception {
- final DavProperty<?> property = getProperty((GenericURLFileName)
getName(), DavConstants.PROPERTY_GETLASTMODIFIED);
- if (property != null) {
- final String value = (String) property.getValue();
- return DateUtils.parseDate(value).getTime();
- }
- return 0;
- }
-
- @Override
- protected OutputStream doGetOutputStream(final boolean bAppend) throws
Exception {
- return new WebdavOutputStream(this);
- }
-
- /**
- * Determines the type of this file. Must not return null. The return
value of this method is cached, so the
- * implementation can be expensive.
- */
- @Override
- protected FileType doGetType() throws Exception {
- try {
- return isDirectory((GenericURLFileName) getName()) ?
FileType.FOLDER : FileType.FILE;
- } catch (final FileNotFolderException | FileNotFoundException fnfe) {
- return FileType.IMAGINARY;
- }
-
- }
-
- /**
- * Determines if this file can be written to. Is only called if {@link
#doGetType} does not return
- * {@link FileType#IMAGINARY}.
- * <p>
- * This implementation always returns true.
- *
- * @return true if the file is writable.
- * @throws Exception if an error occurs.
- */
- @Override
- protected boolean doIsWriteable() throws Exception {
- return true;
- }
-
- /**
- * Lists the children of the file.
- */
- @Override
- protected String[] doListChildren() throws Exception {
- // use doListChildrenResolved for performance
- return null;
- }
-
- /**
- * Lists the children of the file.
- */
- @Override
- protected FileObject[] doListChildrenResolved() throws Exception {
- HttpPropfind request = null;
- try {
- final GenericURLFileName name = (GenericURLFileName) getName();
- if (isDirectory(name)) {
- final DavPropertyNameSet nameSet = new DavPropertyNameSet();
-
nameSet.add(DavPropertyName.create(DavConstants.PROPERTY_DISPLAYNAME));
-
- request = new HttpPropfind(toUrlString(name), nameSet,
DavConstants.DEPTH_1);
-
- final HttpResponse res = executeRequest(request);
- final List<Webdav4FileObject> vfs = new ArrayList<>();
- if (request.succeeded(res)) {
- final MultiStatusResponse[] responses =
request.getResponseBodyAsMultiStatus(res).getResponses();
-
- for (final MultiStatusResponse response : responses) {
- if (isCurrentFile(response.getHref(), name)) {
- continue;
- }
- final String resourceName =
resourceName(response.getHref());
- if (!resourceName.isEmpty()) {
- final Webdav4FileObject fo = (Webdav4FileObject)
FileObjectUtils.getAbstractFileObject(
-
getFileSystem().resolveFile(getFileSystem().getFileSystemManager()
- .resolveName(getName(),
resourceName, NameScope.CHILD)));
- vfs.add(fo);
- }
- }
- }
- return vfs.toArray(EMPTY_ARRAY);
- }
- throw new FileNotFolderException(getName());
- } catch (final FileNotFolderException fnfe) {
- throw fnfe;
- } catch (final DavException | IOException e) {
- throw new FileSystemException(e.getMessage(), e);
- } finally {
- if (request != null) {
- request.releaseConnection();
- }
- }
- }
-
- /**
- * Rename the file.
- */
- @Override
- protected void doRename(final FileObject newFile) throws Exception {
- final String url =
URIUtils.encodePath(toUrlString((GenericURLFileName) getName()));
- final String dest = toUrlString((GenericURLFileName)
newFile.getName(), false);
- final HttpMove request = new HttpMove(url, dest, false);
- setupRequest(request);
- executeRequest(request);
- }
-
- /**
- * Sets an attribute of this file. Is only called if {@link #doGetType}
does not return {@link FileType#IMAGINARY}.
- */
- @Override
- protected void doSetAttribute(final String attrName, final Object value)
throws Exception {
- try {
- final GenericURLFileName fileName = (GenericURLFileName) getName();
- final String urlStr = toUrlString(fileName);
- final DavPropertySet properties = new DavPropertySet();
- final DavPropertyNameSet propertyNameSet = new
DavPropertyNameSet();
- final DavProperty<Object> property = new
DefaultDavProperty<>(attrName, value, Namespace.EMPTY_NAMESPACE);
- if (value != null) {
- properties.add(property);
- } else {
- propertyNameSet.add(property.getName()); // remove property
- }
-
- final HttpProppatch request = new HttpProppatch(urlStr,
properties, propertyNameSet);
- setupRequest(request);
- final HttpResponse response = executeRequest(request);
- if (!request.succeeded(response)) {
- throw new FileSystemException("Property '" + attrName + "'
could not be set.");
- }
- } catch (final FileSystemException fse) {
- throw fse;
- } catch (final Exception e) {
- throw new
FileSystemException("vfs.provider.webdav/set-attributes", e, getName(),
attrName);
- }
- }
-
- private HttpResponse executeRequest(final HttpUriRequest request) throws
FileSystemException {
- final HttpResponse response;
-
- try {
- response = executeHttpUriRequest(request);
- final int status = response.getStatusLine().getStatusCode();
- if (status == HttpURLConnection.HTTP_NOT_FOUND || status ==
HttpURLConnection.HTTP_GONE) {
- throw new FileNotFoundException(request.getURI());
- }
-
- if (request instanceof BaseDavRequest) {
- ((BaseDavRequest) request).checkSuccess(response);
- }
-
- return response;
- } catch (final FileSystemException fse) {
- throw fse;
- } catch (final IOException e) {
- throw new FileSystemException(e);
- } catch (final DavException e) {
- throw ExceptionConverter.generate(e);
- } finally {
- if (request instanceof HttpRequestBase) {
- ((HttpRequestBase) request).releaseConnection();
- }
- }
- }
-
- @Override
- protected FileContentInfoFactory getFileContentInfoFactory() {
- return new Webdav4FileContentInfoFactory();
- }
-
- DavPropertySet getProperties(final GenericURLFileName name) throws
FileSystemException {
- return getProperties(name, DavConstants.PROPFIND_ALL_PROP, new
DavPropertyNameSet(), false);
- }
-
- DavPropertySet getProperties(final GenericURLFileName name, final
DavPropertyNameSet nameSet, final boolean addEncoding)
- throws FileSystemException {
- return getProperties(name, DavConstants.PROPFIND_BY_PROPERTY, nameSet,
addEncoding);
- }
-
- DavPropertySet getProperties(final GenericURLFileName name, final int
type, final DavPropertyNameSet nameSet,
- final boolean addEncoding) throws FileSystemException {
- try {
- final String urlStr = toUrlString(name);
- final HttpPropfind request = new HttpPropfind(urlStr, type,
nameSet, DavConstants.DEPTH_0);
- setupRequest(request);
- final HttpResponse res = executeRequest(request);
- if (request.succeeded(res)) {
- final MultiStatus multiStatus =
request.getResponseBodyAsMultiStatus(res);
- final MultiStatusResponse response =
multiStatus.getResponses()[0];
- final DavPropertySet props =
response.getProperties(HttpStatus.SC_OK);
- if (addEncoding) {
- final ContentType resContentType =
ContentType.getOrDefault(res.getEntity());
- final DavProperty<String> prop = new
DefaultDavProperty<>(RESPONSE_CHARSET,
- resContentType.getCharset().name());
- props.add(prop);
- }
- return props;
- }
- return new DavPropertySet();
- } catch (final FileSystemException fse) {
- throw fse;
- } catch (final Exception e) {
- throw new
FileSystemException("vfs.provider.webdav/get-property.error", e, getName(),
name, type,
- nameSet.getContent(), addEncoding);
- }
- }
-
- DavProperty<?> getProperty(final GenericURLFileName fileName, final
DavPropertyName name) throws FileSystemException {
- final DavPropertyNameSet nameSet = new DavPropertyNameSet();
- nameSet.add(name);
- final DavPropertySet propertySet = getProperties(fileName, nameSet,
false);
- return propertySet.get(name);
- }
-
- DavProperty<?> getProperty(final GenericURLFileName fileName, final String
property) throws FileSystemException {
- return getProperty(fileName, DavPropertyName.create(property));
- }
-
- DavPropertySet getPropertyNames(final GenericURLFileName name) throws
FileSystemException {
- return getProperties(name, DavConstants.PROPFIND_PROPERTY_NAMES, new
DavPropertyNameSet(), false);
- }
-
- /**
- * Convert the FileName to an encoded url String.
- *
- * @param name The FileName.
- * @return The encoded URL String.
- */
- private String hrefString(final GenericURLFileName name) {
- try {
- final GenericURLFileName newFile = new
GenericURLFileName(getInternalURI().getScheme(), name.getHostName(),
name.getPort(), name.getDefaultPort(),
- null, null, name.getPath(), name.getType(),
name.getQueryString());
- return newFile.getURIEncoded(this.getUrlCharset());
- } catch (final Exception e) {
- return name.getURI();
- }
- }
-
- private boolean isCurrentFile(final String href, final GenericURLFileName
fileName) {
- String name = hrefString(fileName);
- if (href.endsWith("/") && !name.endsWith("/")) {
- name += "/";
- }
- return href.equals(name) || href.equals(fileName.getPath());
- }
-
- private boolean isDirectory(final GenericURLFileName name) throws
IOException {
- try {
- final DavProperty<?> property = getProperty(name,
DavConstants.PROPERTY_RESOURCETYPE);
- final Node node;
- if (property != null && (node = (Node) property.getValue()) !=
null) {
- return node.getLocalName().equals(DavConstants.XML_COLLECTION);
- }
- return false;
- } catch (final FileNotFoundException fse) {
- throw new FileNotFolderException(name);
- }
- }
-
- void log(final Exception ex) {
- // TODO Consider logging
- }
-
- /**
- * Returns the resource name from the path.
- *
- * @param path the path to the file.
- * @return The resource name
- */
- private String resourceName(String path) {
- if (path.endsWith("/")) {
- path = path.substring(0, path.length() - 1);
- }
- final int i = path.lastIndexOf("/");
- return i >= 0 ? path.substring(i + 1) : path;
- }
-
- private void setupRequest(final HttpUriRequest request) {
- // NOTE: *FileSystemConfigBuilder takes care of redirect option and
user agent.
- request.addHeader("Cache-control", "no-cache");
- request.addHeader("Cache-store", "no-store");
- request.addHeader("Pragma", "no-cache");
- request.addHeader("Expires", "0");
- }
-
- /**
- * Converts the given URLFileName to an encoded URL String to internally
use in real DAV operations.
- *
- * @param name The FileName.
- * @return The encoded URL String.
- */
- String toUrlString(final GenericURLFileName name) {
- return toUrlString(name, true);
- }
-
- /**
- * Converts the given URLFileName to an encoded URL String to internally
use in real DAV operations.
- *
- * @param name The FileName.
- * @param includeUserInfo true if user information should be included.
- * @return The encoded URL String.
- */
- private String toUrlString(final GenericURLFileName name, final boolean
includeUserInfo) {
- String user = null;
- String password = null;
- if (includeUserInfo) {
- user = name.getUserName();
- password = name.getPassword();
- }
- try {
- final GenericURLFileName newFile = new
GenericURLFileName(getInternalURI().getScheme(), name.getHostName(),
name.getPort(), name.getDefaultPort(),
- user, password, name.getPath(), name.getType(),
name.getQueryString());
- return newFile.getURIEncoded(this.getUrlCharset());
- } catch (final Exception e) {
- return name.getURI();
- }
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.commons.vfs2.provider.webdav4;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.vfs2.FileContentInfoFactory;
+import org.apache.commons.vfs2.FileNotFolderException;
+import org.apache.commons.vfs2.FileNotFoundException;
+import org.apache.commons.vfs2.FileObject;
+import org.apache.commons.vfs2.FileSystemException;
+import org.apache.commons.vfs2.FileType;
+import org.apache.commons.vfs2.NameScope;
+import org.apache.commons.vfs2.provider.AbstractFileName;
+import org.apache.commons.vfs2.provider.DefaultFileContent;
+import org.apache.commons.vfs2.provider.GenericURLFileName;
+import org.apache.commons.vfs2.provider.http4.Http4FileObject;
+import org.apache.commons.vfs2.util.FileObjectUtils;
+import org.apache.commons.vfs2.util.MonitorOutputStream;
+import org.apache.commons.vfs2.util.URIUtils;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.client.methods.HttpRequestBase;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.client.utils.DateUtils;
+import org.apache.http.entity.ByteArrayEntity;
+import org.apache.http.entity.ContentType;
+import org.apache.jackrabbit.webdav.DavConstants;
+import org.apache.jackrabbit.webdav.DavException;
+import org.apache.jackrabbit.webdav.MultiStatus;
+import org.apache.jackrabbit.webdav.MultiStatusResponse;
+import org.apache.jackrabbit.webdav.client.methods.BaseDavRequest;
+import org.apache.jackrabbit.webdav.client.methods.HttpCheckin;
+import org.apache.jackrabbit.webdav.client.methods.HttpCheckout;
+import org.apache.jackrabbit.webdav.client.methods.HttpDelete;
+import org.apache.jackrabbit.webdav.client.methods.HttpMkcol;
+import org.apache.jackrabbit.webdav.client.methods.HttpMove;
+import org.apache.jackrabbit.webdav.client.methods.HttpPropfind;
+import org.apache.jackrabbit.webdav.client.methods.HttpProppatch;
+import org.apache.jackrabbit.webdav.client.methods.HttpVersionControl;
+import org.apache.jackrabbit.webdav.property.DavProperty;
+import org.apache.jackrabbit.webdav.property.DavPropertyName;
+import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
+import org.apache.jackrabbit.webdav.property.DavPropertySet;
+import org.apache.jackrabbit.webdav.property.DefaultDavProperty;
+import org.apache.jackrabbit.webdav.version.DeltaVConstants;
+import org.apache.jackrabbit.webdav.version.VersionControlledResource;
+import org.apache.jackrabbit.webdav.xml.Namespace;
+import org.w3c.dom.Node;
+
+/**
+ * A WebDAV file.
+ *
+ * @since 2.5.0
+ */
+public class Webdav4FileObject extends Http4FileObject<Webdav4FileSystem> {
+
+ /**
+ * An OutputStream that writes to a Webdav resource.
+ * <p>
+ * TODO - Use piped stream to avoid temporary file.
+ */
+ private class WebdavOutputStream extends MonitorOutputStream {
+ private final Webdav4FileObject file;
+
+ WebdavOutputStream(final Webdav4FileObject file) {
+ super(new ByteArrayOutputStream());
+ this.file = file;
+ }
+
+ private boolean createVersion(final String urlStr) {
+ try {
+ final HttpVersionControl request = new
HttpVersionControl(urlStr);
+ setupRequest(request);
+ executeRequest(request);
+ return true;
+ } catch (final Exception ex) {
+ return false;
+ }
+ }
+
+ /**
+ * Called after this stream is closed.
+ */
+ @Override
+ protected void onClose() throws IOException {
+ final HttpEntity entity = new
ByteArrayEntity(((ByteArrayOutputStream) out).toByteArray());
+ final GenericURLFileName fileName = (GenericURLFileName) getName();
+ final String urlStr = toUrlString(fileName);
+ if (builder.isVersioning(getFileSystem().getFileSystemOptions())) {
+ DavPropertySet set = null;
+ boolean fileExists = true;
+ boolean isCheckedIn = true;
+ try {
+ set = getPropertyNames(fileName);
+ } catch (final FileNotFoundException fnfe) {
+ fileExists = false;
+ }
+ if (fileExists && set != null) {
+ if (set.contains(VersionControlledResource.CHECKED_OUT)) {
+ isCheckedIn = false;
+ } else if
(!set.contains(VersionControlledResource.CHECKED_IN)) {
+ DavProperty<?> prop =
set.get(VersionControlledResource.AUTO_VERSION);
+ if (prop != null) {
+ prop = getProperty(fileName,
VersionControlledResource.AUTO_VERSION);
+ if
(DeltaVConstants.XML_CHECKOUT_CHECKIN.equals(prop.getValue())) {
+ createVersion(urlStr);
+ }
+ }
+ }
+ }
+ if (fileExists && isCheckedIn) {
+ try {
+ final HttpCheckout request = new HttpCheckout(urlStr);
+ setupRequest(request);
+ executeRequest(request);
+ isCheckedIn = false;
+ } catch (final FileSystemException ex) {
+ log(ex);
+ }
+ }
+
+ try {
+ final HttpPut request = new HttpPut(urlStr);
+ request.setEntity(entity);
+ setupRequest(request);
+ executeRequest(request);
+ setUserName(fileName, urlStr);
+ } catch (final FileSystemException ex) {
+ if (!isCheckedIn) {
+ try {
+ final HttpCheckin request = new
HttpCheckin(urlStr);
+ setupRequest(request);
+ executeRequest(request);
+ isCheckedIn = true;
+ } catch (final Exception e) {
+ // Going to throw original.
+ log(e);
+ }
+ throw ex;
+ }
+ }
+ if (!fileExists) {
+ createVersion(urlStr);
+ try {
+ final DavPropertySet props =
getPropertyNames(fileName);
+ isCheckedIn =
!props.contains(VersionControlledResource.CHECKED_OUT);
+ } catch (final FileNotFoundException fnfe) {
+ log(fnfe);
+ }
+ }
+ if (!isCheckedIn) {
+ final HttpCheckin request = new HttpCheckin(urlStr);
+ setupRequest(request);
+ executeRequest(request);
+ }
+ } else {
+ final HttpPut request = new HttpPut(urlStr);
+ request.setEntity(entity);
+ setupRequest(request);
+ executeRequest(request);
+ try {
+ setUserName(fileName, urlStr);
+ } catch (final IOException e) {
+ // Unable to set the user name.
+ log(e);
+ }
+ }
+ ((DefaultFileContent) this.file.getContent()).resetAttributes();
+ }
+
+ private void setUserName(final GenericURLFileName fileName, final
String urlStr) throws IOException {
+ final DavPropertySet setProperties = new DavPropertySet();
+ final DavPropertyNameSet removeProperties = new
DavPropertyNameSet();
+ String name =
builder.getCreatorName(getFileSystem().getFileSystemOptions());
+ final String userName = fileName.getUserName();
+ if (name == null) {
+ name = userName;
+ } else if (userName != null) {
+ final String comment = "Modified by user " + userName;
+ setProperties.add(new
DefaultDavProperty<>(DeltaVConstants.COMMENT, comment));
+ }
+ setProperties.add(new
DefaultDavProperty<>(DeltaVConstants.CREATOR_DISPLAYNAME, name));
+ final HttpProppatch request = new HttpProppatch(urlStr,
setProperties, removeProperties);
+ setupRequest(request);
+ executeRequest(request);
+ }
+ }
+
+ /** The character set property name. */
+ public static final DavPropertyName RESPONSE_CHARSET =
DavPropertyName.create("response-charset");
+
+ /**
+ * An empty immutable {@code Webdav4FileObject} array.
+ */
+ private static final Webdav4FileObject[] EMPTY_ARRAY = {};
+
+ /** The FileSystemConfigBuilder */
+ private final Webdav4FileSystemConfigBuilder builder;
+
+
+ protected Webdav4FileObject(final AbstractFileName name, final
Webdav4FileSystem fileSystem)
+ throws FileSystemException {
+ this(name, fileSystem, Webdav4FileSystemConfigBuilder.getInstance());
+ }
+
+ protected Webdav4FileObject(final AbstractFileName name, final
Webdav4FileSystem fileSystem,
+ final Webdav4FileSystemConfigBuilder builder) throws
FileSystemException {
+ super(name, fileSystem, builder);
+ this.builder = builder;
+ }
+
+ /**
+ * Creates this file as a folder.
+ */
+ @Override
+ protected void doCreateFolder() throws Exception {
+ final HttpMkcol request = new
HttpMkcol(toUrlString((GenericURLFileName) getName()));
+ setupRequest(request);
+ try {
+ executeRequest(request);
+ } catch (final FileSystemException fse) {
+ throw new
FileSystemException("vfs.provider.webdav/create-collection.error", getName(),
fse);
+ }
+ }
+
+ /**
+ * Deletes the file.
+ */
+ @Override
+ protected void doDelete() throws Exception {
+ final HttpDelete request = new
HttpDelete(toUrlString((GenericURLFileName) getName()));
+ setupRequest(request);
+ executeRequest(request);
+ }
+
+ /**
+ * Returns the properties of the Webdav resource.
+ */
+ @Override
+ protected Map<String, Object> doGetAttributes() throws Exception {
+ final Map<String, Object> attributes = new HashMap<>();
+ try {
+ final GenericURLFileName fileName = (GenericURLFileName) getName();
+ DavPropertySet properties = getProperties(fileName,
DavConstants.PROPFIND_ALL_PROP,
+ new DavPropertyNameSet(), false);
+ for (final DavProperty<?> property : properties) {
+ attributes.put(property.getName().toString(),
property.getValue());
+ }
+ properties = getPropertyNames(fileName);
+ for (DavProperty<?> property : properties) {
+ if (!attributes.containsKey(property.getName().getName())) {
+ property = getProperty(fileName, property.getName());
+ if (property != null) {
+ final Object name = property.getName();
+ final Object value = property.getValue();
+ if (name != null && value != null) {
+ attributes.put(name.toString(), value);
+ }
+ }
+ }
+ }
+ return attributes;
+ } catch (final Exception e) {
+ throw new
FileSystemException("vfs.provider.webdav/get-attributes.error", getName(), e);
+ }
+ }
+
+ /**
+ * Returns the size of the file content (in bytes).
+ */
+ @Override
+ protected long doGetContentSize() throws Exception {
+ final DavProperty<?> property = getProperty((GenericURLFileName)
getName(), DavConstants.PROPERTY_GETCONTENTLENGTH);
+ if (property != null) {
+ final String value = (String) property.getValue();
+ return Long.parseLong(value);
+ }
+ return 0;
+ }
+
+ /**
+ * Returns the last modified time of this file. Is only called if {@link
#doGetType} does not return
+ * {@link FileType#IMAGINARY}.
+ */
+ @Override
+ protected long doGetLastModifiedTime() throws Exception {
+ final DavProperty<?> property = getProperty((GenericURLFileName)
getName(), DavConstants.PROPERTY_GETLASTMODIFIED);
+ if (property != null) {
+ final String value = (String) property.getValue();
+ return DateUtils.parseDate(value).getTime();
+ }
+ return 0;
+ }
+
+ @Override
+ protected OutputStream doGetOutputStream(final boolean bAppend) throws
Exception {
+ return new WebdavOutputStream(this);
+ }
+
+ /**
+ * Determines the type of this file. Must not return null. The return
value of this method is cached, so the
+ * implementation can be expensive.
+ */
+ @Override
+ protected FileType doGetType() throws Exception {
+ try {
+ return isDirectory((GenericURLFileName) getName()) ?
FileType.FOLDER : FileType.FILE;
+ } catch (final FileNotFolderException | FileNotFoundException fnfe) {
+ return FileType.IMAGINARY;
+ }
+
+ }
+
+ /**
+ * Determines if this file can be written to. Is only called if {@link
#doGetType} does not return
+ * {@link FileType#IMAGINARY}.
+ * <p>
+ * This implementation always returns true.
+ *
+ * @return true if the file is writable.
+ * @throws Exception if an error occurs.
+ */
+ @Override
+ protected boolean doIsWriteable() throws Exception {
+ return true;
+ }
+
+ /**
+ * Lists the children of the file.
+ */
+ @Override
+ protected String[] doListChildren() throws Exception {
+ // use doListChildrenResolved for performance
+ return null;
+ }
+
+ /**
+ * Lists the children of the file.
+ */
+ @Override
+ protected FileObject[] doListChildrenResolved() throws Exception {
+ HttpPropfind request = null;
+ try {
+ final GenericURLFileName name = (GenericURLFileName) getName();
+ if (isDirectory(name)) {
+ final DavPropertyNameSet nameSet = new DavPropertyNameSet();
+
nameSet.add(DavPropertyName.create(DavConstants.PROPERTY_DISPLAYNAME));
+
+ request = new HttpPropfind(toUrlString(name), nameSet,
DavConstants.DEPTH_1);
+
+ final HttpResponse res = executeRequest(request);
+ final List<Webdav4FileObject> vfs = new ArrayList<>();
+ if (request.succeeded(res)) {
+ final MultiStatusResponse[] responses =
request.getResponseBodyAsMultiStatus(res).getResponses();
+
+ for (final MultiStatusResponse response : responses) {
+ if (isCurrentFile(response.getHref(), name)) {
+ continue;
+ }
+ final String resourceName =
resourceName(response.getHref());
+ if (!resourceName.isEmpty()) {
+ final Webdav4FileObject fo = (Webdav4FileObject)
FileObjectUtils.getAbstractFileObject(
+
getFileSystem().resolveFile(getFileSystem().getFileSystemManager()
+ .resolveName(getName(),
resourceName, NameScope.CHILD)));
+ vfs.add(fo);
+ }
+ }
+ }
+ return vfs.toArray(EMPTY_ARRAY);
+ }
+ throw new FileNotFolderException(getName());
+ } catch (final FileNotFolderException fnfe) {
+ throw fnfe;
+ } catch (final DavException | IOException e) {
+ throw new FileSystemException(e.getMessage(), e);
+ } finally {
+ if (request != null) {
+ request.releaseConnection();
+ }
+ }
+ }
+
+ /**
+ * Rename the file.
+ */
+ @Override
+ protected void doRename(final FileObject newFile) throws Exception {
+ final String url =
URIUtils.encodePath(toUrlString((GenericURLFileName) getName()));
+ final String dest = toUrlString((GenericURLFileName)
newFile.getName(), false);
+ final HttpMove request = new HttpMove(url, dest, false);
+ setupRequest(request);
+ executeRequest(request);
+ }
+
+ /**
+ * Sets an attribute of this file. Is only called if {@link #doGetType}
does not return {@link FileType#IMAGINARY}.
+ */
+ @Override
+ protected void doSetAttribute(final String attrName, final Object value)
throws Exception {
+ try {
+ final GenericURLFileName fileName = (GenericURLFileName) getName();
+ final String urlStr = toUrlString(fileName);
+ final DavPropertySet properties = new DavPropertySet();
+ final DavPropertyNameSet propertyNameSet = new
DavPropertyNameSet();
+ final DavProperty<Object> property = new
DefaultDavProperty<>(attrName, value, Namespace.EMPTY_NAMESPACE);
+ if (value != null) {
+ properties.add(property);
+ } else {
+ propertyNameSet.add(property.getName()); // remove property
+ }
+
+ final HttpProppatch request = new HttpProppatch(urlStr,
properties, propertyNameSet);
+ setupRequest(request);
+ final HttpResponse response = executeRequest(request);
+ if (!request.succeeded(response)) {
+ throw new FileSystemException("Property '" + attrName + "'
could not be set.");
+ }
+ } catch (final FileSystemException fse) {
+ throw fse;
+ } catch (final Exception e) {
+ throw new
FileSystemException("vfs.provider.webdav/set-attributes", e, getName(),
attrName);
+ }
+ }
+
+ private HttpResponse executeRequest(final HttpUriRequest request) throws
FileSystemException {
+ final HttpResponse response;
+
+ try {
+ response = executeHttpUriRequest(request);
+ final int status = response.getStatusLine().getStatusCode();
+ if (status == HttpURLConnection.HTTP_NOT_FOUND || status ==
HttpURLConnection.HTTP_GONE) {
+ throw new FileNotFoundException(request.getURI());
+ }
+
+ if (request instanceof BaseDavRequest) {
+ ((BaseDavRequest) request).checkSuccess(response);
+ }
+
+ return response;
+ } catch (final FileSystemException fse) {
+ throw fse;
+ } catch (final IOException e) {
+ throw new FileSystemException(e);
+ } catch (final DavException e) {
+ throw ExceptionConverter.generate(e);
+ } finally {
+ if (request instanceof HttpRequestBase) {
+ ((HttpRequestBase) request).releaseConnection();
+ }
+ }
+ }
+
+ @Override
+ protected FileContentInfoFactory getFileContentInfoFactory() {
+ return new Webdav4FileContentInfoFactory();
+ }
+
+ DavPropertySet getProperties(final GenericURLFileName name) throws
FileSystemException {
+ return getProperties(name, DavConstants.PROPFIND_ALL_PROP, new
DavPropertyNameSet(), false);
+ }
+
+ DavPropertySet getProperties(final GenericURLFileName name, final
DavPropertyNameSet nameSet, final boolean addEncoding)
+ throws FileSystemException {
+ return getProperties(name, DavConstants.PROPFIND_BY_PROPERTY, nameSet,
addEncoding);
+ }
+
+ DavPropertySet getProperties(final GenericURLFileName name, final int
type, final DavPropertyNameSet nameSet,
+ final boolean addEncoding) throws FileSystemException {
+ try {
+ final String urlStr = toUrlString(name);
+ final HttpPropfind request = new HttpPropfind(urlStr, type,
nameSet, DavConstants.DEPTH_0);
+ setupRequest(request);
+ final HttpResponse res = executeRequest(request);
+ if (request.succeeded(res)) {
+ final MultiStatus multiStatus =
request.getResponseBodyAsMultiStatus(res);
+ final MultiStatusResponse response =
multiStatus.getResponses()[0];
+ final DavPropertySet props =
response.getProperties(HttpStatus.SC_OK);
+ if (addEncoding) {
+ final ContentType resContentType =
ContentType.getOrDefault(res.getEntity());
+ final DavProperty<String> prop = new
DefaultDavProperty<>(RESPONSE_CHARSET,
+ resContentType.getCharset().name());
+ props.add(prop);
+ }
+ return props;
+ }
+ return new DavPropertySet();
+ } catch (final FileSystemException fse) {
+ throw fse;
+ } catch (final Exception e) {
+ throw new
FileSystemException("vfs.provider.webdav/get-property.error", e, getName(),
name, type,
+ nameSet.getContent(), addEncoding);
+ }
+ }
+
+ DavProperty<?> getProperty(final GenericURLFileName fileName, final
DavPropertyName name) throws FileSystemException {
+ final DavPropertyNameSet nameSet = new DavPropertyNameSet();
+ nameSet.add(name);
+ final DavPropertySet propertySet = getProperties(fileName, nameSet,
false);
+ return propertySet.get(name);
+ }
+
+ DavProperty<?> getProperty(final GenericURLFileName fileName, final String
property) throws FileSystemException {
+ return getProperty(fileName, DavPropertyName.create(property));
+ }
+
+ DavPropertySet getPropertyNames(final GenericURLFileName name) throws
FileSystemException {
+ return getProperties(name, DavConstants.PROPFIND_PROPERTY_NAMES, new
DavPropertyNameSet(), false);
+ }
+
+ /**
+ * Convert the FileName to an encoded url String.
+ *
+ * @param name The FileName.
+ * @return The encoded URL String.
+ */
+ private String hrefString(final GenericURLFileName name) {
+ try {
+ final GenericURLFileName newFile = new
GenericURLFileName(getInternalURI().getScheme(), name.getHostName(),
name.getPort(), name.getDefaultPort(),
+ null, null, name.getPath(), name.getType(),
name.getQueryString());
+ return newFile.getURIEncoded(this.getUrlCharset());
+ } catch (final Exception e) {
+ return name.getURI();
+ }
+ }
+
+ private boolean isCurrentFile(final String href, final GenericURLFileName
fileName) {
+ String name = hrefString(fileName);
+ if (href.endsWith("/") && !name.endsWith("/")) {
+ name += "/";
+ }
+ return href.equals(name) || href.equals(fileName.getPath());
+ }
+
+ private boolean isDirectory(final GenericURLFileName name) throws
IOException {
+ try {
+ final DavProperty<?> property = getProperty(name,
DavConstants.PROPERTY_RESOURCETYPE);
+ final Node node;
+ if (property != null && (node = (Node) property.getValue()) !=
null) {
+ return node.getLocalName().equals(DavConstants.XML_COLLECTION);
+ }
+ return false;
+ } catch (final FileNotFoundException fse) {
+ throw new FileNotFolderException(name);
+ }
+ }
+
+ void log(final Exception ex) {
+ // TODO Consider logging
+ }
+
+ /**
+ * Returns the resource name from the path.
+ *
+ * @param path the path to the file.
+ * @return The resource name
+ */
+ private String resourceName(String path) {
+ if (path.endsWith("/")) {
+ path = path.substring(0, path.length() - 1);
+ }
+ final int i = path.lastIndexOf("/");
+ return i >= 0 ? path.substring(i + 1) : path;
+ }
+
+ private void setupRequest(final HttpUriRequest request) {
+ // NOTE: *FileSystemConfigBuilder takes care of redirect option and
user agent.
+ request.addHeader("Cache-control", "no-cache");
+ request.addHeader("Cache-store", "no-store");
+ request.addHeader("Pragma", "no-cache");
+ request.addHeader("Expires", "0");
+ }
+
+ /**
+ * Converts the given URLFileName to an encoded URL String to internally
use in real DAV operations.
+ *
+ * @param name The FileName.
+ * @return The encoded URL String.
+ */
+ String toUrlString(final GenericURLFileName name) {
+ return toUrlString(name, true);
+ }
+
+ /**
+ * Converts the given URLFileName to an encoded URL String to internally
use in real DAV operations.
+ *
+ * @param name The FileName.
+ * @param includeUserInfo true if user information should be included.
+ * @return The encoded URL String.
+ */
+ private String toUrlString(final GenericURLFileName name, final boolean
includeUserInfo) {
+ String user = null;
+ String password = null;
+ if (includeUserInfo) {
+ user = name.getUserName();
+ password = name.getPassword();
+ }
+ try {
+ final GenericURLFileName newFile = new
GenericURLFileName(getInternalURI().getScheme(), name.getHostName(),
name.getPort(), name.getDefaultPort(),
+ user, password, name.getPath(), name.getType(),
name.getQueryString());
+ return newFile.getURIEncoded(this.getUrlCharset());
+ } catch (final Exception e) {
+ return name.getURI();
+ }
+ }
+}