]> source.dussan.org Git - archiva.git/commitdiff
Moving filesystem storage classes in sub package
authorMartin Stockhammer <martin_s@apache.org>
Sat, 29 Feb 2020 18:04:01 +0000 (19:04 +0100)
committerMartin Stockhammer <martin_s@apache.org>
Sat, 29 Feb 2020 18:04:01 +0000 (19:04 +0100)
45 files changed:
archiva-modules/archiva-base/archiva-consumers/archiva-core-consumers/src/main/java/org/apache/archiva/consumers/core/repository/AbstractRepositoryPurge.java
archiva-modules/archiva-base/archiva-policies/src/test/java/org/apache/archiva/policies/CachedFailuresPolicyTest.java
archiva-modules/archiva-base/archiva-policies/src/test/java/org/apache/archiva/policies/ChecksumPolicyTest.java
archiva-modules/archiva-base/archiva-policies/src/test/java/org/apache/archiva/policies/PropagateErrorsDownloadPolicyTest.java
archiva-modules/archiva-base/archiva-policies/src/test/java/org/apache/archiva/policies/PropagateErrorsOnUpdateDownloadPolicyTest.java
archiva-modules/archiva-base/archiva-policies/src/test/java/org/apache/archiva/policies/SnapshotsPolicyTest.java
archiva-modules/archiva-base/archiva-proxy/src/main/java/org/apache/archiva/proxy/DefaultRepositoryProxyHandler.java
archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/mock/ArchivaIndexManagerMock.java
archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/mock/MavenIndexContextMock.java
archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/BasicManagedRepository.java
archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/BasicRemoteRepository.java
archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/content/base/ContentItemTest.java
archiva-modules/archiva-base/archiva-repository-scanner/src/test/java/org/apache/archiva/repository/scanner/RepositoryScannerTest.java
archiva-modules/archiva-base/archiva-repository-scanner/src/test/java/org/apache/archiva/repository/scanner/mock/ManagedRepositoryContentMock.java
archiva-modules/archiva-base/archiva-storage-fs/src/main/java/org/apache/archiva/repository/storage/FilesystemAsset.java [deleted file]
archiva-modules/archiva-base/archiva-storage-fs/src/main/java/org/apache/archiva/repository/storage/FilesystemStorage.java [deleted file]
archiva-modules/archiva-base/archiva-storage-fs/src/main/java/org/apache/archiva/repository/storage/FsStorageUtil.java [deleted file]
archiva-modules/archiva-base/archiva-storage-fs/src/main/java/org/apache/archiva/repository/storage/fs/FilesystemAsset.java [new file with mode: 0644]
archiva-modules/archiva-base/archiva-storage-fs/src/main/java/org/apache/archiva/repository/storage/fs/FilesystemStorage.java [new file with mode: 0644]
archiva-modules/archiva-base/archiva-storage-fs/src/main/java/org/apache/archiva/repository/storage/fs/FsStorageUtil.java [new file with mode: 0644]
archiva-modules/archiva-base/archiva-storage-fs/src/test/java/org/apache/archiva/repository/storage/FilesystemAssetTest.java [deleted file]
archiva-modules/archiva-base/archiva-storage-fs/src/test/java/org/apache/archiva/repository/storage/FilesystemStorageTest.java [deleted file]
archiva-modules/archiva-base/archiva-storage-fs/src/test/java/org/apache/archiva/repository/storage/fs/FilesystemAssetTest.java [new file with mode: 0644]
archiva-modules/archiva-base/archiva-storage-fs/src/test/java/org/apache/archiva/repository/storage/fs/FilesystemStorageTest.java [new file with mode: 0644]
archiva-modules/archiva-maven/archiva-maven-indexer/src/main/java/org/apache/archiva/indexer/maven/MavenIndexContext.java
archiva-modules/archiva-maven/archiva-maven-indexer/src/main/java/org/apache/archiva/indexer/maven/MavenIndexManager.java
archiva-modules/archiva-maven/archiva-maven-proxy/src/test/java/org/apache/archiva/proxy/MetadataTransferTest.java
archiva-modules/archiva-maven/archiva-maven-proxy/src/test/java/org/apache/archiva/repository/mock/ManagedRepositoryContentMock.java
archiva-modules/archiva-maven/archiva-maven-repository/src/main/java/org/apache/archiva/repository/maven2/MavenManagedRepository.java
archiva-modules/archiva-maven/archiva-maven-repository/src/main/java/org/apache/archiva/repository/maven2/MavenRemoteRepository.java
archiva-modules/archiva-maven/archiva-maven-repository/src/main/java/org/apache/archiva/repository/maven2/MavenRepositoryGroup.java
archiva-modules/archiva-maven/archiva-maven-repository/src/main/java/org/apache/archiva/repository/maven2/MavenRepositoryProvider.java
archiva-modules/archiva-maven/archiva-maven-repository/src/main/java/org/apache/archiva/stagerepository/merge/Maven2RepositoryMerger.java
archiva-modules/archiva-maven/archiva-maven-repository/src/test/java/org/apache/archiva/repository/index/mock/ArchivaIndexManagerMock.java
archiva-modules/archiva-maven/archiva-maven-repository/src/test/java/org/apache/archiva/repository/index/mock/MavenIndexContextMock.java
archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/java/org/apache/archiva/mock/ArchivaIndexManagerMock.java
archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/java/org/apache/archiva/mock/MavenIndexContextMock.java
archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/DefaultBrowseService.java
archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/DefaultRepositoriesService.java
archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/test/java/org/apache/archiva/rest/services/ArtifactContentEntriesTests.java
archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/test/java/org/apache/archiva/rest/services/utils/ArtifactBuilderTest.java
archiva-modules/archiva-web/archiva-rss/src/test/java/org/apache/archiva/rss/processor/NewVersionsOfArtifactRssFeedProcessorTest.java
archiva-modules/archiva-web/archiva-web-common/src/test/java/org/apache/archiva/web/rss/RssFeedServletTest.java
archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/archiva/webdav/ArchivaDavResourceFactory.java
archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/archiva/webdav/DavResourceTest.java

index a3979e6a19f5299162de3ee13ce072b694be54af..2e04e667a278d2d512786f87fa92ae575b931d9c 100644 (file)
@@ -28,7 +28,6 @@ import org.apache.archiva.model.ArtifactReference;
 import org.apache.archiva.repository.ContentNotFoundException;
 import org.apache.archiva.repository.ManagedRepositoryContent;
 import org.apache.archiva.metadata.audit.RepositoryListener;
-import org.apache.archiva.repository.storage.FsStorageUtil;
 import org.apache.archiva.repository.storage.StorageAsset;
 import org.apache.archiva.repository.storage.util.StorageUtil;
 import org.apache.commons.lang3.StringUtils;
index 27cda9728769fdafe9b0151e2692966901d62ad1..d46cfd498a38253bd1f8ff608614539c1e11bf52 100644 (file)
@@ -22,7 +22,7 @@ package org.apache.archiva.policies;
 import junit.framework.TestCase;
 import org.apache.archiva.common.filelock.DefaultFileLockManager;
 import org.apache.archiva.policies.urlcache.UrlFailureCache;
-import org.apache.archiva.repository.storage.FilesystemStorage;
+import org.apache.archiva.repository.storage.fs.FilesystemStorage;
 import org.apache.archiva.repository.storage.StorageAsset;
 import org.apache.archiva.test.utils.ArchivaSpringJUnit4ClassRunner;
 import org.junit.Test;
index d4c131c8e57897b1ce94787a9bc6ff967051e149..b24695fe6ccda38c325783b0b597c15cb9296fbe 100644 (file)
@@ -19,9 +19,8 @@ package org.apache.archiva.policies;
  * under the License.
  */
 
-import org.apache.archiva.checksum.Checksum;
 import org.apache.archiva.common.filelock.DefaultFileLockManager;
-import org.apache.archiva.repository.storage.FilesystemStorage;
+import org.apache.archiva.repository.storage.fs.FilesystemStorage;
 import org.apache.archiva.repository.storage.StorageAsset;
 import org.apache.archiva.test.utils.ArchivaSpringJUnit4ClassRunner;
 import org.apache.commons.io.FileUtils;
index 4aff8c7ab9fc930891b9c8156de31d467790ee65..1509a5d6f7c69fa058fa027a895d4d10fc1951c8 100644 (file)
@@ -22,7 +22,7 @@ package org.apache.archiva.policies;
 import junit.framework.TestCase;
 import org.apache.archiva.common.filelock.DefaultFileLockManager;
 import org.apache.archiva.policies.urlcache.UrlFailureCache;
-import org.apache.archiva.repository.storage.FilesystemStorage;
+import org.apache.archiva.repository.storage.fs.FilesystemStorage;
 import org.apache.archiva.repository.storage.StorageAsset;
 import org.apache.archiva.test.utils.ArchivaSpringJUnit4ClassRunner;
 import org.junit.Test;
index 9c09bd92fb478661ae625f47e9f8a6566e7018b9..a059aff060e91a883731d35356e616a805d50f03 100644 (file)
@@ -22,7 +22,7 @@ package org.apache.archiva.policies;
 import junit.framework.TestCase;
 import org.apache.archiva.common.filelock.DefaultFileLockManager;
 import org.apache.archiva.policies.urlcache.UrlFailureCache;
-import org.apache.archiva.repository.storage.FilesystemStorage;
+import org.apache.archiva.repository.storage.fs.FilesystemStorage;
 import org.apache.archiva.repository.storage.StorageAsset;
 import org.apache.archiva.test.utils.ArchivaSpringJUnit4ClassRunner;
 import org.junit.Test;
index 635d216c46ac361e76f16abf1545e4229d22e84b..813c97d5cd3b30d02f672f43e966eb564aec7a46 100644 (file)
@@ -20,7 +20,7 @@ package org.apache.archiva.policies;
  */
 
 import junit.framework.TestCase;
-import org.apache.archiva.repository.storage.FilesystemStorage;
+import org.apache.archiva.repository.storage.fs.FilesystemStorage;
 import org.apache.archiva.repository.storage.StorageAsset;
 import org.apache.archiva.test.utils.ArchivaSpringJUnit4ClassRunner;
 import org.junit.Before;
@@ -32,7 +32,6 @@ import javax.inject.Inject;
 import javax.inject.Named;
 import java.nio.charset.Charset;
 import java.nio.file.Files;
-import java.nio.file.Path;
 import java.nio.file.attribute.FileTime;
 import java.util.Locale;
 import java.util.MissingResourceException;
index ddeb499f47256f127ef944ef81c22f9f53b8cfeb..3406c0243f225684cafa8a373a4c862fe067fcf0 100644 (file)
@@ -49,8 +49,8 @@ import org.apache.archiva.repository.RemoteRepositoryContent;
 import org.apache.archiva.repository.RepositoryType;
 import org.apache.archiva.repository.metadata.base.MetadataTools;
 import org.apache.archiva.repository.metadata.RepositoryMetadataException;
-import org.apache.archiva.repository.storage.FilesystemStorage;
-import org.apache.archiva.repository.storage.FsStorageUtil;
+import org.apache.archiva.repository.storage.fs.FilesystemStorage;
+import org.apache.archiva.repository.storage.fs.FsStorageUtil;
 import org.apache.archiva.repository.storage.StorageAsset;
 import org.apache.archiva.scheduler.ArchivaTaskScheduler;
 import org.apache.archiva.scheduler.repository.model.RepositoryTask;
index 127c314834e6a97e7b693305f133d62d9628a443..31b115ae57a6df8150504275a6af9d0625badd94 100644 (file)
@@ -39,8 +39,8 @@ import org.apache.archiva.repository.RemoteRepository;
 import org.apache.archiva.repository.Repository;
 import org.apache.archiva.repository.RepositoryType;
 import org.apache.archiva.repository.UnsupportedRepositoryTypeException;
-import org.apache.archiva.repository.storage.FilesystemAsset;
-import org.apache.archiva.repository.storage.FilesystemStorage;
+import org.apache.archiva.repository.storage.fs.FilesystemAsset;
+import org.apache.archiva.repository.storage.fs.FilesystemStorage;
 import org.apache.archiva.repository.storage.StorageAsset;
 import org.apache.archiva.repository.features.IndexCreationFeature;
 import org.apache.archiva.repository.features.RemoteIndexFeature;
index 843df59fee776d3accd1a2def4271fc5d5e045dd..ebdd0c7612da064b0ae42dcbf7925af087fb065a 100644 (file)
@@ -22,13 +22,12 @@ package org.apache.archiva.admin.mock;
 import org.apache.archiva.common.filelock.DefaultFileLockManager;
 import org.apache.archiva.indexer.ArchivaIndexingContext;
 import org.apache.archiva.repository.Repository;
-import org.apache.archiva.repository.storage.FilesystemAsset;
-import org.apache.archiva.repository.storage.FilesystemStorage;
+import org.apache.archiva.repository.storage.fs.FilesystemAsset;
+import org.apache.archiva.repository.storage.fs.FilesystemStorage;
 import org.apache.archiva.repository.storage.StorageAsset;
 import org.apache.maven.index.context.IndexingContext;
 
 import java.io.IOException;
-import java.net.URI;
 import java.nio.file.Files;
 import java.nio.file.NoSuchFileException;
 import java.sql.Date;
index 56f8bf963f828e19ce116f4b6bf3c5060d1d12db..f3e13617a2bee2e1204f555e45b2d3878ea6553a 100644 (file)
@@ -26,7 +26,7 @@ import org.apache.archiva.repository.RepositoryCapabilities;
 import org.apache.archiva.repository.RepositoryRequestInfo;
 import org.apache.archiva.repository.RepositoryType;
 import org.apache.archiva.repository.StandardCapabilities;
-import org.apache.archiva.repository.storage.FilesystemStorage;
+import org.apache.archiva.repository.storage.fs.FilesystemStorage;
 import org.apache.archiva.repository.storage.RepositoryStorage;
 import org.apache.archiva.repository.features.ArtifactCleanupFeature;
 import org.apache.archiva.repository.features.IndexCreationFeature;
index ae62582166949a8dc0d134b38d8a995dc94ce80c..afec07069ce5f25ea4e810c6a8ca7cdc2e719535 100644 (file)
@@ -25,7 +25,7 @@ import org.apache.archiva.repository.ReleaseScheme;
 import org.apache.archiva.repository.RepositoryCapabilities;
 import org.apache.archiva.repository.RepositoryType;
 import org.apache.archiva.repository.StandardCapabilities;
-import org.apache.archiva.repository.storage.FilesystemStorage;
+import org.apache.archiva.repository.storage.fs.FilesystemStorage;
 import org.apache.archiva.repository.storage.RepositoryStorage;
 import org.apache.archiva.repository.features.IndexCreationFeature;
 import org.apache.archiva.repository.features.RemoteIndexFeature;
index a1c3fd65c467aac3ca902df3e0cd4a5e6e1de183..8f266d2923d159fa0d21499f5091241ef3b99fac 100644 (file)
@@ -22,7 +22,7 @@ import org.apache.archiva.common.filelock.DefaultFileLockManager;
 import org.apache.archiva.repository.content.ContentItem;
 import org.apache.archiva.repository.content.base.builder.OptBuilder;
 import org.apache.archiva.repository.mock.ManagedRepositoryContentMock;
-import org.apache.archiva.repository.storage.FilesystemStorage;
+import org.apache.archiva.repository.storage.fs.FilesystemStorage;
 import org.apache.archiva.repository.storage.StorageAsset;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
index bdf10b13c1bd3ffc8a6e3c7c8b62babe3b0fd69a..45476eebf1d685877c0bbfe4d83e4ec38cdfd74a 100644 (file)
@@ -29,11 +29,10 @@ import org.apache.archiva.repository.base.BasicRemoteRepository;
 import org.apache.archiva.repository.EditableManagedRepository;
 import org.apache.archiva.repository.EditableRemoteRepository;
 import org.apache.archiva.repository.ManagedRepository;
-import org.apache.archiva.repository.storage.FilesystemStorage;
+import org.apache.archiva.repository.storage.fs.FilesystemStorage;
 import org.apache.archiva.repository.scanner.mock.ManagedRepositoryContentMock;
 import org.apache.archiva.test.utils.ArchivaSpringJUnit4ClassRunner;
 import org.apache.commons.io.FileUtils;
-import org.hamcrest.CoreMatchers;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.springframework.context.ApplicationContext;
@@ -43,7 +42,6 @@ import javax.inject.Inject;
 import java.io.IOException;
 import java.net.URI;
 import java.net.URISyntaxException;
-import java.net.URL;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
index 8c7ebabd117fc543664ff3e3e7907a5a1c8579a8..b19dd5b735a24953ebe00baf3ca789981d9cee6b 100644 (file)
@@ -35,7 +35,7 @@ import org.apache.archiva.repository.content.ItemSelector;
 import org.apache.archiva.repository.content.Namespace;
 import org.apache.archiva.repository.content.Project;
 import org.apache.archiva.repository.content.Version;
