1 package org.apache.maven.surefire.api.util;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.io.UncheckedIOException;
25 import java.time.LocalDateTime;
26 import java.time.format.DateTimeFormatter;
27 import java.util.ArrayList;
28 import java.util.LinkedHashMap;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.concurrent.atomic.AtomicInteger;
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 public final class TempFileManager
47 {
48
49 private static final Map<File, TempFileManager> INSTANCES = new LinkedHashMap<>();
50
51 private static final AtomicInteger FILE_ID = new AtomicInteger( 1 );
52 private static final String SUFFIX_TMP = ".tmp";
53
54 private static Thread shutdownHook;
55
56
57 private final File tempDir;
58
59 private final String baseName;
60
61
62 private final List<File> tempFiles;
63
64
65 private boolean deleteOnExit;
66
67 private TempFileManager( File tempDir )
68 {
69 this.tempDir = tempDir;
70 this.baseName = DateTimeFormatter.ofPattern( "yyyyMMddHHmmssSSS" ).format( LocalDateTime.now() );
71 this.tempFiles = new ArrayList<>();
72 }
73
74 private static File calcTempDir( String subDirName )
75 {
76 String tempDirName = subDirName == null ? null
77 : subDirName.trim().isEmpty() ? null : subDirName.trim();
78 File tempDirCandidate = tempDirName == null ? new File( getJavaIoTmpDir() )
79 : new File( getJavaIoTmpDir(), tempDirName );
80 return tempDirCandidate;
81 }
82
83 public static TempFileManager instance( )
84 {
85 return instance( ( File ) null );
86 }
87
88
89
90
91
92
93 public static TempFileManager instance( String subDirName )
94 {
95 return instance( calcTempDir( subDirName ) );
96 }
97
98 public static synchronized TempFileManager instance( File tempDir )
99 {
100
101
102 if ( shutdownHook == null )
103 {
104 ThreadGroup tg = Thread.currentThread().getThreadGroup();
105 while ( tg.getParent() != null )
106 {
107 tg = tg.getParent();
108 }
109 shutdownHook = new Thread( tg, TempFileManager::shutdownAll,
110 TempFileManager.class.getSimpleName() + "-ShutdownHook" );
111 Runtime.getRuntime().addShutdownHook( shutdownHook );
112 }
113
114 return INSTANCES.computeIfAbsent(
115 tempDir == null ? new File( getJavaIoTmpDir() ) : tempDir,
116 TempFileManager::new );
117 }
118
119 public synchronized void deleteAll()
120 {
121 tempFiles.forEach( File::delete );
122 tempFiles.clear();
123 tempDir.delete();
124 }
125
126 static void shutdownAll()
127 {
128 INSTANCES.values().stream()
129 .filter( TempFileManager::isDeleteOnExit )
130 .forEach( TempFileManager::deleteAll );
131 }
132
133
134
135
136
137
138 public File getTempDir()
139 {
140 return tempDir;
141 }
142
143
144
145
146
147
148
149
150
151
152
153
154
155 public synchronized File createTempFile( String prefix, String suffix )
156 {
157
158 prefix = prefix == null ? "" : ( new File( prefix ) ).getName();
159 suffix = suffix == null ? "" : suffix;
160
161 String name = String.join( "-", prefix, baseName + "_" + FILE_ID.getAndIncrement() ) + suffix;
162 File tempFile = new File( tempDir, name );
163 if ( !name.equals( tempFile.getName() ) )
164 {
165 throw new UncheckedIOException( new IOException( "Unable to create temporary file " + tempFile ) );
166 }
167
168 if ( tempFile.exists() || tempFiles.contains( tempFile ) )
169 {
170
171 return createTempFile( prefix, suffix );
172 }
173 else
174 {
175
176 if ( !tempDir.exists() )
177 {
178 if ( !tempDir.mkdirs() )
179 {
180 throw new UncheckedIOException( new IOException(
181 "Unable to create temporary directory " + tempDir.getAbsolutePath() ) );
182 }
183 }
184
185 try
186 {
187 tempFile.createNewFile();
188 }
189 catch ( IOException ex )
190 {
191 throw new UncheckedIOException( "Unable to create temporary file " + tempFile.getAbsolutePath(), ex );
192 }
193
194 tempFiles.add( tempFile );
195 return tempFile;
196 }
197 }
198
199 public File createTempFile( String prefix )
200 {
201 return createTempFile( prefix, SUFFIX_TMP );
202 }
203
204 public boolean isDeleteOnExit()
205 {
206 return deleteOnExit;
207 }
208
209
210
211
212
213
214
215 public void setDeleteOnExit( boolean deleteOnExit )
216 {
217 this.deleteOnExit = deleteOnExit;
218 }
219
220 @Override
221 public String toString()
222 {
223 return String.format( "%s[tempDir=%s, deleteOnExit=%s, baseName=%s, tempFiles=%d]",
224 getClass().getSimpleName(), tempDir, deleteOnExit, baseName, tempFiles.size() );
225 }
226
227
228
229
230
231
232 public static String getJavaIoTmpDir()
233 {
234 String tmpDir = System.getProperty( "java.io.tmpdir" );
235 if ( !tmpDir.endsWith( File.separator ) )
236 {
237 tmpDir += File.separatorChar;
238 }
239 return tmpDir;
240 }
241
242 }