--- /dev/null
+# 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.
+
+name: Coverage
+
+on: [push, pull_request]
+
+permissions:
+ contents: read
+
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ java: [ 8 ]
+
+ steps:
+ - uses: actions/checkout@v3
+ - uses: actions/cache@v3.0.7
+ with:
+ path: ~/.m2/repository
+ key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+ restore-keys: |
+ ${{ runner.os }}-maven-
+ - name: Set up JDK ${{ matrix.java }}
+ uses: actions/setup-java@v3
+ with:
+ distribution: 'temurin'
+ java-version: ${{ matrix.java }}
+ - name: Build with Maven
+ run: mvn -V test jacoco:report --file pom.xml --no-transfer-progress
+
+ - name: Upload coverage to Codecov
+ uses: codecov/codecov-action@v3
+ with:
+ files: ./target/site/jacoco/jacoco.xml
steps:
- uses: actions/checkout@v3
- - uses: actions/cache@v3.0.3
+ - uses: actions/cache@v3.0.7
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
o Bump net.sourceforge.pmd:pmd-* from 6.32.0 to 6.33.0.
o Bump checkstyle from 8.41 to 8.44 #175. Thanks to Dependabot, Gary Gregory.
o Bump actions/setup-java to v2 #177. Thanks to Boris Petrov.
-o Bump mockito-core from 3.8.0 to 3.11.2 #178. Thanks to Dependabot, Gary GRegory.
+o Bump mockito-core from 3.8.0 to 3.11.2 #178. Thanks to Dependabot, Gary Gregory.
o Bump commons-io from 2.8.0 to 2.10.0. Thanks to Gary Gregory.
o Bump actions/cache from 2.1.4 to 2.1.6 #183. Thanks to Dependabot.
o Bump jackrabbit2.version from 2.21.5 to 2.21.6 #180. Thanks to Dependabot.
o Update from to javax.mail:mail 1.4.7 to com.sun.mail:jakarta.mail 1.6.7. Thanks to Gary Gregory.
-Historical list of changes: http://commons.apache.org/proper/commons-vfs/changes-report.html
+Historical list of changes: https://commons.apache.org/proper/commons-vfs/changes-report.html
For complete information on Apache Commons VFS Project, including instructions on how to submit bug reports,
patches, or suggestions for improvement, see the Apache Apache Commons VFS Project website:
-http://commons.apache.org/proper/commons-vfs/
+https://commons.apache.org/proper/commons-vfs/
-Download page: http://commons.apache.org/proper/commons-vfs/download_vfs.cgi
+Download page: https://commons.apache.org/proper/commons-vfs/download_vfs.cgi
-----------------------------------------------------------------------------
o Update commons-lang3 3.11 -> 3.12.0. Thanks to Gary Gregory.
-Historical list of changes: http://commons.apache.org/proper/commons-vfs/changes-report.html
+Historical list of changes: https://commons.apache.org/proper/commons-vfs/changes-report.html
For complete information on Apache Commons VFS Project, including instructions on how to submit bug reports,
patches, or suggestions for improvement, see the Apache Apache Commons VFS Project website:
-http://commons.apache.org/proper/commons-vfs/
+https://commons.apache.org/proper/commons-vfs/
-Download page: http://commons.apache.org/proper/commons-vfs/download_vfs.cgi
+Download page: https://commons.apache.org/proper/commons-vfs/download_vfs.cgi
-----------------------------------------------------------------------------
o Update JUnit from 4.13 to 4.13.1. Thanks to Gary Gregory.
-Historical list of changes: http://commons.apache.org/proper/commons-vfs/changes-report.html
+Historical list of changes: https://commons.apache.org/proper/commons-vfs/changes-report.html
For complete information on Apache Commons VFS Project, including instructions on how to submit bug reports,
patches, or suggestions for improvement, see the Apache Apache Commons VFS Project website:
-http://commons.apache.org/proper/commons-vfs/
+https://commons.apache.org/proper/commons-vfs/
-Download page: http://commons.apache.org/proper/commons-vfs/download_vfs.cgi
+Download page: https://commons.apache.org/proper/commons-vfs/download_vfs.cgi
-----------------------------------------------------------------------------
o Update JUnit from 4.12 to 4.13. Thanks to Gary Gregory.
-Historical list of changes: http://commons.apache.org/proper/commons-vfs/changes-report.html
+Historical list of changes: https://commons.apache.org/proper/commons-vfs/changes-report.html
For complete information on Apache Commons VFS Project, including instructions on how to submit bug reports,
patches, or suggestions for improvement, see the Apache Apache Commons VFS Project website:
-http://commons.apache.org/proper/commons-vfs/
+https://commons.apache.org/proper/commons-vfs/
-Download page: http://commons.apache.org/proper/commons-vfs/download_vfs.cgi
+Download page: https://commons.apache.org/proper/commons-vfs/download_vfs.cgi
-----------------------------------------------------------------------------
o VFS-749: Update Apache Commons Parent from 48 to 50. Thanks to Gary Gregory.
-Historical list of changes: http://commons.apache.org/proper/commons-vfs/changes-report.html
+Historical list of changes: https://commons.apache.org/proper/commons-vfs/changes-report.html
For complete information on Apache Commons VFS, including instructions on how to submit bug reports,
patches, or suggestions for improvement, see the Apache Apache Commons VFS website:
-http://commons.apache.org/proper/commons-vfs/
+https://commons.apache.org/proper/commons-vfs/
-Download it from http://commons.apache.org/proper/commons-vfs/download_vfs.cgi
+Download it from https://commons.apache.org/proper/commons-vfs/download_vfs.cgi
-----------------------------------------------------------------------------
o Javadoc fixes. Thanks to Gary Gregory.
-Historical list of changes: http://commons.apache.org/proper/commons-vfs/changes-report.html
+Historical list of changes: https://commons.apache.org/proper/commons-vfs/changes-report.html
For complete information on Apache Commons VFS, including instructions on how to submit bug reports,
patches, or suggestions for improvement, see the Apache Apache Commons VFS website:
-Visit http://commons.apache.org/proper/commons-vfs/
+Visit https://commons.apache.org/proper/commons-vfs/
-Download it from http://commons.apache.org/proper/commons-vfs/download_vfs.cgi
+Download it from https://commons.apache.org/proper/commons-vfs/download_vfs.cgi
-----------------------------------------------------------------------------
o Public API note: The overridden method org.apache.commons.vfs2.provider.sftp.SftpFileProvider#init() was removed but is implemented in a superclass.
-Historical list of changes: http://commons.apache.org/proper/commons-vfs/changes-report.html
+Historical list of changes: https://commons.apache.org/proper/commons-vfs/changes-report.html
For complete information on Apache Commons VFS, including instructions on how to submit bug reports,
patches, or suggestions for improvement, see the Apache Apache Commons VFS website:
-Visit http://commons.apache.org/proper/commons-vfs/
+Visit https://commons.apache.org/proper/commons-vfs/
-Download it from http://commons.apache.org/proper/commons-vfs/download_vfs.cgi
+Download it from https://commons.apache.org/proper/commons-vfs/download_vfs.cgi
-----------------------------------------------------------------------------
o VFS-688: [SFTP] Update jsch from 0.1.54 to 0.1.55.
-Historical list of changes: http://commons.apache.org/proper/commons-vfs/changes-report.html
+Historical list of changes: https://commons.apache.org/proper/commons-vfs/changes-report.html
For complete information on Apache Commons VFS, including instructions on how to submit bug reports,
patches, or suggestions for improvement, see the Apache Apache Commons VFS website:
-Visit http://commons.apache.org/proper/commons-vfs/
+Visit https://commons.apache.org/proper/commons-vfs/
-Download it from http://commons.apache.org/proper/commons-vfs/download_vfs.cgi
+Download it from https://commons.apache.org/proper/commons-vfs/download_vfs.cgi
-----------------------------------------------------------------------------
o VFS-645: VfsClassLoaderTests fails on Java 9.
-Historical list of changes: http://commons.apache.org/proper/commons-vfs/changes-report.html
+Historical list of changes: https://commons.apache.org/proper/commons-vfs/changes-report.html
For complete information on Apache Commons VFS, including instructions on how to submit bug reports,
patches, or suggestions for improvement, see the Apache Apache Commons VFS website:
-Visit http://commons.apache.org/proper/commons-vfs/
+Visit https://commons.apache.org/proper/commons-vfs/
-Download it from http://commons.apache.org/proper/commons-vfs/download_vfs.cgi
+Download it from https://commons.apache.org/proper/commons-vfs/download_vfs.cgi
-----------------------------------------------------------------------------
o VFS-313: [FTP] Configuration does not include option for setting socket timeout. Thanks to bdavis@saintandreas.org.
o VFS-414: [FTP] Add config API to set the file type.
o VFS-182: [FTP] Usage of FTP with heterogeneous FTP server (possibility of using Ascii file type).
-o VFS-381: Iterate over a FileObject using the Java "foreach" statement, to provide all descendents of a FileObject.
+o VFS-381: Iterate over a FileObject using the Java "foreach" statement, to provide all descendants of a FileObject.
o VFS-373: Add FileContent write APIs.
o VFS-372: Add constructors FileDepthSelector() and FileDepthSelector(int).
o VFS-371: Add FileObject API deleteAll().
o VFS-490: [vfsclassloader] Do not open folders with .jar extension. Adds tests.
o VFS-582: [tests] revert rename of getTestDirectoryFile to make test classes more compatible for external providers.
o VFS-480: Make startup of SoftRefsFileCache cleaner thread work and less racy to avoid leaks.
-o VFS-549: Use File.seperator instead of getProperty("file.separator").
+o VFS-549: Use File.separator instead of getProperty("file.separator").
o VFS-567: [ftp] Ignore exceptions while QUIT/disconnect. Thanks to Antonio Petrelli.
o VFS-572: [sftp] better documentation for knownhosts file option. Thanks to Sandra Parsick.
-o VFS-574: Ensure FileOpertionProviders are closed. Adds some testcases.
+o VFS-574: Ensure FileOperationProviders are closed. Adds some testcases.
The error code for missing operations exceptions corrected: vfs.operation/operation-not-supported.error
o VFS-279: [local] Avoid ClassCastException when replicating local files while OnCall caching is active. Thanks to Didier Earith, Simon Legner.
o VFS-297: [sftp] VSF fails to reuse FileSystem instances if FileSystemOptions contain
keys only, a new structure EntityInfo has been created. SftpFileSystemConfigBuilder has now the new
getter and setter methods getIdentityInfo and setIdentity info which replace the now deprecated methods
getIdentities and setIdentities.
-o VFS-463: FileSytemConfigBuilder supports system properties for the value of enum-based configuration entries.
+o VFS-463: FileSystemConfigBuilder supports system properties for the value of enum-based configuration entries.
o VFS-462: [FTPS] Deprecate FtpsFileSystemConfigBuilder.setFtpsType and FtpsFileSystemConfigBuilder.getFtpsType
in favor of FtpsFileSystemConfigBuilder.setFtpsMode and FtpsFileSystemConfigBuilder.getFtpsMode which
use new enum FtpsMode instead.
o VFS-459: [FTP/FTPS] Sent commands and the received answer is logged at debug level.
o VFS-457: Update test dependencies: sshd-core version 0.7.0 to 0.8.0; mina-core 2.0.4 to 2.0.7; junit 4.11 to 4.12; slf4j-* 1.5.5 to 1.5.11
-o VFS-456: Use org.bouncycastel:bcprov-jdk16 instead of org.bouncycastle:bcprof-jdk15on since Java 1.6 is required.
+o VFS-456: Use org.bouncycastle:bcprov-jdk16 instead of org.bouncycastle:bcprof-jdk15on since Java 1.6 is required.
o VFS-415: Update VFS requirement to Java 1.6.
o VFS-418: Update to Apache Commons Compress 1.4.1.
o VFS-321: AbstractFileObject sometimes uses getFileSystem() and sometimes references "fs" field directly. Thanks to sebb.
Removed:
o VFS-469: Remove unused dependency to javax.jcr:jcr.
-Historical list of changes: http://commons.apache.org/proper/commons-vfs/changes-report.html
+Historical list of changes: https://commons.apache.org/proper/commons-vfs/changes-report.html
For complete information on Apache Commons VFS, including instructions on how to submit bug reports,
patches, or suggestions for improvement, see the Apache Apache Commons VFS website:
-Visit http://commons.apache.org/proper/commons-vfs/
+Visit https://commons.apache.org/proper/commons-vfs/
-Download it from http://commons.apache.org/proper/commons-vfs/download_vfs.cgi
+Download it from https://commons.apache.org/proper/commons-vfs/download_vfs.cgi
------------------------------------------------------------------------------
\ No newline at end of file
+-----------------------------------------------------------------------------
<property name="localeLanguage" value="en" />
<!-- Checks that a package-info.java file exists for each package. -->
- <!-- See http://checkstyle.sourceforge.net/config_javadoc.html -->
+ <!-- See https://checkstyle.org/config_javadoc.html#JavadocPackage -->
<module name="JavadocPackage" />
<!-- Checks whether files end with a new line. -->
- <!-- See http://checkstyle.sf.net/config_misc.html#NewlineAtEndOfFile -->
+ <!-- See https://checkstyle.org/config_misc.html#NewlineAtEndOfFile -->
<module name="NewlineAtEndOfFile" />
<!-- Checks that property files contain the same keys. -->
- <!-- See http://checkstyle.sf.net/config_misc.html#Translation -->
+ <!-- See https://checkstyle.org/config_misc.html#Translation -->
<module name="Translation" />
<!-- Checks for Tab characters -->
- <!-- See http://checkstyle.sourceforge.net/config_whitespace.html#FileTabCharacter -->
+ <!-- See https://checkstyle.org/config_whitespace.html#FileTabCharacter -->
<module name="FileTabCharacter">
<property name="fileExtensions" value="java" />
</module>
<!-- Checks for white space at the end of the line -->
- <!-- See http://checkstyle.sourceforge.net/config_regexp.html -->
+ <!-- See https://checkstyle.org/config_regexp.html#RegexpSingleline -->
<module name="RegexpSingleline">
<property name="format" value="\s+$" />
<property name="message" value="Line has trailing spaces." />
</module>
<!-- Checks for Size Violations. -->
- <!-- See http://checkstyle.sf.net/config_sizes.html -->
+ <!-- See https://checkstyle.org/config_sizes.html#LineLength -->
<module name="LineLength">
<property name="max" value="160" />
</module>
<module name="TreeWalker">
<!-- Checks for Javadoc comments. -->
- <!-- See http://checkstyle.sf.net/config_javadoc.html -->
+ <!-- See https://checkstyle.org/config_javadoc.html -->
<module name="JavadocMethod">
<property name="accessModifiers" value="public" />
</module>
<module name="MissingJavadocMethod"/>
- <!-- http://checkstyle.sourceforge.net/config_javadoc.html#JavadocType -->
+ <!-- https://checkstyle.org/config_javadoc.html#JavadocType -->
<module name="JavadocType">
<!-- It is unfortunate to have to do this but checkstyle doesn't allow custom tags -->
<property name="allowUnknownTags" value="true" />
</module>
<!-- Checks for Naming Conventions. -->
- <!-- See http://checkstyle.sf.net/config_naming.html -->
+ <!-- See https://checkstyle.org/config_naming.html -->
<module name="ConstantName">
<property name="format" value="^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$|^capabilities$|^log$" />
</module>
<!-- <module name="RegexpHeader"/> -->
<!-- Checks for imports -->
- <!-- See http://checkstyle.sf.net/config_import.html -->
+ <!-- See https://checkstyle.org/config_imports.html -->
<module name="AvoidStarImport" />
<module name="IllegalImport" /> <!-- defaults to sun.* packages -->
<module name="RedundantImport" />
<module name="UnusedImports" />
<!-- Checks for Size Violations. -->
- <!-- See http://checkstyle.sf.net/config_sizes.html -->
+ <!-- See https://checkstyle.org/config_sizes.html -->
<!--<module name="FileLength"/> -->
<module name="MethodLength" />
<module name="ParameterNumber">
</module>
<!-- Checks for whitespace -->
- <!-- See http://checkstyle.sf.net/config_whitespace.html -->
+ <!-- See https://checkstyle.org/config_whitespace.html -->
<module name="EmptyForIteratorPad" />
<module name="NoWhitespaceAfter" />
<module name="NoWhitespaceBefore" />
<module name="GenericWhitespace" />
<!-- Modifier Checks -->
- <!-- See http://checkstyle.sf.net/config_modifiers.html -->
+ <!-- See https://checkstyle.org/config_modifier.html -->
<module name="ModifierOrder" />
<module name="RedundantModifier" />
<!-- Checks for blocks. You know, those {}'s -->
- <!-- See http://checkstyle.sf.net/config_blocks.html -->
+ <!-- See https://checkstyle.org/config_blocks.html -->
<module name="AvoidNestedBlocks" />
<!-- Require empty catch blocks to have at least a comment -->
<module name="EmptyBlock">
</module>
<!-- Checks for common coding problems -->
- <!-- See http://checkstyle.sf.net/config_coding.html -->
+ <!-- See https://checkstyle.org/config_coding.html -->
<module name="CovariantEquals" />
<module name="EqualsHashCode" />
<module name="IllegalInstantiation" />
<!-- <module name="UnnecessaryParentheses"/> -->
<!-- Checks for class design -->
- <!-- See http://checkstyle.sf.net/config_design.html -->
+ <!-- See https://checkstyle.org/config_design.html -->
<module name="FinalClass" />
<module name="HideUtilityClassConstructor" />
<module name="InterfaceIsType" />
</module>
<!-- Miscellaneous other checks. -->
- <!-- See http://checkstyle.sf.net/config_misc.html -->
+ <!-- See https://checkstyle.org/config_misc.html -->
<module name="ArrayTypeStyle" />
<module name="TodoComment">
<property name="severity" value="info" />
-------------
More information can be found on the [Apache Commons VFS Examples homepage](https://commons.apache.org/proper/commons-vfs).
-The [Javadoc](https://commons.apache.org/proper/commons-vfs/apidocs) can be browsed.
+The [Javadoc](https://commons.apache.org/proper/commons-vfs/commons-vfs2/apidocs/index.html) can be browsed.
Questions related to the usage of Apache Commons VFS Examples should be posted to the [user mailing list][ml].
Where can I get the latest release?
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
- <version>3.0.0</version>
+ <version>3.1.0</version>
<executions>
<execution>
<phase>validate</phase>
-/*
- * 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();
- }
- }
-}
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements. See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License. You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.apache.commons.vfs2.provider.webdav4;\r
+\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.IOException;\r
+import java.io.OutputStream;\r
+import java.net.HttpURLConnection;\r
+import java.util.ArrayList;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+import java.util.Map;\r
+\r
+import org.apache.commons.vfs2.FileContentInfoFactory;\r
+import org.apache.commons.vfs2.FileNotFolderException;\r
+import org.apache.commons.vfs2.FileNotFoundException;\r
+import org.apache.commons.vfs2.FileObject;\r
+import org.apache.commons.vfs2.FileSystemException;\r
+import org.apache.commons.vfs2.FileType;\r
+import org.apache.commons.vfs2.NameScope;\r
+import org.apache.commons.vfs2.provider.AbstractFileName;\r
+import org.apache.commons.vfs2.provider.DefaultFileContent;\r
+import org.apache.commons.vfs2.provider.GenericURLFileName;\r
+import org.apache.commons.vfs2.provider.http4.Http4FileObject;\r
+import org.apache.commons.vfs2.util.FileObjectUtils;\r
+import org.apache.commons.vfs2.util.MonitorOutputStream;\r
+import org.apache.commons.vfs2.util.URIUtils;\r
+import org.apache.http.HttpEntity;\r
+import org.apache.http.HttpResponse;\r
+import org.apache.http.HttpStatus;\r
+import org.apache.http.client.methods.HttpPut;\r
+import org.apache.http.client.methods.HttpRequestBase;\r
+import org.apache.http.client.methods.HttpUriRequest;\r
+import org.apache.http.client.utils.DateUtils;\r
+import org.apache.http.entity.ByteArrayEntity;\r
+import org.apache.http.entity.ContentType;\r
+import org.apache.jackrabbit.webdav.DavConstants;\r
+import org.apache.jackrabbit.webdav.DavException;\r
+import org.apache.jackrabbit.webdav.MultiStatus;\r
+import org.apache.jackrabbit.webdav.MultiStatusResponse;\r
+import org.apache.jackrabbit.webdav.client.methods.BaseDavRequest;\r
+import org.apache.jackrabbit.webdav.client.methods.HttpCheckin;\r
+import org.apache.jackrabbit.webdav.client.methods.HttpCheckout;\r
+import org.apache.jackrabbit.webdav.client.methods.HttpDelete;\r
+import org.apache.jackrabbit.webdav.client.methods.HttpMkcol;\r
+import org.apache.jackrabbit.webdav.client.methods.HttpMove;\r
+import org.apache.jackrabbit.webdav.client.methods.HttpPropfind;\r
+import org.apache.jackrabbit.webdav.client.methods.HttpProppatch;\r
+import org.apache.jackrabbit.webdav.client.methods.HttpVersionControl;\r
+import org.apache.jackrabbit.webdav.property.DavProperty;\r
+import org.apache.jackrabbit.webdav.property.DavPropertyName;\r
+import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;\r
+import org.apache.jackrabbit.webdav.property.DavPropertySet;\r
+import org.apache.jackrabbit.webdav.property.DefaultDavProperty;\r
+import org.apache.jackrabbit.webdav.version.DeltaVConstants;\r
+import org.apache.jackrabbit.webdav.version.VersionControlledResource;\r
+import org.apache.jackrabbit.webdav.xml.Namespace;\r
+import org.w3c.dom.Node;\r
+\r
+/**\r
+ * A WebDAV file.\r
+ *\r
+ * @since 2.5.0\r
+ */\r
+public class Webdav4FileObject extends Http4FileObject<Webdav4FileSystem> {\r
+\r
+ /**\r
+ * An OutputStream that writes to a Webdav resource.\r
+ * <p>\r
+ * TODO - Use piped stream to avoid temporary file.\r
+ */\r
+ private class WebdavOutputStream extends MonitorOutputStream {\r
+ private final Webdav4FileObject file;\r
+\r
+ WebdavOutputStream(final Webdav4FileObject file) {\r
+ super(new ByteArrayOutputStream());\r
+ this.file = file;\r
+ }\r
+\r
+ private boolean createVersion(final String urlStr) {\r
+ try {\r
+ final HttpVersionControl request = new HttpVersionControl(urlStr);\r
+ setupRequest(request);\r
+ executeRequest(request);\r
+ return true;\r
+ } catch (final Exception ex) {\r
+ return false;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Called after this stream is closed.\r
+ */\r
+ @Override\r
+ protected void onClose() throws IOException {\r
+ final HttpEntity entity = new ByteArrayEntity(((ByteArrayOutputStream) out).toByteArray());\r
+ final GenericURLFileName fileName = (GenericURLFileName) getName();\r
+ final String urlStr = toUrlString(fileName);\r
+ if (builder.isVersioning(getFileSystem().getFileSystemOptions())) {\r
+ DavPropertySet set = null;\r
+ boolean fileExists = true;\r
+ boolean isCheckedIn = true;\r
+ try {\r
+ set = getPropertyNames(fileName);\r
+ } catch (final FileNotFoundException fnfe) {\r
+ fileExists = false;\r
+ }\r
+ if (fileExists && set != null) {\r
+ if (set.contains(VersionControlledResource.CHECKED_OUT)) {\r
+ isCheckedIn = false;\r
+ } else if (!set.contains(VersionControlledResource.CHECKED_IN)) {\r
+ DavProperty<?> prop = set.get(VersionControlledResource.AUTO_VERSION);\r
+ if (prop != null) {\r
+ prop = getProperty(fileName, VersionControlledResource.AUTO_VERSION);\r
+ if (DeltaVConstants.XML_CHECKOUT_CHECKIN.equals(prop.getValue())) {\r
+ createVersion(urlStr);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ if (fileExists && isCheckedIn) {\r
+ try {\r
+ final HttpCheckout request = new HttpCheckout(urlStr);\r
+ setupRequest(request);\r
+ executeRequest(request);\r
+ isCheckedIn = false;\r
+ } catch (final FileSystemException ex) {\r
+ log(ex);\r
+ }\r
+ }\r
+\r
+ try {\r
+ final HttpPut request = new HttpPut(urlStr);\r
+ request.setEntity(entity);\r
+ setupRequest(request);\r
+ executeRequest(request);\r
+ setUserName(fileName, urlStr);\r
+ } catch (final FileSystemException ex) {\r
+ if (!isCheckedIn) {\r
+ try {\r
+ final HttpCheckin request = new HttpCheckin(urlStr);\r
+ setupRequest(request);\r
+ executeRequest(request);\r
+ isCheckedIn = true;\r
+ } catch (final Exception e) {\r
+ // Going to throw original.\r
+ log(e);\r
+ }\r
+ throw ex;\r
+ }\r
+ }\r
+ if (!fileExists) {\r
+ createVersion(urlStr);\r
+ try {\r
+ final DavPropertySet props = getPropertyNames(fileName);\r
+ isCheckedIn = !props.contains(VersionControlledResource.CHECKED_OUT);\r
+ } catch (final FileNotFoundException fnfe) {\r
+ log(fnfe);\r
+ }\r
+ }\r
+ if (!isCheckedIn) {\r
+ final HttpCheckin request = new HttpCheckin(urlStr);\r
+ setupRequest(request);\r
+ executeRequest(request);\r
+ }\r
+ } else {\r
+ final HttpPut request = new HttpPut(urlStr);\r
+ request.setEntity(entity);\r
+ setupRequest(request);\r
+ executeRequest(request);\r
+ try {\r
+ setUserName(fileName, urlStr);\r
+ } catch (final IOException e) {\r
+ // Unable to set the user name.\r
+ log(e);\r
+ }\r
+ }\r
+ ((DefaultFileContent) this.file.getContent()).resetAttributes();\r
+ }\r
+\r
+ private void setUserName(final GenericURLFileName fileName, final String urlStr) throws IOException {\r
+ final DavPropertySet setProperties = new DavPropertySet();\r
+ final DavPropertyNameSet removeProperties = new DavPropertyNameSet();\r
+ String name = builder.getCreatorName(getFileSystem().getFileSystemOptions());\r
+ final String userName = fileName.getUserName();\r
+ if (name == null) {\r
+ name = userName;\r
+ } else if (userName != null) {\r
+ final String comment = "Modified by user " + userName;\r
+ setProperties.add(new DefaultDavProperty<>(DeltaVConstants.COMMENT, comment));\r
+ }\r
+ setProperties.add(new DefaultDavProperty<>(DeltaVConstants.CREATOR_DISPLAYNAME, name));\r
+ final HttpProppatch request = new HttpProppatch(urlStr, setProperties, removeProperties);\r
+ setupRequest(request);\r
+ executeRequest(request);\r
+ }\r
+ }\r
+\r
+ /** The character set property name. */\r
+ public static final DavPropertyName RESPONSE_CHARSET = DavPropertyName.create("response-charset");\r
+\r
+ /**\r
+ * An empty immutable {@code Webdav4FileObject} array.\r
+ */\r
+ private static final Webdav4FileObject[] EMPTY_ARRAY = {};\r
+\r
+ /** The FileSystemConfigBuilder */\r
+ private final Webdav4FileSystemConfigBuilder builder;\r
+\r
+\r
+ protected Webdav4FileObject(final AbstractFileName name, final Webdav4FileSystem fileSystem)\r
+ throws FileSystemException {\r
+ this(name, fileSystem, Webdav4FileSystemConfigBuilder.getInstance());\r
+ }\r
+\r
+ protected Webdav4FileObject(final AbstractFileName name, final Webdav4FileSystem fileSystem,\r
+ final Webdav4FileSystemConfigBuilder builder) throws FileSystemException {\r
+ super(name, fileSystem, builder);\r
+ this.builder = builder;\r
+ }\r
+\r
+ /**\r
+ * Creates this file as a folder.\r
+ */\r
+ @Override\r
+ protected void doCreateFolder() throws Exception {\r
+ final HttpMkcol request = new HttpMkcol(toUrlString((GenericURLFileName) getName()));\r
+ setupRequest(request);\r
+ try {\r
+ executeRequest(request);\r
+ } catch (final FileSystemException fse) {\r
+ throw new FileSystemException("vfs.provider.webdav/create-collection.error", getName(), fse);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Deletes the file.\r
+ */\r
+ @Override\r
+ protected void doDelete() throws Exception {\r
+ final HttpDelete request = new HttpDelete(toUrlString((GenericURLFileName) getName()));\r
+ setupRequest(request);\r
+ executeRequest(request);\r
+ }\r
+\r
+ /**\r
+ * Returns the properties of the Webdav resource.\r
+ */\r
+ @Override\r
+ protected Map<String, Object> doGetAttributes() throws Exception {\r
+ final Map<String, Object> attributes = new HashMap<>();\r
+ try {\r
+ final GenericURLFileName fileName = (GenericURLFileName) getName();\r
+ DavPropertySet properties = getProperties(fileName, DavConstants.PROPFIND_ALL_PROP,\r
+ new DavPropertyNameSet(), false);\r
+ for (final DavProperty<?> property : properties) {\r
+ attributes.put(property.getName().toString(), property.getValue());\r
+ }\r
+ properties = getPropertyNames(fileName);\r
+ for (DavProperty<?> property : properties) {\r
+ if (!attributes.containsKey(property.getName().getName())) {\r
+ property = getProperty(fileName, property.getName());\r
+ if (property != null) {\r
+ final Object name = property.getName();\r
+ final Object value = property.getValue();\r
+ if (name != null && value != null) {\r
+ attributes.put(name.toString(), value);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ return attributes;\r
+ } catch (final Exception e) {\r
+ throw new FileSystemException("vfs.provider.webdav/get-attributes.error", getName(), e);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Returns the size of the file content (in bytes).\r
+ */\r
+ @Override\r
+ protected long doGetContentSize() throws Exception {\r
+ final DavProperty<?> property = getProperty((GenericURLFileName) getName(), DavConstants.PROPERTY_GETCONTENTLENGTH);\r
+ if (property != null) {\r
+ final String value = (String) property.getValue();\r
+ return Long.parseLong(value);\r
+ }\r
+ return 0;\r
+ }\r
+\r
+ /**\r
+ * Returns the last modified time of this file. Is only called if {@link #doGetType} does not return\r
+ * {@link FileType#IMAGINARY}.\r
+ */\r
+ @Override\r
+ protected long doGetLastModifiedTime() throws Exception {\r
+ final DavProperty<?> property = getProperty((GenericURLFileName) getName(), DavConstants.PROPERTY_GETLASTMODIFIED);\r
+ if (property != null) {\r
+ final String value = (String) property.getValue();\r
+ return DateUtils.parseDate(value).getTime();\r
+ }\r
+ return 0;\r
+ }\r
+\r
+ @Override\r
+ protected OutputStream doGetOutputStream(final boolean bAppend) throws Exception {\r
+ return new WebdavOutputStream(this);\r
+ }\r
+\r
+ /**\r
+ * Determines the type of this file. Must not return null. The return value of this method is cached, so the\r
+ * implementation can be expensive.\r
+ */\r
+ @Override\r
+ protected FileType doGetType() throws Exception {\r
+ try {\r
+ return isDirectory((GenericURLFileName) getName()) ? FileType.FOLDER : FileType.FILE;\r
+ } catch (final FileNotFolderException | FileNotFoundException fnfe) {\r
+ return FileType.IMAGINARY;\r
+ }\r
+\r
+ }\r
+\r
+ /**\r
+ * Determines if this file can be written to. Is only called if {@link #doGetType} does not return\r
+ * {@link FileType#IMAGINARY}.\r
+ * <p>\r
+ * This implementation always returns true.\r
+ *\r
+ * @return true if the file is writable.\r
+ * @throws Exception if an error occurs.\r
+ */\r
+ @Override\r
+ protected boolean doIsWriteable() throws Exception {\r
+ return true;\r
+ }\r
+\r
+ /**\r
+ * Lists the children of the file.\r
+ */\r
+ @Override\r
+ protected String[] doListChildren() throws Exception {\r
+ // use doListChildrenResolved for performance\r
+ return null;\r
+ }\r
+\r
+ /**\r
+ * Lists the children of the file.\r
+ */\r
+ @Override\r
+ protected FileObject[] doListChildrenResolved() throws Exception {\r
+ HttpPropfind request = null;\r
+ try {\r
+ final GenericURLFileName name = (GenericURLFileName) getName();\r
+ if (isDirectory(name)) {\r
+ final DavPropertyNameSet nameSet = new DavPropertyNameSet();\r
+ nameSet.add(DavPropertyName.create(DavConstants.PROPERTY_DISPLAYNAME));\r
+\r
+ request = new HttpPropfind(toUrlString(name), nameSet, DavConstants.DEPTH_1);\r
+\r
+ final HttpResponse res = executeRequest(request);\r
+ final List<Webdav4FileObject> vfs = new ArrayList<>();\r
+ if (request.succeeded(res)) {\r
+ final MultiStatusResponse[] responses = request.getResponseBodyAsMultiStatus(res).getResponses();\r
+\r
+ for (final MultiStatusResponse response : responses) {\r
+ if (isCurrentFile(response.getHref(), name)) {\r
+ continue;\r
+ }\r
+ final String resourceName = resourceName(response.getHref());\r
+ if (!resourceName.isEmpty()) {\r
+ final Webdav4FileObject fo = (Webdav4FileObject) FileObjectUtils.getAbstractFileObject(\r
+ getFileSystem().resolveFile(getFileSystem().getFileSystemManager()\r
+ .resolveName(getName(), resourceName, NameScope.CHILD)));\r
+ vfs.add(fo);\r
+ }\r
+ }\r
+ }\r
+ return vfs.toArray(EMPTY_ARRAY);\r
+ }\r
+ throw new FileNotFolderException(getName());\r
+ } catch (final FileNotFolderException fnfe) {\r
+ throw fnfe;\r
+ } catch (final DavException | IOException e) {\r
+ throw new FileSystemException(e.getMessage(), e);\r
+ } finally {\r
+ if (request != null) {\r
+ request.releaseConnection();\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Rename the file.\r
+ */\r
+ @Override\r
+ protected void doRename(final FileObject newFile) throws Exception {\r
+ final String url = URIUtils.encodePath(toUrlString((GenericURLFileName) getName()));\r
+ final String dest = toUrlString((GenericURLFileName) newFile.getName(), false);\r
+ final HttpMove request = new HttpMove(url, dest, false);\r
+ setupRequest(request);\r
+ executeRequest(request);\r
+ }\r
+\r
+ /**\r
+ * Sets an attribute of this file. Is only called if {@link #doGetType} does not return {@link FileType#IMAGINARY}.\r
+ */\r
+ @Override\r
+ protected void doSetAttribute(final String attrName, final Object value) throws Exception {\r
+ try {\r
+ final GenericURLFileName fileName = (GenericURLFileName) getName();\r
+ final String urlStr = toUrlString(fileName);\r
+ final DavPropertySet properties = new DavPropertySet();\r
+ final DavPropertyNameSet propertyNameSet = new DavPropertyNameSet();\r
+ final DavProperty<Object> property = new DefaultDavProperty<>(attrName, value, Namespace.EMPTY_NAMESPACE);\r
+ if (value != null) {\r
+ properties.add(property);\r
+ } else {\r
+ propertyNameSet.add(property.getName()); // remove property\r
+ }\r
+\r
+ final HttpProppatch request = new HttpProppatch(urlStr, properties, propertyNameSet);\r
+ setupRequest(request);\r
+ final HttpResponse response = executeRequest(request);\r
+ if (!request.succeeded(response)) {\r
+ throw new FileSystemException("Property '" + attrName + "' could not be set.");\r
+ }\r
+ } catch (final FileSystemException fse) {\r
+ throw fse;\r
+ } catch (final Exception e) {\r
+ throw new FileSystemException("vfs.provider.webdav/set-attributes", e, getName(), attrName);\r
+ }\r
+ }\r
+\r
+ private HttpResponse executeRequest(final HttpUriRequest request) throws FileSystemException {\r
+ final HttpResponse response;\r
+\r
+ try {\r
+ response = executeHttpUriRequest(request);\r
+ final int status = response.getStatusLine().getStatusCode();\r
+ if (status == HttpURLConnection.HTTP_NOT_FOUND || status == HttpURLConnection.HTTP_GONE) {\r
+ throw new FileNotFoundException(request.getURI());\r
+ }\r
+\r
+ if (request instanceof BaseDavRequest) {\r
+ ((BaseDavRequest) request).checkSuccess(response);\r
+ }\r
+\r
+ return response;\r
+ } catch (final FileSystemException fse) {\r
+ throw fse;\r
+ } catch (final IOException e) {\r
+ throw new FileSystemException(e);\r
+ } catch (final DavException e) {\r
+ throw ExceptionConverter.generate(e);\r
+ } finally {\r
+ if (request instanceof HttpRequestBase) {\r
+ ((HttpRequestBase) request).releaseConnection();\r
+ }\r
+ }\r
+ }\r
+\r
+ @Override\r
+ protected FileContentInfoFactory getFileContentInfoFactory() {\r
+ return new Webdav4FileContentInfoFactory();\r
+ }\r
+\r
+ DavPropertySet getProperties(final GenericURLFileName name) throws FileSystemException {\r
+ return getProperties(name, DavConstants.PROPFIND_ALL_PROP, new DavPropertyNameSet(), false);\r
+ }\r
+\r
+ DavPropertySet getProperties(final GenericURLFileName name, final DavPropertyNameSet nameSet, final boolean addEncoding)\r
+ throws FileSystemException {\r
+ return getProperties(name, DavConstants.PROPFIND_BY_PROPERTY, nameSet, addEncoding);\r
+ }\r
+\r
+ DavPropertySet getProperties(final GenericURLFileName name, final int type, final DavPropertyNameSet nameSet,\r
+ final boolean addEncoding) throws FileSystemException {\r
+ try {\r
+ final String urlStr = toUrlString(name);\r
+ final HttpPropfind request = new HttpPropfind(urlStr, type, nameSet, DavConstants.DEPTH_0);\r
+ setupRequest(request);\r
+ final HttpResponse res = executeRequest(request);\r
+ if (request.succeeded(res)) {\r
+ final MultiStatus multiStatus = request.getResponseBodyAsMultiStatus(res);\r
+ final MultiStatusResponse response = multiStatus.getResponses()[0];\r
+ final DavPropertySet props = response.getProperties(HttpStatus.SC_OK);\r
+ if (addEncoding) {\r
+ final ContentType resContentType = ContentType.getOrDefault(res.getEntity());\r
+ final DavProperty<String> prop = new DefaultDavProperty<>(RESPONSE_CHARSET,\r
+ resContentType.getCharset().name());\r
+ props.add(prop);\r
+ }\r
+ return props;\r
+ }\r
+ return new DavPropertySet();\r
+ } catch (final FileSystemException fse) {\r
+ throw fse;\r
+ } catch (final Exception e) {\r
+ throw new FileSystemException("vfs.provider.webdav/get-property.error", e, getName(), name, type,\r
+ nameSet.getContent(), addEncoding);\r
+ }\r
+ }\r
+\r
+ DavProperty<?> getProperty(final GenericURLFileName fileName, final DavPropertyName name) throws FileSystemException {\r
+ final DavPropertyNameSet nameSet = new DavPropertyNameSet();\r
+ nameSet.add(name);\r
+ final DavPropertySet propertySet = getProperties(fileName, nameSet, false);\r
+ return propertySet.get(name);\r
+ }\r
+\r
+ DavProperty<?> getProperty(final GenericURLFileName fileName, final String property) throws FileSystemException {\r
+ return getProperty(fileName, DavPropertyName.create(property));\r
+ }\r
+\r
+ DavPropertySet getPropertyNames(final GenericURLFileName name) throws FileSystemException {\r
+ return getProperties(name, DavConstants.PROPFIND_PROPERTY_NAMES, new DavPropertyNameSet(), false);\r
+ }\r
+\r
+ /**\r
+ * Convert the FileName to an encoded url String.\r
+ *\r
+ * @param name The FileName.\r
+ * @return The encoded URL String.\r
+ */\r
+ private String hrefString(final GenericURLFileName name) {\r
+ try {\r
+ final GenericURLFileName newFile = new GenericURLFileName(getInternalURI().getScheme(), name.getHostName(), name.getPort(), name.getDefaultPort(),\r
+ null, null, name.getPath(), name.getType(), name.getQueryString());\r
+ return newFile.getURIEncoded(this.getUrlCharset());\r
+ } catch (final Exception e) {\r
+ return name.getURI();\r
+ }\r
+ }\r
+\r
+ private boolean isCurrentFile(final String href, final GenericURLFileName fileName) {\r
+ String name = hrefString(fileName);\r
+ if (href.endsWith("/") && !name.endsWith("/")) {\r
+ name += "/";\r
+ }\r
+ return href.equals(name) || href.equals(fileName.getPath());\r
+ }\r
+\r
+ private boolean isDirectory(final GenericURLFileName name) throws IOException {\r
+ try {\r
+ final DavProperty<?> property = getProperty(name, DavConstants.PROPERTY_RESOURCETYPE);\r
+ final Node node;\r
+ if (property != null && (node = (Node) property.getValue()) != null) {\r
+ return node.getLocalName().equals(DavConstants.XML_COLLECTION);\r
+ }\r
+ return false;\r
+ } catch (final FileNotFoundException fse) {\r
+ throw new FileNotFolderException(name);\r
+ }\r
+ }\r
+\r
+ void log(final Exception ex) {\r
+ // TODO Consider logging\r
+ }\r
+\r
+ /**\r
+ * Returns the resource name from the path.\r
+ *\r
+ * @param path the path to the file.\r
+ * @return The resource name\r
+ */\r
+ private String resourceName(String path) {\r
+ if (path.endsWith("/")) {\r
+ path = path.substring(0, path.length() - 1);\r
+ }\r
+ final int i = path.lastIndexOf("/");\r
+ return i >= 0 ? path.substring(i + 1) : path;\r
+ }\r
+\r
+ private void setupRequest(final HttpUriRequest request) {\r
+ // NOTE: *FileSystemConfigBuilder takes care of redirect option and user agent.\r
+ request.addHeader("Cache-control", "no-cache");\r
+ request.addHeader("Cache-store", "no-store");\r
+ request.addHeader("Pragma", "no-cache");\r
+ request.addHeader("Expires", "0");\r
+ }\r
+\r
+ /**\r
+ * Converts the given URLFileName to an encoded URL String to internally use in real DAV operations.\r
+ *\r
+ * @param name The FileName.\r
+ * @return The encoded URL String.\r
+ */\r
+ String toUrlString(final GenericURLFileName name) {\r
+ return toUrlString(name, true);\r
+ }\r
+\r
+ /**\r
+ * Converts the given URLFileName to an encoded URL String to internally use in real DAV operations.\r
+ *\r
+ * @param name The FileName.\r
+ * @param includeUserInfo true if user information should be included.\r
+ * @return The encoded URL String.\r
+ */\r
+ private String toUrlString(final GenericURLFileName name, final boolean includeUserInfo) {\r
+ String user = null;\r
+ String password = null;\r
+ if (includeUserInfo) {\r
+ user = name.getUserName();\r
+ password = name.getPassword();\r
+ }\r
+ try {\r
+ final GenericURLFileName newFile = new GenericURLFileName(getInternalURI().getScheme(), name.getHostName(), name.getPort(), name.getDefaultPort(),\r
+ user, password, name.getPath(), name.getType(), name.getQueryString());\r
+ return newFile.getURIEncoded(this.getUrlCharset());\r
+ } catch (final Exception e) {\r
+ return name.getURI();\r
+ }\r
+ }\r
+}\r
providers</a>) which cannot be shipped with the official Apache release.\r
This includes experimental code as well as components which have \r
<a href="dependencies.html">dependencies</a> not compatible with the \r
- <a href="http://www.apache.org/legal/resolved.html#category-x">ASF redistribution policy\r
+ <a href="https://www.apache.org/legal/resolved.html#category-x">ASF redistribution policy\r
(especially LGPL)</a>.\r
</p><p>\r
To build the sandbox binaries, see the <a href="../download.html">download and build\r
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!--
- 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.
- -->
-
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-
- <modelVersion>4.0.0</modelVersion>
-
- <name>Apache Commons VFS</name>
- <artifactId>commons-vfs2</artifactId>
- <description>Apache Commons VFS is a Virtual File System library.</description>
- <url>http://commons.apache.org/proper/commons-vfs/</url>
-
- <parent>
- <groupId>org.apache.commons</groupId>
- <artifactId>commons-vfs2-project</artifactId>
- <version>2.10.0-SNAPSHOT</version>
- <relativePath>../</relativePath>
- </parent>
-
- <dependencies>
- <dependency>
- <groupId>commons-logging</groupId>
- <artifactId>commons-logging</artifactId>
- </dependency>
- <dependency>
- <groupId>ant</groupId>
- <artifactId>ant</artifactId>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>commons-net</groupId>
- <artifactId>commons-net</artifactId>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>org.apache.commons</groupId>
- <artifactId>commons-compress</artifactId>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>org.apache.commons</groupId>
- <artifactId>commons-collections4</artifactId>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>org.apache.hadoop</groupId>
- <artifactId>hadoop-hdfs-client</artifactId>
- </dependency>
- <dependency>
- <groupId>org.apache.hadoop</groupId>
- <artifactId>hadoop-common</artifactId>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>org.apache.hadoop</groupId>
- <artifactId>hadoop-hdfs</artifactId>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>commons-httpclient</groupId>
- <artifactId>commons-httpclient</artifactId>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>org.apache.httpcomponents</groupId>
- <artifactId>httpclient</artifactId>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>org.apache.httpcomponents.client5</groupId>
- <artifactId>httpclient5</artifactId>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>com.jcraft</groupId>
- <artifactId>jsch</artifactId>
- <optional>true</optional>
- </dependency>
-
- <dependency>
- <groupId>org.junit.jupiter</groupId>
- <artifactId>junit-jupiter-engine</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.junit.vintage</groupId>
- <artifactId>junit-vintage-engine</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.mockito</groupId>
- <artifactId>mockito-core</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.apache.commons</groupId>
- <artifactId>commons-lang3</artifactId>
- </dependency>
- <!-- Test FTP with Apache FTP Server (MINA) -->
- <dependency>
- <groupId>org.apache.ftpserver</groupId>
- <artifactId>ftpserver-core</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.apache.logging.log4j</groupId>
- <artifactId>log4j-slf4j-impl</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.apache.logging.log4j</groupId>
- <artifactId>log4j-core</artifactId>
- <scope>test</scope>
- </dependency>
- <!-- Test SFTP with Apache SHHd Server (MINA) -->
- <dependency>
- <groupId>org.apache.sshd</groupId>
- <artifactId>sshd-core</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.bouncycastle</groupId>
- <artifactId>bcprov-jdk16</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>commons-io</groupId>
- <artifactId>commons-io</artifactId>
- <scope>test</scope>
- </dependency>
- <!-- Test HTTP with Apache HttpComponent Core -->
- <dependency>
- <groupId>org.apache.httpcomponents</groupId>
- <artifactId>httpcore-nio</artifactId>
- <scope>test</scope>
- </dependency>
- <!-- Test HDFS with Apache Hadoop -->
- <dependency>
- <groupId>org.apache.hadoop</groupId>
- <artifactId>hadoop-common</artifactId>
- <type>test-jar</type>
- <scope>test</scope>
- <exclusions>
- <exclusion>
- <!-- VFS-606 - tools.jar not available in Java 9
- This exclusion can be removed after upgrading Hadoop
- to 2.7.1 or later
- -->
- <groupId>jdk.tools</groupId>
- <artifactId>jdk.tools</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <dependency>
- <groupId>org.apache.hadoop</groupId>
- <artifactId>hadoop-hdfs</artifactId>
- <type>test-jar</type>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>javax.ws.rs</groupId>
- <artifactId>jsr311-api</artifactId>
- <scope>test</scope>
- </dependency>
- </dependencies>
-
- <properties>
- <vfs.parent.dir>${basedir}/..</vfs.parent.dir>
- <commons.osgi.import>
- org.apache.hadoop.*;resolution:=optional,
- org.apache.tools.ant.*;resolution:=optional,
- org.apache.commons.httpclient.*;resolution:=optional,
- *
- </commons.osgi.import>
- </properties>
-
- <build>
- <resources>
- <resource>
- <directory>${basedir}/src/main/resources</directory>
- </resource>
- <!-- include NOTICE/LICENSE in generated jar -->
- <resource>
- <directory>${vfs.parent.dir}</directory>
- <targetPath>META-INF</targetPath>
- <includes>
- <include>NOTICE.txt</include>
- <include>LICENSE.txt</include>
- </includes>
- </resource>
- </resources>
-
- <testResources>
- <testResource>
- <directory>src/test/resources</directory>
- </testResource>
- <!-- include NOTICE/LICENSE in generated test jar -->
- <testResource>
- <directory>${vfs.parent.dir}</directory>
- <targetPath>META-INF</targetPath>
- <includes>
- <include>NOTICE.txt</include>
- <include>LICENSE.txt</include>
- </includes>
- </testResource>
- </testResources>
-
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-jar-plugin</artifactId>
- <executions>
- <execution>
- <goals>
- <goal>test-jar</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-antrun-plugin</artifactId>
- <executions>
- <execution>
- <phase>process-test-classes</phase>
- <configuration>
- <target>
- <move todir="${project.build.testOutputDirectory}/test-data/code" failonerror="false">
- <fileset dir="${project.build.testOutputDirectory}/code" />
- </move>
- </target>
- </configuration>
- <goals>
- <goal>run</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <trimStackTrace>false</trimStackTrace>
- <systemPropertyVariables>
- <test.basedir>target/test-classes/test-data</test.basedir>
- <test.basedir.res>test-data</test.basedir.res>
- <derby.stream.error.file>target/derby.log</derby.stream.error.file>
- </systemPropertyVariables>
- <excludes>
- <!-- Main class -->
- <exclude>**/RunTest.java</exclude>
- <!-- inner classes -->
- <exclude>**/*$*</exclude>
- <!-- Need to port fully to JUnit 4 or 5. -->
- <!-- *Tests.java files with @Test methods should not be run since these classes are in fact JUnit 3 classes used in custom JUnit 3 test suites. -->
- <exclude>**/*Tests.java</exclude>
- </excludes>
- </configuration>
- </plugin>
- </plugins>
- </build>
-
- <profiles>
- <profile>
- <id>webdav</id>
- <activation>
- <activeByDefault>false</activeByDefault>
- </activation>
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <systemPropertyVariables>
- <test.webdav.uri>${test.webdav.uri}</test.webdav.uri>
- </systemPropertyVariables>
- </configuration>
- </plugin>
- </plugins>
- </build>
- </profile>
-
- <profile>
- <id>ftp</id>
- <activation>
- <activeByDefault>false</activeByDefault>
- </activation>
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <systemPropertyVariables>
- <test.ftp.uri>${test.ftp.uri}</test.ftp.uri>
- </systemPropertyVariables>
- </configuration>
- </plugin>
- </plugins>
- </build>
- </profile>
-
- <profile>
- <id>sftp</id>
- <activation>
- <activeByDefault>false</activeByDefault>
- </activation>
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <systemPropertyVariables>
- <test.sftp.uri>${test.sftp.uri}</test.sftp.uri>
- </systemPropertyVariables>
- </configuration>
- </plugin>
- </plugins>
- </build>
- </profile>
-
- <profile>
- <id>http</id>
- <activation>
- <activeByDefault>false</activeByDefault>
- </activation>
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <systemPropertyVariables>
- <test.http.uri>${test.http.uri}</test.http.uri>
- </systemPropertyVariables>
- </configuration>
- </plugin>
- </plugins>
- </build>
- </profile>
-
- <!-- On Windows we disable hdfs tests by default. -->
- <profile>
- <id>no-test-hdfs</id>
- <activation>
- <activeByDefault>false</activeByDefault>
- <os>
- <family>Windows</family>
- </os>
- </activation>
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <excludes>
- <exclude>**/HdfsFileProviderTest.java</exclude>
- <exclude>**/HdfsFileProviderTestCase.java</exclude>
- <!-- Need to port fully to JUnit 4 or 5. -->
- <!-- *Tests.java files with @Test methods should not be run since these classes are in fact JUnit 3 classes used in custom JUnit 3 test suites. -->
- <exclude>**/*Tests.java</exclude>
- </excludes>
- </configuration>
- </plugin>
- </plugins>
- </build>
- </profile>
- </profiles>
-
-</project>
+<?xml version="1.0" encoding="UTF-8"?>\r
+\r
+<!--\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+ -->\r
+\r
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">\r
+\r
+ <modelVersion>4.0.0</modelVersion>\r
+\r
+ <name>Apache Commons VFS</name>\r
+ <artifactId>commons-vfs2</artifactId>\r
+ <description>Apache Commons VFS is a Virtual File System library.</description>\r
+ <url>https://commons.apache.org/proper/commons-vfs/</url>\r
+\r
+ <parent>\r
+ <groupId>org.apache.commons</groupId>\r
+ <artifactId>commons-vfs2-project</artifactId>\r
+ <version>2.10.0-SNAPSHOT</version>\r
+ <relativePath>../</relativePath>\r
+ </parent>\r
+\r
+ <dependencies>\r
+ <dependency>\r
+ <groupId>commons-logging</groupId>\r
+ <artifactId>commons-logging</artifactId>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>ant</groupId>\r
+ <artifactId>ant</artifactId>\r
+ <optional>true</optional>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>commons-net</groupId>\r
+ <artifactId>commons-net</artifactId>\r
+ <optional>true</optional>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>org.apache.commons</groupId>\r
+ <artifactId>commons-compress</artifactId>\r
+ <optional>true</optional>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>org.apache.commons</groupId>\r
+ <artifactId>commons-collections4</artifactId>\r
+ <optional>true</optional>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>org.apache.hadoop</groupId>\r
+ <artifactId>hadoop-hdfs-client</artifactId>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>org.apache.hadoop</groupId>\r
+ <artifactId>hadoop-common</artifactId>\r
+ <optional>true</optional>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>org.apache.hadoop</groupId>\r
+ <artifactId>hadoop-hdfs</artifactId>\r
+ <optional>true</optional>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>commons-httpclient</groupId>\r
+ <artifactId>commons-httpclient</artifactId>\r
+ <optional>true</optional>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>org.apache.httpcomponents</groupId>\r
+ <artifactId>httpclient</artifactId>\r
+ <optional>true</optional>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>org.apache.httpcomponents.client5</groupId>\r
+ <artifactId>httpclient5</artifactId>\r
+ <optional>true</optional>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>com.jcraft</groupId>\r
+ <artifactId>jsch</artifactId>\r
+ <optional>true</optional>\r
+ </dependency>\r
+ <!-- Tests -->\r
+ <dependency>\r
+ <groupId>org.junit.jupiter</groupId>\r
+ <artifactId>junit-jupiter-engine</artifactId>\r
+ <scope>test</scope>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>org.junit.vintage</groupId>\r
+ <artifactId>junit-vintage-engine</artifactId>\r
+ <scope>test</scope>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>org.mockito</groupId>\r
+ <artifactId>mockito-core</artifactId>\r
+ <scope>test</scope>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>org.apache.commons</groupId>\r
+ <artifactId>commons-lang3</artifactId>\r
+ </dependency>\r
+ <!-- Test FTP with Apache FTP Server (MINA) -->\r
+ <dependency>\r
+ <groupId>org.apache.ftpserver</groupId>\r
+ <artifactId>ftpserver-core</artifactId>\r
+ <scope>test</scope>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>org.slf4j</groupId>\r
+ <artifactId>slf4j-api</artifactId>\r
+ <scope>test</scope>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>org.apache.logging.log4j</groupId>\r
+ <artifactId>log4j-slf4j-impl</artifactId>\r
+ <scope>test</scope>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>org.apache.logging.log4j</groupId>\r
+ <artifactId>log4j-core</artifactId>\r
+ <scope>test</scope>\r
+ </dependency>\r
+ <!-- Test SFTP with Apache SHHd Server (MINA) -->\r
+ <dependency>\r
+ <groupId>org.apache.sshd</groupId>\r
+ <artifactId>sshd-core</artifactId>\r
+ <scope>test</scope>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>org.bouncycastle</groupId>\r
+ <artifactId>bcprov-jdk16</artifactId>\r
+ <scope>test</scope>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>commons-io</groupId>\r
+ <artifactId>commons-io</artifactId>\r
+ <scope>test</scope>\r
+ </dependency>\r
+ <!-- Test HTTP with Apache HttpComponent Core -->\r
+ <dependency>\r
+ <groupId>org.apache.httpcomponents</groupId>\r
+ <artifactId>httpcore-nio</artifactId>\r
+ <scope>test</scope>\r
+ </dependency>\r
+ <!-- Test HDFS with Apache Hadoop -->\r
+ <dependency>\r
+ <groupId>org.apache.hadoop</groupId>\r
+ <artifactId>hadoop-common</artifactId>\r
+ <type>test-jar</type>\r
+ <scope>test</scope>\r
+ <exclusions>\r
+ <exclusion>\r
+ <!-- VFS-606 - tools.jar not available in Java 9\r
+ This exclusion can be removed after upgrading Hadoop\r
+ to 2.7.1 or later \r
+ -->\r
+ <groupId>jdk.tools</groupId>\r
+ <artifactId>jdk.tools</artifactId>\r
+ </exclusion>\r
+ </exclusions>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>org.apache.hadoop</groupId>\r
+ <artifactId>hadoop-hdfs</artifactId>\r
+ <type>test-jar</type>\r
+ <scope>test</scope>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>javax.ws.rs</groupId>\r
+ <artifactId>jsr311-api</artifactId>\r
+ <scope>test</scope>\r
+ </dependency>\r
+ </dependencies>\r
+\r
+ <properties>\r
+ <vfs.parent.dir>${basedir}/..</vfs.parent.dir>\r
+ <commons.osgi.import>\r
+ org.apache.hadoop.*;resolution:=optional,\r
+ org.apache.tools.ant.*;resolution:=optional,\r
+ org.apache.commons.httpclient.*;resolution:=optional,\r
+ *\r
+ </commons.osgi.import>\r
+ </properties>\r
+\r
+ <build>\r
+ <resources>\r
+ <resource>\r
+ <directory>${basedir}/src/main/resources</directory>\r
+ </resource>\r
+ <!-- include NOTICE/LICENSE in generated jar -->\r
+ <resource>\r
+ <directory>${vfs.parent.dir}</directory>\r
+ <targetPath>META-INF</targetPath>\r
+ <includes>\r
+ <include>NOTICE.txt</include>\r
+ <include>LICENSE.txt</include>\r
+ </includes>\r
+ </resource>\r
+ </resources>\r
+\r
+ <testResources>\r
+ <testResource>\r
+ <directory>src/test/resources</directory>\r
+ </testResource>\r
+ <!-- include NOTICE/LICENSE in generated test jar -->\r
+ <testResource>\r
+ <directory>${vfs.parent.dir}</directory>\r
+ <targetPath>META-INF</targetPath>\r
+ <includes>\r
+ <include>NOTICE.txt</include>\r
+ <include>LICENSE.txt</include>\r
+ </includes>\r
+ </testResource>\r
+ </testResources>\r
+\r
+ <plugins>\r
+ <plugin>\r
+ <groupId>org.apache.maven.plugins</groupId>\r
+ <artifactId>maven-jar-plugin</artifactId>\r
+ <executions>\r
+ <execution>\r
+ <goals>\r
+ <goal>test-jar</goal>\r
+ </goals>\r
+ </execution>\r
+ </executions>\r
+ </plugin>\r
+\r
+ <plugin>\r
+ <groupId>org.apache.maven.plugins</groupId>\r
+ <artifactId>maven-antrun-plugin</artifactId>\r
+ <executions>\r
+ <execution>\r
+ <phase>process-test-classes</phase>\r
+ <configuration>\r
+ <target>\r
+ <move todir="${project.build.testOutputDirectory}/test-data/code" failonerror="false">\r
+ <fileset dir="${project.build.testOutputDirectory}/code" />\r
+ </move>\r
+ </target>\r
+ </configuration>\r
+ <goals>\r
+ <goal>run</goal>\r
+ </goals>\r
+ </execution>\r
+ </executions>\r
+ </plugin>\r
+\r
+ <plugin>\r
+ <groupId>org.apache.maven.plugins</groupId>\r
+ <artifactId>maven-surefire-plugin</artifactId>\r
+ <configuration>\r
+ <trimStackTrace>false</trimStackTrace>\r
+ <systemPropertyVariables>\r
+ <test.basedir>target/test-classes/test-data</test.basedir>\r
+ <test.basedir.res>test-data</test.basedir.res>\r
+ <derby.stream.error.file>target/derby.log</derby.stream.error.file>\r
+ </systemPropertyVariables>\r
+ <excludes>\r
+ <!-- Main class -->\r
+ <exclude>**/RunTest.java</exclude>\r
+ <!-- inner classes -->\r
+ <exclude>**/*$*</exclude>\r
+ <!-- Need to port fully to JUnit 4 or 5. -->\r
+ <!-- *Tests.java files with @Test methods should not be run since these classes are in fact JUnit 3 classes used in custom JUnit 3 test suites. -->\r
+ <exclude>**/*Tests.java</exclude>\r
+ </excludes>\r
+ </configuration>\r
+ </plugin>\r
+ </plugins>\r
+ </build>\r
+\r
+ <profiles>\r
+ <profile>\r
+ <id>webdav</id>\r
+ <activation>\r
+ <activeByDefault>false</activeByDefault>\r
+ </activation>\r
+ <build>\r
+ <plugins>\r
+ <plugin>\r
+ <groupId>org.apache.maven.plugins</groupId>\r
+ <artifactId>maven-surefire-plugin</artifactId>\r
+ <configuration>\r
+ <systemPropertyVariables>\r
+ <test.webdav.uri>${test.webdav.uri}</test.webdav.uri>\r
+ </systemPropertyVariables>\r
+ </configuration>\r
+ </plugin>\r
+ </plugins>\r
+ </build>\r
+ </profile>\r
+\r
+ <profile>\r
+ <id>ftp</id>\r
+ <activation>\r
+ <activeByDefault>false</activeByDefault>\r
+ </activation>\r
+ <build>\r
+ <plugins>\r
+ <plugin>\r
+ <groupId>org.apache.maven.plugins</groupId>\r
+ <artifactId>maven-surefire-plugin</artifactId>\r
+ <configuration>\r
+ <systemPropertyVariables>\r
+ <test.ftp.uri>${test.ftp.uri}</test.ftp.uri>\r
+ </systemPropertyVariables>\r
+ </configuration>\r
+ </plugin>\r
+ </plugins>\r
+ </build>\r
+ </profile>\r
+\r
+ <profile>\r
+ <id>sftp</id>\r
+ <activation>\r
+ <activeByDefault>false</activeByDefault>\r
+ </activation>\r
+ <build>\r
+ <plugins>\r
+ <plugin>\r
+ <groupId>org.apache.maven.plugins</groupId>\r
+ <artifactId>maven-surefire-plugin</artifactId>\r
+ <configuration>\r
+ <systemPropertyVariables>\r
+ <test.sftp.uri>${test.sftp.uri}</test.sftp.uri>\r
+ </systemPropertyVariables>\r
+ </configuration>\r
+ </plugin>\r
+ </plugins>\r
+ </build>\r
+ </profile>\r
+\r
+ <profile>\r
+ <id>http</id>\r
+ <activation>\r
+ <activeByDefault>false</activeByDefault>\r
+ </activation>\r
+ <build>\r
+ <plugins>\r
+ <plugin>\r
+ <groupId>org.apache.maven.plugins</groupId>\r
+ <artifactId>maven-surefire-plugin</artifactId>\r
+ <configuration>\r
+ <systemPropertyVariables>\r
+ <test.http.uri>${test.http.uri}</test.http.uri>\r
+ </systemPropertyVariables>\r
+ </configuration>\r
+ </plugin>\r
+ </plugins>\r
+ </build>\r
+ </profile>\r
+\r
+ <!-- On Windows we disable hdfs tests by default. -->\r
+ <profile>\r
+ <id>no-test-hdfs</id>\r
+ <activation>\r
+ <activeByDefault>false</activeByDefault>\r
+ <os>\r
+ <family>Windows</family>\r
+ </os>\r
+ </activation>\r
+ <build>\r
+ <plugins>\r
+ <plugin>\r
+ <groupId>org.apache.maven.plugins</groupId>\r
+ <artifactId>maven-surefire-plugin</artifactId>\r
+ <configuration>\r
+ <excludes>\r
+ <exclude>**/HdfsFileProviderTest.java</exclude>\r
+ <exclude>**/HdfsFileProviderTestCase.java</exclude>\r
+ <!-- Need to port fully to JUnit 4 or 5. -->\r
+ <!-- *Tests.java files with @Test methods should not be run since these classes are in fact JUnit 3 classes used in custom JUnit 3 test suites. -->\r
+ <exclude>**/*Tests.java</exclude>\r
+ </excludes>\r
+ </configuration>\r
+ </plugin>\r
+ </plugins>\r
+ </build>\r
+ </profile>\r
+ </profiles>\r
+\r
+</project>\r
/**
* Gets the value of an attribute of the file's content.
*
- * @param attrName The name of the attribute. Attribute names are case insensitive.
+ * @param attrName The name of the attribute. Attribute names are case-insensitive.
* @return The value of the attribute, or null if the attribute value is unknown.
* @throws FileSystemException If the file does not exist, or does not support attributes.
*/
}
/**
- * Gets an stream for reading/writing the file's content.
+ * Gets a stream for reading/writing the file's content.
* <p>
* If the file does not exist, and you use one of the write* methods, this method creates it, and the parent folder,
* if necessary. If the file does exist, parts of the file are replaced with whatever is written at a given
public interface FileContentInfoFactory {
/**
- * Creates a FileContentInfo for a the given FileContent.
+ * Creates a FileContentInfo for the given FileContent.
*
* @param fileContent Use this FileContent to create a matching FileContentInfo
* @return a FileContentInfo for the given FileContent.
*/
@Override
public boolean includeFile(final FileSelectInfo fileInfo) throws Exception {
- for (final String extension : this.extensions) {
- if (fileInfo.getFile().getName().getExtension().equalsIgnoreCase(extension)) {
- return true;
- }
- }
- return false;
+ return extensions.stream().anyMatch(extension -> fileInfo.getFile().getName().getExtension().equalsIgnoreCase(extension));
}
/**
* Determines whether a folder should be traversed.
*
* @param fileInfo The file selection information.
- * @return true if descendants should be traversed, fase otherwise.
+ * @return true if descendants should be traversed, false otherwise.
*/
@Override
public boolean traverseDescendents(final FileSelectInfo fileInfo) throws Exception {
package org.apache.commons.vfs2;
/**
- * Information about a file, that is used to select files during the traversal of a hierarchy.
+ * Gets information about a file, used to select files during the traversal of a hierarchy.
* <p>
* TODO - Rename this interface, as it is used by both FileSelector and FileVisitor.
* </p>
public interface FileSelectInfo {
/**
- * Returns the base folder of the traversal.
+ * Gets the base folder of the traversal.
*
* @return FileObject representing the base folder.
*/
FileObject getBaseFolder();
/**
- * Returns the depth of the file relative to the base folder.
+ * Gets the depth of the file relative to the base folder.
*
* @return The depth of the file relative to the base folder.
*/
int getDepth();
/**
- * Returns the file (or folder) to be considered.
+ * Gets the file (or folder) to be considered.
*
* @return The FileObject.
*/
package org.apache.commons.vfs2;
/**
- * This interface is used to select files when traversing a file hierarchy.
+ * Selects what to traverse a file hierarchy.
*
* @see Selectors
*/
public interface FileSelector {
/**
- * Determines if a file or folder should be selected. This method is called in depthwise order (that is, it is
+ * Tests if a file or folder should be selected. This method is called in depthwise order (that is, it is
* called for the children of a folder before it is called for the folder itself).
*
* @param fileInfo the file or folder to select.
boolean includeFile(FileSelectInfo fileInfo) throws Exception;
/**
- * Determines whether a folder should be traversed. If this method returns true, {@link #includeFile} is called for
+ * Tests whether a folder should be traversed. If this method returns true, {@link #includeFile} is called for
* each of the children of the folder, and each of the child folders is recursively traversed.
* <p>
* This method is called on a folder before {@link #includeFile} is called.
* @param fileInfo the file or folder to select.
* @return true if the folder should be traversed.
* @throws Exception if an error occurs.
+ * @since 2.10.0
*/
+ default boolean traverseDescendants(FileSelectInfo fileInfo) throws Exception {
+ return traverseDescendents(fileInfo);
+ }
+
+ /**
+ * Tests whether a folder should be traversed. If this method returns true, {@link #includeFile} is called for
+ * each of the children of the folder, and each of the child folders is recursively traversed.
+ * <p>
+ * This method is called on a folder before {@link #includeFile} is called.
+ * </p>
+ *
+ * @param fileInfo the file or folder to select.
+ * @return true if the folder should be traversed.
+ * @throws Exception if an error occurs.
+ * @deprecated Use {@link #traverseDescendants(FileSelectInfo)}.
+ */
+ @Deprecated
boolean traverseDescendents(FileSelectInfo fileInfo) throws Exception;
}
Object getAttribute(String attrName) throws FileSystemException;
/**
- * Returns a reference to the FileSytemManager.
+ * Returns a reference to the FileSystemManager.
*
* @return The FileSystemManager.
*/
* Creates a temporary local copy of a file and its descendants. If this file is already a local file, a copy is not
* made.
* <p>
- * Note that the local copy may include additonal files, that were not selected by the given selector.
+ * Note that the local copy may include additional files, that were not selected by the given selector.
* </p>
* <p>
* TODO - Add options to indicate whether the caller is happy to deal with extra files being present locally (eg if
* we can register {@code SvnWsOperationProvider} and {@code CvsOperationProvider.}
* </p>
*
- * @param scheme The scheme assoicated with this provider.
+ * @param scheme The scheme associated with this provider.
* @param operationProvider The FileOperationProvider to add.
* @throws FileSystemException if an error occurs.
*/
/**
* Gets the configuration builder for the given scheme.
*
- * @param scheme The schem to use to obtain the FileSystemConfigBuidler.
+ * @param scheme The scheme to use to obtain the FileSystemConfigBuilder.
* @return A FileSystemConfigBuilder appropriate for the given scheme.
- * @throws FileSystemException if the given scheme is not konwn.
+ * @throws FileSystemException if the given scheme is not known.
*/
FileSystemConfigBuilder getFileSystemConfigBuilder(String scheme) throws FileSystemException;
/**
* Gets Providers for file operations.
*
- * @param scheme the scheme for wich we want to get the list af registered providers.
+ * @param scheme the scheme for which we want to get the list af registered providers.
*
* @return the registered FileOperationProviders for the specified scheme. If there were no providers registered for
* the scheme, it returns null.
*
* @param scheme The scheme to use to locate the provider's capabilities.
* @return A Collection of the various capabilities.
- * @throws FileSystemException if the given scheme is not konwn.
+ * @throws FileSystemException if the given scheme is not known.
*/
Collection<Capability> getProviderCapabilities(String scheme) throws FileSystemException;
*/
@Override
public boolean traverseDescendents(final FileSelectInfo fileInfo) throws Exception {
- return delegateFileSelector.traverseDescendents(fileInfo);
+ return delegateFileSelector.traverseDescendants(fileInfo);
}
}
/**
* This class is to keep the old logging behavior (for ant-task) and to be able to correctly use commons-logging.
- * I hope i could remove it sometimes.
+ * I hope I could remove it sometimes.
*/
public final class VfsLog {
private final Lock writeLock = rwLock.writeLock();
/**
- * Default constructor. Uses a LRU size of 100 per file system.
+ * Default constructor. Uses an LRU size of 100 per file system.
*/
public LRUFilesCache() {
this(DEFAULT_LRU_SIZE);
/**
* This implementation caches every file as long as it is strongly reachable by the java vm. As soon as the object is no
* longer reachable it will be discarded. In contrast to the SoftRefFilesCache this implementation might free resources
- * faster as it don't wait until a memory limitation.
+ * faster as it doesn't wait until a memory limitation.
*
* @see java.lang.ref.WeakReference
*/
* </pre>
*
* @author This code was originally ported from Apache Commons IO File Filter
- * @see "http://commons.apache.org/proper/commons-io/"
+ * @see "https://commons.apache.org/proper/commons-io/"
* @since 2.4
*/
public class AgeFileFilter implements FileFilter, Serializable {
* Constructs a new age file filter for files older than (at or before) a
* certain File (whose last modification time will be used as reference).
*
- * @param cutoffReference the file whose last modification time is usesd as the
+ * @param cutoffReference the file whose last modification time is used as the
* threshold age of the files
*
* @throws FileSystemException Error reading the last modification time from the
* Constructs a new age file filter for files on any one side of a certain File
* (whose last modification time will be used as reference).
*
- * @param cutoffReference the file whose last modification time is usesd as the
+ * @param cutoffReference the file whose last modification time is used as the
* threshold age of the files
* @param acceptOlder if true, older files (at or before the cutoff) are
* accepted, else newer ones (after the cutoff).
}
/**
- * Provide a String representaion of this file filter.
+ * Provide a String representation of this file filter.
*
- * @return a String representaion
+ * @return a String representation
*/
@Override
public String toString() {
* when the first filter returns {@code false}.
*
* @author This code was originally ported from Apache Commons IO File Filter
- * @see "http://commons.apache.org/proper/commons-io/"
+ * @see "https://commons.apache.org/proper/commons-io/"
* @since 2.4
*/
public class AndFileFilter implements FileFilter, ConditionalFileFilter, Serializable {
* }
* </pre>
*
- * @see "http://commons.apache.org/proper/commons-io/"
+ * @see "https://commons.apache.org/proper/commons-io/"
* @since 2.4
*/
public class CanExecuteFileFilter implements FileFilter, Serializable {
* </pre>
*
* @author This code was originally ported from Apache Commons IO File Filter
- * @see "http://commons.apache.org/proper/commons-io/"
+ * @see "https://commons.apache.org/proper/commons-io/"
* @since 2.4
*/
public class CanReadFileFilter implements FileFilter, Serializable {
* </p>
*
* @author This code was originally ported from Apache Commons IO File Filter
- * @see "http://commons.apache.org/proper/commons-io/"
+ * @see "https://commons.apache.org/proper/commons-io/"
* @since 2.4
*/
public class CanWriteFileFilter implements FileFilter, Serializable {
* Defines operations for conditional file filters.
*
* @author This code was originally ported from Apache Commons IO File Filter
- * @see "http://commons.apache.org/proper/commons-io/"
+ * @see "https://commons.apache.org/proper/commons-io/"
* @since 2.4
*/
public interface ConditionalFileFilter {
* </pre>
*
* @author This code was originally ported from Apache Commons IO File Filter
- * @see "http://commons.apache.org/proper/commons-io/"
+ * @see "https://commons.apache.org/proper/commons-io/"
* @since 2.4
*/
public class DirectoryFileFilter implements FileFilter, Serializable {
* </pre>
*
* @author This code was originally ported from Apache Commons IO File Filter
- * @see "http://commons.apache.org/proper/commons-io/"
+ * @see "https://commons.apache.org/proper/commons-io/"
* @since 2.4
*/
public class EmptyFileFilter implements FileFilter, Serializable {
* A file filter that always returns false.
*
* @author This code was originally ported from Apache Commons IO File Filter
- * @see "http://commons.apache.org/proper/commons-io/"
+ * @see "https://commons.apache.org/proper/commons-io/"
* @since 2.4
*/
public class FalseFileFilter implements FileFilter, Serializable {
* </pre>
*
* @author This code was originally ported from Apache Commons IO File Filter
- * @see "http://commons.apache.org/proper/commons-io/"
+ * @see "https://commons.apache.org/proper/commons-io/"
* @since 2.4
*/
public class FileFileFilter implements FileFilter, Serializable {
* </pre>
*
* @author This code was originally ported from Apache Commons IO File Filter
- * @see "http://commons.apache.org/proper/commons-io/"
+ * @see "https://commons.apache.org/proper/commons-io/"
* @since 2.4
*/
public class HiddenFileFilter implements FileFilter, Serializable {
}
/**
- * Checks to see if the file is hidden. Non existing files won't be accepted.
+ * Checks to see if the file is hidden. Non-existing files won't be accepted.
*
* @param fileSelectInfo the File to check
*
* </p>
*
* @author This code was originally ported from Apache Commons IO File Filter
- * @see "http://commons.apache.org/proper/commons-io/"
+ * @see "https://commons.apache.org/proper/commons-io/"
* @since 2.4
*/
public enum IOCase {
/**
- * The constant for case sensitive regardless of operating system.
+ * The constant for case-sensitive regardless of operating system.
*/
SENSITIVE("Sensitive", true),
/**
- * The constant for case insensitive regardless of operating system.
+ * The constant for case-insensitive regardless of operating system.
*/
INSENSITIVE("Insensitive", false),
* Windows is case-insensitive when comparing file names, Unix is case-sensitive.
* <p>
* <strong>Note:</strong> This only caters for Windows and Unix. Other operating
- * systems (e.g. OSX and OpenVMS) are treated as case sensitive if they use the
+ * systems (e.g. OSX and OpenVMS) are treated as case-sensitive if they use the
* Unix file separator and case-insensitive if they use the Windows file
* separator (see {@link java.io.File#separatorChar}).
* <p>
}
/**
- * Does the object represent case sensitive comparison.
+ * Does the object represent case-sensitive comparison.
*
- * @return true if case sensitive
+ * @return true if case-sensitive
*/
public boolean isCaseSensitive() {
return sensitive;
* </pre>
*
* @author This code was originally ported from Apache Commons IO File Filter
- * @see "http://commons.apache.org/proper/commons-io/"
+ * @see "https://commons.apache.org/proper/commons-io/"
* @since 2.4
*/
public class NameFileFilter implements FileFilter, Serializable {
private static final long serialVersionUID = 1L;
- /** Whether the comparison is case sensitive. */
+ /** Whether the comparison is case-sensitive. */
private final IOCase caseSensitivity;
/** The file names to search for. */
@Override
public boolean accept(final FileSelectInfo fileSelectInfo) {
final String name = fileSelectInfo.getFile().getName().getBaseName();
- for (final String name2 : this.names) {
- if (caseSensitivity.checkEquals(name, name2)) {
- return true;
- }
- }
- return false;
+ return names.stream().anyMatch(name2 -> caseSensitivity.checkEquals(name, name2));
}
/**
buffer.append(super.toString());
buffer.append("(");
if (names != null) {
- for (int i = 0; i < names.size(); i++) {
- if (i > 0) {
- buffer.append(",");
- }
- buffer.append(names.get(i));
- }
+ buffer.append(String.join(",", names));
}
buffer.append(")");
return buffer.toString();
* This filter produces a logical NOT of the filters specified.
*
* @author This code was originally ported from Apache Commons IO File Filter
- * @see "http://commons.apache.org/proper/commons-io/"
+ * @see "https://commons.apache.org/proper/commons-io/"
* @since 2.4
*/
public class NotFileFilter implements FileFilter, Serializable {
* file filter list stops when the first filter returns {@code true}.
*
* @author This code was originally ported from Apache Commons IO File Filter
- * @see "http://commons.apache.org/proper/commons-io/"
+ * @see "https://commons.apache.org/proper/commons-io/"
* @since 2.4
*/
public class OrFileFilter implements FileFilter, ConditionalFileFilter, Serializable {
* </pre>
*
* @author This code was originally ported from Apache Commons IO File Filter
- * @see "http://commons.apache.org/proper/commons-io/"
+ * @see "https://commons.apache.org/proper/commons-io/"
* @since 2.4
*/
public class PrefixFileFilter implements FileFilter, Serializable {
private static final long serialVersionUID = 1L;
- /** Whether the comparison is case sensitive. */
+ /** Whether the comparison is case-sensitive. */
private final IOCase caseSensitivity;
/** The file name prefixes to search for. */
@Override
public boolean accept(final FileSelectInfo fileSelectInfo) {
final String name = fileSelectInfo.getFile().getName().getBaseName();
- for (final String prefix : this.prefixes) {
- if (caseSensitivity.checkStartsWith(name, prefix)) {
- return true;
- }
- }
- return false;
+ return prefixes.stream().anyMatch(prefix -> caseSensitivity.checkStartsWith(name, prefix));
}
/**
buffer.append(super.toString());
buffer.append("(");
if (prefixes != null) {
- for (int i = 0; i < prefixes.size(); i++) {
- if (i > 0) {
- buffer.append(",");
- }
- buffer.append(prefixes.get(i));
- }
+ buffer.append(String.join(",", prefixes));
}
buffer.append(")");
return buffer.toString();
* </pre>
*
* @author This code was originally ported from Apache Commons IO File Filter
- * @see "http://commons.apache.org/proper/commons-io/"
+ * @see "https://commons.apache.org/proper/commons-io/"
* @since 2.4
*/
public class RegexFileFilter implements FileFilter, Serializable {
* </pre>
*
* @author This code was originally ported from Apache Commons IO File Filter
- * @see "http://commons.apache.org/proper/commons-io/"
+ * @see "https://commons.apache.org/proper/commons-io/"
* @since 2.4
*/
public class SizeFileFilter implements FileFilter, Serializable {
* </pre>
*
* @author This code was originally ported from Apache Commons IO File Filter
- * @see "http://commons.apache.org/proper/commons-io/"
+ * @see "https://commons.apache.org/proper/commons-io/"
* @since 2.4
*/
public class SuffixFileFilter implements FileFilter, Serializable {
private static final long serialVersionUID = 1L;
- /** Whether the comparison is case sensitive. */
+ /** Whether the comparison is case-sensitive. */
private final IOCase caseSensitivity;
/** The file name suffixes to search for. */
}
/**
- * Constructs a new Suffix file filter for an array of suffixs specifying
+ * Constructs a new Suffix file filter for an array of suffixes specifying
* case-sensitivity.
*
* @param suffixes the suffixes to allow, must not be null
@Override
public boolean accept(final FileSelectInfo fileSelectInfo) {
final String name = fileSelectInfo.getFile().getName().getBaseName();
- for (final String suffix : this.suffixes) {
- if (caseSensitivity.checkEndsWith(name, suffix)) {
- return true;
- }
- }
- return false;
+ return suffixes.stream().anyMatch(suffix -> caseSensitivity.checkEndsWith(name, suffix));
}
/**
buffer.append(super.toString());
buffer.append("(");
if (suffixes != null) {
- for (int i = 0; i < suffixes.size(); i++) {
- if (i > 0) {
- buffer.append(",");
- }
- buffer.append(suffixes.get(i));
- }
+ buffer.append(String.join(",", suffixes));
}
buffer.append(")");
return buffer.toString();
}
/**
- * Checks to see if the file is a symbolic link. Non existing files won't be accepted.
+ * Checks to see if the file is a symbolic link. Non-existing files won't be accepted.
*
* @param fileSelectInfo the file to check
*
* A file filter that always returns true.
*
* @author This code was originally ported from Apache Commons IO File Filter
- * @see "http://commons.apache.org/proper/commons-io/"
+ * @see "https://commons.apache.org/proper/commons-io/"
* @since 2.4
*/
public class TrueFileFilter implements FileFilter, Serializable {
* </pre>
*
* @author This code was originally ported from Apache Commons IO File Filter
- * @see "http://commons.apache.org/proper/commons-io/"
+ * @see "https://commons.apache.org/proper/commons-io/"
* @since 2.4
*/
public class WildcardFileFilter implements FileFilter, Serializable {
private static final long serialVersionUID = 1L;
- /** Whether the comparison is case sensitive. */
+ /** Whether the comparison is case-sensitive. */
private final IOCase caseSensitivity;
/** The wildcards that will be used to match file names. */
* @param caseSensitivity what case sensitivity rule to use, null means
* case-sensitive
*
- * @return true if the file name matches the wilcard string
+ * @return true if the file name matches the wildcard string
*/
// CHECKSTYLE:OFF TODO xxx Cyclomatic complexity of 19 should be refactored
static boolean wildcardMatch(final String fileName, final String wildcardMatcher, IOCase caseSensitivity) {
}
} else if (!caseSensitivity.checkRegionMatches(fileName, textIdx, wcs[wcsIdx])) {
// matching from current position
- // couldnt match token
+ // couldn't match token
break;
}
@Override
public boolean accept(final FileSelectInfo fileSelectInfo) {
final String name = fileSelectInfo.getFile().getName().getBaseName();
- for (final String wildcard : wildcards) {
- if (wildcardMatch(name, wildcard, caseSensitivity)) {
- return true;
- }
- }
- return false;
+ return wildcards.stream().anyMatch(wildcard -> wildcardMatch(name, wildcard, caseSensitivity));
}
// CHECKSTYLE:ON
buffer.append(super.toString());
buffer.append("(");
if (wildcards != null) {
- for (int i = 0; i < wildcards.size(); i++) {
- if (i > 0) {
- buffer.append(",");
- }
- buffer.append(wildcards.get(i));
- }
+ buffer.append(String.join(",", wildcards));
}
buffer.append(")");
return buffer.toString();
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
+import java.util.stream.Stream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
try {
if (this.defaultFileMonitor.isRecursive() && child.getType().hasChildren()) {
- final FileObject[] newChildren = child.getChildren();
- for (final FileObject element : newChildren) {
- fireAllCreate(element);
- }
+ Stream.of(child.getChildren()).forEach(this::fireAllCreate);
}
} catch (final FileSystemException fse) {
LOG.error(fse.getLocalizedMessage(), fse);
try {
if (this.fileObject.getType().hasChildren()) {
this.children = new HashMap<>();
- final FileObject[] childrenList = this.fileObject.getChildren();
- for (final FileObject element : childrenList) {
+ for (final FileObject element : this.fileObject.getChildren()) {
this.children.put(element.getName(), new Object()); // null?
}
}
if (file.getType().hasChildren() && this.recursive) {
// Traverse the children
- final FileObject[] children = file.getChildren();
- for (final FileObject element : children) {
- this.addFile(element); // Add depth first
- }
+ // Add depth first
+ Stream.of(file.getChildren()).forEach(this::addFile);
}
} catch (final FileSystemException fse) {
}
/**
- * Sets the number of files to check per run. a additional delay will be added if there are more files to check
+ * Sets the number of files to check per run. An additional delay will be added if there are more files to check.
*
* @param checksPerRun a value less than 1 will disable this feature
*/
}
/**
- * Removes a instance from the list of copies.
+ * Removes an instance from the list of copies.
*
* @param file The File to remove.
*/
}
/**
- * Sets the user authenticator to get authentication informations.
+ * Sets the user authenticator to get authentication information.
*
* @param opts The FileSystemOptions.
* @param userAuthenticator The UserAuthenticator.
}
/**
- * Adds an file name extension mapping.
+ * Adds a file name extension mapping.
*
* @param extension The file name extension.
* @param scheme The scheme to use for files with this extension.
// inform the cache ...
getFilesCache().clear(fileSystem);
- // just in case the cache didnt call _closeFileSystem
+ // just in case the cache didn't call _closeFileSystem
_closeFileSystem(fileSystem);
}
}
// Close the providers.
- for (final FileProvider fileProvider : providers.values()) {
+ providers.values().forEach(fileProvider -> {
if (fileProvider instanceof AbstractFileProvider) {
((AbstractFileProvider) fileProvider).freeUnusedResources();
}
- }
+ });
// vfsProvider does not need to free resources
}
*
* @param scheme The scheme to locate.
* @return The FileSystemConfigBuilder for the scheme.
- * @throws FileSystemException if the given scheme is not konwn
+ * @throws FileSystemException if the given scheme is not known
*/
@Override
public FileSystemConfigBuilder getFileSystemConfigBuilder(final String scheme) throws FileSystemException {
}
/**
- * @param scheme the scheme for wich we want to get the list af registered providers.
+ * @param scheme the scheme for which we want to get the list af registered providers.
*
* @return the registered FileOperationProviders for the specified scheme. If there were no providers registered for
* the scheme, it returns null.
/**
* Get the capabilities for a given scheme.
*
- * @param scheme The scheme to located.
+ * @param scheme The scheme to locate.
* @return A Collection of capabilities.
- * @throws FileSystemException if the given scheme is not konwn
+ * @throws FileSystemException if the given scheme is not known
*/
@Override
public Collection<Capability> getProviderCapabilities(final String scheme) throws FileSystemException {
/**
* Resolves a URI, relative to a base file.
*
- * @param baseFile The base FileOjbect to use to locate the file.
+ * @param baseFile The base FileObject to use to locate the file.
* @param uri The URI of the file to locate.
* @return The FileObject for the located file.
* @throws FileSystemException if the file cannot be located or an error occurs.
* Resolves a URI, relative to a base file with specified FileSystem configuration.
*
* @param baseFile The base file.
- * @param uri The file name. May be a fully qualified or relative path or a url.
+ * @param uri The file name. May be a fully qualified or relative path or an url.
* @param fileSystemOptions Options to pass to the file system.
* @return A FileObject representing the target file.
* @throws FileSystemException if an error occurs accessing the file.
* Can only be set before the FileSystemManager is initialized.
* </p>
*
- * @param fileObjectDecorator must be inherted from {@link DecoratedFileObject} a has to provide a constructor with
+ * @param fileObjectDecorator must be inherited from {@link DecoratedFileObject} a has to provide a constructor with
* a single {@link FileObject} as argument
* @throws FileSystemException if an error occurs setting the decorator.
*/
* </p>
*
* @param filesCache The FilesCache.
- * @throws FileSystemException if an error occurs setting the cache..
+ * @throws FileSystemException if an error occurs setting the cache.
*/
public void setFilesCache(final FilesCache filesCache) throws FileSystemException {
if (init) {
/**
* Initializes a component, if it has not already been initialized.
*
- * @param component The component to setup.
+ * @param component The component to set up.
* @throws FileSystemException if an error occurs.
*/
private void setupComponent(final Object component) throws FileSystemException {
* Converts a local file into a {@link FileObject}.
*
* @param file The input File.
- * @return the create FileObject
+ * @return the created FileObject
* @throws FileSystemException if an error occurs creating the file.
*/
@Override
private String className;
private final List<String> schemes = new ArrayList<>(10);
- private final List<String> dependenies = new ArrayList<>(10);
+ private final List<String> dependencies = new ArrayList<>(10);
/**
* Constructs a new instance.
* @return the dependency.
*/
public List<String> getDependencies() {
- return dependenies;
+ return dependencies;
}
/**
* @param dependency the dependency.
*/
public void setDependency(final String dependency) {
- dependenies.add(dependency);
+ dependencies.add(dependency);
}
/**
-/*
- * 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.impl;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.Objects;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-
-import org.apache.commons.lang3.ArrayUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.vfs2.FileSystemException;
-import org.apache.commons.vfs2.VfsLog;
-import org.apache.commons.vfs2.operations.FileOperationProvider;
-import org.apache.commons.vfs2.provider.FileProvider;
-import org.apache.commons.vfs2.util.Messages;
-import org.w3c.dom.Element;
-import org.w3c.dom.NodeList;
-
-/**
- * A {@link org.apache.commons.vfs2.FileSystemManager} that configures itself from an XML (Default: providers.xml)
- * configuration file.
- * <p>
- * Certain providers are only loaded and available if the dependent library is in your classpath. You have to configure
- * your debugging facility to log "debug" messages to see if a provider was skipped due to "unresolved externals".
- * </p>
- */
-public class StandardFileSystemManager extends DefaultFileSystemManager {
- private static final String CONFIG_RESOURCE = "providers.xml";
- private static final String PLUGIN_CONFIG_RESOURCE = "META-INF/vfs-providers.xml";
-
- private URL configUri;
- private ClassLoader classLoader;
-
- /**
- * Adds an extension map.
- *
- * @param map containing the Elements.
- */
- private void addExtensionMap(final Element map) {
- final String extension = map.getAttribute("extension");
- final String scheme = map.getAttribute("scheme");
- if (!StringUtils.isEmpty(scheme)) {
- addExtensionMap(extension, scheme);
- }
- }
-
- /**
- * Adds a mime-type map.
- *
- * @param map containing the Elements.
- */
- private void addMimeTypeMap(final Element map) {
- final String mimeType = map.getAttribute("mime-type");
- final String scheme = map.getAttribute("scheme");
- addMimeTypeMap(mimeType, scheme);
- }
-
- /**
- * Adds a operationProvider from a operationProvider definition.
- */
- private void addOperationProvider(final Element providerDef) throws FileSystemException {
- final String classname = providerDef.getAttribute("class-name");
-
- // Attach only to available schemas
- final String[] schemas = getSchemas(providerDef);
- for (final String schema : schemas) {
- if (hasProvider(schema)) {
- final FileOperationProvider operationProvider = (FileOperationProvider) createInstance(classname);
- addOperationProvider(schema, operationProvider);
- }
- }
- }
-
- /**
- * Adds a provider from a provider definition.
- *
- * @param providerDef the provider definition
- * @param isDefault true if the default should be used.
- * @throws FileSystemException if an error occurs.
- */
- private void addProvider(final Element providerDef, final boolean isDefault) throws FileSystemException {
- final String classname = providerDef.getAttribute("class-name");
-
- // Make sure all required schemes are available
- final String[] requiredSchemes = getRequiredSchemes(providerDef);
- for (final String requiredScheme : requiredSchemes) {
- if (!hasProvider(requiredScheme)) {
- final String msg = Messages.getString("vfs.impl/skipping-provider-scheme.debug", classname,
- requiredScheme);
- VfsLog.debug(getLogger(), getLogger(), msg);
- return;
- }
- }
-
- // Make sure all required classes are in classpath
- final String[] requiredClasses = getRequiredClasses(providerDef);
- for (final String requiredClass : requiredClasses) {
- if (!findClass(requiredClass)) {
- final String msg = Messages.getString("vfs.impl/skipping-provider.debug", classname, requiredClass);
- VfsLog.debug(getLogger(), getLogger(), msg);
- return;
- }
- }
-
- // Create and register the provider
- final FileProvider provider = (FileProvider) createInstance(classname);
- final String[] schemas = getSchemas(providerDef);
- if (schemas.length > 0) {
- addProvider(schemas, provider);
- }
-
- // Set as default, if required
- if (isDefault) {
- setDefaultProvider(provider);
- }
- }
-
- /**
- * Configures this manager from an parsed XML configuration file
- *
- * @param config The configuration Element.
- * @throws FileSystemException if an error occurs.
- */
- private void configure(final Element config) throws FileSystemException {
- // Add the providers
- final NodeList providers = config.getElementsByTagName("provider");
- final int count = providers.getLength();
- for (int i = 0; i < count; i++) {
- final Element provider = (Element) providers.item(i);
- addProvider(provider, false);
- }
-
- // Add the operation providers
- final NodeList operationProviders = config.getElementsByTagName("operationProvider");
- for (int i = 0; i < operationProviders.getLength(); i++) {
- final Element operationProvider = (Element) operationProviders.item(i);
- addOperationProvider(operationProvider);
- }
-
- // Add the default provider
- final NodeList defProviders = config.getElementsByTagName("default-provider");
- if (defProviders.getLength() > 0) {
- final Element provider = (Element) defProviders.item(0);
- addProvider(provider, true);
- }
-
- // Add the mime-type maps
- final NodeList mimeTypes = config.getElementsByTagName("mime-type-map");
- for (int i = 0; i < mimeTypes.getLength(); i++) {
- final Element map = (Element) mimeTypes.item(i);
- addMimeTypeMap(map);
- }
-
- // Add the extension maps
- final NodeList extensions = config.getElementsByTagName("extension-map");
- for (int i = 0; i < extensions.getLength(); i++) {
- final Element map = (Element) extensions.item(i);
- addExtensionMap(map);
- }
- }
-
- /**
- * Configures this manager from an XML configuration file.
- *
- * @param configUri The URI of the configuration.
- * @param configStream An InputStream containing the configuration.
- * @throws FileSystemException if an error occurs.
- */
- @SuppressWarnings("unused")
- private void configure(final String configUri, final InputStream configStream) throws FileSystemException {
- try {
- // Load up the config
- // TODO - validate
- configure(createDocumentBuilder().parse(configStream).getDocumentElement());
-
- } catch (final Exception e) {
- throw new FileSystemException("vfs.impl/load-config.error", configUri, e);
- }
- }
-
- /**
- * Configures this manager from an XML configuration file.
- *
- * @param configUri The URI of the configuration.
- * @throws FileSystemException if an error occus.
- */
- private void configure(final URL configUri) throws FileSystemException {
- InputStream configStream = null;
- try {
- // Load up the config
- // TODO - validate
- final DocumentBuilder builder = createDocumentBuilder();
- configStream = configUri.openStream();
- final Element config = builder.parse(configStream).getDocumentElement();
-
- configure(config);
- } catch (final Exception e) {
- throw new FileSystemException("vfs.impl/load-config.error", configUri.toString(), e);
- } finally {
- if (configStream != null) {
- try {
- configStream.close();
- } catch (final IOException e) {
- getLogger().warn(e.getLocalizedMessage(), e);
- }
- }
- }
- }
-
- /**
- * Scans the classpath to find any droped plugin.
- * <p>
- * The plugin-description has to be in {@code /META-INF/vfs-providers.xml}.
- * </p>
- *
- * @throws FileSystemException if an error occurs.
- */
- protected void configurePlugins() throws FileSystemException {
- final Enumeration<URL> enumResources;
- try {
- enumResources = enumerateResources(PLUGIN_CONFIG_RESOURCE);
- } catch (final IOException e) {
- throw new FileSystemException(e);
- }
-
- while (enumResources.hasMoreElements()) {
- configure(enumResources.nextElement());
- }
- }
-
- protected DefaultFileReplicator createDefaultFileReplicator() {
- return new DefaultFileReplicator();
- }
-
- /**
- * Configure and create a DocumentBuilder
- *
- * @return A DocumentBuilder for the configuration.
- * @throws ParserConfigurationException if an error occurs.
- */
- private DocumentBuilder createDocumentBuilder() throws ParserConfigurationException {
- final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- factory.setIgnoringElementContentWhitespace(true);
- factory.setIgnoringComments(true);
- factory.setExpandEntityReferences(true);
- return factory.newDocumentBuilder();
- }
-
- /**
- * Creates a provider.
- */
- private Object createInstance(final String className) throws FileSystemException {
- try {
- return loadClass(className).newInstance();
- } catch (final Exception e) {
- throw new FileSystemException("vfs.impl/create-provider.error", className, e);
- }
- }
-
- /**
- * Enumerates resources from different class loaders.
- *
- * @throws IOException if {@code getResource} failed.
- * @see #findClassLoader()
- */
- private Enumeration<URL> enumerateResources(final String name) throws IOException {
- Enumeration<URL> enumeration = findClassLoader().getResources(name);
- if (enumeration == null || !enumeration.hasMoreElements()) {
- enumeration = getValidClassLoader(getClass()).getResources(name);
- }
- return enumeration;
- }
-
- /**
- * Tests if a class is available.
- */
- private boolean findClass(final String className) {
- try {
- loadClass(className);
- return true;
- } catch (final ClassNotFoundException e) {
- return false;
- }
- }
-
- /**
- * Returns a class loader or null since some Java implementation is null for the bootstrap class loader.
- *
- * @return A class loader or null since some Java implementation is null for the bootstrap class loader.
- */
- private ClassLoader findClassLoader() {
- if (classLoader != null) {
- return classLoader;
- }
- final ClassLoader cl = Thread.currentThread().getContextClassLoader();
- if (cl != null) {
- return cl;
- }
- return getValidClassLoader(getClass());
- }
-
- /**
- * Extracts the required classes from a provider definition.
- */
- private String[] getRequiredClasses(final Element providerDef) {
- final ArrayList<String> classes = new ArrayList<>();
- final NodeList deps = providerDef.getElementsByTagName("if-available");
- final int count = deps.getLength();
- for (int i = 0; i < count; i++) {
- final Element dep = (Element) deps.item(i);
- final String className = dep.getAttribute("class-name");
- if (!StringUtils.isEmpty(className)) {
- classes.add(className);
- }
- }
- return classes.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
- }
-
- /**
- * Extracts the required schemes from a provider definition.
- */
- private String[] getRequiredSchemes(final Element providerDef) {
- final ArrayList<String> schemes = new ArrayList<>();
- final NodeList deps = providerDef.getElementsByTagName("if-available");
- final int count = deps.getLength();
- for (int i = 0; i < count; i++) {
- final Element dep = (Element) deps.item(i);
- final String scheme = dep.getAttribute("scheme");
- if (!StringUtils.isEmpty(scheme)) {
- schemes.add(scheme);
- }
- }
- return schemes.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
- }
-
- /**
- * Extracts the schema names from a provider definition.
- */
- private String[] getSchemas(final Element provider) {
- final ArrayList<String> schemas = new ArrayList<>();
- final NodeList schemaElements = provider.getElementsByTagName("scheme");
- final int count = schemaElements.getLength();
- for (int i = 0; i < count; i++) {
- final Element scheme = (Element) schemaElements.item(i);
- schemas.add(scheme.getAttribute("name"));
- }
- return schemas.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
- }
-
- private ClassLoader getValidClassLoader(final Class<?> clazz) {
- return validateClassLoader(clazz.getClassLoader(), clazz);
- }
-
- /**
- * Initializes this manager. Adds the providers and replicator.
- *
- * @throws FileSystemException if an error occurs.
- */
- @Override
- public void init() throws FileSystemException {
- // Set the replicator and temporary file store (use the same component)
- final DefaultFileReplicator replicator = createDefaultFileReplicator();
- setReplicator(new PrivilegedFileReplicator(replicator));
- setTemporaryFileStore(replicator);
-
- if (configUri == null) {
- // Use default config
- final URL url = getClass().getResource(CONFIG_RESOURCE);
- FileSystemException.requireNonNull(url, "vfs.impl/find-config-file.error", CONFIG_RESOURCE);
- configUri = url;
- }
-
- configure(configUri);
- configurePlugins();
-
- // Initialize super-class
- super.init();
- }
-
- /**
- * Load a class from different class loaders.
- *
- * @throws ClassNotFoundException if last {@code loadClass} failed.
- * @see #findClassLoader()
- */
- private Class<?> loadClass(final String className) throws ClassNotFoundException {
- try {
- return findClassLoader().loadClass(className);
- } catch (final ClassNotFoundException e) {
- return getValidClassLoader(getClass()).loadClass(className);
- }
- }
-
- /**
- * Sets the ClassLoader to use to load the providers. Default is to use the ClassLoader that loaded this class.
- *
- * @param classLoader The ClassLoader.
- */
- public void setClassLoader(final ClassLoader classLoader) {
- this.classLoader = classLoader;
- }
-
- /**
- * Sets the configuration file for this manager.
- *
- * @param configUri The URI for this manager.
- */
- public void setConfiguration(final String configUri) {
- try {
- setConfiguration(new URL(configUri));
- } catch (final MalformedURLException e) {
- getLogger().warn(e.getLocalizedMessage(), e);
- }
- }
-
- /**
- * Sets the configuration file for this manager.
- *
- * @param configUri The URI forthis manager.
- */
- public void setConfiguration(final URL configUri) {
- this.configUri = configUri;
- }
-
- private ClassLoader validateClassLoader(final ClassLoader clazzLoader, final Class<?> clazz) {
- return Objects.requireNonNull(clazzLoader, "The class loader for " + clazz
- + " is null; some Java implementions use null for the bootstrap class loader.");
- }
-
-}
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements. See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License. You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.apache.commons.vfs2.impl;\r
+\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.net.MalformedURLException;\r
+import java.net.URL;\r
+import java.util.ArrayList;\r
+import java.util.Enumeration;\r
+import java.util.Objects;\r
+\r
+import javax.xml.parsers.DocumentBuilder;\r
+import javax.xml.parsers.DocumentBuilderFactory;\r
+import javax.xml.parsers.ParserConfigurationException;\r
+\r
+import org.apache.commons.lang3.ArrayUtils;\r
+import org.apache.commons.lang3.StringUtils;\r
+import org.apache.commons.vfs2.FileSystemException;\r
+import org.apache.commons.vfs2.VfsLog;\r
+import org.apache.commons.vfs2.operations.FileOperationProvider;\r
+import org.apache.commons.vfs2.provider.FileProvider;\r
+import org.apache.commons.vfs2.util.Messages;\r
+import org.w3c.dom.Element;\r
+import org.w3c.dom.NodeList;\r
+\r
+/**\r
+ * A {@link org.apache.commons.vfs2.FileSystemManager} that configures itself from an XML (Default: providers.xml)\r
+ * configuration file.\r
+ * <p>\r
+ * Certain providers are only loaded and available if the dependent library is in your classpath. You have to configure\r
+ * your debugging facility to log "debug" messages to see if a provider was skipped due to "unresolved externals".\r
+ * </p>\r
+ */\r
+public class StandardFileSystemManager extends DefaultFileSystemManager {\r
+ private static final String CONFIG_RESOURCE = "providers.xml";\r
+ private static final String PLUGIN_CONFIG_RESOURCE = "META-INF/vfs-providers.xml";\r
+\r
+ private URL configUri;\r
+ private ClassLoader classLoader;\r
+\r
+ /**\r
+ * Adds an extension map.\r
+ *\r
+ * @param map containing the Elements.\r
+ */\r
+ private void addExtensionMap(final Element map) {\r
+ final String extension = map.getAttribute("extension");\r
+ final String scheme = map.getAttribute("scheme");\r
+ if (!StringUtils.isEmpty(scheme)) {\r
+ addExtensionMap(extension, scheme);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Adds a mime-type map.\r
+ *\r
+ * @param map containing the Elements.\r
+ */\r
+ private void addMimeTypeMap(final Element map) {\r
+ final String mimeType = map.getAttribute("mime-type");\r
+ final String scheme = map.getAttribute("scheme");\r
+ addMimeTypeMap(mimeType, scheme);\r
+ }\r
+\r
+ /**\r
+ * Adds a operationProvider from a operationProvider definition.\r
+ */\r
+ private void addOperationProvider(final Element providerDef) throws FileSystemException {\r
+ final String classname = providerDef.getAttribute("class-name");\r
+\r
+ // Attach only to available schemas\r
+ final String[] schemas = getSchemas(providerDef);\r
+ for (final String schema : schemas) {\r
+ if (hasProvider(schema)) {\r
+ final FileOperationProvider operationProvider = (FileOperationProvider) createInstance(classname);\r
+ addOperationProvider(schema, operationProvider);\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Adds a provider from a provider definition.\r
+ *\r
+ * @param providerDef the provider definition\r
+ * @param isDefault true if the default should be used.\r
+ * @throws FileSystemException if an error occurs.\r
+ */\r
+ private void addProvider(final Element providerDef, final boolean isDefault) throws FileSystemException {\r
+ final String classname = providerDef.getAttribute("class-name");\r
+\r
+ // Make sure all required schemes are available\r
+ final String[] requiredSchemes = getRequiredSchemes(providerDef);\r
+ for (final String requiredScheme : requiredSchemes) {\r
+ if (!hasProvider(requiredScheme)) {\r
+ final String msg = Messages.getString("vfs.impl/skipping-provider-scheme.debug", classname,\r
+ requiredScheme);\r
+ VfsLog.debug(getLogger(), getLogger(), msg);\r
+ return;\r
+ }\r
+ }\r
+\r
+ // Make sure all required classes are in classpath\r
+ final String[] requiredClasses = getRequiredClasses(providerDef);\r
+ for (final String requiredClass : requiredClasses) {\r
+ if (!findClass(requiredClass)) {\r
+ final String msg = Messages.getString("vfs.impl/skipping-provider.debug", classname, requiredClass);\r
+ VfsLog.debug(getLogger(), getLogger(), msg);\r
+ return;\r
+ }\r
+ }\r
+\r
+ // Create and register the provider\r
+ final FileProvider provider = (FileProvider) createInstance(classname);\r
+ final String[] schemas = getSchemas(providerDef);\r
+ if (schemas.length > 0) {\r
+ addProvider(schemas, provider);\r
+ }\r
+\r
+ // Set as default, if required\r
+ if (isDefault) {\r
+ setDefaultProvider(provider);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Configures this manager from a parsed XML configuration file\r
+ *\r
+ * @param config The configuration Element.\r
+ * @throws FileSystemException if an error occurs.\r
+ */\r
+ private void configure(final Element config) throws FileSystemException {\r
+ // Add the providers\r
+ final NodeList providers = config.getElementsByTagName("provider");\r
+ final int count = providers.getLength();\r
+ for (int i = 0; i < count; i++) {\r
+ final Element provider = (Element) providers.item(i);\r
+ addProvider(provider, false);\r
+ }\r
+\r
+ // Add the operation providers\r
+ final NodeList operationProviders = config.getElementsByTagName("operationProvider");\r
+ for (int i = 0; i < operationProviders.getLength(); i++) {\r
+ final Element operationProvider = (Element) operationProviders.item(i);\r
+ addOperationProvider(operationProvider);\r
+ }\r
+\r
+ // Add the default provider\r
+ final NodeList defProviders = config.getElementsByTagName("default-provider");\r
+ if (defProviders.getLength() > 0) {\r
+ final Element provider = (Element) defProviders.item(0);\r
+ addProvider(provider, true);\r
+ }\r
+\r
+ // Add the mime-type maps\r
+ final NodeList mimeTypes = config.getElementsByTagName("mime-type-map");\r
+ for (int i = 0; i < mimeTypes.getLength(); i++) {\r
+ final Element map = (Element) mimeTypes.item(i);\r
+ addMimeTypeMap(map);\r
+ }\r
+\r
+ // Add the extension maps\r
+ final NodeList extensions = config.getElementsByTagName("extension-map");\r
+ for (int i = 0; i < extensions.getLength(); i++) {\r
+ final Element map = (Element) extensions.item(i);\r
+ addExtensionMap(map);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Configures this manager from an XML configuration file.\r
+ *\r
+ * @param configUri The URI of the configuration.\r
+ * @throws FileSystemException if an error occurs.\r
+ */\r
+ private void configure(final URL configUri) throws FileSystemException {\r
+ InputStream configStream = null;\r
+ try {\r
+ // Load up the config\r
+ // TODO - validate\r
+ final DocumentBuilder builder = createDocumentBuilder();\r
+ configStream = configUri.openStream();\r
+ final Element config = builder.parse(configStream).getDocumentElement();\r
+\r
+ configure(config);\r
+ } catch (final Exception e) {\r
+ throw new FileSystemException("vfs.impl/load-config.error", configUri.toString(), e);\r
+ } finally {\r
+ if (configStream != null) {\r
+ try {\r
+ configStream.close();\r
+ } catch (final IOException e) {\r
+ getLogger().warn(e.getLocalizedMessage(), e);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Scans the classpath to find any dropped plugin.\r
+ * <p>\r
+ * The plugin-description has to be in {@code /META-INF/vfs-providers.xml}.\r
+ * </p>\r
+ *\r
+ * @throws FileSystemException if an error occurs.\r
+ */\r
+ protected void configurePlugins() throws FileSystemException {\r
+ final Enumeration<URL> enumResources;\r
+ try {\r
+ enumResources = enumerateResources(PLUGIN_CONFIG_RESOURCE);\r
+ } catch (final IOException e) {\r
+ throw new FileSystemException(e);\r
+ }\r
+\r
+ while (enumResources.hasMoreElements()) {\r
+ configure(enumResources.nextElement());\r
+ }\r
+ }\r
+\r
+ protected DefaultFileReplicator createDefaultFileReplicator() {\r
+ return new DefaultFileReplicator();\r
+ }\r
+\r
+ /**\r
+ * Configure and create a DocumentBuilder\r
+ *\r
+ * @return A DocumentBuilder for the configuration.\r
+ * @throws ParserConfigurationException if an error occurs.\r
+ */\r
+ private DocumentBuilder createDocumentBuilder() throws ParserConfigurationException {\r
+ final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();\r
+ factory.setIgnoringElementContentWhitespace(true);\r
+ factory.setIgnoringComments(true);\r
+ factory.setExpandEntityReferences(true);\r
+ return factory.newDocumentBuilder();\r
+ }\r
+\r
+ /**\r
+ * Creates a provider.\r
+ */\r
+ private Object createInstance(final String className) throws FileSystemException {\r
+ try {\r
+ return loadClass(className).newInstance();\r
+ } catch (final Exception e) {\r
+ throw new FileSystemException("vfs.impl/create-provider.error", className, e);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Enumerates resources from different class loaders.\r
+ *\r
+ * @throws IOException if {@code getResource} failed.\r
+ * @see #findClassLoader()\r
+ */\r
+ private Enumeration<URL> enumerateResources(final String name) throws IOException {\r
+ Enumeration<URL> enumeration = findClassLoader().getResources(name);\r
+ if (enumeration == null || !enumeration.hasMoreElements()) {\r
+ enumeration = getValidClassLoader(getClass()).getResources(name);\r
+ }\r
+ return enumeration;\r
+ }\r
+\r
+ /**\r
+ * Tests if a class is available.\r
+ */\r
+ private boolean findClass(final String className) {\r
+ try {\r
+ loadClass(className);\r
+ return true;\r
+ } catch (final ClassNotFoundException e) {\r
+ return false;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Returns a class loader or null since some Java implementation is null for the bootstrap class loader.\r
+ *\r
+ * @return A class loader or null since some Java implementation is null for the bootstrap class loader.\r
+ */\r
+ private ClassLoader findClassLoader() {\r
+ if (classLoader != null) {\r
+ return classLoader;\r
+ }\r
+ final ClassLoader cl = Thread.currentThread().getContextClassLoader();\r
+ if (cl != null) {\r
+ return cl;\r
+ }\r
+ return getValidClassLoader(getClass());\r
+ }\r
+\r
+ /**\r
+ * Extracts the required classes from a provider definition.\r
+ */\r
+ private String[] getRequiredClasses(final Element providerDef) {\r
+ final ArrayList<String> classes = new ArrayList<>();\r
+ final NodeList deps = providerDef.getElementsByTagName("if-available");\r
+ final int count = deps.getLength();\r
+ for (int i = 0; i < count; i++) {\r
+ final Element dep = (Element) deps.item(i);\r
+ final String className = dep.getAttribute("class-name");\r
+ if (!StringUtils.isEmpty(className)) {\r
+ classes.add(className);\r
+ }\r
+ }\r
+ return classes.toArray(ArrayUtils.EMPTY_STRING_ARRAY);\r
+ }\r
+\r
+ /**\r
+ * Extracts the required schemes from a provider definition.\r
+ */\r
+ private String[] getRequiredSchemes(final Element providerDef) {\r
+ final ArrayList<String> schemes = new ArrayList<>();\r
+ final NodeList deps = providerDef.getElementsByTagName("if-available");\r
+ final int count = deps.getLength();\r
+ for (int i = 0; i < count; i++) {\r
+ final Element dep = (Element) deps.item(i);\r
+ final String scheme = dep.getAttribute("scheme");\r
+ if (!StringUtils.isEmpty(scheme)) {\r
+ schemes.add(scheme);\r
+ }\r
+ }\r
+ return schemes.toArray(ArrayUtils.EMPTY_STRING_ARRAY);\r
+ }\r
+\r
+ /**\r
+ * Extracts the schema names from a provider definition.\r
+ */\r
+ private String[] getSchemas(final Element provider) {\r
+ final ArrayList<String> schemas = new ArrayList<>();\r
+ final NodeList schemaElements = provider.getElementsByTagName("scheme");\r
+ final int count = schemaElements.getLength();\r
+ for (int i = 0; i < count; i++) {\r
+ final Element scheme = (Element) schemaElements.item(i);\r
+ schemas.add(scheme.getAttribute("name"));\r
+ }\r
+ return schemas.toArray(ArrayUtils.EMPTY_STRING_ARRAY);\r
+ }\r
+\r
+ private ClassLoader getValidClassLoader(final Class<?> clazz) {\r
+ return validateClassLoader(clazz.getClassLoader(), clazz);\r
+ }\r
+\r
+ /**\r
+ * Initializes this manager. Adds the providers and replicator.\r
+ *\r
+ * @throws FileSystemException if an error occurs.\r
+ */\r
+ @Override\r
+ public void init() throws FileSystemException {\r
+ // Set the replicator and temporary file store (use the same component)\r
+ final DefaultFileReplicator replicator = createDefaultFileReplicator();\r
+ setReplicator(new PrivilegedFileReplicator(replicator));\r
+ setTemporaryFileStore(replicator);\r
+\r
+ if (configUri == null) {\r
+ // Use default config\r
+ final URL url = getClass().getResource(CONFIG_RESOURCE);\r
+ FileSystemException.requireNonNull(url, "vfs.impl/find-config-file.error", CONFIG_RESOURCE);\r
+ configUri = url;\r
+ }\r
+\r
+ configure(configUri);\r
+ configurePlugins();\r
+\r
+ // Initialize super-class\r
+ super.init();\r
+ }\r
+\r
+ /**\r
+ * Load a class from different class loaders.\r
+ *\r
+ * @throws ClassNotFoundException if last {@code loadClass} failed.\r
+ * @see #findClassLoader()\r
+ */\r
+ private Class<?> loadClass(final String className) throws ClassNotFoundException {\r
+ try {\r
+ return findClassLoader().loadClass(className);\r
+ } catch (final ClassNotFoundException e) {\r
+ return getValidClassLoader(getClass()).loadClass(className);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Sets the ClassLoader to use to load the providers. Default is to use the ClassLoader that loaded this class.\r
+ *\r
+ * @param classLoader The ClassLoader.\r
+ */\r
+ public void setClassLoader(final ClassLoader classLoader) {\r
+ this.classLoader = classLoader;\r
+ }\r
+\r
+ /**\r
+ * Sets the configuration file for this manager.\r
+ *\r
+ * @param configUri The URI for this manager.\r
+ */\r
+ public void setConfiguration(final String configUri) {\r
+ try {\r
+ setConfiguration(new URL(configUri));\r
+ } catch (final MalformedURLException e) {\r
+ getLogger().warn(e.getLocalizedMessage(), e);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Sets the configuration file for this manager.\r
+ *\r
+ * @param configUri The URI for this manager.\r
+ */\r
+ public void setConfiguration(final URL configUri) {\r
+ this.configUri = configUri;\r
+ }\r
+\r
+ private ClassLoader validateClassLoader(final ClassLoader clazzLoader, final Class<?> clazz) {\r
+ return Objects.requireNonNull(clazzLoader, "The class loader for " + clazz\r
+ + " is null; some Java implementations use null for the bootstrap class loader.");\r
+ }\r
+\r
+}\r
import org.apache.commons.vfs2.NameScope;
/**
- * This decorator synchronize all access to the FileObject.
+ * This decorator synchronizes all access to the FileObject.
*/
public class SynchronizedFileObject extends DecoratedFileObject {
setURL(u, url.getProtocol(), url.getHost(), url.getPort(), url.getAuthority(), url.getUserInfo(),
url.getFile(), url.getQuery(), url.getRef());
} catch (final MalformedURLException mue) {
- // We retrow this as a simple runtime exception.
- // It is retrown in URL as a MalformedURLException anyway.
+ // We rethrow this as a simple runtime exception.
+ // It is rethrown in URL as a MalformedURLException anyway.
throw new RuntimeException(mue.getMessage());
}
}
* Constructors a new VFSClassLoader for the given file.
*
* @param file the file to load the classes and resources from.
- * @param manager the FileManager to use when trying create a layered Jar file system.
+ * @param manager the FileManager to use when trying to create a layered Jar file system.
* @throws FileSystemException if an error occurs.
*/
public VFSClassLoader(final FileObject file, final FileSystemManager manager) throws FileSystemException {
* Constructors a new VFSClassLoader for the given file.
*
* @param file the file to load the classes and resources from.
- * @param manager the FileManager to use when trying create a layered Jar file system.
+ * @param manager the FileManager to use when trying to create a layered Jar file system.
* @param parent the parent class loader for delegation.
* @throws FileSystemException if an error occurs.
*/
* Constructors a new VFSClassLoader for the given files. The files will be searched in the order specified.
*
* @param files the files to load the classes and resources from.
- * @param manager the FileManager to use when trying create a layered Jar file system.
+ * @param manager the FileManager to use when trying to create a layered Jar file system.
* @throws FileSystemException if an error occurs.
*/
public VFSClassLoader(final FileObject[] files, final FileSystemManager manager) throws FileSystemException {
* specified.
*
* @param files the FileObjects to load the classes and resources from.
- * @param manager the FileManager to use when trying create a layered Jar file system.
+ * @param manager the FileManager to use when trying to create a layered Jar file system.
* @param parent the parent class loader for delegation.
* @throws FileSystemException if an error occurs.
*/
*/
protected void copyPermissions(final PermissionCollection src, final PermissionCollection dest) {
for (final Enumeration<Permission> elem = src.elements(); elem.hasMoreElements();) {
- final Permission permission = elem.nextElement();
- dest.add(permission);
+ dest.add(elem.nextElement());
}
}
}
/**
- * Returns true if the we should seal the package where res resides.
+ * Returns true if we should seal the package where res resides.
*/
private boolean isSealed(final Resource res) throws FileSystemException {
final String sealed = res.getPackageAttribute(Attributes.Name.SEALED);
// The name points to the junction point directly
return name;
}
-
// Find matching junction
- for (final FileName junctionPoint : junctions.keySet()) {
- if (junctionPoint.isDescendent(name)) {
- return junctionPoint;
- }
- }
-
- // None
- return null;
+ return junctions.keySet().stream().filter(fileName -> fileName.isDescendent(name)).findFirst().orElse(null);
}
/**
public abstract class AbstractFileOperation implements FileOperation {
/**
- * FileObject which the FileOperation is operate on.
+ * FileObject which the FileOperation is operated on.
*/
private final FileObject fileObject;
}
/**
- * @return an instance of FileObject which this FileOperation is operate on.
+ * @return an instance of FileObject which this FileOperation is operated on.
*/
protected FileObject getFileObject() {
return fileObject;
Collection<Class<? extends FileOperation>> resultList, FileObject file) throws FileSystemException;
/**
- * @param file the FileObject for which we need a operation.
+ * @param file the FileObject for which we need an operation.
* @param operationClass the Class which instance we are needed.
* @return the required operation instance.
* @throws FileSystemException if operation cannot be retrieved.
* Get operation instance for specified FileOperation subclass.
*
* @param file the file this operation should act on.
- * @param operationClass the class of an file operation interface to instantiate.
+ * @param operationClass the class of a file operation interface to instantiate.
* @return a new file operation
* @throws FileSystemException if operation cannot be instantiated.
*/
/**
* Get implementation for a given FileObject and FileOperation interface.
*
- * @param file the FileObject for which we need a operation.
+ * @param file the FileObject for which we need an operation.
* @param operationClass the Class which instance we are needed.
* @return the required operation instance.
*
/**
* FileOperations interface provides API to work with operations.
*
- * @see FileOperation on what a operation in the context of VFS is.
+ * @see FileOperation on what an operation in the context of VFS is.
*
* @since 0.1
*/
public interface FileOperations {
/**
* @param operationClass the operation Class.
- * @return a operation implementing the given {@code operationClass}
- * @throws FileSystemException if an error occus.
+ * @return an operation implementing the given {@code operationClass}
+ * @throws FileSystemException if an error occurs.
*/
FileOperation getOperation(Class<? extends FileOperation> operationClass) throws FileSystemException;
/**
* @param operationClass the operation Class.
- * @return if a operation {@code operationClass} is available
- * @throws FileSystemException if an error ocurs.
+ * @return if an operation {@code operationClass} is available
+ * @throws FileSystemException if an error occurs.
*/
boolean hasOperation(Class<? extends FileOperation> operationClass) throws FileSystemException;
}
public interface VcsCheckout extends FileOperation {
/**
- * @param export if true, administrative .svn directoies will not be created on the retrieved tree. The checkout
+ * @param export if true, administrative .svn directories will not be created on the retrieved tree. The checkout
* operation in this case is equivalent to export function.
*/
void setExport(boolean export);
-/*
- * 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;
-
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.vfs2.FileName;
-import org.apache.commons.vfs2.FileSystemException;
-import org.apache.commons.vfs2.FileType;
-import org.apache.commons.vfs2.NameScope;
-import org.apache.commons.vfs2.VFS;
-
-/**
- * A default file name implementation.
- */
-public abstract class AbstractFileName implements FileName {
-
- // URI Characters that are possible in local file names, but must be escaped
- // for proper URI handling.
- //
- // How reserved URI chars were selected:
- //
- // URIs can contain :, /, ?, #, @
- // See https://docs.oracle.com/javase/8/docs/api/java/net/URI.html
- // http://tools.ietf.org/html/rfc3986#section-2.2
- //
- // Since : and / occur before the path, only chars after path are escaped (i.e., # and ?)
- // ? is a reserved filesystem character for Windows and Unix, so can't be part of a file name.
- // Therefore only # is a reserved char in a URI as part of the path that can be in the file name.
- private static final char[] RESERVED_URI_CHARS = {'#', ' '};
-
- private final String scheme;
- private final String absPath;
- private FileType type;
-
- // Cached attributes
- private String uriString;
- private String baseName;
- private String rootUri;
- private String extension;
- private String decodedAbsPath;
-
- private String key;
-
- /**
- * Constructs a new instance.
- *
- * @param scheme The scheme.
- * @param absolutePath the absolute path, maybe empty or null.
- * @param type the file type.
- */
- public AbstractFileName(final String scheme, final String absolutePath, final FileType type) {
- this.rootUri = null;
- this.scheme = scheme;
- this.type = type;
- if (StringUtils.isEmpty(absolutePath)) {
- this.absPath = ROOT_PATH;
- } else if (absolutePath.length() > 1 && absolutePath.endsWith("/")) {
- this.absPath = absolutePath.substring(0, absolutePath.length() - 1);
- } else {
- this.absPath = absolutePath;
- }
- }
-
- /**
- * Checks whether a path fits in a particular scope of another path.
- *
- * @param basePath An absolute, normalised path.
- * @param path An absolute, normalised path.
- * @param scope The NameScope.
- * @return true if the path fits in the scope, false otherwise.
- */
- public static boolean checkName(final String basePath, final String path, final NameScope scope) {
- if (scope == NameScope.FILE_SYSTEM) {
- // All good
- return true;
- }
-
- if (!path.startsWith(basePath)) {
- return false;
- }
-
- int baseLen = basePath.length();
- if (VFS.isUriStyle()) {
- // strip the trailing "/"
- baseLen--;
- }
-
- if (scope == NameScope.CHILD) {
- return path.length() != baseLen && (baseLen <= 1 || path.charAt(baseLen) == SEPARATOR_CHAR)
- && path.indexOf(SEPARATOR_CHAR, baseLen + 1) == -1;
- }
- if (scope == NameScope.DESCENDENT) {
- return path.length() != baseLen && (baseLen <= 1 || path.charAt(baseLen) == SEPARATOR_CHAR);
- }
- if (scope == NameScope.DESCENDENT_OR_SELF) {
- return baseLen <= 1 || path.length() <= baseLen || path.charAt(baseLen) == SEPARATOR_CHAR;
- }
- throw new IllegalArgumentException();
- }
-
- /**
- * Builds the root URI for this file name. Note that the root URI must not end with a separator character.
- *
- * @param buffer A StringBuilder to use to construct the URI.
- * @param addPassword true if the password should be added, false otherwise.
- */
- protected abstract void appendRootUri(StringBuilder buffer, boolean addPassword);
-
- /**
- * Implement Comparable.
- *
- * @param obj another abstract file name
- * @return negative number if less than, 0 if equal, positive if greater than.
- */
- @Override
- public int compareTo(final FileName obj) {
- final AbstractFileName name = (AbstractFileName) obj;
- return getKey().compareTo(name.getKey());
- }
-
- /**
- * Factory method for creating name instances.
- *
- * @param absolutePath The absolute path.
- * @param fileType The FileType.
- * @return The FileName.
- */
- public abstract FileName createName(String absolutePath, FileType fileType);
-
- protected String createURI() {
- return createURI(false, true);
- }
-
- private String createURI(final boolean useAbsolutePath, final boolean usePassword) {
- final StringBuilder buffer = new StringBuilder();
- appendRootUri(buffer, usePassword);
- buffer.append(handleURISpecialCharacters(useAbsolutePath ? absPath : getPath()));
- return buffer.toString();
- }
-
- @Override
- public boolean equals(final Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- final AbstractFileName that = (AbstractFileName) o;
-
- return getKey().equals(that.getKey());
- }
-
- /**
- * Returns the base name of the file.
- *
- * @return The base name of the file.
- */
- @Override
- public String getBaseName() {
- if (baseName == null) {
- final int idx = getPath().lastIndexOf(SEPARATOR_CHAR);
- if (idx == -1) {
- baseName = getPath();
- } else {
- baseName = getPath().substring(idx + 1);
- }
- }
-
- return baseName;
- }
-
- /**
- * Returns the depth of this file name, within its file system.
- *
- * @return The depth of the file name.
- */
- @Override
- public int getDepth() {
- final int len = getPath().length();
- if (len == 0 || len == 1 && getPath().charAt(0) == SEPARATOR_CHAR) {
- return 0;
- }
- int depth = 1;
- for (int pos = 0; pos > -1 && pos < len; depth++) {
- pos = getPath().indexOf(SEPARATOR_CHAR, pos + 1);
- }
- return depth;
- }
-
- /**
- * Returns the extension of this file name.
- *
- * @return The file extension.
- */
- @Override
- public String getExtension() {
- if (extension == null) {
- getBaseName();
- final int pos = baseName.lastIndexOf('.');
- // if ((pos == -1) || (pos == baseName.length() - 1))
- // imario@ops.co.at: Review of patch from adagoubard@chello.nl
- // do not treat file names like
- // .bashrc c:\windows\.java c:\windows\.javaws c:\windows\.jedit c:\windows\.appletviewer
- // as extension
- if (pos < 1 || pos == baseName.length() - 1) {
- // No extension
- extension = "";
- } else {
- extension = baseName.substring(pos + 1).intern();
- }
- }
- return extension;
- }
-
- /**
- * Returns the URI without a password.
- *
- * @return Returns the URI without a password.
- */
- @Override
- public String getFriendlyURI() {
- return createURI(false, false);
- }
-
- /**
- * Create a path that does not use the FileType since that field is not immutable.
- *
- * @return The key.
- */
- private String getKey() {
- if (key == null) {
- key = getURI();
- }
- return key;
- }
-
- /**
- * Returns the name of the parent of the file.
- *
- * @return the FileName of the parent.
- */
- @Override
- public FileName getParent() {
- final String parentPath;
- final int idx = getPath().lastIndexOf(SEPARATOR_CHAR);
- if (idx == -1 || idx == getPath().length() - 1) {
- // No parent
- return null;
- }
- if (idx == 0) {
- // Root is the parent
- parentPath = SEPARATOR;
- } else {
- parentPath = getPath().substring(0, idx);
- }
- return createName(parentPath, FileType.FOLDER);
- }
-
- /**
- * Returns the absolute path of the file, relative to the root of the file system that the file belongs to.
- *
- * @return The path String.
- */
- @Override
- public String getPath() {
- if (VFS.isUriStyle()) {
- return absPath + getUriTrailer();
- }
- return absPath;
- }
-
- /**
- * Returns the decoded path.
- *
- * @return The decoded path String.
- * @throws FileSystemException If an error occurs.
- */
- @Override
- public String getPathDecoded() throws FileSystemException {
- if (decodedAbsPath == null) {
- decodedAbsPath = UriParser.decode(getPath());
- }
-
- return decodedAbsPath;
- }
-
- /**
- * Converts a file name to a relative name, relative to this file name.
- *
- * @param name The FileName.
- * @return The relative path to the file.
- * @throws FileSystemException if an error occurs.
- */
- @Override
- public String getRelativeName(final FileName name) throws FileSystemException {
- final String path = name.getPath();
-
- // Calculate the common prefix
- final int basePathLen = getPath().length();
- final int pathLen = path.length();
-
- // Deal with root
- if (basePathLen == 1 && pathLen == 1) {
- return ".";
- }
- if (basePathLen == 1) {
- return path.substring(1);
- }
-
- final int maxlen = Math.min(basePathLen, pathLen);
- int pos = 0;
- for (; pos < maxlen && getPath().charAt(pos) == path.charAt(pos); pos++) {
- // empty
- }
-
- if (pos == basePathLen && pos == pathLen) {
- // Same names
- return ".";
- }
- if (pos == basePathLen && pos < pathLen && path.charAt(pos) == SEPARATOR_CHAR) {
- // A descendent of the base path
- return path.substring(pos + 1);
- }
-
- // Strip the common prefix off the path
- final StringBuilder buffer = new StringBuilder();
- if (pathLen > 1 && (pos < pathLen || getPath().charAt(pos) != SEPARATOR_CHAR)) {
- // Not a direct ancestor, need to back up
- pos = getPath().lastIndexOf(SEPARATOR_CHAR, pos);
- buffer.append(path.substring(pos));
- }
-
- // Prepend a '../' for each element in the base path past the common
- // prefix
- buffer.insert(0, "..");
- pos = getPath().indexOf(SEPARATOR_CHAR, pos + 1);
- while (pos != -1) {
- buffer.insert(0, "../");
- pos = getPath().indexOf(SEPARATOR_CHAR, pos + 1);
- }
-
- return buffer.toString();
- }
-
- /**
- * find the root of the file system.
- *
- * @return The root FileName.
- */
- @Override
- public FileName getRoot() {
- FileName root = this;
- while (root.getParent() != null) {
- root = root.getParent();
- }
-
- return root;
- }
-
- /**
- * Returns the root URI of the file system this file belongs to.
- *
- * @return The URI of the root.
- */
- @Override
- public String getRootURI() {
- if (rootUri == null) {
- final StringBuilder buffer = new StringBuilder();
- appendRootUri(buffer, true);
- buffer.append(SEPARATOR_CHAR);
- rootUri = buffer.toString().intern();
- }
- return rootUri;
- }
-
- /**
- * Returns the URI scheme of this file.
- *
- * @return The protocol used to access the file.
- */
- @Override
- public String getScheme() {
- return scheme;
- }
-
- /**
- * Returns the requested or current type of this name.
- * <p>
- * The "requested" type is the one determined during resolving the name. n this case the name is a
- * {@link FileType#FOLDER} if it ends with an "/" else it will be a {@link FileType#FILE}.
- * </p>
- * <p>
- * Once attached it will be changed to reflect the real type of this resource.
- * </p>
- *
- * @return {@link FileType#FOLDER} or {@link FileType#FILE}
- */
- @Override
- public FileType getType() {
- return type;
- }
-
- /**
- * Returns the absolute URI of the file.
- *
- * @return The absolute URI of the file.
- */
- @Override
- public String getURI() {
- if (uriString == null) {
- uriString = createURI();
- }
- return uriString;
- }
-
- protected String getUriTrailer() {
- return getType().hasChildren() ? "/" : "";
- }
-
- private String handleURISpecialCharacters(String uri) {
- if (!StringUtils.isEmpty(uri)) {
- try {
- // VFS-325: Handle URI special characters in file name
- // Decode the base URI and re-encode with URI special characters
- uri = UriParser.decode(uri);
-
- return UriParser.encode(uri, RESERVED_URI_CHARS);
- } catch (final FileSystemException e) {
- // Default to base URI value?
- return uri;
- }
- }
-
- return uri;
- }
-
- @Override
- public int hashCode() {
- return getKey().hashCode();
- }
-
- /**
- * Determines if another file name is an ancestor of this file name.
- *
- * @param ancestor The FileName to check.
- * @return true if the FileName is an ancestor, false otherwise.
- */
- @Override
- public boolean isAncestor(final FileName ancestor) {
- if (!ancestor.getRootURI().equals(getRootURI())) {
- return false;
- }
- return checkName(ancestor.getPath(), getPath(), NameScope.DESCENDENT);
- }
-
- /**
- * Determines if another file name is a descendent of this file name.
- *
- * @param descendent The FileName to check.
- * @return true if the FileName is a descendent, false otherwise.
- */
- @Override
- public boolean isDescendent(final FileName descendent) {
- return isDescendent(descendent, NameScope.DESCENDENT);
- }
-
- /**
- * Determines if another file name is a descendent of this file name.
- *
- * @param descendent The FileName to check.
- * @param scope The NameScope.
- * @return true if the FileName is a descendent, false otherwise.
- */
- @Override
- public boolean isDescendent(final FileName descendent, final NameScope scope) {
- if (!descendent.getRootURI().equals(getRootURI())) {
- return false;
- }
- return checkName(getPath(), descendent.getPath(), scope);
- }
-
- /**
- * Checks if this file name is a name for a regular file by using its type.
- *
- * @return true if this file is a regular file.
- * @throws FileSystemException may be thrown by subclasses.
- * @see #getType()
- * @see FileType#FILE
- */
- @Override
- public boolean isFile() throws FileSystemException {
- // Use equals instead of == to avoid any class loader worries.
- return FileType.FILE.equals(this.getType());
- }
-
- /**
- * Sets the type of this file e.g. when it will be attached.
- *
- * @param type {@link FileType#FOLDER} or {@link FileType#FILE}
- * @throws FileSystemException if an error occurs.
- */
- void setType(final FileType type) throws FileSystemException {
- if (type != FileType.FOLDER && type != FileType.FILE && type != FileType.FILE_OR_FOLDER) {
- throw new FileSystemException("vfs.provider/filename-type.error");
- }
-
- this.type = type;
- }
-
- /**
- * Returns the URI of the file.
- *
- * @return the FileName as a URI.
- */
- @Override
- public String toString() {
- return getURI();
- }
-}
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements. See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License. You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.apache.commons.vfs2.provider;\r
+\r
+import org.apache.commons.lang3.StringUtils;\r
+import org.apache.commons.vfs2.FileName;\r
+import org.apache.commons.vfs2.FileSystemException;\r
+import org.apache.commons.vfs2.FileType;\r
+import org.apache.commons.vfs2.NameScope;\r
+import org.apache.commons.vfs2.VFS;\r
+\r
+/**\r
+ * A default file name implementation.\r
+ */\r
+public abstract class AbstractFileName implements FileName {\r
+\r
+ // URI Characters that are possible in local file names, but must be escaped\r
+ // for proper URI handling.\r
+ //\r
+ // How reserved URI chars were selected:\r
+ //\r
+ // URIs can contain :, /, ?, #, @\r
+ // See https://docs.oracle.com/javase/8/docs/api/java/net/URI.html\r
+ // https://datatracker.ietf.org/doc/html/rfc3986#section-2.2\r
+ //\r
+ // Since : and / occur before the path, only chars after path are escaped (i.e., # and ?)\r
+ // ? is a reserved filesystem character for Windows and Unix, so can't be part of a file name.\r
+ // Therefore only # is a reserved char in a URI as part of the path that can be in the file name.\r
+ private static final char[] RESERVED_URI_CHARS = {'#', ' '};\r
+\r
+ private final String scheme;\r
+ private final String absPath;\r
+ private FileType type;\r
+\r
+ // Cached attributes\r
+ private String uriString;\r
+ private String baseName;\r
+ private String rootUri;\r
+ private String extension;\r
+ private String decodedAbsPath;\r
+\r
+ private String key;\r
+\r
+ /**\r
+ * Constructs a new instance.\r
+ *\r
+ * @param scheme The scheme.\r
+ * @param absolutePath the absolute path, maybe empty or null.\r
+ * @param type the file type.\r
+ */\r
+ public AbstractFileName(final String scheme, final String absolutePath, final FileType type) {\r
+ this.rootUri = null;\r
+ this.scheme = scheme;\r
+ this.type = type;\r
+ if (StringUtils.isEmpty(absolutePath)) {\r
+ this.absPath = ROOT_PATH;\r
+ } else if (absolutePath.length() > 1 && absolutePath.endsWith("/")) {\r
+ this.absPath = absolutePath.substring(0, absolutePath.length() - 1);\r
+ } else {\r
+ this.absPath = absolutePath;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Checks whether a path fits in a particular scope of another path.\r
+ *\r
+ * @param basePath An absolute, normalised path.\r
+ * @param path An absolute, normalised path.\r
+ * @param scope The NameScope.\r
+ * @return true if the path fits in the scope, false otherwise.\r
+ */\r
+ public static boolean checkName(final String basePath, final String path, final NameScope scope) {\r
+ if (scope == NameScope.FILE_SYSTEM) {\r
+ // All good\r
+ return true;\r
+ }\r
+\r
+ if (!path.startsWith(basePath)) {\r
+ return false;\r
+ }\r
+\r
+ int baseLen = basePath.length();\r
+ if (VFS.isUriStyle()) {\r
+ // strip the trailing "/"\r
+ baseLen--;\r
+ }\r
+\r
+ if (scope == NameScope.CHILD) {\r
+ return path.length() != baseLen && (baseLen <= 1 || path.charAt(baseLen) == SEPARATOR_CHAR)\r
+ && path.indexOf(SEPARATOR_CHAR, baseLen + 1) == -1;\r
+ }\r
+ if (scope == NameScope.DESCENDENT) {\r
+ return path.length() != baseLen && (baseLen <= 1 || path.charAt(baseLen) == SEPARATOR_CHAR);\r
+ }\r
+ if (scope == NameScope.DESCENDENT_OR_SELF) {\r
+ return baseLen <= 1 || path.length() <= baseLen || path.charAt(baseLen) == SEPARATOR_CHAR;\r
+ }\r
+ throw new IllegalArgumentException();\r
+ }\r
+\r
+ /**\r
+ * Builds the root URI for this file name. Note that the root URI must not end with a separator character.\r
+ *\r
+ * @param buffer A StringBuilder to use to construct the URI.\r
+ * @param addPassword true if the password should be added, false otherwise.\r
+ */\r
+ protected abstract void appendRootUri(StringBuilder buffer, boolean addPassword);\r
+\r
+ /**\r
+ * Implement Comparable.\r
+ *\r
+ * @param obj another abstract file name\r
+ * @return negative number if less than, 0 if equal, positive if greater than.\r
+ */\r
+ @Override\r
+ public int compareTo(final FileName obj) {\r
+ final AbstractFileName name = (AbstractFileName) obj;\r
+ return getKey().compareTo(name.getKey());\r
+ }\r
+\r
+ /**\r
+ * Factory method for creating name instances.\r
+ *\r
+ * @param absolutePath The absolute path.\r
+ * @param fileType The FileType.\r
+ * @return The FileName.\r
+ */\r
+ public abstract FileName createName(String absolutePath, FileType fileType);\r
+\r
+ protected String createURI() {\r
+ return createURI(false, true);\r
+ }\r
+\r
+ private String createURI(final boolean useAbsolutePath, final boolean usePassword) {\r
+ final StringBuilder buffer = new StringBuilder();\r
+ appendRootUri(buffer, usePassword);\r
+ buffer.append(handleURISpecialCharacters(useAbsolutePath ? absPath : getPath()));\r
+ return buffer.toString();\r
+ }\r
+\r
+ @Override\r
+ public boolean equals(final Object o) {\r
+ if (this == o) {\r
+ return true;\r
+ }\r
+ if (o == null || getClass() != o.getClass()) {\r
+ return false;\r
+ }\r
+\r
+ final AbstractFileName that = (AbstractFileName) o;\r
+\r
+ return getKey().equals(that.getKey());\r
+ }\r
+\r
+ /**\r
+ * Returns the base name of the file.\r
+ *\r
+ * @return The base name of the file.\r
+ */\r
+ @Override\r
+ public String getBaseName() {\r
+ if (baseName == null) {\r
+ final int idx = getPath().lastIndexOf(SEPARATOR_CHAR);\r
+ if (idx == -1) {\r
+ baseName = getPath();\r
+ } else {\r
+ baseName = getPath().substring(idx + 1);\r
+ }\r
+ }\r
+\r
+ return baseName;\r
+ }\r
+\r
+ /**\r
+ * Returns the depth of this file name, within its file system.\r
+ *\r
+ * @return The depth of the file name.\r
+ */\r
+ @Override\r
+ public int getDepth() {\r
+ final int len = getPath().length();\r
+ if (len == 0 || len == 1 && getPath().charAt(0) == SEPARATOR_CHAR) {\r
+ return 0;\r
+ }\r
+ int depth = 1;\r
+ for (int pos = 0; pos > -1 && pos < len; depth++) {\r
+ pos = getPath().indexOf(SEPARATOR_CHAR, pos + 1);\r
+ }\r
+ return depth;\r
+ }\r
+\r
+ /**\r
+ * Returns the extension of this file name.\r
+ *\r
+ * @return The file extension.\r
+ */\r
+ @Override\r
+ public String getExtension() {\r
+ if (extension == null) {\r
+ getBaseName();\r
+ final int pos = baseName.lastIndexOf('.');\r
+ // if ((pos == -1) || (pos == baseName.length() - 1))\r
+ // imario@ops.co.at: Review of patch from adagoubard@chello.nl\r
+ // do not treat file names like\r
+ // .bashrc c:\windows\.java c:\windows\.javaws c:\windows\.jedit c:\windows\.appletviewer\r
+ // as extension\r
+ if (pos < 1 || pos == baseName.length() - 1) {\r
+ // No extension\r
+ extension = "";\r
+ } else {\r
+ extension = baseName.substring(pos + 1).intern();\r
+ }\r
+ }\r
+ return extension;\r
+ }\r
+\r
+ /**\r
+ * Returns the URI without a password.\r
+ *\r
+ * @return Returns the URI without a password.\r
+ */\r
+ @Override\r
+ public String getFriendlyURI() {\r
+ return createURI(false, false);\r
+ }\r
+\r
+ /**\r
+ * Create a path that does not use the FileType since that field is not immutable.\r
+ *\r
+ * @return The key.\r
+ */\r
+ private String getKey() {\r
+ if (key == null) {\r
+ key = getURI();\r
+ }\r
+ return key;\r
+ }\r
+\r
+ /**\r
+ * Returns the name of the parent of the file.\r
+ *\r
+ * @return the FileName of the parent.\r
+ */\r
+ @Override\r
+ public FileName getParent() {\r
+ final String parentPath;\r
+ final int idx = getPath().lastIndexOf(SEPARATOR_CHAR);\r
+ if (idx == -1 || idx == getPath().length() - 1) {\r
+ // No parent\r
+ return null;\r
+ }\r
+ if (idx == 0) {\r
+ // Root is the parent\r
+ parentPath = SEPARATOR;\r
+ } else {\r
+ parentPath = getPath().substring(0, idx);\r
+ }\r
+ return createName(parentPath, FileType.FOLDER);\r
+ }\r
+\r
+ /**\r
+ * Returns the absolute path of the file, relative to the root of the file system that the file belongs to.\r
+ *\r
+ * @return The path String.\r
+ */\r
+ @Override\r
+ public String getPath() {\r
+ if (VFS.isUriStyle()) {\r
+ return absPath + getUriTrailer();\r
+ }\r
+ return absPath;\r
+ }\r
+\r
+ /**\r
+ * Returns the decoded path.\r
+ *\r
+ * @return The decoded path String.\r
+ * @throws FileSystemException If an error occurs.\r
+ */\r
+ @Override\r
+ public String getPathDecoded() throws FileSystemException {\r
+ if (decodedAbsPath == null) {\r
+ decodedAbsPath = UriParser.decode(getPath());\r
+ }\r
+\r
+ return decodedAbsPath;\r
+ }\r
+\r
+ /**\r
+ * Converts a file name to a relative name, relative to this file name.\r
+ *\r
+ * @param name The FileName.\r
+ * @return The relative path to the file.\r
+ * @throws FileSystemException if an error occurs.\r
+ */\r
+ @Override\r
+ public String getRelativeName(final FileName name) throws FileSystemException {\r
+ final String path = name.getPath();\r
+\r
+ // Calculate the common prefix\r
+ final int basePathLen = getPath().length();\r
+ final int pathLen = path.length();\r
+\r
+ // Deal with root\r
+ if (basePathLen == 1 && pathLen == 1) {\r
+ return ".";\r
+ }\r
+ if (basePathLen == 1) {\r
+ return path.substring(1);\r
+ }\r
+\r
+ final int maxlen = Math.min(basePathLen, pathLen);\r
+ int pos = 0;\r
+ while (pos < maxlen && getPath().charAt(pos) == path.charAt(pos)) {\r
+ pos++;\r
+ }\r
+\r
+ if (pos == basePathLen && pos == pathLen) {\r
+ // Same names\r
+ return ".";\r
+ }\r
+ if (pos == basePathLen && pos < pathLen && path.charAt(pos) == SEPARATOR_CHAR) {\r
+ // A descendent of the base path\r
+ return path.substring(pos + 1);\r
+ }\r
+\r
+ // Strip the common prefix off the path\r
+ final StringBuilder buffer = new StringBuilder();\r
+ if (pathLen > 1 && (pos < pathLen || getPath().charAt(pos) != SEPARATOR_CHAR)) {\r
+ // Not a direct ancestor, need to back up\r
+ pos = getPath().lastIndexOf(SEPARATOR_CHAR, pos);\r
+ buffer.append(path.substring(pos));\r
+ }\r
+\r
+ // Prepend a '../' for each element in the base path past the common\r
+ // prefix\r
+ buffer.insert(0, "..");\r
+ pos = getPath().indexOf(SEPARATOR_CHAR, pos + 1);\r
+ while (pos != -1) {\r
+ buffer.insert(0, "../");\r
+ pos = getPath().indexOf(SEPARATOR_CHAR, pos + 1);\r
+ }\r
+\r
+ return buffer.toString();\r
+ }\r
+\r
+ /**\r
+ * find the root of the file system.\r
+ *\r
+ * @return The root FileName.\r
+ */\r
+ @Override\r
+ public FileName getRoot() {\r
+ FileName root = this;\r
+ while (root.getParent() != null) {\r
+ root = root.getParent();\r
+ }\r
+\r
+ return root;\r
+ }\r
+\r
+ /**\r
+ * Returns the root URI of the file system this file belongs to.\r
+ *\r
+ * @return The URI of the root.\r
+ */\r
+ @Override\r
+ public String getRootURI() {\r
+ if (rootUri == null) {\r
+ final StringBuilder buffer = new StringBuilder();\r
+ appendRootUri(buffer, true);\r
+ buffer.append(SEPARATOR_CHAR);\r
+ rootUri = buffer.toString().intern();\r
+ }\r
+ return rootUri;\r
+ }\r
+\r
+ /**\r
+ * Returns the URI scheme of this file.\r
+ *\r
+ * @return The protocol used to access the file.\r
+ */\r
+ @Override\r
+ public String getScheme() {\r
+ return scheme;\r
+ }\r
+\r
+ /**\r
+ * Returns the requested or current type of this name.\r
+ * <p>\r
+ * The "requested" type is the one determined during resolving the name. n this case the name is a\r
+ * {@link FileType#FOLDER} if it ends with an "/" else it will be a {@link FileType#FILE}.\r
+ * </p>\r
+ * <p>\r
+ * Once attached it will be changed to reflect the real type of this resource.\r
+ * </p>\r
+ *\r
+ * @return {@link FileType#FOLDER} or {@link FileType#FILE}\r
+ */\r
+ @Override\r
+ public FileType getType() {\r
+ return type;\r
+ }\r
+\r
+ /**\r
+ * Returns the absolute URI of the file.\r
+ *\r
+ * @return The absolute URI of the file.\r
+ */\r
+ @Override\r
+ public String getURI() {\r
+ if (uriString == null) {\r
+ uriString = createURI();\r
+ }\r
+ return uriString;\r
+ }\r
+\r
+ protected String getUriTrailer() {\r
+ return getType().hasChildren() ? "/" : "";\r
+ }\r
+\r
+ private String handleURISpecialCharacters(String uri) {\r
+ if (!StringUtils.isEmpty(uri)) {\r
+ try {\r
+ // VFS-325: Handle URI special characters in file name\r
+ // Decode the base URI and re-encode with URI special characters\r
+ uri = UriParser.decode(uri);\r
+\r
+ return UriParser.encode(uri, RESERVED_URI_CHARS);\r
+ } catch (final FileSystemException e) {\r
+ // Default to base URI value?\r
+ return uri;\r
+ }\r
+ }\r
+\r
+ return uri;\r
+ }\r
+\r
+ @Override\r
+ public int hashCode() {\r
+ return getKey().hashCode();\r
+ }\r
+\r
+ /**\r
+ * Determines if another file name is an ancestor of this file name.\r
+ *\r
+ * @param ancestor The FileName to check.\r
+ * @return true if the FileName is an ancestor, false otherwise.\r
+ */\r
+ @Override\r
+ public boolean isAncestor(final FileName ancestor) {\r
+ if (!ancestor.getRootURI().equals(getRootURI())) {\r
+ return false;\r
+ }\r
+ return checkName(ancestor.getPath(), getPath(), NameScope.DESCENDENT);\r
+ }\r
+\r
+ /**\r
+ * Determines if another file name is a descendent of this file name.\r
+ *\r
+ * @param descendent The FileName to check.\r
+ * @return true if the FileName is a descendent, false otherwise.\r
+ */\r
+ @Override\r
+ public boolean isDescendent(final FileName descendent) {\r
+ return isDescendent(descendent, NameScope.DESCENDENT);\r
+ }\r
+\r
+ /**\r
+ * Determines if another file name is a descendent of this file name.\r
+ *\r
+ * @param descendent The FileName to check.\r
+ * @param scope The NameScope.\r
+ * @return true if the FileName is a descendent, false otherwise.\r
+ */\r
+ @Override\r
+ public boolean isDescendent(final FileName descendent, final NameScope scope) {\r
+ if (!descendent.getRootURI().equals(getRootURI())) {\r
+ return false;\r
+ }\r
+ return checkName(getPath(), descendent.getPath(), scope);\r
+ }\r
+\r
+ /**\r
+ * Checks if this file name is a name for a regular file by using its type.\r
+ *\r
+ * @return true if this file is a regular file.\r
+ * @throws FileSystemException may be thrown by subclasses.\r
+ * @see #getType()\r
+ * @see FileType#FILE\r
+ */\r
+ @Override\r
+ public boolean isFile() throws FileSystemException {\r
+ // Use equals instead of == to avoid any class loader worries.\r
+ return FileType.FILE.equals(this.getType());\r
+ }\r
+\r
+ /**\r
+ * Sets the type of this file e.g. when it will be attached.\r
+ *\r
+ * @param type {@link FileType#FOLDER} or {@link FileType#FILE}\r
+ * @throws FileSystemException if an error occurs.\r
+ */\r
+ void setType(final FileType type) throws FileSystemException {\r
+ if (type != FileType.FOLDER && type != FileType.FILE && type != FileType.FILE_OR_FOLDER) {\r
+ throw new FileSystemException("vfs.provider/filename-type.error");\r
+ }\r
+\r
+ this.type = type;\r
+ }\r
+\r
+ /**\r
+ * Returns the URI of the file.\r
+ *\r
+ * @return the FileName as a URI.\r
+ */\r
+ @Override\r
+ public String toString() {\r
+ return getURI();\r
+ }\r
+}\r
-/*
- * 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;
-
-import java.io.BufferedInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.URL;
-import java.security.AccessController;
-import java.security.PrivilegedActionException;
-import java.security.PrivilegedExceptionAction;
-import java.security.cert.Certificate;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Stream;
-
-import org.apache.commons.vfs2.Capability;
-import org.apache.commons.vfs2.FileContent;
-import org.apache.commons.vfs2.FileContentInfoFactory;
-import org.apache.commons.vfs2.FileName;
-import org.apache.commons.vfs2.FileNotFolderException;
-import org.apache.commons.vfs2.FileObject;
-import org.apache.commons.vfs2.FileSelector;
-import org.apache.commons.vfs2.FileSystem;
-import org.apache.commons.vfs2.FileSystemException;
-import org.apache.commons.vfs2.FileType;
-import org.apache.commons.vfs2.NameScope;
-import org.apache.commons.vfs2.RandomAccessContent;
-import org.apache.commons.vfs2.Selectors;
-import org.apache.commons.vfs2.operations.DefaultFileOperations;
-import org.apache.commons.vfs2.operations.FileOperations;
-import org.apache.commons.vfs2.util.FileObjectUtils;
-import org.apache.commons.vfs2.util.RandomAccessMode;
-
-/**
- * A partial file object implementation.
- *
- * TODO - Chop this class up - move all the protected methods to several interfaces, so that structure and content can
- * be separately overridden.
- *
- * <p>
- * TODO - Check caps in methods like getChildren(), etc, and give better error messages (eg 'this file type does not
- * support listing children', vs 'this is not a folder')
- * </p>
- *
- * @param <AFS> An AbstractFileSystem subclass
- */
-public abstract class AbstractFileObject<AFS extends AbstractFileSystem> implements FileObject {
-
- /**
- * Same as {@link BufferedInputStream}.
- */
- public static final int DEFAULT_BUFFER_SIZE = 8192;
-
- private static final int INITIAL_LIST_SIZE = 5;
-
- private static final String DO_GET_INPUT_STREAM_INT = "doGetInputStream(int)";
-
- private final AbstractFileName fileName;
- private final AFS fileSystem;
-
- private FileContent content;
- // Cached info
- private boolean attached;
- private FileType type;
-
- private FileObject parent;
- // Changed to hold only the name of the children and let the object
- // go into the global files cache
- // private FileObject[] children;
- private FileName[] children;
-
- private List<Object> objects;
-
- /**
- * FileServices instance.
- */
- private FileOperations operations;
-
- /**
- * Constructs a new instance.
- *
- * @param fileName the file name.
- * @param fileSystem the file system.
- */
- protected AbstractFileObject(final AbstractFileName fileName, final AFS fileSystem) {
- this.fileName = fileName;
- this.fileSystem = fileSystem;
- fileSystem.fileObjectHanded(this);
- }
-
- /**
- * Traverses a file.
- */
- private static void traverse(final DefaultFileSelectorInfo fileInfo, final FileSelector selector,
- final boolean depthwise, final List<FileObject> selected) throws Exception {
- // Check the file itself
- final FileObject file = fileInfo.getFile();
- final int index = selected.size();
-
- // If the file is a folder, traverse it
- if (file.getType().hasChildren() && selector.traverseDescendents(fileInfo)) {
- final int curDepth = fileInfo.getDepth();
- fileInfo.setDepth(curDepth + 1);
-
- // Traverse the children
- final FileObject[] children = file.getChildren();
- for (final FileObject child : children) {
- fileInfo.setFile(child);
- traverse(fileInfo, selector, depthwise, selected);
- }
-
- fileInfo.setFile(file);
- fileInfo.setDepth(curDepth);
- }
-
- // Add the file if doing depthwise traversal
- if (selector.includeFile(fileInfo)) {
- if (depthwise) {
- // Add this file after its descendants
- selected.add(file);
- } else {
- // Add this file before its descendants
- selected.add(index, file);
- }
- }
- }
-
- /**
- * Attaches to the file.
- *
- * @throws FileSystemException if an error occurs.
- */
- private void attach() throws FileSystemException {
- synchronized (fileSystem) {
- if (attached) {
- return;
- }
-
- try {
- // Attach and determine the file type
- doAttach();
- attached = true;
- // now the type could already be injected by doAttach (e.g from parent to child)
-
- /*
- * VFS-210: determine the type when really asked fore if (type == null) { setFileType(doGetType()); } if
- * (type == null) { setFileType(FileType.IMAGINARY); }
- */
- } catch (final Exception exc) {
- throw new FileSystemException("vfs.provider/get-type.error", exc, fileName);
- }
-
- // fs.fileAttached(this);
- }
- }
-
- /**
- * Queries the object if a simple rename to the file name of {@code newfile} is possible.
- *
- * @param newfile the new file name
- * @return true if rename is possible
- */
- @Override
- public boolean canRenameTo(final FileObject newfile) {
- return fileSystem == newfile.getFileSystem();
- }
-
- /**
- * Notifies the file that its children have changed.
- *
- * @param childName The name of the child.
- * @param newType The type of the child.
- * @throws Exception if an error occurs.
- */
- protected void childrenChanged(final FileName childName, final FileType newType) throws Exception {
- // TODO - this may be called when not attached
-
- if (children != null && childName != null && newType != null) {
- // TODO - figure out if children[] can be replaced by list
- final ArrayList<FileName> list = new ArrayList<>(Arrays.asList(children));
- if (newType.equals(FileType.IMAGINARY)) {
- list.remove(childName);
- } else {
- list.add(childName);
- }
- children = list.toArray(FileName.EMPTY_ARRAY);
- }
-
- // removeChildrenCache();
- onChildrenChanged(childName, newType);
- }
-
- /**
- * Closes this file, and its content.
- *
- * @throws FileSystemException if an error occurs.
- */
- @Override
- public void close() throws FileSystemException {
- FileSystemException exc = null;
-
- synchronized (fileSystem) {
- // Close the content
- if (content != null) {
- try {
- content.close();
- content = null;
- } catch (final FileSystemException e) {
- exc = e;
- }
- }
-
- // Detach from the file
- try {
- detach();
- } catch (final Exception e) {
- exc = new FileSystemException("vfs.provider/close.error", fileName, e);
- }
-
- if (exc != null) {
- throw exc;
- }
- }
- }
-
- /**
- * Compares two FileObjects (ignores case).
- *
- * @param file the object to compare.
- * @return a negative integer, zero, or a positive integer when this object is less than, equal to, or greater than
- * the given object.
- */
- @Override
- public int compareTo(final FileObject file) {
- if (file == null) {
- return 1;
- }
- return this.toString().compareToIgnoreCase(file.toString());
- }
-
- /**
- * Copies another file to this file.
- *
- * @param file The FileObject to copy.
- * @param selector The FileSelector.
- * @throws FileSystemException if an error occurs.
- */
- @Override
- public void copyFrom(final FileObject file, final FileSelector selector) throws FileSystemException {
- if (!FileObjectUtils.exists(file)) {
- throw new FileSystemException("vfs.provider/copy-missing-file.error", file);
- }
-
- // Locate the files to copy across
- final ArrayList<FileObject> files = new ArrayList<>();
- file.findFiles(selector, false, files);
-
- // Copy everything across
- for (final FileObject srcFile : files) {
- // Determine the destination file
- final String relPath = file.getName().getRelativeName(srcFile.getName());
- final FileObject destFile = resolveFile(relPath, NameScope.DESCENDENT_OR_SELF);
-
- // Clean up the destination file, if necessary
- if (FileObjectUtils.exists(destFile) && destFile.getType() != srcFile.getType()) {
- // The destination file exists, and is not of the same type,
- // so delete it
- // TODO - add a pluggable policy for deleting and overwriting existing files
- destFile.deleteAll();
- }
-
- // Copy across
- try {
- if (srcFile.getType().hasContent()) {
- FileObjectUtils.writeContent(srcFile, destFile);
- } else if (srcFile.getType().hasChildren()) {
- destFile.createFolder();
- }
- } catch (final IOException e) {
- throw new FileSystemException("vfs.provider/copy-file.error", e, srcFile, destFile);
- }
- }
- }
-
- /**
- * Creates this file, if it does not exist.
- *
- * @throws FileSystemException if an error occurs.
- */
- @Override
- public void createFile() throws FileSystemException {
- synchronized (fileSystem) {
- try {
- // VFS-210: We do not want to trunc any existing file, checking for its existence is
- // still required
- if (exists() && !isFile()) {
- throw new FileSystemException("vfs.provider/create-file.error", fileName);
- }
-
- if (!exists()) {
- try (FileContent content = getContent()) {
- if (content != null) {
- try (OutputStream outputStream = content.getOutputStream()) {
- // Avoids NPE on OutputStream#close()
- }
- }
- }
- }
- } catch (final RuntimeException re) {
- throw re;
- } catch (final Exception e) {
- throw new FileSystemException("vfs.provider/create-file.error", fileName, e);
- }
- }
- }
-
- /**
- * Creates this folder, if it does not exist. Also creates any ancestor files which do not exist.
- *
- * @throws FileSystemException if an error occurs.
- */
- @Override
- public void createFolder() throws FileSystemException {
- synchronized (fileSystem) {
- // VFS-210: we create a folder only if it does not already exist. So this check should be safe.
- if (getType().hasChildren()) {
- // Already exists as correct type
- return;
- }
- if (getType() != FileType.IMAGINARY) {
- throw new FileSystemException("vfs.provider/create-folder-mismatched-type.error", fileName);
- }
- /*
- * VFS-210: checking for writable is not always possible as the security constraint might be more complex
- * if (!isWriteable()) { throw new FileSystemException("vfs.provider/create-folder-read-only.error", name);
- * }
- */
-
- // Traverse up the hierarchy and make sure everything is a folder
- final FileObject parent = getParent();
- if (parent != null) {
- parent.createFolder();
- }
-
- try {
- // Create the folder
- doCreateFolder();
-
- // Update cached info
- handleCreate(FileType.FOLDER);
- } catch (final RuntimeException re) {
- throw re;
- } catch (final Exception exc) {
- throw new FileSystemException("vfs.provider/create-folder.error", fileName, exc);
- }
- }
- }
-
- /**
- * Deletes this file.
- * <p>
- * TODO - This will not fail if this is a non-empty folder.
- * </p>
- *
- * @return true if this object has been deleted
- * @throws FileSystemException if an error occurs.
- */
- @Override
- public boolean delete() throws FileSystemException {
- return delete(Selectors.SELECT_SELF) > 0;
- }
-
- /**
- * Deletes this file, and all children matching the {@code selector}.
- *
- * @param selector The FileSelector.
- * @return the number of deleted files.
- * @throws FileSystemException if an error occurs.
- */
- @Override
- public int delete(final FileSelector selector) throws FileSystemException {
- int nuofDeleted = 0;
-
- /*
- * VFS-210 if (getType() == FileType.IMAGINARY) { // File does not exist return nuofDeleted; }
- */
-
- // Locate all the files to delete
- final ArrayList<FileObject> files = new ArrayList<>();
- findFiles(selector, true, files);
-
- // Delete 'em
- for (final FileObject fileObject : files) {
- final AbstractFileObject file = FileObjectUtils.getAbstractFileObject(fileObject);
- // file.attach();
-
- // VFS-210: It seems impossible to me that findFiles will return a list with hidden files/directories
- // in it, else it would not be hidden. Checking for the file-type seems ok in this case
- // If the file is a folder, make sure all its children have been deleted
- if (file.getType().hasChildren() && file.getChildren().length != 0) {
- // Skip - as the selector forced us not to delete all files
- continue;
- }
-
- // Delete the file
- if (file.deleteSelf()) {
- nuofDeleted++;
- }
- }
-
- return nuofDeleted;
- }
-
- /**
- * Deletes this file and all children. Shorthand for {@code delete(Selectors.SELECT_ALL)}
- *
- * @return the number of deleted files.
- * @throws FileSystemException if an error occurs.
- * @see #delete(FileSelector)
- * @see Selectors#SELECT_ALL
- */
- @Override
- public int deleteAll() throws FileSystemException {
- return this.delete(Selectors.SELECT_ALL);
- }
-
- /**
- * Deletes this file, once all its children have been deleted
- *
- * @return true if this file has been deleted
- * @throws FileSystemException if an error occurs.
- */
- private boolean deleteSelf() throws FileSystemException {
- synchronized (fileSystem) {
- // Its possible to delete a read-only file if you have write-execute access to the directory
-
- /*
- * VFS-210 if (getType() == FileType.IMAGINARY) { // File does not exist return false; }
- */
-
- try {
- // Delete the file
- doDelete();
-
- // Update cached info
- handleDelete();
- } catch (final RuntimeException re) {
- throw re;
- } catch (final Exception exc) {
- throw new FileSystemException("vfs.provider/delete.error", exc, fileName);
- }
-
- return true;
- }
- }
-
- /**
- * Detaches this file, invalidating all cached info. This will force a call to {@link #doAttach} next time this file
- * is used.
- *
- * @throws Exception if an error occurs.
- */
- private void detach() throws Exception {
- synchronized (fileSystem) {
- if (attached) {
- try {
- doDetach();
- } finally {
- attached = false;
- setFileType(null);
- parent = null;
-
- // fs.fileDetached(this);
-
- removeChildrenCache();
- // children = null;
- }
- }
- }
- }
-
- /**
- * Attaches this file object to its file resource.
- * <p>
- * This method is called before any of the doBlah() or onBlah() methods. Sub-classes can use this method to perform
- * lazy initialization.
- * </p>
- * <p>
- * This implementation does nothing.
- * </p>
- *
- * @throws Exception if an error occurs.
- */
- protected void doAttach() throws Exception {
- // noop
- }
-
- /**
- * Create a FileContent implementation.
- *
- * @return The FileContent.
- * @throws FileSystemException if an error occurs.
- &n