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 public static TempFileManager instance(String subDirName) {
89 return instance(calcTempDir(subDirName));
90 }
91
92 public static synchronized TempFileManager instance(File tempDir) {
93
94
95 if (shutdownHook == null) {
96 ThreadGroup tg = Thread.currentThread().getThreadGroup();
97 while (tg.getParent() != null) {
98 tg = tg.getParent();
99 }
100 shutdownHook = new Thread(
101 tg, TempFileManager::shutdownAll, TempFileManager.class.getSimpleName() + "-ShutdownHook");
102 Runtime.getRuntime().addShutdownHook(shutdownHook);
103 }
104
105 return INSTANCES.computeIfAbsent(tempDir == null ? new File(getJavaIoTmpDir()) : tempDir, TempFileManager::new);
106 }
107
108 public synchronized void deleteAll() {
109 tempFiles.forEach(File::delete);
110 tempFiles.clear();
111 tempDir.delete();
112 }
113
114 static void shutdownAll() {
115 INSTANCES.values().stream().filter(TempFileManager::isDeleteOnExit).forEach(TempFileManager::deleteAll);
116 }
117
118
119
120
121
122
123 public File getTempDir() {
124 return tempDir;
125 }
126
127
128
129
130
131
132
133
134
135
136
137
138
139 public synchronized File createTempFile(String prefix, String suffix) {
140
141 prefix = prefix == null ? "" : (new File(prefix)).getName();
142 suffix = suffix == null ? "" : suffix;
143
144 String name = String.join("-", prefix, baseName + "_" + FILE_ID.getAndIncrement()) + suffix;
145 File tempFile = new File(tempDir, name);
146 if (!name.equals(tempFile.getName())) {
147 throw new UncheckedIOException(new IOException("Unable to create temporary file " + tempFile));
148 }
149
150 if (tempFile.exists() || tempFiles.contains(tempFile)) {
151
152 return createTempFile(prefix, suffix);
153 } else {
154
155 if (!tempDir.exists()) {
156 if (!tempDir.mkdirs()) {
157 throw new UncheckedIOException(
158 new IOException("Unable to create temporary directory " + tempDir.getAbsolutePath()));
159 }
160 }
161
162 try {
163 tempFile.createNewFile();
164 } catch (IOException ex) {
165 throw new UncheckedIOException("Unable to create temporary file " + tempFile.getAbsolutePath(), ex);
166 }
167
168 tempFiles.add(tempFile);
169 return tempFile;
170 }
171 }
172
173 public File createTempFile(String prefix) {
174 return createTempFile(prefix, SUFFIX_TMP);
175 }
176
177 public boolean isDeleteOnExit() {
178 return deleteOnExit;
179 }
180
181
182
183
184
185
186
187 public void setDeleteOnExit(boolean deleteOnExit) {
188 this.deleteOnExit = deleteOnExit;
189 }
190
191 @Override
192 public String toString() {
193 return String.format(
194 "%s[tempDir=%s, deleteOnExit=%s, baseName=%s, tempFiles=%d]",
195 getClass().getSimpleName(), tempDir, deleteOnExit, baseName, tempFiles.size());
196 }
197
198
199
200
201
202
203 public static String getJavaIoTmpDir() {
204 String tmpDir = System.getProperty("java.io.tmpdir");
205 if (!tmpDir.endsWith(File.separator)) {
206 tmpDir += File.separatorChar;
207 }
208 return tmpDir;
209 }
210 }