aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Stockhammer <martin_s@apache.org>2020-02-16 21:20:37 +0100
committerMartin Stockhammer <martin_s@apache.org>2020-02-16 21:20:37 +0100
commitdfe9604884b74199ea1880b826be6f578390f5c8 (patch)
tree34b422c7340a9b22d56214a0f2c1721f873a6339
parent33bfded28d0841dd815a25f621f6f6bb78821532 (diff)
downloadarchiva-dfe9604884b74199ea1880b826be6f578390f5c8.tar.gz
archiva-dfe9604884b74199ea1880b826be6f578390f5c8.zip
Adding recursive delete with cumulated result status to FileUtils
-rw-r--r--archiva-modules/archiva-base/archiva-common/pom.xml6
-rw-r--r--archiva-modules/archiva-base/archiva-common/src/main/java/org/apache/archiva/common/utils/FileStatus.java72
-rw-r--r--archiva-modules/archiva-base/archiva-common/src/main/java/org/apache/archiva/common/utils/FileUtils.java54
-rw-r--r--archiva-modules/archiva-base/archiva-common/src/main/java/org/apache/archiva/common/utils/IOStatus.java168
-rw-r--r--archiva-modules/archiva-base/archiva-common/src/main/java/org/apache/archiva/common/utils/StatusResult.java29
-rw-r--r--archiva-modules/archiva-base/archiva-common/src/test/java/org/apache/archiva/common/utils/FileUtilsTest.java40
-rw-r--r--archiva-modules/archiva-base/archiva-common/src/test/resources/log4j2-test.xml2
7 files changed, 359 insertions, 12 deletions
diff --git a/archiva-modules/archiva-base/archiva-common/pom.xml b/archiva-modules/archiva-base/archiva-common/pom.xml
index 6e62f1417..283cbff41 100644
--- a/archiva-modules/archiva-base/archiva-common/pom.xml
+++ b/archiva-modules/archiva-base/archiva-common/pom.xml
@@ -52,6 +52,12 @@
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-slf4j-impl</artifactId>
+ <scope>test</scope>
+ </dependency>
+
</dependencies>
<build>
<pluginManagement>
diff --git a/archiva-modules/archiva-base/archiva-common/src/main/java/org/apache/archiva/common/utils/FileStatus.java b/archiva-modules/archiva-base/archiva-common/src/main/java/org/apache/archiva/common/utils/FileStatus.java
new file mode 100644
index 000000000..78f3ed361
--- /dev/null
+++ b/archiva-modules/archiva-base/archiva-common/src/main/java/org/apache/archiva/common/utils/FileStatus.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.archiva.common.utils;
+
+import java.io.IOException;
+import java.nio.file.Path;
+
+/**
+ * File operation status for a given file.
+ *
+ * @author Martin Stockhammer <martin_s@apache.org>
+ */
+public class FileStatus
+{
+ final private Path path;
+ final private StatusResult result;
+ final private IOException exception;
+
+ /**
+ * Success status
+ *
+ * @param path the file path
+ * @param statusResult the status of the file operation
+ */
+ FileStatus( Path path, StatusResult statusResult) {
+ this.path = path;
+ this.result = statusResult;
+ this.exception = null;
+ }
+
+ /**
+ * Error status
+ * @param path the file path
+ * @param e the exception, that occured during the file operation
+ */
+ FileStatus( Path path, IOException e) {
+ this.path = path;
+ this.result = StatusResult.ERROR;
+ this.exception = e;
+ }
+
+ public IOException getException( )
+ {
+ return exception;
+ }
+
+ public Path getPath( )
+ {
+ return path;
+ }
+
+ public StatusResult getResult( )
+ {
+ return result;
+ }
+}
diff --git a/archiva-modules/archiva-base/archiva-common/src/main/java/org/apache/archiva/common/utils/FileUtils.java b/archiva-modules/archiva-base/archiva-common/src/main/java/org/apache/archiva/common/utils/FileUtils.java
index 67b27cb19..3dc95432b 100644
--- a/archiva-modules/archiva-base/archiva-common/src/main/java/org/apache/archiva/common/utils/FileUtils.java
+++ b/archiva-modules/archiva-base/archiva-common/src/main/java/org/apache/archiva/common/utils/FileUtils.java
@@ -29,6 +29,7 @@ import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Comparator;
import java.util.Optional;
+import java.util.stream.Stream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@@ -46,14 +47,17 @@ public class FileUtils {
* @param dir
*/
public static void deleteQuietly(Path dir) {
- try {
- Files.walk(dir)
- .sorted(Comparator.reverseOrder())
- .forEach(file -> {
+ try(Stream<Path> stream = Files.walk(dir)) {
+ stream
+ .sorted( Comparator.reverseOrder() )
+ .forEach(file -> {
try {
Files.delete(file);
} catch (IOException e) {
// Ignore this
+ if (log.isDebugEnabled()) {
+ log.debug( "Exception during file delete: {}", e.getMessage( ), e );
+ }
}
});
@@ -64,6 +68,38 @@ public class FileUtils {
}
+ public static IOStatus deleteDirectoryWithStatus(Path dir) throws IOException {
+ if (!Files.exists(dir)) {
+ IOStatus status = new IOStatus( );
+ status.addError( dir, new FileNotFoundException( "Directory not found " + dir ) );
+ return status;
+ }
+ if (!Files.isDirectory(dir)) {
+ IOStatus status = new IOStatus( );
+ status.addError(dir, new IOException("Given path is not a directory " + dir));
+ }
+ try( Stream<Path> stream = Files.walk(dir)) {
+ return stream
+ .sorted( Comparator.reverseOrder() )
+ .map(file ->
+ {
+ try {
+ Files.delete(file);
+ return new FileStatus( file, StatusResult.DELETED );
+ } catch (UncheckedIOException e) {
+ log.warn("File could not be deleted {}", file);
+ return new FileStatus( file, e.getCause( ) );
+ }
+ catch ( IOException e )
+ {
+ return new FileStatus( file, e );
+ }
+ }).collect( IOStatus::new, IOStatus::accumulate, IOStatus::combine );
+ } catch (UncheckedIOException e) {
+ throw new IOException("File deletion failed ", e);
+ }
+ }
+
public static void deleteDirectory(Path dir) throws IOException {
if (!Files.exists(dir)) {
return;
@@ -72,16 +108,16 @@ public class FileUtils {
throw new IOException("Given path is not a directory " + dir);
}
boolean result = true;
- try {
- result = Files.walk(dir)
- .sorted(Comparator.reverseOrder())
- .map(file ->
+ try(Stream<Path> stream = Files.walk(dir)) {
+ result = stream
+ .sorted( Comparator.reverseOrder() )
+ .map(file ->
{
try {
Files.delete(file);
return Optional.of(Boolean.TRUE);
} catch (UncheckedIOException | IOException e) {
- log.warn("File could not be deleted {}", file);
+ log.warn("File could not be deleted {}: {}", file, e.getMessage());
return Optional.empty();
}
diff --git a/archiva-modules/archiva-base/archiva-common/src/main/java/org/apache/archiva/common/utils/IOStatus.java b/archiva-modules/archiva-base/archiva-common/src/main/java/org/apache/archiva/common/utils/IOStatus.java
new file mode 100644
index 000000000..ea67978a9
--- /dev/null
+++ b/archiva-modules/archiva-base/archiva-common/src/main/java/org/apache/archiva/common/utils/IOStatus.java
@@ -0,0 +1,168 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.archiva.common.utils;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ *
+ * Collects information about file system operational status, e.g. if a file could be deleted,
+ * or IOException was thrown.
+ *
+ * @author Martin Stockhammer <martin_s@apache.org>
+ */
+public class IOStatus
+{
+
+ Map<Path,IOException> errorList;
+ Map<Path, StatusResult> okList = new TreeMap<>( );
+
+ /**
+ * Returns <code>true</code>, if no error was recorded.
+ * @return
+ */
+ boolean isOk() {
+ return !hasErrors( );
+ }
+
+ /**
+ * Returns <code>true</code>, if at least one error was recorded
+ * @return
+ */
+ boolean hasErrors() {
+ if (errorList==null || errorList.size()==0) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Accumulator method used for stream collecting
+ *
+ * @param ioStatus
+ * @param fileStatus
+ * @return
+ */
+ public static IOStatus accumulate(IOStatus ioStatus, FileStatus fileStatus) {
+ ioStatus.addStatus( fileStatus );
+ return ioStatus;
+ }
+
+ /**
+ * Combiner used for stream collecting
+ * @param ioStatus1
+ * @param ioStatus2
+ * @return
+ */
+ public static IOStatus combine(IOStatus ioStatus1, IOStatus ioStatus2) {
+ IOStatus status = new IOStatus( );
+ status.addAllSuccess( ioStatus1.getSuccessFiles() );
+ status.addAllSuccess( ioStatus2.getSuccessFiles( ) );
+ status.addAllErrors( ioStatus1.getErrorFiles( ) );
+ status.addAllErrors( ioStatus2.getErrorFiles( ) );
+ return status;
+ }
+
+ /**
+ * Add the status for a specific file to this status collection.
+ *
+ * @param status the status for a given file
+ * @return the status object itself
+ */
+ public IOStatus addStatus(FileStatus status) {
+ if (status.getResult()== StatusResult.ERROR) {
+ addError( status.getPath( ), status.getException( ) );
+ } else {
+ addSuccess( status.getPath( ), status.getResult( ) );
+ }
+ return this;
+ }
+
+ /**
+ * Adds an error to the status collection.
+ *
+ * @param path the file path
+ * @param e the exception thrown during the file operation
+ */
+ public void addError( Path path, IOException e) {
+ if (errorList==null) {
+ errorList = new TreeMap<>( );
+ }
+ errorList.put( path, e );
+ }
+
+ /**
+ * Adds multiple errors to the collection.
+ *
+ * @param errors the map of file, error pairs
+ */
+ public void addAllErrors(Map<Path, IOException> errors) {
+ if (errorList == null) {
+ errorList = new TreeMap<>( );
+ }
+ errorList.putAll( errors );
+ }
+
+ /**
+ * Adds all successful states to the collection.
+ *
+ * @param success a map of file, StatusResult pairs
+ */
+ public void addAllSuccess( Map<Path, StatusResult> success) {
+ okList.putAll( success );
+ }
+
+ /**
+ * Add success status for a given file to the collection.
+ *
+ * @param path the file path
+ * @param status the status of the file operation, e.g. DELETED
+ */
+ public void addSuccess( Path path, StatusResult status) {
+ okList.put( path, status );
+ }
+
+ /**
+ * Returns all the recorded errors as map of path, exception pairs.
+ * @return the map of path, exception pairs.
+ */
+ public Map<Path, IOException> getErrorFiles() {
+ if (errorList==null) {
+ return Collections.emptyMap( );
+ }
+ return errorList;
+ }
+
+ /**
+ * Returns all the recorded successful operations.
+ *
+ * @return the map of path, StatusResult pairs
+ */
+ public Map<Path, StatusResult> getSuccessFiles() {
+ if (okList==null) {
+ return Collections.emptyMap( );
+ }
+ return okList;
+ }
+}
diff --git a/archiva-modules/archiva-base/archiva-common/src/main/java/org/apache/archiva/common/utils/StatusResult.java b/archiva-modules/archiva-base/archiva-common/src/main/java/org/apache/archiva/common/utils/StatusResult.java
new file mode 100644
index 000000000..354437229
--- /dev/null
+++ b/archiva-modules/archiva-base/archiva-common/src/main/java/org/apache/archiva/common/utils/StatusResult.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.archiva.common.utils;
+
+/**
+ * Result status for file operations.
+ *
+ * @author Martin Stockhammer <martin_s@apache.org>
+ */
+public enum StatusResult
+{
+ DELETED, EXIST, ERROR
+}
diff --git a/archiva-modules/archiva-base/archiva-common/src/test/java/org/apache/archiva/common/utils/FileUtilsTest.java b/archiva-modules/archiva-base/archiva-common/src/test/java/org/apache/archiva/common/utils/FileUtilsTest.java
index 998efb147..93d40aac3 100644
--- a/archiva-modules/archiva-base/archiva-common/src/test/java/org/apache/archiva/common/utils/FileUtilsTest.java
+++ b/archiva-modules/archiva-base/archiva-common/src/test/java/org/apache/archiva/common/utils/FileUtilsTest.java
@@ -34,8 +34,7 @@ import java.nio.file.attribute.PosixFilePermission;
import java.util.HashSet;
import java.util.Set;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
/**
* @author Martin Stockhammer <martin_s@apache.org>
@@ -110,6 +109,43 @@ public class FileUtilsTest
}
+
+ @Test
+ public void testDeleteWithStatus() throws IOException
+ {
+ Path td = Files.createTempDirectory( "FileUtilsTest" );
+ Path f1 = td.resolve("file1.txt");
+ Path f2 = td.resolve("file2.txt");
+ Path d1 = td.resolve("dir1");
+ Files.createDirectory( d1 );
+ Path d11 = d1.resolve("dir11");
+ Files.createDirectory( d11 );
+ Path f111 = d11.resolve("file111.txt");
+ Path f112 = d11.resolve("file112.txt");
+ Files.write(f1,"file1".getBytes());
+ Files.write(f2, "file2".getBytes());
+ Files.write(f111, "file111".getBytes());
+ Files.write(f112, "file112".getBytes());
+ assertTrue(Files.exists(d1));
+ assertTrue(Files.exists(f1));
+ assertTrue(Files.exists(f2));
+ assertTrue(Files.exists(f111));
+ assertTrue(Files.exists(f112));
+
+ IOStatus status = FileUtils.deleteDirectoryWithStatus( td );
+ assertFalse(Files.exists(f1));
+ assertFalse(Files.exists(f2));
+ assertFalse(Files.exists(f111));
+ assertFalse(Files.exists(f112));
+ assertFalse(Files.exists(d1));
+
+ assertTrue( status.isOk( ) );
+ assertFalse( status.hasErrors( ) );
+ assertEquals( 7, status.getSuccessFiles( ).size( ) );
+ assertEquals( 0, status.getErrorFiles( ).size() );
+ }
+
+
@Test
public void testDeleteNonExist() throws IOException
{
diff --git a/archiva-modules/archiva-base/archiva-common/src/test/resources/log4j2-test.xml b/archiva-modules/archiva-base/archiva-common/src/test/resources/log4j2-test.xml
index 03547df43..c7275f874 100644
--- a/archiva-modules/archiva-base/archiva-common/src/test/resources/log4j2-test.xml
+++ b/archiva-modules/archiva-base/archiva-common/src/test/resources/log4j2-test.xml
@@ -33,7 +33,7 @@
</appenders>
<loggers>
<logger name="org.apache.archiva" level="info"/>
- <logger name="org.apache.archiva.repository.scanner" level="info"/>
+ <logger name="org.apache.archiva.common.utils" level="info"
<root level="error" includeLocation="true">
<appender-ref ref="console"/>
</root>