2121
2222import java .io .File ;
2323import java .io .IOException ;
24+ import java .nio .file .AtomicMoveNotSupportedException ;
25+ import java .nio .file .FileAlreadyExistsException ;
2426import java .nio .file .Files ;
27+ import java .nio .file .Path ;
28+ import java .nio .file .StandardCopyOption ;
2529import javax .annotation .CheckForNull ;
2630
2731/**
3135 */
3236public class FileCache {
3337
34- /** Maximum loop count when creating temp directories. */
35- private static final int TEMP_DIR_ATTEMPTS = 10000 ;
36-
37- private final File dir ;
38- private final File tmpDir ;
38+ private final Path dir ;
39+ private final Path tmpDir ;
3940 private final FileHashes hashes ;
4041 private final Logger logger ;
4142
42- FileCache (File dir , FileHashes fileHashes , Logger logger ) {
43+ FileCache (Path dir , FileHashes fileHashes , Logger logger ) {
4344 this .hashes = fileHashes ;
4445 this .logger = logger ;
4546 this .dir = createDir (dir , "user cache" );
46- logger .info (String .format ("User cache: %s" , dir .getAbsolutePath ()));
47- this .tmpDir = createDir (new File ( dir , "_tmp" ), "temp dir" );
47+ logger .info (String .format ("User cache: %s" , dir .toString ()));
48+ this .tmpDir = createDir (dir . resolve ( "_tmp" ), "temp dir" );
4849 }
4950
50- static FileCache create (File dir , Logger logger ) {
51+ static FileCache create (Path dir , Logger logger ) {
5152 return new FileCache (dir , new FileHashes (), logger );
5253 }
5354
5455 public File getDir () {
55- return dir ;
56+ return dir . toFile () ;
5657 }
5758
5859 /**
@@ -61,9 +62,9 @@ public File getDir() {
6162 */
6263 @ CheckForNull
6364 public File get (String filename , String hash ) {
64- File cachedFile = new File ( new File ( dir , hash ), filename );
65- if (cachedFile .exists ()) {
66- return cachedFile ;
65+ Path cachedFile = dir . resolve ( hash ). resolve ( filename );
66+ if (Files .exists (cachedFile )) {
67+ return cachedFile . toFile () ;
6768 }
6869 logger .debug (String .format ("No file found in the cache with name %s and hash %s" , filename , hash ));
6970 return null ;
@@ -76,84 +77,74 @@ public interface Downloader {
7677
7778 public File get (String filename , String hash , Downloader downloader ) {
7879 // Does not fail if another process tries to create the directory at the same time.
79- File hashDir = hashDir (hash );
80- File targetFile = new File ( hashDir , filename );
81- if (!targetFile .exists ()) {
82- File tempFile = newTempFile ();
80+ Path hashDir = hashDir (hash );
81+ Path targetFile = hashDir . resolve ( filename );
82+ if (!Files .exists (targetFile )) {
83+ Path tempFile = newTempFile ();
8384 download (downloader , filename , tempFile );
84- String downloadedHash = hashes .of (tempFile );
85+ String downloadedHash = hashes .of (tempFile . toFile () );
8586 if (!hash .equals (downloadedHash )) {
86- throw new IllegalStateException ("INVALID HASH: File " + tempFile .getAbsolutePath () + " was expected to have hash " + hash
87+ throw new IllegalStateException ("INVALID HASH: File " + tempFile .toAbsolutePath () + " was expected to have hash " + hash
8788 + " but was downloaded with hash " + downloadedHash );
8889 }
8990 mkdirQuietly (hashDir );
9091 renameQuietly (tempFile , targetFile );
9192 }
92- return targetFile ;
93+ return targetFile . toFile () ;
9394 }
9495
95- private void download (Downloader downloader , String filename , File tempFile ) {
96+ private static void download (Downloader downloader , String filename , Path tempFile ) {
9697 try {
97- downloader .download (filename , tempFile );
98+ downloader .download (filename , tempFile . toFile () );
9899 } catch (IOException e ) {
99100 throw new IllegalStateException ("Fail to download " + filename + " to " + tempFile , e );
100101 }
101102 }
102103
103- private void renameQuietly (File sourceFile , File targetFile ) {
104- boolean rename = sourceFile . renameTo ( targetFile );
105- // Check if the file was cached by another process during download
106- if (! rename && ! targetFile . exists () ) {
107- logger .warn (String .format ("Unable to rename %s to %s" , sourceFile .getAbsolutePath (), targetFile .getAbsolutePath ()));
104+ private void renameQuietly (Path sourceFile , Path targetFile ) {
105+ try {
106+ Files . move ( sourceFile , targetFile , StandardCopyOption . ATOMIC_MOVE );
107+ } catch ( AtomicMoveNotSupportedException ex ) {
108+ logger .warn (String .format ("Unable to rename %s to %s" , sourceFile .toAbsolutePath (), targetFile .toAbsolutePath ()));
108109 logger .warn ("A copy/delete will be tempted but with no guarantee of atomicity" );
109110 try {
110- Files .move (sourceFile . toPath () , targetFile . toPath () );
111+ Files .move (sourceFile , targetFile );
111112 } catch (IOException e ) {
112- throw new IllegalStateException ("Fail to move " + sourceFile .getAbsolutePath () + " to " + targetFile , e );
113+ throw new IllegalStateException ("Fail to move " + sourceFile .toAbsolutePath () + " to " + targetFile , e );
113114 }
115+ } catch (FileAlreadyExistsException e ) {
116+ // File was probably cached by another process in the mean time
117+ } catch (IOException e ) {
118+ throw new IllegalStateException ("Fail to move " + sourceFile .toAbsolutePath () + " to " + targetFile , e );
114119 }
115120 }
116121
117- private File hashDir (String hash ) {
118- return new File ( dir , hash );
122+ private Path hashDir (String hash ) {
123+ return dir . resolve ( hash );
119124 }
120125
121- private static void mkdirQuietly (File hashDir ) {
126+ private static void mkdirQuietly (Path hashDir ) {
122127 try {
123- Files .createDirectories (hashDir . toPath () );
128+ Files .createDirectories (hashDir );
124129 } catch (IOException e ) {
125130 throw new IllegalStateException ("Fail to create cache directory: " + hashDir , e );
126131 }
127132 }
128133
129- private File newTempFile () {
134+ private Path newTempFile () {
130135 try {
131- return File .createTempFile ("fileCache" , null , tmpDir );
136+ return Files .createTempFile (tmpDir , "fileCache" , null );
132137 } catch (IOException e ) {
133138 throw new IllegalStateException ("Fail to create temp file in " + tmpDir , e );
134139 }
135140 }
136141
137- public File createTempDir () {
138- String baseName = System .currentTimeMillis () + "-" ;
139-
140- for (int counter = 0 ; counter < TEMP_DIR_ATTEMPTS ; counter ++) {
141- File tempDir = new File (tmpDir , baseName + counter );
142- if (tempDir .mkdir ()) {
143- return tempDir ;
144- }
145- }
146- throw new IllegalStateException ("Failed to create directory in " + tmpDir );
147- }
148-
149- private File createDir (File dir , String debugTitle ) {
150- if (!dir .isDirectory () || !dir .exists ()) {
151- logger .debug ("Create : " + dir .getAbsolutePath ());
152- try {
153- Files .createDirectories (dir .toPath ());
154- } catch (IOException e ) {
155- throw new IllegalStateException ("Unable to create " + debugTitle + dir .getAbsolutePath (), e );
156- }
142+ private Path createDir (Path dir , String debugTitle ) {
143+ logger .debug ("Create: " + dir .toString ());
144+ try {
145+ Files .createDirectories (dir );
146+ } catch (IOException e ) {
147+ throw new IllegalStateException ("Unable to create " + debugTitle + dir .toString (), e );
157148 }
158149 return dir ;
159150 }
0 commit comments