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