1 package auxtestlib;
2
3 import java.io.File;
4 import java.io.IOException;
5
6 /**
7 * Class that creates a temporary file or directory. This file or directory is
8 * removed when the JVM terminates (it may be deleted sooner if the
9 * {@link #delete()} method is called explicitly). If the created file is a
10 * directory, it will be removed recursively.
11 */
12 public class TemporaryFile {
13 /**
14 * Created file. If <code>null</code> means it was already removed.
15 */
16 private File m_created;
17
18 /**
19 * Creates a new temporary file (or directory). This is equivalent to call
20 * {@link #TemporaryFile(File, boolean, String, String)} with all other
21 * arguments as <code>null</code>.
22 * @param directory should a directory be created? If <code>false</code> a
23 * file is created
24 * @throws IOException failed to create the file
25 */
26 public TemporaryFile(boolean directory) throws IOException {
27 this(null, directory, null, null);
28 }
29
30 /**
31 * Creates a new file (or directory).
32 * @param path path to the parent directory. If <code>null</code> the
33 * file/directory will be created on the default location.
34 * @param directory should a directory be created? If <code>false</code> a
35 * file is created
36 * @param prefix an optional prefix for the file (it a prefix is provided it
37 * must contain at least 3 characters).
38 * @param suffix an optional suffix for the file
39 * @throws IOException failed to create the file
40 */
41 public TemporaryFile(File path, boolean directory, String prefix,
42 String suffix) throws IOException {
43 String pfx = prefix;
44
45 if (pfx == null) {
46 pfx = "junit_";
47 }
48
49 if (pfx.length() < 3) {
50 throw new IllegalArgumentException("prefix must have at least "
51 + "3 characters");
52 }
53
54 m_created = File.createTempFile(pfx, suffix, path);
55 if (directory) {
56 if (!m_created.delete()) {
57 throw new IOException("Failed to delete file '"
58 + m_created.getAbsolutePath() + "'");
59 }
60
61 if (!m_created.mkdir()) {
62 throw new IOException("Failed to create directory '"
63 + m_created.getAbsolutePath() + "'");
64 }
65 }
66
67 Thread t = new Thread(new Runnable() {
68 @Override
69 public void run() {
70 shutdown_delete();
71 }
72 });
73
74 Runtime.getRuntime().addShutdownHook(t);
75 }
76
77 /**
78 * Obtains a reference to the created file.
79 * @return the created file (or directory).
80 * @deprecated use {@link #file()} instead
81 */
82 @Deprecated
83 public File getFile() {
84 return file();
85 }
86
87 /**
88 * Obtains a reference to the created file.
89 * @return the created file (or directory).
90 */
91 public File file() {
92 if (m_created == null) {
93 throw new IllegalStateException("File/directory already deleted.");
94 }
95
96 return m_created;
97 }
98
99 /**
100 * Deletes the file or directory. If this represents a directory, all its
101 * contents are recursively deleted.
102 */
103 public void delete() {
104 if (m_created == null) {
105 throw new IllegalStateException("File already deleted.");
106 }
107
108 shutdown_delete();
109 }
110
111 /**
112 * Removes the file or directory if it hasn't been removed yet. If this
113 * represents a directory, all its contents are recursively deleted.
114 */
115 private void shutdown_delete() {
116 if (m_created == null) {
117 return;
118 }
119
120 do_delete(m_created);
121
122 m_created = null;
123 }
124
125 /**
126 * Deletes a file. If the file is a directory, it is removed with all its
127 * contents.
128 * @param f the file or directory to remove
129 */
130 private void do_delete(File f) {
131 assert f != null;
132
133 if (f.exists()) {
134 if (f.isDirectory()) {
135 doDeleteDir(f);
136 }
137 boolean res = f.delete();
138 assert res || !res; // Otherwise findbugs complains.
139 }
140 }
141
142 /**
143 * Removes a directory and all its contents
144 * @param d the directory to remove
145 */
146 private void doDeleteDir(File d) {
147 assert d != null;
148 assert d.isDirectory();
149
150 File f[] = d.listFiles();
151 for (int i = 0; i < f.length; i++) {
152 do_delete(f[i]);
153 }
154 }
155 }