View Javadoc
1   package fr.ifremer.quadrige2.core.dao.technical;
2   
3   /*-
4    * #%L
5    * Quadrige2 Core :: Quadrige2 Core Shared
6    * $Id:$
7    * $HeadURL:$
8    * %%
9    * Copyright (C) 2017 Ifremer
10   * %%
11   * This program is free software: you can redistribute it and/or modify
12   * it under the terms of the GNU Affero General Public License as published by
13   * the Free Software Foundation, either version 3 of the License, or
14   * (at your option) any later version.
15   * 
16   * This program is distributed in the hope that it will be useful,
17   * but WITHOUT ANY WARRANTY; without even the implied warranty of
18   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   * GNU General Public License for more details.
20   * 
21   * You should have received a copy of the GNU Affero General Public License
22   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23   * #L%
24   */
25  import fr.ifremer.quadrige2.core.exception.Quadrige2TechnicalException;
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  import org.apache.commons.net.io.CopyStreamListener;
29  import org.apache.commons.net.io.Util;
30  import org.apache.commons.vfs2.FileObject;
31  import org.nuiton.jaxx.application.ApplicationIOUtil;
32  
33  import java.io.File;
34  import java.io.IOException;
35  import java.io.InputStream;
36  import java.io.OutputStream;
37  import java.nio.file.*;
38  import java.nio.file.attribute.BasicFileAttributes;
39  
40  /**
41   * @author peck7 on 30/06/2017.
42   */
43  public class Files {
44  
45      private static final Log log = LogFactory.getLog(Files.class);
46      private static final int DEFAULT_IO_BUFFER_SIZE = 1048576;
47  
48      private Files() {
49          // no instance
50      }
51  
52      /**
53       * Copy a file with progression monitor. Use VFS2 file resolver and streams
54       *
55       * @param sourceFileName a {@link java.lang.String} object.
56       * @param destinationFileName a {@link java.lang.String} object.
57       * @param progressMonitor a {@link org.apache.commons.net.io.CopyStreamListener} object.
58       * @throws java.io.IOException if any.
59       */
60      public static void copy(String sourceFileName, String destinationFileName, CopyStreamListener progressMonitor) throws IOException {
61  
62          FileObject sourceFile = ApplicationIOUtil.resolveFile(sourceFileName, "Can't resolve " + sourceFileName);
63          FileObject destinationFile = ApplicationIOUtil.resolveFile(destinationFileName, "Can't resolve " + destinationFileName);
64  
65          try (InputStream sourceFileIn = sourceFile.getContent().getInputStream();
66               OutputStream destinationFileOut = destinationFile.getContent().getOutputStream()) {
67              Util.copyStream(sourceFileIn, destinationFileOut, DEFAULT_IO_BUFFER_SIZE, sourceFile.getContent().getSize(), progressMonitor);
68          }
69      }
70  
71      /**
72       * <p>cleanDirectory.</p>
73       *
74       * @param directory a {@link java.io.File} object.
75       * @param failMessage a {@link java.lang.String} object.
76       */
77      public static void cleanDirectory(File directory, String failMessage) {
78  
79          Path path = directory.toPath();
80          int nbAttempt = 0;
81          IOException lastException = null;
82          while (isDirectoryNotEmpty(path) && nbAttempt < 10) {
83              nbAttempt++;
84              try {
85                  java.nio.file.Files.walkFileTree(path, new RecursiveDeleteFileVisitor(path));
86                  lastException = null;
87              } catch (NoSuchFileException ignored) {
88              } catch (AccessDeniedException ade) {
89                  if (java.nio.file.Files.exists(Paths.get(ade.getFile()))) {
90                      lastException = ade;
91                      break;
92                  }
93              } catch (IOException e) {
94                  lastException = e;
95                  // wait a while
96                  try {
97                      Thread.sleep(500);
98                  } catch (InterruptedException ignored) {
99                  }
100             }
101         }
102         if (lastException != null) {
103             throw new Quadrige2TechnicalException(failMessage, lastException);
104         }
105         if (log.isWarnEnabled() && nbAttempt > 1) {
106             log.warn(String.format("cleaning the directory '%s' successful after %d attempts", directory.getAbsolutePath(), nbAttempt));
107         }
108     }
109 
110     private static boolean isDirectoryNotEmpty(final Path path) {
111         if (!java.nio.file.Files.isDirectory(path)) {
112             return false;
113         }
114         try {
115             try (DirectoryStream<Path> dirStream = java.nio.file.Files.newDirectoryStream(path)) {
116                 return dirStream.iterator().hasNext();
117             }
118         } catch (IOException e) {
119             return false;
120         }
121     }
122 
123     private static class RecursiveDeleteFileVisitor extends SimpleFileVisitor<Path> {
124 
125         private final Path root;
126 
127         private RecursiveDeleteFileVisitor(Path root) {
128             this.root = root;
129         }
130 
131         @Override
132         public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
133 
134             // delete the file
135             java.nio.file.Files.deleteIfExists(file);
136             return FileVisitResult.CONTINUE;
137         }
138 
139         @Override
140         public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
141 
142             // don't delete the root
143             if (dir == root) {
144                 return FileVisitResult.TERMINATE;
145             }
146 
147             // delete the directory
148             java.nio.file.Files.deleteIfExists(dir);
149             return FileVisitResult.CONTINUE;
150         }
151 
152     }
153 }