-import org.apache.archiva.repository.storage.FilesystemStorage;
+import org.apache.archiva.repository.storage.fs.FilesystemStorage;
 import org.apache.archiva.repository.storage.StorageAsset;
 import org.apache.commons.lang3.StringUtils;
 
diff --git a/archiva-modules/archiva-base/archiva-storage-fs/src/main/java/org/apache/archiva/repository/storage/FilesystemAsset.java b/archiva-modules/archiva-base/archiva-storage-fs/src/main/java/org/apache/archiva/repository/storage/FilesystemAsset.java
deleted file mode 100644 (file)
index 2f501d6..0000000
+++ /dev/null
@@ -1,523 +0,0 @@
-package org.apache.archiva.repository.storage;
-
-/*
- * 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.
- */
-
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.channels.FileChannel;
-import java.nio.channels.ReadableByteChannel;
-import java.nio.channels.WritableByteChannel;
-import java.nio.file.*;
-import java.nio.file.attribute.*;
-import java.time.Instant;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/**
- * Implementation of an asset that is stored on the filesystem.
- * <p>
- * The implementation does not check the given paths. Caller should normalize the asset path
- * and check, if the base path is a parent of the resulting path.
- * <p>
- * The file must not exist for all operations.
- *
- * @author Martin Stockhammer <martin_s@apache.org>
- */
-public class FilesystemAsset implements StorageAsset, Comparable {
-
-    private final static Logger log = LoggerFactory.getLogger(FilesystemAsset.class);
-
-    private final Path basePath;
-    private final Path assetPath;
-    private final String relativePath;
-
-    public static final String DEFAULT_POSIX_FILE_PERMS = "rw-rw----";
-    public static final String DEFAULT_POSIX_DIR_PERMS = "rwxrwx---";
-
-    public static final Set<PosixFilePermission> DEFAULT_POSIX_FILE_PERMISSIONS;
-    public static final Set<PosixFilePermission> DEFAULT_POSIX_DIR_PERMISSIONS;
-
-    public static final AclEntryPermission[] DEFAULT_ACL_FILE_PERMISSIONS = new AclEntryPermission[]{
-            AclEntryPermission.DELETE, AclEntryPermission.READ_ACL, AclEntryPermission.READ_ATTRIBUTES, AclEntryPermission.READ_DATA, AclEntryPermission.WRITE_ACL,
-            AclEntryPermission.WRITE_ATTRIBUTES, AclEntryPermission.WRITE_DATA, AclEntryPermission.APPEND_DATA
-    };
-
-    public static final AclEntryPermission[] DEFAULT_ACL_DIR_PERMISSIONS = new AclEntryPermission[]{
-            AclEntryPermission.ADD_FILE, AclEntryPermission.ADD_SUBDIRECTORY, AclEntryPermission.DELETE_CHILD,
-            AclEntryPermission.DELETE, AclEntryPermission.READ_ACL, AclEntryPermission.READ_ATTRIBUTES, AclEntryPermission.READ_DATA, AclEntryPermission.WRITE_ACL,
-            AclEntryPermission.WRITE_ATTRIBUTES, AclEntryPermission.WRITE_DATA, AclEntryPermission.APPEND_DATA
-    };
-
-    static {
-
-        DEFAULT_POSIX_FILE_PERMISSIONS = PosixFilePermissions.fromString(DEFAULT_POSIX_FILE_PERMS);
-        DEFAULT_POSIX_DIR_PERMISSIONS = PosixFilePermissions.fromString(DEFAULT_POSIX_DIR_PERMS);
-    }
-
-    Set<PosixFilePermission> defaultPosixFilePermissions = DEFAULT_POSIX_FILE_PERMISSIONS;
-    Set<PosixFilePermission> defaultPosixDirectoryPermissions = DEFAULT_POSIX_DIR_PERMISSIONS;
-
-    List<AclEntry> defaultFileAcls;
-    List<AclEntry> defaultDirectoryAcls;
-
-    boolean supportsAcl = false;
-    boolean supportsPosix = false;
-    final boolean setPermissionsForNew;
-    final RepositoryStorage storage;
-
-    boolean directoryHint = false;
-
-    private static final OpenOption[] REPLACE_OPTIONS = new OpenOption[]{StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE};
-    private static final OpenOption[] APPEND_OPTIONS = new OpenOption[]{StandardOpenOption.APPEND};
-
-
-    FilesystemAsset(RepositoryStorage storage, String path, Path assetPath, Path basePath) {
-        this.assetPath = assetPath;
-        this.relativePath = normalizePath(path);
-        this.setPermissionsForNew=false;
-        this.basePath = basePath;
-        this.storage = storage;
-        init();
-    }
-
-    /**
-     * Creates an asset for the given path. The given paths are not checked.
-     * The base path should be an absolute path.
-     *
-     * @param path The logical path for the asset relative to the repository.
-     * @param assetPath The asset path.
-     */
-    public FilesystemAsset(RepositoryStorage storage, String path, Path assetPath) {
-        this.assetPath = assetPath;
-        this.relativePath = normalizePath(path);
-        this.setPermissionsForNew = false;
-        this.basePath = null;
-        this.storage = storage;
-        // The base directory is always a directory
-        if ("".equals(path) || "/".equals(path)) {
-            this.directoryHint = true;
-        }
-        init();
-    }
-
-    /**
-     * Creates an asset for the given path. The given paths are not checked.
-     * The base path should be an absolute path.
-     *
-     * @param path The logical path for the asset relative to the repository
-     * @param assetPath The asset path.
-     * @param directory This is only relevant, if the represented file or directory does not exist yet and
-     *                  is a hint.
-     */
-    public FilesystemAsset(RepositoryStorage storage, String path, Path assetPath, Path basePath, boolean directory) {
-        this.assetPath = assetPath;
-        this.relativePath = normalizePath(path);
-        this.directoryHint = directory;
-        this.setPermissionsForNew = false;
-        this.basePath = basePath;
-        this.storage = storage;
-        init();
-    }
-
-    /**
-     * Creates an asset for the given path. The given paths are not checked.
-     * The base path should be an absolute path.
-     *
-     * @param path The logical path for the asset relative to the repository
-     * @param assetPath The asset path.
-     * @param directory This is only relevant, if the represented file or directory does not exist yet and
-     *                  is a hint.
-     */
-    public FilesystemAsset(RepositoryStorage storage, String path, Path assetPath, Path basePath, boolean directory, boolean setPermissionsForNew) {
-        this.assetPath = assetPath;
-        this.relativePath = normalizePath(path);
-        this.directoryHint = directory;
-        this.setPermissionsForNew = setPermissionsForNew;
-        this.basePath = basePath;
-        this.storage = storage;
-        init();
-    }
-
-    private String normalizePath(final String path) {
-        if (!path.startsWith("/")) {
-            return "/"+path;
-        } else {
-            String tmpPath = path;
-            while (tmpPath.startsWith("//")) {
-                tmpPath = tmpPath.substring(1);
-            }
-            return tmpPath;
-        }
-    }
-
-    private void init() {
-
-        if (setPermissionsForNew) {
-            try {
-                supportsAcl = Files.getFileStore(assetPath.getRoot()).supportsFileAttributeView(AclFileAttributeView.class);
-            } catch (IOException e) {
-                log.error("Could not check filesystem capabilities {}", e.getMessage());
-            }
-            try {
-                supportsPosix = Files.getFileStore(assetPath.getRoot()).supportsFileAttributeView(PosixFileAttributeView.class);
-            } catch (IOException e) {
-                log.error("Could not check filesystem capabilities {}", e.getMessage());
-            }
-
-            if (supportsAcl) {
-                AclFileAttributeView aclView = Files.getFileAttributeView(assetPath.getParent(), AclFileAttributeView.class);
-                UserPrincipal owner = null;
-                try {
-                    owner = aclView.getOwner();
-                    setDefaultFileAcls(processPermissions(owner, DEFAULT_ACL_FILE_PERMISSIONS));
-                    setDefaultDirectoryAcls(processPermissions(owner, DEFAULT_ACL_DIR_PERMISSIONS));
-
-                } catch (IOException e) {
-                    supportsAcl = false;
-                }
-
-
-            }
-        }
-    }
-
-    private List<AclEntry> processPermissions(UserPrincipal owner, AclEntryPermission[] defaultAclFilePermissions) {
-        AclEntry.Builder aclBuilder = AclEntry.newBuilder();
-        aclBuilder.setPermissions(defaultAclFilePermissions);
-        aclBuilder.setType(AclEntryType.ALLOW);
-        aclBuilder.setPrincipal(owner);
-        ArrayList<AclEntry> aclList = new ArrayList<>();
-        aclList.add(aclBuilder.build());
-        return aclList;
-    }
-
-
-    @Override
-    public RepositoryStorage getStorage( )
-    {
-        return storage;
-    }
-
-    @Override
-    public String getPath() {
-        return relativePath;
-    }
-
-    @Override
-    public String getName() {
-        return assetPath.getFileName().toString();
-    }
-
-    @Override
-    public Instant getModificationTime() {
-        try {
-            return Files.getLastModifiedTime(assetPath).toInstant();
-        } catch (IOException e) {
-            log.error("Could not read modification time of {}", assetPath);
-            return Instant.now();
-        }
-    }
-
-    /**
-     * Returns true, if the path of this asset points to a directory
-     *
-     * @return
-     */
-    @Override
-    public boolean isContainer() {
-        if (Files.exists(assetPath)) {
-            return Files.isDirectory(assetPath);
-        } else {
-            return directoryHint;
-        }
-    }
-
-    @Override
-    public boolean isLeaf( )
-    {
-        if (Files.exists( assetPath )) {
-            return Files.isRegularFile( assetPath );
-        } else {
-            return !directoryHint;
-        }
-    }
-
-    /**
-     * Returns the list of directory entries, if this asset represents a directory.
-     * Otherwise a empty list will be returned.
-     *
-     * @return The list of entries in the directory, if it exists.
-     */
-    @Override
-    public List<StorageAsset> list() {
-        try {
-            return Files.list(assetPath).map(p -> new FilesystemAsset(storage, relativePath + "/" + p.getFileName().toString(), assetPath.resolve(p)))
-                    .collect(Collectors.toList());
-        } catch (IOException e) {
-            return Collections.EMPTY_LIST;
-        }
-    }
-
-    /**
-     * Returns the size of the represented file. If it cannot be determined, -1 is returned.
-     *
-     * @return
-     */
-    @Override
-    public long getSize() {
-        try {
-            return Files.size(assetPath);
-        } catch (IOException e) {
-            return -1;
-        }
-    }
-
-    /**
-     * Returns a input stream to the underlying file, if it exists. The caller has to make sure, that
-     * the stream is closed after it was used.
-     *
-     * @return
-     * @throws IOException
-     */
-    @Override
-    public InputStream getReadStream() throws IOException {
-        if (isContainer()) {
-            throw new IOException("Can not create input stream for container");
-        }
-        return Files.newInputStream(assetPath);
-    }
-
-    @Override
-    public ReadableByteChannel getReadChannel( ) throws IOException
-    {
-        return FileChannel.open( assetPath, StandardOpenOption.READ );
-    }
-
-    private OpenOption[] getOpenOptions(boolean replace) {
-        return replace ? REPLACE_OPTIONS : APPEND_OPTIONS;
-    }
-
-    @Override
-    public OutputStream getWriteStream( boolean replace) throws IOException {
-        OpenOption[] options = getOpenOptions( replace );
-        if (!Files.exists( assetPath )) {
-            create();
-        }
-        return Files.newOutputStream(assetPath, options);
-    }
-
-    @Override
-    public WritableByteChannel getWriteChannel( boolean replace ) throws IOException
-    {
-        OpenOption[] options = getOpenOptions( replace );
-        return FileChannel.open( assetPath, options );
-    }
-
-    @Override
-    public boolean replaceDataFromFile( Path newData) throws IOException {
-        final boolean createNew = !Files.exists(assetPath);
-        Path backup = null;
-        if (!createNew) {
-            backup = findBackupFile(assetPath);
-        }
-        try {
-            if (!createNew) {
-                Files.move(assetPath, backup);
-            }
-            Files.move(newData, assetPath, StandardCopyOption.REPLACE_EXISTING);
-            applyDefaultPermissions(assetPath);
-            return true;
-        } catch (IOException e) {
-            log.error("Could not overwrite file {}", assetPath);
-            // Revert if possible
-            if (backup != null && Files.exists(backup)) {
-                Files.move(backup, assetPath, StandardCopyOption.REPLACE_EXISTING);
-            }
-            throw e;
-        } finally {
-            if (backup != null) {
-                try {
-                    Files.deleteIfExists(backup);
-                } catch (IOException e) {
-                    log.error("Could not delete backup file {}", backup);
-                }
-            }
-        }
-
-    }
-
-    private void applyDefaultPermissions(Path filePath) {
-        try {
-            if (supportsPosix) {
-                Set<PosixFilePermission> perms;
-                if (Files.isDirectory(filePath)) {
-                    perms = defaultPosixFilePermissions;
-                } else {
-                    perms = defaultPosixDirectoryPermissions;
-                }
-                Files.setPosixFilePermissions(filePath, perms);
-            } else if (supportsAcl) {
-                List<AclEntry> perms;
-                if (Files.isDirectory(filePath)) {
-                    perms = getDefaultDirectoryAcls();
-                } else {
-                    perms = getDefaultFileAcls();
-                }
-                AclFileAttributeView aclAttr = Files.getFileAttributeView(filePath, AclFileAttributeView.class);
-                aclAttr.setAcl(perms);
-            }
-        } catch (IOException e) {
-            log.error("Could not set permissions for {}: {}", filePath, e.getMessage());
-        }
-    }
-
-    private Path findBackupFile(Path file) {
-        String ext = ".bak";
-        Path backupPath = file.getParent().resolve(file.getFileName().toString() + ext);
-        int idx = 0;
-        while (Files.exists(backupPath)) {
-            backupPath = file.getParent().resolve(file.getFileName().toString() + ext + idx++);
-        }
-        return backupPath;
-    }
-
-    @Override
-    public boolean exists() {
-        return Files.exists(assetPath);
-    }
-
-    @Override
-    public Path getFilePath() throws UnsupportedOperationException {
-        return assetPath;
-    }
-
-    @Override
-    public boolean isFileBased( )
-    {
-        return true;
-    }
-
-    @Override
-    public boolean hasParent( )
-    {
-        if (basePath!=null && assetPath.equals(basePath)) {
-                return false;
-        }
-        return assetPath.getParent()!=null;
-    }
-
-    @Override
-    public StorageAsset getParent( )
-    {
-        Path parentPath;
-        if (basePath!=null && assetPath.equals( basePath )) {
-            parentPath=null;
-        } else
-        {
-            parentPath = assetPath.getParent( );
-        }
-        String relativeParent = StringUtils.substringBeforeLast( relativePath,"/");
-        if (parentPath!=null) {
-            return new FilesystemAsset(storage, relativeParent, parentPath, basePath, true, setPermissionsForNew );
-        } else {
-            return null;
-        }
-    }
-
-    @Override
-    public StorageAsset resolve(String toPath) {
-        return storage.getAsset(this.getPath()+"/"+toPath);
-    }
-
-
-    public void setDefaultFileAcls(List<AclEntry> acl) {
-        defaultFileAcls = acl;
-    }
-
-    public List<AclEntry> getDefaultFileAcls() {
-        return defaultFileAcls;
-    }
-
-    public void setDefaultPosixFilePermissions(Set<PosixFilePermission> perms) {
-        defaultPosixFilePermissions = perms;
-    }
-
-    public Set<PosixFilePermission> getDefaultPosixFilePermissions() {
-        return defaultPosixFilePermissions;
-    }
-
-    public void setDefaultDirectoryAcls(List<AclEntry> acl) {
-        defaultDirectoryAcls = acl;
-    }
-
-    public List<AclEntry> getDefaultDirectoryAcls() {
-        return defaultDirectoryAcls;
-    }
-
-    public void setDefaultPosixDirectoryPermissions(Set<PosixFilePermission> perms) {
-        defaultPosixDirectoryPermissions = perms;
-    }
-
-    public Set<PosixFilePermission> getDefaultPosixDirectoryPermissions() {
-        return defaultPosixDirectoryPermissions;
-    }
-
-    @Override
-    public void create() throws IOException {
-        if (!Files.exists(assetPath)) {
-            if (directoryHint) {
-                Files.createDirectories(assetPath);
-            } else {
-                if (!Files.exists( assetPath.getParent() )) {
-                    Files.createDirectories( assetPath.getParent( ) );
-                }
-                Files.createFile(assetPath);
-            }
-            if (setPermissionsForNew) {
-                applyDefaultPermissions(assetPath);
-            }
-        }
-    }
-
-    @Override
-    public String toString() {
-        return relativePath+":"+assetPath;
-    }
-
-    @Override
-    public int compareTo(Object o) {
-        if (o instanceof FilesystemAsset) {
-            if (this.getPath()!=null) {
-                return this.getPath().compareTo(((FilesystemAsset) o).getPath());
-            } else {
-                return 0;
-            }
-        }
-        return 0;
-    }
-}
diff --git a/archiva-modules/archiva-base/archiva-storage-fs/src/main/java/org/apache/archiva/repository/storage/FilesystemStorage.java b/archiva-modules/archiva-base/archiva-storage-fs/src/main/java/org/apache/archiva/repository/storage/FilesystemStorage.java
deleted file mode 100644 (file)
index ced3bac..0000000
+++ /dev/null
@@ -1,409 +0,0 @@
-package org.apache.archiva.repository.storage;
-
-/*
- * 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.
- */
-
-import org.apache.archiva.common.filelock.FileLockException;
-import org.apache.archiva.common.filelock.FileLockManager;
-import org.apache.archiva.common.filelock.FileLockTimeoutException;
-import org.apache.archiva.common.filelock.Lock;
-import org.apache.archiva.common.utils.PathUtil;
-import org.apache.commons.io.FileUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.URI;
-import java.nio.channels.FileChannel;
-import java.nio.channels.ReadableByteChannel;
-import java.nio.channels.WritableByteChannel;
-import java.nio.file.*;
-import java.util.function.Consumer;
-
-/**
- * Implementation of <code>{@link RepositoryStorage}</code> where data is stored in the filesystem.
- *
- * All files are relative to a given base path. Path values are separated by '/', '..' is allowed to navigate
- * to a parent directory, but navigation out of the base path will lead to a exception.
- */
-public class FilesystemStorage implements RepositoryStorage {
-
-    private static final Logger log = LoggerFactory.getLogger(FilesystemStorage.class);
-
-    private Path basePath;
-    private final FileLockManager fileLockManager;
-
-    public FilesystemStorage(Path basePath, FileLockManager fileLockManager) throws IOException {
-        if (!Files.exists(basePath)) {
-            Files.createDirectories(basePath);
-        }
-        this.basePath = basePath.normalize().toRealPath();
-        this.fileLockManager = fileLockManager;
-    }
-
-    private Path normalize(final String path) {
-        String nPath = path;
-        while (nPath.startsWith("/")) {
-            nPath = nPath.substring(1);
-        }
-        return Paths.get(nPath);
-    }
-
-    private Path getAssetPath(String path) throws IOException {
-        Path assetPath = basePath.resolve(normalize(path)).normalize();
-        if (!assetPath.startsWith(basePath))
-        {
-            throw new IOException("Path navigation out of allowed scope: "+path);
-        }
-        return assetPath;
-    }
-
-    @Override
-    public void consumeData(StorageAsset asset, Consumer<InputStream> consumerFunction, boolean readLock ) throws IOException
-    {
-        final Path path = asset.getFilePath();
-        try {
-            if (readLock) {
-                consumeDataLocked( path, consumerFunction );
-            } else
-            {
-                try ( InputStream is = Files.newInputStream( path ) )
-                {
-                    consumerFunction.accept( is );
-                }
-                catch ( IOException e )
-                {
-                    log.error("Could not read the input stream from file {}", path);
-                    throw e;
-                }
-            }
-        } catch (RuntimeException e)
-        {
-            log.error( "Runtime exception during data consume from artifact {}. Error: {}", path, e.getMessage() );
-            throw new IOException( e );
-        }
-
-    }
-
-    @Override
-    public void consumeDataFromChannel( StorageAsset asset, Consumer<ReadableByteChannel> consumerFunction, boolean readLock ) throws IOException
-    {
-        final Path path = asset.getFilePath();
-        try {
-            if (readLock) {
-                consumeDataFromChannelLocked( path, consumerFunction );
-            } else
-            {
-                try ( FileChannel is = FileChannel.open( path, StandardOpenOption.READ ) )
-                {
-                    consumerFunction.accept( is );
-                }
-                catch ( IOException e )
-                {
-                    log.error("Could not read the input stream from file {}", path);
-                    throw e;
-                }
-            }
-        } catch (RuntimeException e)
-        {
-            log.error( "Runtime exception during data consume from artifact {}. Error: {}", path, e.getMessage() );
-            throw new IOException( e );
-        }
-    }
-
-    @Override
-    public void writeData( StorageAsset asset, Consumer<OutputStream> consumerFunction, boolean writeLock ) throws IOException
-    {
-        final Path path = asset.getFilePath();
-        try {
-            if (writeLock) {
-                writeDataLocked( path, consumerFunction );
-            } else
-            {
-                try ( OutputStream is = Files.newOutputStream( path ) )
-                {
-                    consumerFunction.accept( is );
-                }
-                catch ( IOException e )
-                {
-                    log.error("Could not write the output stream to file {}", path);
-                    throw e;
-                }
-            }
-        } catch (RuntimeException e)
-        {
-            log.error( "Runtime exception during data consume from artifact {}. Error: {}", path, e.getMessage() );
-            throw new IOException( e );
-        }
-
-    }
-
-    @Override
-    public void writeDataToChannel( StorageAsset asset, Consumer<WritableByteChannel> consumerFunction, boolean writeLock ) throws IOException
-    {
-        final Path path = asset.getFilePath();
-        try {
-            if (writeLock) {
-                writeDataToChannelLocked( path, consumerFunction );
-            } else
-            {
-                try ( FileChannel os = FileChannel.open( path, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE ))
-                {
-                    consumerFunction.accept( os );
-                }
-                catch ( IOException e )
-                {
-                    log.error("Could not write the data to file {}", path);
-                    throw e;
-                }
-            }
-        } catch (RuntimeException e)
-        {
-            log.error( "Runtime exception during data consume from artifact {}. Error: {}", path, e.getMessage() );
-            throw new IOException( e );
-        }
-    }
-
-    private void consumeDataLocked( Path file, Consumer<InputStream> consumerFunction) throws IOException
-    {
-
-        final Lock lock;
-        try
-        {
-            lock = fileLockManager.readFileLock( file );
-            try ( InputStream is = Files.newInputStream( lock.getFile()))
-            {
-                consumerFunction.accept( is );
-            }
-            catch ( IOException e )
-            {
-                log.error("Could not read the input stream from file {}", file);
-                throw e;
-            } finally
-            {
-                fileLockManager.release( lock );
-            }
-        }
-        catch ( FileLockException | FileNotFoundException | FileLockTimeoutException e)
-        {
-            log.error("Locking error on file {}", file);
-            throw new IOException(e);
-        }
-    }
-
-    private void consumeDataFromChannelLocked( Path file, Consumer<ReadableByteChannel> consumerFunction) throws IOException
-    {
-
-        final Lock lock;
-        try
-        {
-            lock = fileLockManager.readFileLock( file );
-            try ( FileChannel is = FileChannel.open( lock.getFile( ), StandardOpenOption.READ ))
-            {
-                consumerFunction.accept( is );
-            }
-            catch ( IOException e )
-            {
-                log.error("Could not read the input stream from file {}", file);
-                throw e;
-            } finally
-            {
-                fileLockManager.release( lock );
-            }
-        }
-        catch ( FileLockException | FileNotFoundException | FileLockTimeoutException e)
-        {
-            log.error("Locking error on file {}", file);
-            throw new IOException(e);
-        }
-    }
-
-
-    private void writeDataLocked( Path file, Consumer<OutputStream> consumerFunction) throws IOException
-    {
-
-        final Lock lock;
-        try
-        {
-            lock = fileLockManager.writeFileLock( file );
-            try ( OutputStream is = Files.newOutputStream( lock.getFile()))
-            {
-                consumerFunction.accept( is );
-            }
-            catch ( IOException e )
-            {
-                log.error("Could not write the output stream to file {}", file);
-                throw e;
-            } finally
-            {
-                fileLockManager.release( lock );
-            }
-        }
-        catch ( FileLockException | FileNotFoundException | FileLockTimeoutException e)
-        {
-            log.error("Locking error on file {}", file);
-            throw new IOException(e);
-        }
-    }
-
-    private void writeDataToChannelLocked( Path file, Consumer<WritableByteChannel> consumerFunction) throws IOException
-    {
-
-        final Lock lock;
-        try
-        {
-            lock = fileLockManager.writeFileLock( file );
-            try ( FileChannel is = FileChannel.open( lock.getFile( ), StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE ))
-            {
-                consumerFunction.accept( is );
-            }
-            catch ( IOException e )
-            {
-                log.error("Could not write to file {}", file);
-                throw e;
-            } finally
-            {
-                fileLockManager.release( lock );
-            }
-        }
-        catch ( FileLockException | FileNotFoundException | FileLockTimeoutException e)
-        {
-            log.error("Locking error on file {}", file);
-            throw new IOException(e);
-        }
-    }
-
-    @Override
-    public URI getLocation() {
-        return basePath.toUri();
-    }
-
-    /**
-     * Updates the location and releases all locks.
-     *
-     * @param newLocation The URI to the new location
-     *
-     * @throws IOException If the directory cannot be created.
-     */
-    @Override
-    public void updateLocation(URI newLocation) throws IOException {
-        Path newPath = PathUtil.getPathFromUri(newLocation).toAbsolutePath();
-        if (!Files.exists(newPath)) {
-            Files.createDirectories(newPath);
-        }
-        basePath = newPath;
-        if (fileLockManager!=null) {
-            fileLockManager.clearLockFiles();
-        }
-    }
-
-    @Override
-    public StorageAsset getAsset( String path )
-    {
-        try {
-            return new FilesystemAsset(this, path, getAssetPath(path));
-        } catch (IOException e) {
-            throw new IllegalArgumentException("Path navigates outside of base directory "+path);
-        }
-    }
-
-    @Override
-    public StorageAsset addAsset( String path, boolean container )
-    {
-        try {
-            return new FilesystemAsset(this, path, getAssetPath(path), basePath, container);
-        } catch (IOException e) {
-            throw new IllegalArgumentException("Path navigates outside of base directory "+path);
-        }
-    }
-
-    @Override
-    public void removeAsset( StorageAsset asset ) throws IOException
-    {
-        Files.delete(asset.getFilePath());
-    }
-
-    @Override
-    public StorageAsset moveAsset( StorageAsset origin, String destination, CopyOption... copyOptions ) throws IOException
-    {
-        boolean container = origin.isContainer();
-        FilesystemAsset newAsset = new FilesystemAsset(this, destination, getAssetPath(destination), basePath, container );
-        moveAsset( origin, newAsset, copyOptions );
-        return newAsset;
-    }
-
-    @Override
-    public void moveAsset( StorageAsset origin, StorageAsset destination, CopyOption... copyOptions ) throws IOException
-    {
-        if (origin.getStorage()!=this) {
-            throw new IOException("The origin asset does not belong to this storage instance. Cannot copy between different storage instances.");
-        }
-        if (destination.getStorage()!=this) {
-            throw new IOException("The destination asset does not belong to this storage instance. Cannot copy between different storage instances.");
-        }
-        Files.move(origin.getFilePath(), destination.getFilePath(), copyOptions);
-    }
-
-    @Override
-    public StorageAsset copyAsset( StorageAsset origin, String destination, CopyOption... copyOptions ) throws IOException
-    {
-        boolean container = origin.isContainer();
-        FilesystemAsset newAsset = new FilesystemAsset(this, destination, getAssetPath(destination), basePath, container );
-        copyAsset( origin, newAsset, copyOptions );
-        return newAsset;
-    }
-
-    @Override
-    public void copyAsset( StorageAsset origin, StorageAsset destination, CopyOption... copyOptions ) throws IOException
-    {
-        if (origin.getStorage()!=this) {
-            throw new IOException("The origin asset does not belong to this storage instance. Cannot copy between different storage instances.");
-        }
-        if (destination.getStorage()!=this) {
-            throw new IOException("The destination asset does not belong to this storage instance. Cannot copy between different storage instances.");
-        }
-        Path destinationPath = destination.getFilePath();
-        boolean overwrite = false;
-        for (int i=0; i<copyOptions.length; i++) {
-            if (copyOptions[i].equals( StandardCopyOption.REPLACE_EXISTING )) {
-                overwrite=true;
-            }
-        }
-        if (Files.exists(destinationPath) && !overwrite) {
-            throw new IOException("Destination file exists already "+ destinationPath);
-        }
-        if (Files.isDirectory( origin.getFilePath() ))
-        {
-            FileUtils.copyDirectory(origin.getFilePath( ).toFile(), destinationPath.toFile() );
-        } else if (Files.isRegularFile( origin.getFilePath() )) {
-            if (!Files.exists( destinationPath )) {
-                Files.createDirectories( destinationPath );
-            }
-            Files.copy( origin.getFilePath( ), destinationPath, copyOptions );
-        }
-    }
-
-    public FileLockManager getFileLockManager() {
-        return fileLockManager;
-    }
-
-}
diff --git a/archiva-modules/archiva-base/archiva-storage-fs/src/main/java/org/apache/archiva/repository/storage/FsStorageUtil.java b/archiva-modules/archiva-base/archiva-storage-fs/src/main/java/org/apache/archiva/repository/storage/FsStorageUtil.java
deleted file mode 100644 (file)
index 50eacac..0000000
+++ /dev/null
@@ -1,199 +0,0 @@
-package org.apache.archiva.repository.storage;
-
-/*
- * 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.
- */
-
-import org.apache.archiva.common.filelock.FileLockException;
-import org.apache.archiva.common.filelock.FileLockManager;
-import org.apache.archiva.common.filelock.Lock;
-import org.apache.archiva.repository.storage.util.StorageUtil;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.nio.channels.FileChannel;
-import java.nio.channels.ReadableByteChannel;
-import java.nio.file.*;
-import java.util.HashSet;
-
-/**
- *
- * Utility class for assets. Allows to copy, move between different storage instances and
- * recursively consume the tree.
- *
- * @author Martin Stockhammer <martin_s@apache.org>
- */
-public class FsStorageUtil
-{
-    private static final Logger log = LoggerFactory.getLogger( FsStorageUtil.class);
-
-    /**
-     * Copies the source asset to the target. The assets may be from different RepositoryStorage instances.
-     * If you know that source and asset are from the same storage instance, the copy method of the storage
-     * instance may be faster.
-     *
-     * @param source The source asset
-     * @param target The target asset
-     * @param locked If true, a readlock is set on the source and a write lock is set on the target.
-     * @param copyOptions Copy options
-     * @throws IOException
-     */
-    public static final void copyAsset( final StorageAsset source,
-                                        final StorageAsset target,
-                                        boolean locked,
-                                        final CopyOption... copyOptions ) throws IOException
-    {
-        if (source.isFileBased() && target.isFileBased()) {
-            // Short cut for FS operations
-            final Path sourcePath = source.getFilePath();
-            final Path targetPath = target.getFilePath( );
-            if (locked) {
-                final FileLockManager lmSource = ((FilesystemStorage)source.getStorage()).getFileLockManager();
-                final FileLockManager lmTarget = ((FilesystemStorage)target.getStorage()).getFileLockManager();
-                Lock lockRead = null;
-                Lock lockWrite = null;
-                try {
-                    lockRead = lmSource.readFileLock(sourcePath);
-                } catch (Exception e) {
-                    log.error("Could not create read lock on {}", sourcePath);
-                    throw new IOException(e);
-                }
-                try {
-                    lockWrite = lmTarget.writeFileLock(targetPath);
-                } catch (Exception e) {
-                    log.error("Could not create write lock on {}", targetPath);
-                    throw new IOException(e);
-                }
-                try {
-                    Files.copy(sourcePath, targetPath, copyOptions);
-                } finally {
-                    if (lockRead!=null) {
-                        try {
-                            lmSource.release(lockRead);
-                        } catch (FileLockException e) {
-                            log.error("Error during lock release of read lock {}", lockRead.getFile());
-                        }
-                    }
-                    if (lockWrite!=null) {
-                        try {
-                            lmTarget.release(lockWrite);
-                        } catch (FileLockException e) {
-                            log.error("Error during lock release of write lock {}", lockWrite.getFile());
-                        }
-                    }
-                }
-            } else
-            {
-                Files.copy( sourcePath, targetPath, copyOptions );
-            }
-        } else {
-            try {
-                final RepositoryStorage sourceStorage = source.getStorage();
-                final RepositoryStorage targetStorage = target.getStorage();
-                sourceStorage.consumeDataFromChannel( source, is -> wrapWriteFunction( is, targetStorage, target, locked ), locked);
-            }  catch (IOException e) {
-                throw e;
-            }  catch (Throwable e) {
-                Throwable cause = e.getCause();
-                if (cause instanceof IOException) {
-                    throw (IOException)cause;
-                } else
-                {
-                    throw new IOException( e );
-                }
-            }
-        }
-    }
-
-    private static final void wrapWriteFunction( ReadableByteChannel is, RepositoryStorage targetStorage, StorageAsset target, boolean locked) {
-        try {
-            targetStorage.writeDataToChannel( target, os -> StorageUtil.copy(is, os), locked );
-        } catch (Exception e) {
-            throw new RuntimeException( e );
-        }
-    }
-
-
-    public static final void copyToLocalFile(StorageAsset asset, Path destination, CopyOption... copyOptions) throws IOException {
-        if (asset.isFileBased()) {
-            Files.copy(asset.getFilePath(), destination, copyOptions);
-        } else {
-            try {
-
-                HashSet<OpenOption> openOptions = new HashSet<>();
-                for (CopyOption option : copyOptions) {
-                    if (option == StandardCopyOption.REPLACE_EXISTING) {
-                        openOptions.add(StandardOpenOption.CREATE);
-                        openOptions.add(StandardOpenOption.TRUNCATE_EXISTING);
-                        openOptions.add(StandardOpenOption.WRITE);
-                    } else {
-                        openOptions.add(StandardOpenOption.WRITE);
-                        openOptions.add(StandardOpenOption.CREATE_NEW);
-                    }
-                }
-                asset.getStorage().consumeDataFromChannel(asset, channel -> {
-                    try {
-                        FileChannel.open(destination, openOptions).transferFrom(channel, 0, Long.MAX_VALUE);
-                    } catch (IOException e) {
-                        throw new RuntimeException(e);
-                    }
-                }, false);
-            } catch (Throwable e) {
-                if (e.getCause() instanceof IOException) {
-                    throw (IOException)e.getCause();
-                } else {
-                    throw new IOException(e);
-                }
-            }
-        }
-    }
-
-    public static class PathInformation {
-        final Path path ;
-        final boolean tmpFile;
-
-        PathInformation(Path path, boolean tmpFile) {
-            this.path = path;
-            this.tmpFile = tmpFile;
-        }
-
-        public Path getPath() {
-            return path;
-        }
-
-        public boolean isTmpFile() {
-            return tmpFile;
-        }
-
-    }
-
-    public static final PathInformation getAssetDataAsPath(StorageAsset asset) throws IOException {
-        if (!asset.exists()) {
-            throw new IOException("Asset does not exist");
-        }
-        if (asset.isFileBased()) {
-            return new PathInformation(asset.getFilePath(), false);
-        } else {
-            Path tmpFile = Files.createTempFile(asset.getName(), org.apache.archiva.repository.storage.util.StorageUtil.getExtension(asset));
-            copyToLocalFile(asset, tmpFile, StandardCopyOption.REPLACE_EXISTING);
-            return new PathInformation(tmpFile, true);
-        }
-    }
-
-}
diff --git a/archiva-modules/archiva-base/archiva-storage-fs/src/main/java/org/apache/archiva/repository/storage/fs/FilesystemAsset.java b/archiva-modules/archiva-base/archiva-storage-fs/src/main/java/org/apache/archiva/repository/storage/fs/FilesystemAsset.java
new file mode 100644 (file)
index 0000000..551729a
--- /dev/null
@@ -0,0 +1,524 @@
+package org.apache.archiva.repository.storage.fs;
+
+/*
+ * 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.
+ */
+
+import org.apache.archiva.repository.storage.RepositoryStorage;
+import org.apache.archiva.repository.storage.StorageAsset;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.channels.FileChannel;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Implementation of an asset that is stored on the filesystem.
+ * <p>
+ * The implementation does not check the given paths. Caller should normalize the asset path
+ * and check, if the base path is a parent of the resulting path.
+ * <p>
+ * The file must not exist for all operations.
+ *
+ * @author Martin Stockhammer <martin_s@apache.org>
+ */
+public class FilesystemAsset implements StorageAsset, Comparable {
+
+    private final static Logger log = LoggerFactory.getLogger(FilesystemAsset.class);
+
+    private final Path basePath;
+    private final Path assetPath;
+    private final String relativePath;
+
+    public static final String DEFAULT_POSIX_FILE_PERMS = "rw-rw----";
+    public static final String DEFAULT_POSIX_DIR_PERMS = "rwxrwx---";
+
+    public static final Set<PosixFilePermission> DEFAULT_POSIX_FILE_PERMISSIONS;
+    public static final Set<PosixFilePermission> DEFAULT_POSIX_DIR_PERMISSIONS;
+
+    public static final AclEntryPermission[] DEFAULT_ACL_FILE_PERMISSIONS = new AclEntryPermission[]{
+            AclEntryPermission.DELETE, AclEntryPermission.READ_ACL, AclEntryPermission.READ_ATTRIBUTES, AclEntryPermission.READ_DATA, AclEntryPermission.WRITE_ACL,
+            AclEntryPermission.WRITE_ATTRIBUTES, AclEntryPermission.WRITE_DATA, AclEntryPermission.APPEND_DATA
+    };
+
+    public static final AclEntryPermission[] DEFAULT_ACL_DIR_PERMISSIONS = new AclEntryPermission[]{
+            AclEntryPermission.ADD_FILE, AclEntryPermission.ADD_SUBDIRECTORY, AclEntryPermission.DELETE_CHILD,
+            AclEntryPermission.DELETE, AclEntryPermission.READ_ACL, AclEntryPermission.READ_ATTRIBUTES, AclEntryPermission.READ_DATA, AclEntryPermission.WRITE_ACL,
+            AclEntryPermission.WRITE_ATTRIBUTES, AclEntryPermission.WRITE_DATA, AclEntryPermission.APPEND_DATA
+    };
+
+    static {
+
+        DEFAULT_POSIX_FILE_PERMISSIONS = PosixFilePermissions.fromString(DEFAULT_POSIX_FILE_PERMS);
+        DEFAULT_POSIX_DIR_PERMISSIONS = PosixFilePermissions.fromString(DEFAULT_POSIX_DIR_PERMS);
+    }
+
+    Set<PosixFilePermission> defaultPosixFilePermissions = DEFAULT_POSIX_FILE_PERMISSIONS;
+    Set<PosixFilePermission> defaultPosixDirectoryPermissions = DEFAULT_POSIX_DIR_PERMISSIONS;
+
+    List<AclEntry> defaultFileAcls;
+    List<AclEntry> defaultDirectoryAcls;
+
+    boolean supportsAcl = false;
+    boolean supportsPosix = false;
+    final boolean setPermissionsForNew;
+    final RepositoryStorage storage;
+
+    boolean directoryHint = false;
+
+    private static final OpenOption[] REPLACE_OPTIONS = new OpenOption[]{StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE};
+    private static final OpenOption[] APPEND_OPTIONS = new OpenOption[]{StandardOpenOption.APPEND};
+
+
+    FilesystemAsset(RepositoryStorage storage, String path, Path assetPath, Path basePath) {
+        this.assetPath = assetPath;
+        this.relativePath = normalizePath(path);
+        this.setPermissionsForNew=false;
+        this.basePath = basePath;
+        this.storage = storage;
+        init();
+    }
+
+    /**
+     * Creates an asset for the given path. The given paths are not checked.
+     * The base path should be an absolute path.
+     *
+     * @param path The logical path for the asset relative to the repository.
+     * @param assetPath The asset path.
+     */
+    public FilesystemAsset(RepositoryStorage storage, String path, Path assetPath) {
+        this.assetPath = assetPath;
+        this.relativePath = normalizePath(path);
+        this.setPermissionsForNew = false;
+        this.basePath = null;
+        this.storage = storage;
+        // The base directory is always a directory
+        if ("".equals(path) || "/".equals(path)) {
+            this.directoryHint = true;
+        }
+        init();
+    }
+
+    /**
+     * Creates an asset for the given path. The given paths are not checked.
+     * The base path should be an absolute path.
+     *
+     * @param path The logical path for the asset relative to the repository
+     * @param assetPath The asset path.
+     * @param directory This is only relevant, if the represented file or directory does not exist yet and
+     *                  is a hint.
+     */
+    public FilesystemAsset(RepositoryStorage storage, String path, Path assetPath, Path basePath, boolean directory) {
+        this.assetPath = assetPath;
+        this.relativePath = normalizePath(path);
+        this.directoryHint = directory;
+        this.setPermissionsForNew = false;
+        this.basePath = basePath;
+        this.storage = storage;
+        init();
+    }
+
+    /**
+     * Creates an asset for the given path. The given paths are not checked.
+     * The base path should be an absolute path.
+     *
+     * @param path The logical path for the asset relative to the repository
+     * @param assetPath The asset path.
+     * @param directory This is only relevant, if the represented file or directory does not exist yet and
+     *                  is a hint.
+     */
+    public FilesystemAsset(RepositoryStorage storage, String path, Path assetPath, Path basePath, boolean directory, boolean setPermissionsForNew) {
+        this.assetPath = assetPath;
+        this.relativePath = normalizePath(path);
+        this.directoryHint = directory;
+        this.setPermissionsForNew = setPermissionsForNew;
+        this.basePath = basePath;
+        this.storage = storage;
+        init();
+    }
+
+    private String normalizePath(final String path) {
+        if (!path.startsWith("/")) {
+            return "/"+path;
+        } else {
+            String tmpPath = path;
+            while (tmpPath.startsWith("//")) {
+                tmpPath = tmpPath.substring(1);
+            }
+            return tmpPath;
+        }
+    }
+
+    private void init() {
+
+        if (setPermissionsForNew) {
+            try {
+                supportsAcl = Files.getFileStore(assetPath.getRoot()).supportsFileAttributeView(AclFileAttributeView.class);
+            } catch (IOException e) {
+                log.error("Could not check filesystem capabilities {}", e.getMessage());
+            }
+            try {
+                supportsPosix = Files.getFileStore(assetPath.getRoot()).supportsFileAttributeView(PosixFileAttributeView.class);
+            } catch (IOException e) {
+                log.error("Could not check filesystem capabilities {}", e.getMessage());
+            }
+
+            if (supportsAcl) {
+                AclFileAttributeView aclView = Files.getFileAttributeView(assetPath.getParent(), AclFileAttributeView.class);
+                UserPrincipal owner = null;
+                try {
+                    owner = aclView.getOwner();
+                    setDefaultFileAcls(processPermissions(owner, DEFAULT_ACL_FILE_PERMISSIONS));
+                    setDefaultDirectoryAcls(processPermissions(owner, DEFAULT_ACL_DIR_PERMISSIONS));
+
+                } catch (IOException e) {
+                    supportsAcl = false;
+                }
+
+
+            }
+        }
+    }
+
+    private List<AclEntry> processPermissions(UserPrincipal owner, AclEntryPermission[] defaultAclFilePermissions) {
+        AclEntry.Builder aclBuilder = AclEntry.newBuilder();
+        aclBuilder.setPermissions(defaultAclFilePermissions);
+        aclBuilder.setType(AclEntryType.ALLOW);
+        aclBuilder.setPrincipal(owner);
+        ArrayList<AclEntry> aclList = new ArrayList<>();
+        aclList.add(aclBuilder.build());
+        return aclList;
+    }
+
+
+    @Override
+    public RepositoryStorage getStorage( )
+    {
+        return storage;
+    }
+
+    @Override
+    public String getPath() {
+        return relativePath;
+    }
+
+    @Override
+    public String getName() {
+        return assetPath.getFileName().toString();
+    }
+
+    @Override
+    public Instant getModificationTime() {
+        try {
+            return Files.getLastModifiedTime(assetPath).toInstant();
+        } catch (IOException e) {
+            log.error("Could not read modification time of {}", assetPath);
+            return Instant.now();
+        }
+    }
+
+    /**
+     * Returns true, if the path of this asset points to a directory
+     *
+     * @return
+     */
+    @Override
+    public boolean isContainer() {
+        if (Files.exists(assetPath)) {
+            return Files.isDirectory(assetPath);
+        } else {
+            return directoryHint;
+        }
+    }
+
+    @Override
+    public boolean isLeaf( )
+    {
+        if (Files.exists( assetPath )) {
+            return Files.isRegularFile( assetPath );
+        } else {
+            return !directoryHint;
+        }
+    }
+
+    /**
+     * Returns the list of directory entries, if this asset represents a directory.
+     * Otherwise a empty list will be returned.
+     *
+     * @return The list of entries in the directory, if it exists.
+     */
+    @Override
+    public List<StorageAsset> list() {
+        try {
+            return Files.list(assetPath).map(p -> new FilesystemAsset(storage, relativePath + "/" + p.getFileName().toString(), assetPath.resolve(p)))
+                    .collect(Collectors.toList());
+        } catch (IOException e) {
+            return Collections.EMPTY_LIST;
+        }
+    }
+
+    /**
+     * Returns the size of the represented file. If it cannot be determined, -1 is returned.
+     *
+     * @return
+     */
+    @Override
+    public long getSize() {
+        try {
+            return Files.size(assetPath);
+        } catch (IOException e) {
+            return -1;
+        }
+    }
+
+    /**
+     * Returns a input stream to the underlying file, if it exists. The caller has to make sure, that
+     * the stream is closed after it was used.
+     *
+     * @return
+     * @throws IOException
+     */
+    @Override
+    public InputStream getReadStream() throws IOException {
+        if (isContainer()) {
+            throw new IOException("Can not create input stream for container");
+        }
+        return Files.newInputStream(assetPath);
+    }
+
+    @Override
+    public ReadableByteChannel getReadChannel( ) throws IOException
+    {
+        return FileChannel.open( assetPath, StandardOpenOption.READ );
+    }
+
+    private OpenOption[] getOpenOptions(boolean replace) {
+        return replace ? REPLACE_OPTIONS : APPEND_OPTIONS;
+    }
+
+    @Override
+    public OutputStream getWriteStream( boolean replace) throws IOException {
+        OpenOption[] options = getOpenOptions( replace );
+        if (!Files.exists( assetPath )) {
+            create();
+        }
+        return Files.newOutputStream(assetPath, options);
+    }
+
+    @Override
+    public WritableByteChannel getWriteChannel( boolean replace ) throws IOException
+    {
+        OpenOption[] options = getOpenOptions( replace );
+        return FileChannel.open( assetPath, options );
+    }
+
+    @Override
+    public boolean replaceDataFromFile( Path newData) throws IOException {
+        final boolean createNew = !Files.exists(assetPath);
+        Path backup = null;
+        if (!createNew) {
+            backup = findBackupFile(assetPath);
+        }
+        try {
+            if (!createNew) {
+                Files.move(assetPath, backup);
+            }
+            Files.move(newData, assetPath, StandardCopyOption.REPLACE_EXISTING);
+            applyDefaultPermissions(assetPath);
+            return true;
+        } catch (IOException e) {
+            log.error("Could not overwrite file {}", assetPath);
+            // Revert if possible
+            if (backup != null && Files.exists(backup)) {
+                Files.move(backup, assetPath, StandardCopyOption.REPLACE_EXISTING);
+            }
+            throw e;
+        } finally {
+            if (backup != null) {
+                try {
+                    Files.deleteIfExists(backup);
+                } catch (IOException e) {
+                    log.error("Could not delete backup file {}", backup);
+                }
+            }
+        }
+
+    }
+
+    private void applyDefaultPermissions(Path filePath) {
+        try {
+            if (supportsPosix) {
+                Set<PosixFilePermission> perms;
+                if (Files.isDirectory(filePath)) {
+                    perms = defaultPosixFilePermissions;
+                } else {
+                    perms = defaultPosixDirectoryPermissions;
+                }
+                Files.setPosixFilePermissions(filePath, perms);
+            } else if (supportsAcl) {
+                List<AclEntry> perms;
+                if (Files.isDirectory(filePath)) {
+                    perms = getDefaultDirectoryAcls();
+                } else {
+                    perms = getDefaultFileAcls();
+                }
+                AclFileAttributeView aclAttr = Files.getFileAttributeView(filePath, AclFileAttributeView.class);
+                aclAttr.setAcl(perms);
+            }
+        } catch (IOException e) {
+            log.error("Could not set permissions for {}: {}", filePath, e.getMessage());
+        }
+    }
+
+    private Path findBackupFile(Path file) {
+        String ext = ".bak";
+        Path backupPath = file.getParent().resolve(file.getFileName().toString() + ext);
+        int idx = 0;
+        while (Files.exists(backupPath)) {
+            backupPath = file.getParent().resolve(file.getFileName().toString() + ext + idx++);
+        }
+        return backupPath;
+    }
+
+    @Override
+    public boolean exists() {
+        return Files.exists(assetPath);
+    }
+
+    @Override
+    public Path getFilePath() throws UnsupportedOperationException {
+        return assetPath;
+    }
+
+    @Override
+    public boolean isFileBased( )
+    {
+        return true;
+    }
+
+    @Override
+    public boolean hasParent( )
+    {
+        if (basePath!=null && assetPath.equals(basePath)) {
+                return false;
+        }
+        return assetPath.getParent()!=null;
+    }
+
+    @Override
+    public StorageAsset getParent( )
+    {
+        Path parentPath;
+        if (basePath!=null && assetPath.equals( basePath )) {
+            parentPath=null;
+        } else
+        {
+            parentPath = assetPath.getParent( );
+        }
+        String relativeParent = StringUtils.substringBeforeLast( relativePath,"/");
+        if (parentPath!=null) {
+            return new FilesystemAsset(storage, relativeParent, parentPath, basePath, true, setPermissionsForNew );
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public StorageAsset resolve(String toPath) {
+        return storage.getAsset(this.getPath()+"/"+toPath);
+    }
+
+
+    public void setDefaultFileAcls(List<AclEntry> acl) {
+        defaultFileAcls = acl;
+    }
+
+    public List<AclEntry> getDefaultFileAcls() {
+        return defaultFileAcls;
+    }
+
+    public void setDefaultPosixFilePermissions(Set<PosixFilePermission> perms) {
+        defaultPosixFilePermissions = perms;
+    }
+
+    public Set<PosixFilePermission> getDefaultPosixFilePermissions() {
+        return defaultPosixFilePermissions;
+    }
+
+    public void setDefaultDirectoryAcls(List<AclEntry> acl) {
+        defaultDirectoryAcls = acl;
+    }
+
+    public List<AclEntry> getDefaultDirectoryAcls() {
+        return defaultDirectoryAcls;
+    }
+
+    public void setDefaultPosixDirectoryPermissions(Set<PosixFilePermission> perms) {
+        defaultPosixDirectoryPermissions = perms;
+    }
+
+    public Set<PosixFilePermission> getDefaultPosixDirectoryPermissions() {
+        return defaultPosixDirectoryPermissions;
+    }
+
+    @Override
+    public void create() throws IOException {
+        if (!Files.exists(assetPath)) {
+            if (directoryHint) {
+                Files.createDirectories(assetPath);
+            } else {
+                if (!Files.exists( assetPath.getParent() )) {
+                    Files.createDirectories( assetPath.getParent( ) );
+                }
+                Files.createFile(assetPath);
+            }
+            if (setPermissionsForNew) {
+                applyDefaultPermissions(assetPath);
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+        return relativePath+":"+assetPath;
+    }
+
+    @Override
+    public int compareTo(Object o) {
+        if (o instanceof FilesystemAsset) {
+            if (this.getPath()!=null) {
+                return this.getPath().compareTo(((FilesystemAsset) o).getPath());
+            } else {
+                return 0;
+            }
+        }
+        return 0;
+    }
+}
diff --git a/archiva-modules/archiva-base/archiva-storage-fs/src/main/java/org/apache/archiva/repository/storage/fs/FilesystemStorage.java b/archiva-modules/archiva-base/archiva-storage-fs/src/main/java/org/apache/archiva/repository/storage/fs/FilesystemStorage.java
new file mode 100644 (file)
index 0000000..0ae56e7
--- /dev/null
@@ -0,0 +1,410 @@
+package org.apache.archiva.repository.storage.fs;
+
+/*
+ * 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.
+ */
+
+import org.apache.archiva.common.filelock.FileLockException;
+import org.apache.archiva.common.filelock.FileLockManager;
+import org.apache.archiva.common.filelock.FileLockTimeoutException;
+import org.apache.archiva.common.filelock.Lock;
+import org.apache.archiva.common.utils.PathUtil;
+import org.apache.archiva.repository.storage.RepositoryStorage;
+import org.apache.archiva.repository.storage.StorageAsset;
+import org.apache.commons.io.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.nio.channels.FileChannel;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+import java.nio.file.*;
+import java.util.function.Consumer;
+
+/**
+ * Implementation of <code>{@link RepositoryStorage}</code> where data is stored in the filesystem.
+ *
+ * All files are relative to a given base path. Path values are separated by '/', '..' is allowed to navigate
+ * to a parent directory, but navigation out of the base path will lead to a exception.
+ */
+public class FilesystemStorage implements RepositoryStorage {
+
+    private static final Logger log = LoggerFactory.getLogger(FilesystemStorage.class);
+
+    private Path basePath;
+    private final FileLockManager fileLockManager;
+
+    public FilesystemStorage(Path basePath, FileLockManager fileLockManager) throws IOException {
+        if (!Files.exists(basePath)) {
+            Files.createDirectories(basePath);
+        }
+        this.basePath = basePath.normalize().toRealPath();
+        this.fileLockManager = fileLockManager;
+    }
+
+    private Path normalize(final String path) {
+        String nPath = path;
+        while (nPath.startsWith("/")) {
+            nPath = nPath.substring(1);
+        }
+        return Paths.get(nPath);
+    }
+
+    private Path getAssetPath(String path) throws IOException {
+        Path assetPath = basePath.resolve(normalize(path)).normalize();
+        if (!assetPath.startsWith(basePath))
+        {
+            throw new IOException("Path navigation out of allowed scope: "+path);
+        }
+        return assetPath;
+    }
+
+    @Override
+    public void consumeData( StorageAsset asset, Consumer<InputStream> consumerFunction, boolean readLock ) throws IOException
+    {
+        final Path path = asset.getFilePath();
+        try {
+            if (readLock) {
+                consumeDataLocked( path, consumerFunction );
+            } else
+            {
+                try ( InputStream is = Files.newInputStream( path ) )
+                {
+                    consumerFunction.accept( is );
+                }
+                catch ( IOException e )
+                {
+                    log.error("Could not read the input stream from file {}", path);
+                    throw e;
+                }
+            }
+        } catch (RuntimeException e)
+        {
+            log.error( "Runtime exception during data consume from artifact {}. Error: {}", path, e.getMessage() );
+            throw new IOException( e );
+        }
+
+    }
+
+    @Override
+    public void consumeDataFromChannel( StorageAsset asset, Consumer<ReadableByteChannel> consumerFunction, boolean readLock ) throws IOException
+    {
+        final Path path = asset.getFilePath();
+        try {
+            if (readLock) {
+                consumeDataFromChannelLocked( path, consumerFunction );
+            } else
+            {
+                try ( FileChannel is = FileChannel.open( path, StandardOpenOption.READ ) )
+                {
+                    consumerFunction.accept( is );
+                }
+                catch ( IOException e )
+                {
+                    log.error("Could not read the input stream from file {}", path);
+                    throw e;
+                }
+            }
+        } catch (RuntimeException e)
+        {
+            log.error( "Runtime exception during data consume from artifact {}. Error: {}", path, e.getMessage() );
+            throw new IOException( e );
+        }
+    }
+
+    @Override
+    public void writeData( StorageAsset asset, Consumer<OutputStream> consumerFunction, boolean writeLock ) throws IOException
+    {
+        final Path path = asset.getFilePath();
+        try {
+            if (writeLock) {
+                writeDataLocked( path, consumerFunction );
+            } else
+            {
+                try ( OutputStream is = Files.newOutputStream( path ) )
+                {
+                    consumerFunction.accept( is );
+                }
+                catch ( IOException e )
+                {
+                    log.error("Could not write the output stream to file {}", path);
+                    throw e;
+                }
+            }
+        } catch (RuntimeException e)
+        {
+            log.error( "Runtime exception during data consume from artifact {}. Error: {}", path, e.getMessage() );
+            throw new IOException( e );
+        }
+
+    }
+
+    @Override
+    public void writeDataToChannel( StorageAsset asset, Consumer<WritableByteChannel> consumerFunction, boolean writeLock ) throws IOException
+    {
+        final Path path = asset.getFilePath();
+        try {
+            if (writeLock) {
+                writeDataToChannelLocked( path, consumerFunction );
+            } else
+            {
+                try ( FileChannel os = FileChannel.open( path, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE ))
+                {
+                    consumerFunction.accept( os );
+                }
+                catch ( IOException e )
+                {
+                    log.error("Could not write the data to file {}", path);
+                    throw e;
+                }
+            }
+        } catch (RuntimeException e)
+        {
+            log.error( "Runtime exception during data consume from artifact {}. Error: {}", path, e.getMessage() );
+            throw new IOException( e );
+        }
+    }
+
+    private void consumeDataLocked( Path file, Consumer<InputStream> consumerFunction) throws IOException
+    {
+
+        final Lock lock;
+        try
+        {
+            lock = fileLockManager.readFileLock( file );
+            try ( InputStream is = Files.newInputStream( lock.getFile()))
+            {
+                consumerFunction.accept( is );
+            }
+            catch ( IOException e )
+            {
+                log.error("Could not read the input stream from file {}", file);
+                throw e;
+            } finally
+            {
+                fileLockManager.release( lock );
+            }
+        }
+        catch ( FileLockException | FileNotFoundException | FileLockTimeoutException e)
+        {
+            log.error("Locking error on file {}", file);
+            throw new IOException(e);
+        }
+    }
+
+    private void consumeDataFromChannelLocked( Path file, Consumer<ReadableByteChannel> consumerFunction) throws IOException
+    {
+
+        final Lock lock;
+        try
+        {
+            lock = fileLockManager.readFileLock( file );
+            try ( FileChannel is = FileChannel.open( lock.getFile( ), StandardOpenOption.READ ))
+            {
+                consumerFunction.accept( is );
+            }
+            catch ( IOException e )
+            {
+                log.error("Could not read the input stream from file {}", file);
+                throw e;
+            } finally
+            {
+                fileLockManager.release( lock );
+            }
+        }
+        catch ( FileLockException | FileNotFoundException | FileLockTimeoutException e)
+        {
+            log.error("Locking error on file {}", file);
+            throw new IOException(e);
+        }
+    }
+
+
+    private void writeDataLocked( Path file, Consumer<OutputStream> consumerFunction) throws IOException
+    {
+
+        final Lock lock;
+        try
+        {
+            lock = fileLockManager.writeFileLock( file );
+            try ( OutputStream is = Files.newOutputStream( lock.getFile()))
+            {
+                consumerFunction.accept( is );
+            }
+            catch ( IOException e )
+            {
+                log.error("Could not write the output stream to file {}", file);
+                throw e;
+            } finally
+            {
+                fileLockManager.release( lock );
+            }
+        }
+        catch ( FileLockException | FileNotFoundException | FileLockTimeoutException e)
+        {
+            log.error("Locking error on file {}", file);
+            throw new IOException(e);
+        }
+    }
+
+    private void writeDataToChannelLocked( Path file, Consumer<WritableByteChannel> consumerFunction) throws IOException
+    {
+
+        final Lock lock;
+        try
+        {
+            lock = fileLockManager.writeFileLock( file );
+            try ( FileChannel is = FileChannel.open( lock.getFile( ), StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE ))
+            {
+                consumerFunction.accept( is );
+            }
+            catch ( IOException e )
+            {
+                log.error("Could not write to file {}", file);
+                throw e;
+            } finally
+            {
+                fileLockManager.release( lock );
+            }
+        }
+        catch ( FileLockException | FileNotFoundException | FileLockTimeoutException e)
+        {
+            log.error("Locking error on file {}", file);
+            throw new IOException(e);
+        }
+    }
+
+    @Override
+    public URI getLocation() {
+        return basePath.toUri();
+    }
+
+    /**
+     * Updates the location and releases all locks.
+     *
+     * @param newLocation The URI to the new location
+     *
+     * @throws IOException If the directory cannot be created.
+     */
+    @Override
+    public void updateLocation(URI newLocation) throws IOException {
+        Path newPath = PathUtil.getPathFromUri(newLocation).toAbsolutePath();
+        if (!Files.exists(newPath)) {
+            Files.createDirectories(newPath);
+        }
+        basePath = newPath;
+        if (fileLockManager!=null) {
+            fileLockManager.clearLockFiles();
+        }
+    }
+
+    @Override
+    public StorageAsset getAsset( String path )
+    {
+        try {
+            return new FilesystemAsset(this, path, getAssetPath(path));
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Path navigates outside of base directory "+path);
+        }
+    }
+
+    @Override
+    public StorageAsset addAsset( String path, boolean container )
+    {
+        try {
+            return new FilesystemAsset(this, path, getAssetPath(path), basePath, container);
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Path navigates outside of base directory "+path);
+        }
+    }
+
+    @Override
+    public void removeAsset( StorageAsset asset ) throws IOException
+    {
+        Files.delete(asset.getFilePath());
+    }
+
+    @Override
+    public StorageAsset moveAsset( StorageAsset origin, String destination, CopyOption... copyOptions ) throws IOException
+    {
+        boolean container = origin.isContainer();
+        FilesystemAsset newAsset = new FilesystemAsset(this, destination, getAssetPath(destination), basePath, container );
+        moveAsset( origin, newAsset, copyOptions );
+        return newAsset;
+    }
+
+    @Override
+    public void moveAsset( StorageAsset origin, StorageAsset destination, CopyOption... copyOptions ) throws IOException
+    {
+        if (origin.getStorage()!=this) {
+            throw new IOException("The origin asset does not belong to this storage instance. Cannot copy between different storage instances.");
+        }
+        if (destination.getStorage()!=this) {
+            throw new IOException("The destination asset does not belong to this storage instance. Cannot copy between different storage instances.");
+        }
+        Files.move(origin.getFilePath(), destination.getFilePath(), copyOptions);
+    }
+
+    @Override
+    public StorageAsset copyAsset( StorageAsset origin, String destination, CopyOption... copyOptions ) throws IOException
+    {
+        boolean container = origin.isContainer();
+        FilesystemAsset newAsset = new FilesystemAsset(this, destination, getAssetPath(destination), basePath, container );
+        copyAsset( origin, newAsset, copyOptions );
+        return newAsset;
+    }
+
+    @Override
+    public void copyAsset( StorageAsset origin, StorageAsset destination, CopyOption... copyOptions ) throws IOException
+    {
+        if (origin.getStorage()!=this) {
+            throw new IOException("The origin asset does not belong to this storage instance. Cannot copy between different storage instances.");
+        }
+        if (destination.getStorage()!=this) {
+            throw new IOException("The destination asset does not belong to this storage instance. Cannot copy between different storage instances.");
+        }
+        Path destinationPath = destination.getFilePath();
+        boolean overwrite = false;
+        for (int i=0; i<copyOptions.length; i++) {
+            if (copyOptions[i].equals( StandardCopyOption.REPLACE_EXISTING )) {
+                overwrite=true;
+            }
+        }
+        if (Files.exists(destinationPath) && !overwrite) {
+            throw new IOException("Destination file exists already "+ destinationPath);
+        }
+        if (Files.isDirectory( origin.getFilePath() ))
+        {
+            FileUtils.copyDirectory(origin.getFilePath( ).toFile(), destinationPath.toFile() );
+        } else if (Files.isRegularFile( origin.getFilePath() )) {
+            if (!Files.exists( destinationPath )) {
+                Files.createDirectories( destinationPath );
+            }
+            Files.copy( origin.getFilePath( ), destinationPath, copyOptions );
+        }
+    }
+
+    public FileLockManager getFileLockManager() {
+        return fileLockManager;
+    }
+
+}
diff --git a/archiva-modules/archiva-base/archiva-storage-fs/src/main/java/org/apache/archiva/repository/storage/fs/FsStorageUtil.java b/archiva-modules/archiva-base/archiva-storage-fs/src/main/java/org/apache/archiva/repository/storage/fs/FsStorageUtil.java
new file mode 100644 (file)
index 0000000..842d22a
--- /dev/null
@@ -0,0 +1,200 @@
+package org.apache.archiva.repository.storage.fs;
+
+/*
+ * 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.
+ */
+
+import org.apache.archiva.common.filelock.FileLockException;
+import org.apache.archiva.common.filelock.FileLockManager;
+import org.apache.archiva.common.filelock.Lock;
+import org.apache.archiva.repository.storage.RepositoryStorage;
+import org.apache.archiva.repository.storage.StorageAsset;
+import org.apache.archiva.repository.storage.util.StorageUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.file.*;
+import java.util.HashSet;
+
+/**
+ *
+ * Utility class for assets. Allows to copy, move between different storage instances and
+ * recursively consume the tree.
+ *
+ * @author Martin Stockhammer <martin_s@apache.org>
+ */
+public class FsStorageUtil
+{
+    private static final Logger log = LoggerFactory.getLogger( FsStorageUtil.class);
+
+    /**
+     * Copies the source asset to the target. The assets may be from different RepositoryStorage instances.
+     * If you know that source and asset are from the same storage instance, the copy method of the storage
+     * instance may be faster.
+     *
+     * @param source The source asset
+     * @param target The target asset
+     * @param locked If true, a readlock is set on the source and a write lock is set on the target.
+     * @param copyOptions Copy options
+     * @throws IOException
+     */
+    public static final void copyAsset( final StorageAsset source,
+                                        final StorageAsset target,
+                                        boolean locked,
+                                        final CopyOption... copyOptions ) throws IOException
+    {
+        if (source.isFileBased() && target.isFileBased()) {
+            // Short cut for FS operations
+            final Path sourcePath = source.getFilePath();
+            final Path targetPath = target.getFilePath( );
+            if (locked) {
+                final FileLockManager lmSource = ((FilesystemStorage)source.getStorage()).getFileLockManager();
+                final FileLockManager lmTarget = ((FilesystemStorage)target.getStorage()).getFileLockManager();
+                Lock lockRead = null;
+                Lock lockWrite = null;
+                try {
+                    lockRead = lmSource.readFileLock(sourcePath);
+                } catch (Exception e) {
+                    log.error("Could not create read lock on {}", sourcePath);
+                    throw new IOException(e);
+                }
+                try {
+                    lockWrite = lmTarget.writeFileLock(targetPath);
+                } catch (Exception e) {
+                    log.error("Could not create write lock on {}", targetPath);
+                    throw new IOException(e);
+                }
+                try {
+                    Files.copy(sourcePath, targetPath, copyOptions);
+                } finally {
+                    if (lockRead!=null) {
+                        try {
+                            lmSource.release(lockRead);
+                        } catch (FileLockException e) {
+                            log.error("Error during lock release of read lock {}", lockRead.getFile());
+                        }
+                    }
+                    if (lockWrite!=null) {
+                        try {
+                            lmTarget.release(lockWrite);
+                        } catch (FileLockException e) {
+                            log.error("Error during lock release of write lock {}", lockWrite.getFile());
+                        }
+                    }
+                }
+            } else
+            {
+                Files.copy( sourcePath, targetPath, copyOptions );
+            }
+        } else {
+            try {
+                final RepositoryStorage sourceStorage = source.getStorage();
+                final RepositoryStorage targetStorage = target.getStorage();
+                sourceStorage.consumeDataFromChannel( source, is -> wrapWriteFunction( is, targetStorage, target, locked ), locked);
+            }  catch (IOException e) {
+                throw e;
+            }  catch (Throwable e) {
+                Throwable cause = e.getCause();
+                if (cause instanceof IOException) {
+                    throw (IOException)cause;
+                } else
+                {
+                    throw new IOException( e );
+                }
+            }
+        }
+    }
+
+    private static final void wrapWriteFunction( ReadableByteChannel is, RepositoryStorage targetStorage, StorageAsset target, boolean locked) {
+        try {
+            targetStorage.writeDataToChannel( target, os -> StorageUtil.copy(is, os), locked );
+        } catch (Exception e) {
+            throw new RuntimeException( e );
+        }
+    }
+
+
+    public static final void copyToLocalFile(StorageAsset asset, Path destination, CopyOption... copyOptions) throws IOException {
+        if (asset.isFileBased()) {
+            Files.copy(asset.getFilePath(), destination, copyOptions);
+        } else {
+            try {
+
+                HashSet<OpenOption> openOptions = new HashSet<>();
+                for (CopyOption option : copyOptions) {
+                    if (option == StandardCopyOption.REPLACE_EXISTING) {
+                        openOptions.add(StandardOpenOption.CREATE);
+                        openOptions.add(StandardOpenOption.TRUNCATE_EXISTING);
+                        openOptions.add(StandardOpenOption.WRITE);
+                    } else {
+                        openOptions.add(StandardOpenOption.WRITE);
+                        openOptions.add(StandardOpenOption.CREATE_NEW);
+                    }
+                }
+                asset.getStorage().consumeDataFromChannel(asset, channel -> {
+                    try {
+                        FileChannel.open(destination, openOptions).transferFrom(channel, 0, Long.MAX_VALUE);
+                    } catch (IOException e) {
+                        throw new RuntimeException(e);
+                    }
+                }, false);
+            } catch (Throwable e) {
+                if (e.getCause() instanceof IOException) {
+                    throw (IOException)e.getCause();
+                } else {
+                    throw new IOException(e);
+                }
+            }
+        }
+    }
+
+    public static class PathInformation {
+        final Path path ;
+        final boolean tmpFile;
+
+        PathInformation(Path path, boolean tmpFile) {
+            this.path = path;
+            this.tmpFile = tmpFile;
+        }
+
+        public Path getPath() {
+            return path;
+        }
+
+        public boolean isTmpFile() {
+            return tmpFile;
+        }
+
+    }
+
+    public static final PathInformation getAssetDataAsPath(StorageAsset asset) throws IOException {
+        if (!asset.exists()) {
+            throw new IOException("Asset does not exist");
+        }
+        if (asset.isFileBased()) {
+            return new PathInformation(asset.getFilePath(), false);
+        } else {
+            Path tmpFile = Files.createTempFile(asset.getName(), org.apache.archiva.repository.storage.util.StorageUtil.getExtension(asset));
+            copyToLocalFile(asset, tmpFile, StandardCopyOption.REPLACE_EXISTING);
+            return new PathInformation(tmpFile, true);
+        }
+    }
+
+}
diff --git a/archiva-modules/archiva-base/archiva-storage-fs/src/test/java/org/apache/archiva/repository/storage/FilesystemAssetTest.java b/archiva-modules/archiva-base/archiva-storage-fs/src/test/java/org/apache/archiva/repository/storage/FilesystemAssetTest.java
deleted file mode 100644 (file)
index 566c0cb..0000000
+++ /dev/null
@@ -1,203 +0,0 @@
-package org.apache.archiva.repository.storage;
-
-/*
- * 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.
- */
-
-import org.apache.archiva.common.filelock.DefaultFileLockManager;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.IOUtils;
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.time.Instant;
-
-public class FilesystemAssetTest {
-
-    Path assetPathFile;
-    Path assetPathDir;
-    FilesystemStorage filesystemStorage;
-
-    @Before
-    public void init() throws IOException {
-        assetPathDir = Files.createTempDirectory("assetDir");
-        assetPathFile = Files.createTempFile(assetPathDir,"assetFile", "dat");
-        filesystemStorage = new FilesystemStorage(assetPathDir, new DefaultFileLockManager());
-    }
-
-    @After
-    public void cleanup() {
-
-        try {
-            Files.deleteIfExists(assetPathFile);
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
-        FileUtils.deleteQuietly(assetPathDir.toFile());
-    }
-
-
-    @Test
-    public void getPath() {
-        FilesystemAsset asset = new FilesystemAsset(filesystemStorage, assetPathFile.getFileName().toString(), assetPathFile);
-        Assert.assertEquals("/"+assetPathFile.getFileName().toString(), asset.getPath());
-    }
-
-    @Test
-    public void getName() {
-        FilesystemAsset asset = new FilesystemAsset(filesystemStorage, "/"+assetPathFile.getFileName().toString(), assetPathFile);
-        Assert.assertEquals(assetPathFile.getFileName().toString(), asset.getName());
-
-    }
-
-    @Test
-    public void getModificationTime() throws IOException {
-        Instant modTime = Files.getLastModifiedTime(assetPathFile).toInstant();
-        FilesystemAsset asset = new FilesystemAsset(filesystemStorage, "/test123", assetPathFile);
-        Assert.assertTrue(modTime.equals(asset.getModificationTime()));
-    }
-
-    @Test
-    public void isContainer() {
-        FilesystemAsset asset = new FilesystemAsset(filesystemStorage, "/test1323", assetPathFile);
-        Assert.assertFalse(asset.isContainer());
-        FilesystemAsset asset2 = new FilesystemAsset(filesystemStorage, "/test1234", assetPathDir);
-        Assert.assertTrue(asset2.isContainer());
-    }
-
-    @Test
-    public void list() throws IOException {
-        FilesystemAsset asset = new FilesystemAsset(filesystemStorage, "/test1234", assetPathFile);
-        Assert.assertEquals(0, asset.list().size());
-
-        FilesystemAsset asset2 = new FilesystemAsset(filesystemStorage, "/test1235", assetPathDir);
-        Assert.assertEquals(1, asset2.list().size());
-        Path f1 = Files.createTempFile(assetPathDir, "testfile", "dat");
-        Path f2 = Files.createTempFile(assetPathDir, "testfile", "dat");
-        Path d1 = Files.createTempDirectory(assetPathDir, "testdir");
-        Assert.assertEquals(4, asset2.list().size());
-        Assert.assertTrue(asset2.list().stream().anyMatch(p -> p.getName().equals(f1.getFileName().toString())));
-        Assert.assertTrue(asset2.list().stream().anyMatch(p -> p.getName().equals(f2.getFileName().toString())));
-        Assert.assertTrue(asset2.list().stream().anyMatch(p -> p.getName().equals(d1.getFileName().toString())));
-        Files.deleteIfExists(f1);
-        Files.deleteIfExists(f2);
-        Files.deleteIfExists(d1);
-
-
-    }
-
-    @Test
-    public void getSize() throws IOException {
-        FilesystemAsset asset = new FilesystemAsset(filesystemStorage, "/test1234", assetPathFile);
-        Assert.assertEquals(0, asset.getSize());
-
-        Files.write(assetPathFile, new String("abcdef").getBytes("ASCII"));
-        Assert.assertTrue(asset.getSize()>=6);
-
-
-    }
-
-    @Test
-    public void getData() throws IOException {
-        FilesystemAsset asset = new FilesystemAsset(filesystemStorage, "/test1234", assetPathFile);
-        Files.write(assetPathFile, "abcdef".getBytes("ASCII"));
-        try(InputStream is = asset.getReadStream()) {
-            Assert.assertEquals("abcdef", IOUtils.toString(is, "ASCII"));
-        }
-
-    }
-
-    @Test
-    public void getDataExceptionOnDir() throws IOException {
-        FilesystemAsset asset = new FilesystemAsset(filesystemStorage, "/test1234", assetPathDir);
-        Files.write(assetPathFile, "abcdef".getBytes("ASCII"));
-        try {
-            InputStream is = asset.getReadStream();
-            Assert.assertFalse("Exception expected for data on dir", true);
-        } catch (IOException e) {
-            // fine
-        }
-
-    }
-
-    @Test
-    public void writeData() throws IOException {
-        FilesystemAsset asset = new FilesystemAsset(filesystemStorage, "/test1234", assetPathFile);
-        Files.write(assetPathFile, "abcdef".getBytes("ASCII"));
-        try(OutputStream os  = asset.getWriteStream(true)) {
-            IOUtils.write("test12345", os, "ASCII");
-        }
-        Assert.assertEquals("test12345", IOUtils.toString(assetPathFile.toUri().toURL(), "ASCII"));
-    }
-
-    @Test
-    public void writeDataAppend() throws IOException {
-        FilesystemAsset asset = new FilesystemAsset(filesystemStorage, "/test1234", assetPathFile);
-        Files.write(assetPathFile, "abcdef".getBytes("ASCII"));
-        try(OutputStream os  = asset.getWriteStream(false)) {
-            IOUtils.write("test12345", os, "ASCII");
-        }
-        Assert.assertEquals("abcdeftest12345", IOUtils.toString(assetPathFile.toUri().toURL(), "ASCII"));
-    }
-
-    @Test
-    public void writeDataExceptionOnDir() throws IOException {
-        FilesystemAsset asset = new FilesystemAsset(filesystemStorage, "/test1234", assetPathDir);
-        try {
-
-            OutputStream os = asset.getWriteStream(true);
-            Assert.assertTrue("Writing to a directory should throw a IOException", false);
-        } catch (IOException e) {
-            // Fine
-        }
-    }
-
-    @Test
-    public void storeDataFile() throws IOException {
-        FilesystemAsset asset = new FilesystemAsset(filesystemStorage, "/test1234", assetPathFile);
-        Path dataFile = Files.createTempFile("testdata", "dat");
-        try(OutputStream os = Files.newOutputStream(dataFile)) {
-            IOUtils.write("testkdkdkd", os, "ASCII");
-        }
-        asset.replaceDataFromFile(dataFile);
-        Assert.assertEquals("testkdkdkd", IOUtils.toString(assetPathFile.toUri().toURL(), "ASCII"));
-    }
-
-    @Test
-    public void exists() {
-        FilesystemAsset asset = new FilesystemAsset(filesystemStorage, "/test1234", assetPathFile);
-        Assert.assertTrue(asset.exists());
-        FilesystemAsset asset2 = new FilesystemAsset(filesystemStorage, "/test1234", Paths.get("abcdefgkdkdk"));
-        Assert.assertFalse(asset2.exists());
-
-    }
-
-    @Test
-    public void getFilePath() {
-        FilesystemAsset asset = new FilesystemAsset(filesystemStorage, "/test1234", assetPathFile);
-        Assert.assertEquals(assetPathFile, asset.getFilePath());
-    }
-}
\ No newline at end of file
diff --git a/archiva-modules/archiva-base/archiva-storage-fs/src/test/java/org/apache/archiva/repository/storage/FilesystemStorageTest.java b/archiva-modules/archiva-base/archiva-storage-fs/src/test/java/org/apache/archiva/repository/storage/FilesystemStorageTest.java
deleted file mode 100644 (file)
index ebbc6a5..0000000
+++ /dev/null
@@ -1,200 +0,0 @@
-package org.apache.archiva.repository.storage;
-
-/*
- * 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.
- */
-
-import org.apache.archiva.common.filelock.DefaultFileLockManager;
-import org.apache.archiva.repository.storage.FilesystemAsset;
-import org.apache.archiva.repository.storage.FilesystemStorage;
-import org.apache.archiva.repository.storage.StorageAsset;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.IOUtils;
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.StandardCopyOption;
-
-import static org.junit.Assert.*;
-
-public class FilesystemStorageTest {
-
-    private FilesystemStorage fsStorage;
-    private FilesystemAsset file1Asset;
-    private FilesystemAsset dir1Asset;
-    private Path baseDir;
-    private Path file1;
-    private Path dir1;
-
-    @Before
-    public void init() throws IOException {
-        baseDir = Files.createTempDirectory("FsStorageTest");
-        DefaultFileLockManager fl = new DefaultFileLockManager();
-        fsStorage = new FilesystemStorage(baseDir,fl);
-        Files.createDirectories(baseDir.resolve("dir1"));
-        Files.createDirectories(baseDir.resolve("dir2"));
-        file1 = Files.createFile(baseDir.resolve("dir1/testfile1.dat"));
-        dir1 = Files.createDirectories(baseDir.resolve("dir1/testdir"));
-        file1Asset = new FilesystemAsset(fsStorage, "/dir1/testfile1.dat", file1);
-        dir1Asset = new FilesystemAsset(fsStorage, "/dir1/testdir", dir1);
-    }
-
-    private class StringResult {
-        public String getData() {
-            return data;
-        }
-
-        public void setData(String data) {
-            this.data = data;
-        }
-
-        String data;
-    }
-
-
-    @After
-    public void cleanup() {
-        FileUtils.deleteQuietly(file1.toFile());
-        FileUtils.deleteQuietly(dir1.toFile());
-        FileUtils.deleteQuietly(baseDir.resolve("dir1").toFile());
-        FileUtils.deleteQuietly(baseDir.resolve("dir2").toFile());
-        FileUtils.deleteQuietly(baseDir.toFile());
-    }
-
-
-
-
-    @Test
-    public void consumeData() throws IOException {
-        try(OutputStream os = Files.newOutputStream(file1)) {
-            IOUtils.write("abcdefghijkl", os, "ASCII");
-        }
-        StringResult result = new StringResult();
-        fsStorage.consumeData(file1Asset, is -> consume(is, result), false );
-        Assert.assertEquals("abcdefghijkl" ,result.getData());
-    }
-
-    private void consume(InputStream is, StringResult result) {
-        try {
-            result.setData(IOUtils.toString(is, "ASCII"));
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
-    }
-
-
-    @Test
-    public void getAsset() {
-        StorageAsset asset = fsStorage.getAsset("/dir1/testfile1.dat");
-        Assert.assertEquals(file1, asset.getFilePath());
-    }
-
-    @Test
-    public void addAsset() {
-        StorageAsset newAsset = fsStorage.addAsset("dir2/test", false);
-        Assert.assertNotNull(newAsset);
-        Assert.assertFalse(newAsset.isContainer());
-        Assert.assertFalse(newAsset.exists());
-
-        StorageAsset newDirAsset = fsStorage.addAsset("/dir2/testdir2", true);
-        Assert.assertNotNull(newDirAsset);
-        Assert.assertTrue(newDirAsset.isContainer());
-        Assert.assertFalse(newDirAsset.exists());
-    }
-
-    @Test
-    public void removeAsset() throws IOException {
-        Assert.assertTrue(Files.exists(file1));
-        fsStorage.removeAsset(file1Asset);
-        Assert.assertFalse(Files.exists(file1));
-
-        Assert.assertTrue(Files.exists(dir1));
-        fsStorage.removeAsset(dir1Asset);
-        Assert.assertFalse(Files.exists(dir1));
-    }
-
-    @Test
-    public void moveAsset() throws IOException {
-        Path newFile=null;
-        Path newDir=null;
-        try {
-            Assert.assertTrue(Files.exists(file1));
-            try (OutputStream os = Files.newOutputStream(file1)) {
-                IOUtils.write("testakdkkdkdkdk", os, "ASCII");
-            }
-            long fileSize = Files.size(file1);
-            fsStorage.moveAsset(file1Asset, "/dir2/testfile2.dat");
-            Assert.assertFalse(Files.exists(file1));
-            newFile = baseDir.resolve("dir2/testfile2.dat");
-            Assert.assertTrue(Files.exists(newFile));
-            Assert.assertEquals(fileSize, Files.size(newFile));
-
-
-            Assert.assertTrue(Files.exists(dir1));
-            newDir = baseDir.resolve("dir2/testdir2");
-            fsStorage.moveAsset(dir1Asset, "dir2/testdir2");
-            Assert.assertFalse(Files.exists(dir1));
-            Assert.assertTrue(Files.exists(newDir));
-        } finally {
-            if (newFile!=null) Files.deleteIfExists(newFile);
-            if (newDir!=null) Files.deleteIfExists(newDir);
-        }
-    }
-
-    @Test
-    public void copyAsset() throws IOException {
-        Path newFile=null;
-        Path newDir=null;
-        try {
-            Assert.assertTrue(Files.exists(file1));
-            try (OutputStream os = Files.newOutputStream(file1)) {
-                IOUtils.write("testakdkkdkdkdk", os, "ASCII");
-            }
-            long fileSize = Files.size(file1);
-            fsStorage.copyAsset(file1Asset, "/dir2/testfile2.dat", StandardCopyOption.REPLACE_EXISTING);
-            Assert.assertTrue(Files.exists(file1));
-            Assert.assertEquals(fileSize, Files.size(file1));
-            newFile = baseDir.resolve("dir2/testfile2.dat");
-            Assert.assertTrue(Files.exists(newFile));
-            Assert.assertEquals(fileSize, Files.size(newFile));
-
-            try {
-                fsStorage.copyAsset(file1Asset, "/dir2/testfile2.dat");
-                Assert.assertTrue("IOException should be thrown (File exists)", false);
-            } catch (IOException ex) {
-                Assert.assertTrue("Exception must contain 'file exists'", ex.getMessage().contains("file exists"));
-            }
-
-            Assert.assertTrue(Files.exists(dir1));
-            newDir = baseDir.resolve("dir2/testdir2");
-            fsStorage.copyAsset(dir1Asset, "dir2/testdir2");
-            Assert.assertTrue(Files.exists(dir1));
-            Assert.assertTrue(Files.exists(newDir));
-        } finally {
-            if (newFile!=null) Files.deleteIfExists(newFile);
-            if (newDir!=null) FileUtils.deleteQuietly(newDir.toFile());
-        }
-    }
-}
\ No newline at end of file
diff --git a/archiva-modules/archiva-base/archiva-storage-fs/src/test/java/org/apache/archiva/repository/storage/fs/FilesystemAssetTest.java b/archiva-modules/archiva-base/archiva-storage-fs/src/test/java/org/apache/archiva/repository/storage/fs/FilesystemAssetTest.java
new file mode 100644 (file)
index 0000000..4eae7f3
--- /dev/null
@@ -0,0 +1,204 @@
+package org.apache.archiva.repository.storage.fs;
+
+/*
+ * 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.
+ */
+
+import org.apache.archiva.common.filelock.DefaultFileLockManager;
+import org.apache.archiva.repository.storage.fs.FilesystemAsset;
+import org.apache.archiva.repository.storage.fs.FilesystemStorage;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.time.Instant;
+
+public class FilesystemAssetTest {
+
+    Path assetPathFile;
+    Path assetPathDir;
+    FilesystemStorage filesystemStorage;
+
+    @Before
+    public void init() throws IOException {
+        assetPathDir = Files.createTempDirectory("assetDir");
+        assetPathFile = Files.createTempFile(assetPathDir,"assetFile", "dat");
+        filesystemStorage = new FilesystemStorage(assetPathDir, new DefaultFileLockManager());
+    }
+
+    @After
+    public void cleanup() {
+
+        try {
+            Files.deleteIfExists(assetPathFile);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        FileUtils.deleteQuietly(assetPathDir.toFile());
+    }
+
+
+    @Test
+    public void getPath() {
+        FilesystemAsset asset = new FilesystemAsset(filesystemStorage, assetPathFile.getFileName().toString(), assetPathFile);
+        Assert.assertEquals("/"+assetPathFile.getFileName().toString(), asset.getPath());
+    }
+
+    @Test
+    public void getName() {
+        FilesystemAsset asset = new FilesystemAsset(filesystemStorage, "/"+assetPathFile.getFileName().toString(), assetPathFile);
+        Assert.assertEquals(assetPathFile.getFileName().toString(), asset.getName());
+
+    }
+
+    @Test
+    public void getModificationTime() throws IOException {
+        Instant modTime = Files.getLastModifiedTime(assetPathFile).toInstant();
+        FilesystemAsset asset = new FilesystemAsset(filesystemStorage, "/test123", assetPathFile);
+        Assert.assertTrue(modTime.equals(asset.getModificationTime()));
+    }
+
+    @Test
+    public void isContainer() {
+        FilesystemAsset asset = new FilesystemAsset(filesystemStorage, "/test1323", assetPathFile);
+        Assert.assertFalse(asset.isContainer());
+        FilesystemAsset asset2 = new FilesystemAsset(filesystemStorage, "/test1234", assetPathDir);
+        Assert.assertTrue(asset2.isContainer());
+    }
+
+    @Test
+    public void list() throws IOException {
+        FilesystemAsset asset = new FilesystemAsset(filesystemStorage, "/test1234", assetPathFile);
+        Assert.assertEquals(0, asset.list().size());
+
+        FilesystemAsset asset2 = new FilesystemAsset(filesystemStorage, "/test1235", assetPathDir);
+        Assert.assertEquals(1, asset2.list().size());
+        Path f1 = Files.createTempFile(assetPathDir, "testfile", "dat");
+        Path f2 = Files.createTempFile(assetPathDir, "testfile", "dat");
+        Path d1 = Files.createTempDirectory(assetPathDir, "testdir");
+        Assert.assertEquals(4, asset2.list().size());
+        Assert.assertTrue(asset2.list().stream().anyMatch(p -> p.getName().equals(f1.getFileName().toString())));
+        Assert.assertTrue(asset2.list().stream().anyMatch(p -> p.getName().equals(f2.getFileName().toString())));
+        Assert.assertTrue(asset2.list().stream().anyMatch(p -> p.getName().equals(d1.getFileName().toString())));
+        Files.deleteIfExists(f1);
+        Files.deleteIfExists(f2);
+        Files.deleteIfExists(d1);
+
+
+    }
+
+    @Test
+    public void getSize() throws IOException {
+        FilesystemAsset asset = new FilesystemAsset(filesystemStorage, "/test1234", assetPathFile);
+        Assert.assertEquals(0, asset.getSize());
+
+        Files.write(assetPathFile, new String("abcdef").getBytes("ASCII"));
+        Assert.assertTrue(asset.getSize()>=6);
+
+
+    }
+
+    @Test
+    public void getData() throws IOException {
+        FilesystemAsset asset = new FilesystemAsset(filesystemStorage, "/test1234", assetPathFile);
+        Files.write(assetPathFile, "abcdef".getBytes("ASCII"));
+        try(InputStream is = asset.getReadStream()) {
+            Assert.assertEquals("abcdef", IOUtils.toString(is, "ASCII"));
+        }
+
+    }
+
+    @Test
+    public void getDataExceptionOnDir() throws IOException {
+        FilesystemAsset asset = new FilesystemAsset(filesystemStorage, "/test1234", assetPathDir);
+        Files.write(assetPathFile, "abcdef".getBytes("ASCII"));
+        try {
+            InputStream is = asset.getReadStream();
+            Assert.assertFalse("Exception expected for data on dir", true);
+        } catch (IOException e) {
+            // fine
+        }
+
+    }
+
+    @Test
+    public void writeData() throws IOException {
+        FilesystemAsset asset = new FilesystemAsset(filesystemStorage, "/test1234", assetPathFile);
+        Files.write(assetPathFile, "abcdef".getBytes("ASCII"));
+        try(OutputStream os  = asset.getWriteStream(true)) {
+            IOUtils.write("test12345", os, "ASCII");
+        }
+        Assert.assertEquals("test12345", IOUtils.toString(assetPathFile.toUri().toURL(), "ASCII"));
+    }
+
+    @Test
+    public void writeDataAppend() throws IOException {
+        FilesystemAsset asset = new FilesystemAsset(filesystemStorage, "/test1234", assetPathFile);
+        Files.write(assetPathFile, "abcdef".getBytes("ASCII"));
+        try(OutputStream os  = asset.getWriteStream(false)) {
+            IOUtils.write("test12345", os, "ASCII");
+        }
+        Assert.assertEquals("abcdeftest12345", IOUtils.toString(assetPathFile.toUri().toURL(), "ASCII"));
+    }
+
+    @Test
+    public void writeDataExceptionOnDir() throws IOException {
+        FilesystemAsset asset = new FilesystemAsset(filesystemStorage, "/test1234", assetPathDir);
+        try {
+
+            OutputStream os = asset.getWriteStream(true);
+            Assert.assertTrue("Writing to a directory should throw a IOException", false);
+        } catch (IOException e) {
+            // Fine
+        }
+    }
+
+    @Test
+    public void storeDataFile() throws IOException {
+        FilesystemAsset asset = new FilesystemAsset(filesystemStorage, "/test1234", assetPathFile);
+        Path dataFile = Files.createTempFile("testdata", "dat");
+        try(OutputStream os = Files.newOutputStream(dataFile)) {
+            IOUtils.write("testkdkdkd", os, "ASCII");
+        }
+        asset.replaceDataFromFile(dataFile);
+        Assert.assertEquals("testkdkdkd", IOUtils.toString(assetPathFile.toUri().toURL(), "ASCII"));
+    }
+
+    @Test
+    public void exists() {
+        FilesystemAsset asset = new FilesystemAsset(filesystemStorage, "/test1234", assetPathFile);
+        Assert.assertTrue(asset.exists());
+        FilesystemAsset asset2 = new FilesystemAsset(filesystemStorage, "/test1234", Paths.get("abcdefgkdkdk"));
+        Assert.assertFalse(asset2.exists());
+
+    }
+
+    @Test
+    public void getFilePath() {
+        FilesystemAsset asset = new FilesystemAsset(filesystemStorage, "/test1234", assetPathFile);
+        Assert.assertEquals(assetPathFile, asset.getFilePath());
+    }
+}
\ No newline at end of file
diff --git a/archiva-modules/archiva-base/archiva-storage-fs/src/test/java/org/apache/archiva/repository/storage/fs/FilesystemStorageTest.java b/archiva-modules/archiva-base/archiva-storage-fs/src/test/java/org/apache/archiva/repository/storage/fs/FilesystemStorageTest.java
new file mode 100644 (file)
index 0000000..ddee6ce
--- /dev/null
@@ -0,0 +1,197 @@
+package org.apache.archiva.repository.storage.fs;
+
+/*
+ * 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.
+ */
+
+import org.apache.archiva.common.filelock.DefaultFileLockManager;
+import org.apache.archiva.repository.storage.StorageAsset;
+import org.apache.archiva.repository.storage.fs.FilesystemAsset;
+import org.apache.archiva.repository.storage.fs.FilesystemStorage;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+
+public class FilesystemStorageTest {
+
+    private FilesystemStorage fsStorage;
+    private FilesystemAsset file1Asset;
+    private FilesystemAsset dir1Asset;
+    private Path baseDir;
+    private Path file1;
+    private Path dir1;
+
+    @Before
+    public void init() throws IOException {
+        baseDir = Files.createTempDirectory("FsStorageTest");
+        DefaultFileLockManager fl = new DefaultFileLockManager();
+        fsStorage = new FilesystemStorage(baseDir,fl);
+        Files.createDirectories(baseDir.resolve("dir1"));
+        Files.createDirectories(baseDir.resolve("dir2"));
+        file1 = Files.createFile(baseDir.resolve("dir1/testfile1.dat"));
+        dir1 = Files.createDirectories(baseDir.resolve("dir1/testdir"));
+        file1Asset = new FilesystemAsset(fsStorage, "/dir1/testfile1.dat", file1);
+        dir1Asset = new FilesystemAsset(fsStorage, "/dir1/testdir", dir1);
+    }
+
+    private class StringResult {
+        public String getData() {
+            return data;
+        }
+
+        public void setData(String data) {
+            this.data = data;
+        }
+
+        String data;
+    }
+
+
+    @After
+    public void cleanup() {
+        FileUtils.deleteQuietly(file1.toFile());
+        FileUtils.deleteQuietly(dir1.toFile());
+        FileUtils.deleteQuietly(baseDir.resolve("dir1").toFile());
+        FileUtils.deleteQuietly(baseDir.resolve("dir2").toFile());
+        FileUtils.deleteQuietly(baseDir.toFile());
+    }
+
+
+
+
+    @Test
+    public void consumeData() throws IOException {
+        try(OutputStream os = Files.newOutputStream(file1)) {
+            IOUtils.write("abcdefghijkl", os, "ASCII");
+        }
+        StringResult result = new StringResult();
+        fsStorage.consumeData(file1Asset, is -> consume(is, result), false );
+        Assert.assertEquals("abcdefghijkl" ,result.getData());
+    }
+
+    private void consume(InputStream is, StringResult result) {
+        try {
+            result.setData(IOUtils.toString(is, "ASCII"));
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+
+    @Test
+    public void getAsset() {
+        StorageAsset asset = fsStorage.getAsset("/dir1/testfile1.dat");
+        Assert.assertEquals(file1, asset.getFilePath());
+    }
+
+    @Test
+    public void addAsset() {
+        StorageAsset newAsset = fsStorage.addAsset("dir2/test", false);
+        Assert.assertNotNull(newAsset);
+        Assert.assertFalse(newAsset.isContainer());
+        Assert.assertFalse(newAsset.exists());
+
+        StorageAsset newDirAsset = fsStorage.addAsset("/dir2/testdir2", true);
+        Assert.assertNotNull(newDirAsset);
+        Assert.assertTrue(newDirAsset.isContainer());
+        Assert.assertFalse(newDirAsset.exists());
+    }
+
+    @Test
+    public void removeAsset() throws IOException {
+        Assert.assertTrue(Files.exists(file1));
+        fsStorage.removeAsset(file1Asset);
+        Assert.assertFalse(Files.exists(file1));
+
+        Assert.assertTrue(Files.exists(dir1));
+        fsStorage.removeAsset(dir1Asset);
+        Assert.assertFalse(Files.exists(dir1));
+    }
+
+    @Test
+    public void moveAsset() throws IOException {
+        Path newFile=null;
+        Path newDir=null;
+        try {
+            Assert.assertTrue(Files.exists(file1));
+            try (OutputStream os = Files.newOutputStream(file1)) {
+                IOUtils.write("testakdkkdkdkdk", os, "ASCII");
+            }
+            long fileSize = Files.size(file1);
+            fsStorage.moveAsset(file1Asset, "/dir2/testfile2.dat");
+            Assert.assertFalse(Files.exists(file1));
+            newFile = baseDir.resolve("dir2/testfile2.dat");
+            Assert.assertTrue(Files.exists(newFile));
+            Assert.assertEquals(fileSize, Files.size(newFile));
+
+
+            Assert.assertTrue(Files.exists(dir1));
+            newDir = baseDir.resolve("dir2/testdir2");
+            fsStorage.moveAsset(dir1Asset, "dir2/testdir2");
+            Assert.assertFalse(Files.exists(dir1));
+            Assert.assertTrue(Files.exists(newDir));
+        } finally {
+            if (newFile!=null) Files.deleteIfExists(newFile);
+            if (newDir!=null) Files.deleteIfExists(newDir);
+        }
+    }
+
+    @Test
+    public void copyAsset() throws IOException {
+        Path newFile=null;
+        Path newDir=null;
+        try {
+            Assert.assertTrue(Files.exists(file1));
+            try (OutputStream os = Files.newOutputStream(file1)) {
+                IOUtils.write("testakdkkdkdkdk", os, "ASCII");
+            }
+            long fileSize = Files.size(file1);
+            fsStorage.copyAsset(file1Asset, "/dir2/testfile2.dat", StandardCopyOption.REPLACE_EXISTING);
+            Assert.assertTrue(Files.exists(file1));
+            Assert.assertEquals(fileSize, Files.size(file1));
+            newFile = baseDir.resolve("dir2/testfile2.dat");
+            Assert.assertTrue(Files.exists(newFile));
+            Assert.assertEquals(fileSize, Files.size(newFile));
+
+            try {
+                fsStorage.copyAsset(file1Asset, "/dir2/testfile2.dat");
+                Assert.assertTrue("IOException should be thrown (File exists)", false);
+            } catch (IOException ex) {
+                Assert.assertTrue("Exception must contain 'file exists'", ex.getMessage().contains("file exists"));
+            }
+
+            Assert.assertTrue(Files.exists(dir1));
+            newDir = baseDir.resolve("dir2/testdir2");
+            fsStorage.copyAsset(dir1Asset, "dir2/testdir2");
+            Assert.assertTrue(Files.exists(dir1));
+            Assert.assertTrue(Files.exists(newDir));
+        } finally {
+            if (newFile!=null) Files.deleteIfExists(newFile);
+            if (newDir!=null) FileUtils.deleteQuietly(newDir.toFile());
+        }
+    }
+}
\ No newline at end of file
index c4c5e3b9f551dda51c65ea799d6190314e44d7d7..3ece4b0a0347b61208b5a60a187bf3775e4ba4a9 100644 (file)
@@ -20,17 +20,15 @@ package org.apache.archiva.indexer.maven;
  */
 
 import org.apache.archiva.common.filelock.DefaultFileLockManager;
-import org.apache.archiva.common.filelock.FileLockManager;
 import org.apache.archiva.indexer.ArchivaIndexingContext;
 import org.apache.archiva.repository.Repository;
-import org.apache.archiva.repository.storage.FilesystemStorage;
+import org.apache.archiva.repository.storage.fs.FilesystemStorage;
 import org.apache.archiva.repository.storage.StorageAsset;
 import org.apache.maven.index.context.IndexingContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
-import java.net.URI;
 import java.nio.file.Files;
 import java.nio.file.NoSuchFileException;
 import java.nio.file.Path;
index 777e6eb30a21fd0090b101c54a146397e6168ae1..5f190fc191b8136304ac83255114fa4e6c7c7245 100644 (file)
@@ -38,7 +38,7 @@ import org.apache.archiva.repository.RemoteRepository;
 import org.apache.archiva.repository.Repository;
 import org.apache.archiva.repository.RepositoryType;
 import org.apache.archiva.repository.UnsupportedRepositoryTypeException;
-import org.apache.archiva.repository.storage.FilesystemStorage;
+import org.apache.archiva.repository.storage.fs.FilesystemStorage;
 import org.apache.archiva.repository.storage.RepositoryStorage;
 import org.apache.archiva.repository.storage.StorageAsset;
 import org.apache.archiva.repository.features.IndexCreationFeature;
index 47c5bda1e121fabdd74f0f1579979545f7c531ee..ff7eb83ed268c0f6a2cea6c4b2600f76e65a73f5 100644 (file)
@@ -22,7 +22,6 @@ package org.apache.archiva.proxy;
 import org.apache.archiva.common.filelock.DefaultFileLockManager;
 import org.apache.archiva.common.utils.VersionUtil;
 import org.apache.archiva.configuration.ProxyConnectorConfiguration;
-import org.apache.archiva.maven2.metadata.MavenMetadataReader;
 import org.apache.archiva.model.ArchivaRepositoryMetadata;
 import org.apache.archiva.model.Plugin;
 import org.apache.archiva.model.ProjectReference;
@@ -35,14 +34,12 @@ import org.apache.archiva.policies.SnapshotsPolicy;
 import org.apache.archiva.repository.metadata.base.MetadataTools;
 import org.apache.archiva.repository.metadata.RepositoryMetadataException;
 import org.apache.archiva.repository.metadata.base.RepositoryMetadataWriter;
-import org.apache.archiva.repository.storage.FilesystemStorage;
+import org.apache.archiva.repository.storage.fs.FilesystemStorage;
 import org.apache.archiva.repository.storage.StorageAsset;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.maven.wagon.TransferFailedException;
 import org.easymock.EasyMock;
 import org.junit.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.xmlunit.builder.DiffBuilder;
 import org.xmlunit.diff.Diff;
 import org.xmlunit.diff.Difference;
index 9b8b82a47c6f4aaa15aa346777583bf3f8a367db..b532d83019611af4b930e6d512d5a850cd79754d 100644 (file)
@@ -35,7 +35,7 @@ import org.apache.archiva.repository.content.ItemSelector;
 import org.apache.archiva.repository.content.Namespace;
 import org.apache.archiva.repository.content.Project;
 import org.apache.archiva.repository.content.Version;
-import org.apache.archiva.repository.storage.FilesystemStorage;
+import org.apache.archiva.repository.storage.fs.FilesystemStorage;
 import org.apache.archiva.repository.storage.RepositoryStorage;
 import org.apache.archiva.repository.storage.StorageAsset;
 import org.apache.commons.lang3.StringUtils;
index 977bc308df28b07d1bfa611575c5aab3819a7175..51467e653852eb8807f3cea573356b0c0b525c1b 100644 (file)
@@ -24,7 +24,7 @@ import org.apache.archiva.common.filelock.FileLockManager;
 import org.apache.archiva.indexer.ArchivaIndexingContext;
 import org.apache.archiva.repository.*;
 import org.apache.archiva.repository.base.AbstractManagedRepository;
-import org.apache.archiva.repository.storage.FilesystemStorage;
+import org.apache.archiva.repository.storage.fs.FilesystemStorage;
 import org.apache.archiva.repository.content.maven2.MavenRepositoryRequestInfo;
 import org.apache.archiva.repository.features.ArtifactCleanupFeature;
 import org.apache.archiva.repository.features.IndexCreationFeature;
index 72621c8533c6a9a645d27525d64a208c04d04aee..74d82aeebbc58f86dc009660b5f825a5286529d9 100644 (file)
@@ -9,7 +9,7 @@ import org.apache.archiva.repository.RepositoryCapabilities;
 import org.apache.archiva.repository.RepositoryType;
 import org.apache.archiva.repository.StandardCapabilities;
 import org.apache.archiva.repository.UnsupportedFeatureException;
-import org.apache.archiva.repository.storage.FilesystemStorage;
+import org.apache.archiva.repository.storage.fs.FilesystemStorage;
 import org.apache.archiva.repository.features.IndexCreationFeature;
 import org.apache.archiva.repository.features.RemoteIndexFeature;
 import org.apache.archiva.repository.features.RepositoryFeature;
index 9bd570d30c479cac340e25951280a3381b6a0eb5..ba88a837c911d7a14f2c1b79ea2cf10f75607b0a 100644 (file)
@@ -23,7 +23,7 @@ import org.apache.archiva.common.filelock.DefaultFileLockManager;
 import org.apache.archiva.common.filelock.FileLockManager;
 import org.apache.archiva.repository.*;
 import org.apache.archiva.repository.base.AbstractRepositoryGroup;
-import org.apache.archiva.repository.storage.FilesystemStorage;
+import org.apache.archiva.repository.storage.fs.FilesystemStorage;
 import org.apache.archiva.repository.features.IndexCreationFeature;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
index aeb547728b33e8117017a2897f5b4acb3440a359..7ca8e0669dc70daf47cc0b6e4088cd445359d97d 100644 (file)
@@ -29,7 +29,7 @@ import org.apache.archiva.repository.features.RemoteIndexFeature;
 import org.apache.archiva.repository.features.StagingRepositoryFeature;
 import org.apache.archiva.repository.base.BasicManagedRepository;
 import org.apache.archiva.repository.base.PasswordCredentials;
-import org.apache.archiva.repository.storage.FilesystemStorage;
+import org.apache.archiva.repository.storage.fs.FilesystemStorage;
 import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
index a37ced0f5ccbab098317ed9c4523669f94952685..77541ee20caec8424378c4e7c338069899253a68 100644 (file)
@@ -38,8 +38,8 @@ import org.apache.archiva.repository.RepositoryException;
 import org.apache.archiva.repository.RepositoryType;
 import org.apache.archiva.repository.metadata.RepositoryMetadataException;
 import org.apache.archiva.repository.metadata.base.RepositoryMetadataWriter;
-import org.apache.archiva.repository.storage.FilesystemAsset;
-import org.apache.archiva.repository.storage.FilesystemStorage;
+import org.apache.archiva.repository.storage.fs.FilesystemAsset;
+import org.apache.archiva.repository.storage.fs.FilesystemStorage;
 import org.apache.archiva.repository.storage.StorageAsset;
 import org.apache.commons.io.FileUtils;
 import org.slf4j.Logger;
index cf5a507a7c858a3e9fec14dd3bacf2c3cd58489a..744a0b24ef841c0c1830732b00a060131a9e5555 100644 (file)
@@ -40,8 +40,8 @@ import org.apache.archiva.repository.RemoteRepository;
 import org.apache.archiva.repository.Repository;
 import org.apache.archiva.repository.RepositoryType;
 import org.apache.archiva.repository.UnsupportedRepositoryTypeException;
-import org.apache.archiva.repository.storage.FilesystemAsset;
-import org.apache.archiva.repository.storage.FilesystemStorage;
+import org.apache.archiva.repository.storage.fs.FilesystemAsset;
+import org.apache.archiva.repository.storage.fs.FilesystemStorage;
 import org.apache.archiva.repository.storage.StorageAsset;
 import org.apache.archiva.repository.features.IndexCreationFeature;
 import org.apache.archiva.repository.features.RemoteIndexFeature;
index ded8ed387f60e56d557a2398425803b0edaba765..e9e2f0f28832d257d19bfa5fe34d61284f35b148 100644 (file)
@@ -22,7 +22,7 @@ package org.apache.archiva.repository.index.mock;
 import org.apache.archiva.common.filelock.DefaultFileLockManager;
 import org.apache.archiva.indexer.ArchivaIndexingContext;
 import org.apache.archiva.repository.Repository;
-import org.apache.archiva.repository.storage.FilesystemStorage;
+import org.apache.archiva.repository.storage.fs.FilesystemStorage;
 import org.apache.archiva.repository.storage.StorageAsset;
 import org.apache.maven.index.context.IndexingContext;
 
index 1776c8f9caf4de3db0853e3225771778f4f20a58..6182be541742b5f7c88a8b3c3d25fdd785fea250 100644 (file)
@@ -39,8 +39,8 @@ import org.apache.archiva.repository.RemoteRepository;
 import org.apache.archiva.repository.Repository;
 import org.apache.archiva.repository.RepositoryType;
 import org.apache.archiva.repository.UnsupportedRepositoryTypeException;
-import org.apache.archiva.repository.storage.FilesystemAsset;
-import org.apache.archiva.repository.storage.FilesystemStorage;
+import org.apache.archiva.repository.storage.fs.FilesystemAsset;
+import org.apache.archiva.repository.storage.fs.FilesystemStorage;
 import org.apache.archiva.repository.storage.StorageAsset;
 import org.apache.archiva.repository.features.IndexCreationFeature;
 import org.apache.archiva.repository.features.RemoteIndexFeature;
index c8e2cd4f0766dd8c9927cdac53868a2351bd6cb7..3d64f098d3bb06269c29de40139cc05d9503cfd3 100644 (file)
@@ -22,13 +22,12 @@ package org.apache.archiva.mock;
 import org.apache.archiva.common.filelock.DefaultFileLockManager;
 import org.apache.archiva.indexer.ArchivaIndexingContext;
 import org.apache.archiva.repository.Repository;
-import org.apache.archiva.repository.storage.FilesystemAsset;
-import org.apache.archiva.repository.storage.FilesystemStorage;
+import org.apache.archiva.repository.storage.fs.FilesystemAsset;
+import org.apache.archiva.repository.storage.fs.FilesystemStorage;
 import org.apache.archiva.repository.storage.StorageAsset;
 import org.apache.maven.index.context.IndexingContext;
 
 import java.io.IOException;
-import java.net.URI;
 import java.nio.file.Files;
 import java.nio.file.NoSuchFileException;
 import java.sql.Date;
index 053e12c3a4ce68057510536f37b6469c8a547e35..d7e2866cf603abba7c9f8ec515fad2bcb0dcdadc 100644 (file)
@@ -44,7 +44,7 @@ import org.apache.archiva.repository.RepositoryNotFoundException;
 import org.apache.archiva.repository.RepositoryRegistry;
 import org.apache.archiva.repository.metadata.MetadataReader;
 import org.apache.archiva.repository.metadata.base.MetadataTools;
-import org.apache.archiva.repository.storage.FsStorageUtil;
+import org.apache.archiva.repository.storage.fs.FsStorageUtil;
 import org.apache.archiva.repository.storage.StorageAsset;
 import org.apache.archiva.rest.api.model.*;
 import org.apache.archiva.rest.api.services.ArchivaRestServiceException;
index 0dcaee6810a7c651b3ecaf6e5729c08dfedb2cee..5c72d42aea77ca31225a0bfc4de39c1d916b7042 100644 (file)
@@ -51,7 +51,7 @@ import org.apache.archiva.repository.RepositoryException;
 import org.apache.archiva.repository.RepositoryNotFoundException;
 import org.apache.archiva.repository.RepositoryRegistry;
 import org.apache.archiva.repository.RepositoryType;
-import org.apache.archiva.repository.storage.FsStorageUtil;
+import org.apache.archiva.repository.storage.fs.FsStorageUtil;
 import org.apache.archiva.repository.storage.RepositoryStorage;
 import org.apache.archiva.repository.storage.StorageAsset;
 import org.apache.archiva.metadata.audit.RepositoryListener;
index 4cd630e3c96a91f29161d4d5912caceaa0c8ac2e..03aba26c44622f19ea492d8fd7f2964ebf09d07a 100644 (file)
@@ -20,8 +20,8 @@ package org.apache.archiva.rest.services;
 
 import junit.framework.TestCase;
 import org.apache.archiva.common.filelock.DefaultFileLockManager;
-import org.apache.archiva.repository.storage.FilesystemAsset;
-import org.apache.archiva.repository.storage.FilesystemStorage;
+import org.apache.archiva.repository.storage.fs.FilesystemAsset;
+import org.apache.archiva.repository.storage.fs.FilesystemStorage;
 import org.apache.archiva.rest.api.model.ArtifactContentEntry;
 import org.apache.archiva.test.utils.ArchivaBlockJUnit4ClassRunner;
 import org.junit.Test;
index f95099252a6faef29cc6ff0e2e2c97c8860c2957..5bc1d9b28b0737b62128c78eaf708321f3caf55d 100644 (file)
@@ -19,8 +19,8 @@ package org.apache.archiva.rest.services.utils;
  */
 
 import org.apache.archiva.common.filelock.DefaultFileLockManager;
-import org.apache.archiva.repository.storage.FilesystemAsset;
-import org.apache.archiva.repository.storage.FilesystemStorage;
+import org.apache.archiva.repository.storage.fs.FilesystemAsset;
+import org.apache.archiva.repository.storage.fs.FilesystemStorage;
 import org.apache.archiva.repository.storage.StorageAsset;
 import org.easymock.TestSubject;
 import org.junit.Test;
index 445b9680c28e3b3ab7e95ae5b0083aaa2d4a58d6..0a35b18528ed5b90392d1504a6ae4d5bfbdbdf1a 100644 (file)
@@ -31,7 +31,7 @@ import org.apache.archiva.repository.base.ArchivaRepositoryRegistry;
 import org.apache.archiva.repository.base.BasicManagedRepository;
 import org.apache.archiva.repository.Repository;
 import org.apache.archiva.repository.RepositoryRegistry;
-import org.apache.archiva.repository.storage.FilesystemStorage;
+import org.apache.archiva.repository.storage.fs.FilesystemStorage;
 import org.apache.archiva.rss.RssFeedGenerator;
 import org.apache.archiva.test.utils.ArchivaBlockJUnit4ClassRunner;
 import org.easymock.EasyMock;
index 374d953a8ef303ff13b477a7977044f328fdd19c..e0079bbf1aaeefeda172f7f973d9c9d266c06515 100644 (file)
@@ -25,7 +25,7 @@ import org.apache.archiva.common.filelock.DefaultFileLockManager;
 import org.apache.archiva.configuration.ArchivaConfiguration;
 import org.apache.archiva.repository.base.BasicManagedRepository;
 import org.apache.archiva.repository.RepositoryRegistry;
-import org.apache.archiva.repository.storage.FilesystemStorage;
+import org.apache.archiva.repository.storage.fs.FilesystemStorage;
 import org.apache.archiva.test.utils.ArchivaSpringJUnit4ClassRunner;
 import org.apache.commons.codec.Encoder;
 import org.apache.commons.codec.binary.Base64;
index a2c90ec3ce93eb5209d50db9a8b61fb68c9fe6b2..2e6f8331909f31fc10b69168fc2dc65eed09397f 100644 (file)
@@ -65,7 +65,7 @@ import org.apache.archiva.repository.ReleaseScheme;
 import org.apache.archiva.repository.RepositoryGroup;
 import org.apache.archiva.repository.RepositoryRegistry;
 import org.apache.archiva.repository.RepositoryRequestInfo;
-import org.apache.archiva.repository.storage.FilesystemStorage;
+import org.apache.archiva.repository.storage.fs.FilesystemStorage;
 import org.apache.archiva.repository.storage.StorageAsset;
 import org.apache.archiva.metadata.audit.AuditListener;
 import org.apache.archiva.repository.features.IndexCreationFeature;
index e10e609a5ca1c5e653a62fea7dedff372e8643bb..5329e091bf2d3dee4c059b96c6384c4b9cea390c 100644 (file)
@@ -24,7 +24,7 @@ import org.apache.archiva.common.filelock.FileLockManager;
 import org.apache.archiva.common.utils.FileUtils;
 import org.apache.archiva.repository.LayoutException;
 import org.apache.archiva.repository.RepositoryRegistry;
-import org.apache.archiva.repository.storage.FilesystemAsset;
+import org.apache.archiva.repository.storage.fs.FilesystemAsset;
 import org.apache.archiva.metadata.audit.AuditListener;
 import org.apache.archiva.repository.maven2.MavenManagedRepository;
 import org.apache.archiva.test.utils.ArchivaSpringJUnit4ClassRunner;