]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics/src/org/simantics/internal/FileServiceImpl.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics / src / org / simantics / internal / FileServiceImpl.java
1 package org.simantics.internal;\r
2 \r
3 import java.io.File;\r
4 import java.io.FileFilter;\r
5 import java.io.IOException;\r
6 import java.util.ArrayDeque;\r
7 import java.util.Collection;\r
8 \r
9 import org.eclipse.core.runtime.IProgressMonitor;\r
10 import org.eclipse.core.runtime.IStatus;\r
11 import org.eclipse.core.runtime.Status;\r
12 import org.eclipse.core.runtime.jobs.Job;\r
13 import org.simantics.utils.FileService;\r
14 import org.simantics.utils.IOperation;\r
15 import org.simantics.utils.IOperationListener;\r
16 \r
17 /**\r
18  * @author Tuukka Lehtonen\r
19  */\r
20 public class FileServiceImpl implements FileService {\r
21 \r
22         private static final long DELETION_DELAY_MS = 10000;\r
23         private static final long DELETION_ATTEMPT_INTERVAL_MS = 10000;\r
24 \r
25         private static abstract class Op<R, E extends Exception> implements IOperation<R, E> {\r
26                 protected boolean done;\r
27                 protected R result;\r
28                 @SuppressWarnings("unused")\r
29                 protected E lastException;\r
30 \r
31                 @Override\r
32                 public R waitFor() throws E {\r
33                         synchronized(this) {\r
34                                 while (!isDone()) {\r
35                                         try {\r
36                                                 wait();\r
37                                         } catch (InterruptedException e) {\r
38                                         }\r
39                                 }\r
40                         }\r
41                         return result;\r
42                 }\r
43 \r
44                 @Override\r
45                 public boolean isDone() {\r
46                         return done;\r
47                 }\r
48 \r
49                 @Override\r
50                 public void addListener(IOperationListener<R, E> listener) {\r
51                         throw new UnsupportedOperationException();\r
52                 }\r
53 \r
54                 public abstract boolean tryExecute();\r
55 \r
56         }\r
57 \r
58         private static class Deletion extends Op<Boolean, IOException> {\r
59 \r
60                 File f;\r
61 \r
62                 EffortOption effort;\r
63                 int tries;\r
64 \r
65                 public Deletion(File f, DeleteOption... options) {\r
66                         this.f = f;\r
67                         parseOptions(options);\r
68                 }\r
69 \r
70                 private void parseOptions(DeleteOption[] options) {\r
71                         for (DeleteOption opt : options) {\r
72                                 if (opt instanceof EffortOption) {\r
73                                         effort = (EffortOption) opt;\r
74                                 }\r
75                         }\r
76                 }\r
77 \r
78                 @Override\r
79                 public boolean tryExecute() {\r
80                         if (effort != null) {\r
81                                 if (tries > effort.maxTries) {\r
82                                         // Give up.\r
83                                         return true;\r
84                                 }\r
85                         }\r
86                         try {\r
87                                 deleteAll(f);\r
88                                 lastException = null;\r
89                                 result = true;\r
90                                 return true;\r
91                         } catch (IOException e) {\r
92                                 ++tries;\r
93                                 lastException = e;\r
94                                 return false;\r
95                         }\r
96                 }\r
97 \r
98                 public void deleteAll(File dir) throws IOException {\r
99                         if (dir.isFile()) {\r
100                                 if (!dir.delete())\r
101                                         throw new IOException("Could not delete file: " + dir.getAbsolutePath());\r
102                                 return;\r
103                         }\r
104                         if (dir.isDirectory()) {\r
105                                 File[] fs = dir.listFiles((FileFilter) null);\r
106                                 if (fs == null)\r
107                                         return;\r
108 \r
109                                 for (File f : fs) {\r
110                                         if (f.isDirectory()) {\r
111                                                 deleteAll(f);\r
112                                         } else {\r
113                                                 if (!f.delete()) {\r
114                                                         throw new IOException("Could not delete file: " + f.getAbsolutePath());\r
115                                                 }\r
116                                         }\r
117                                 }\r
118 \r
119                                 if (!dir.delete()) {\r
120                                         throw new IOException("Could not delete directory: " + dir.getAbsolutePath());\r
121                                 }\r
122                         } else if (dir.exists()) {\r
123                                 if (!dir.delete()) {\r
124                                         throw new IOException("Could not delete file: " + dir.getAbsolutePath());\r
125                                 }\r
126                         }\r
127                 }\r
128 \r
129         }\r
130 \r
131         private ArrayDeque<Deletion> deletionQueue = new ArrayDeque<Deletion>();\r
132         private DeletionJob deletionJob = new DeletionJob();\r
133 \r
134         @Override\r
135         public IOperation<Boolean, IOException> scheduleDeleteIfExists(File file, DeleteOption... options) {\r
136                 if (!file.exists())\r
137                         return null;\r
138                 synchronized (deletionQueue) {\r
139                         Deletion d = new Deletion(file, options);\r
140                         if (deletionQueue.contains(d))\r
141                                 return null;\r
142                         deletionQueue.addLast(d);\r
143                         deletionJob.schedule(DELETION_DELAY_MS);\r
144                         return d;\r
145                 }\r
146         }\r
147 \r
148         class DeletionJob extends Job {\r
149 \r
150                 public DeletionJob() {\r
151                         super("File background deletion");\r
152                 }\r
153 \r
154                 @SuppressWarnings("unchecked")\r
155                 private <O extends Op<?,?>> void process(Collection<O> ops) {\r
156                         Object[] opa = ops.toArray();\r
157                         for (int i = 0; i < opa.length; ++i) {\r
158                                 O op = (O) opa[i];\r
159                                 if (op.tryExecute()) {\r
160                                         // Success. Will be removed from queue.\r
161                                 } else {\r
162                                         opa[i] = null;\r
163                                 }\r
164                         }\r
165                         synchronized (ops) {\r
166                                 for (int i = 0; i < opa.length; ++i) {\r
167                                         if (opa[i] != null)\r
168                                                 ops.remove(opa[i]);\r
169                                 }\r
170                         }\r
171                 }\r
172 \r
173                 @Override\r
174                 protected IStatus run(IProgressMonitor monitor) {\r
175                         process(deletionQueue);\r
176                         if (!deletionQueue.isEmpty())\r
177                                 schedule(DELETION_ATTEMPT_INTERVAL_MS);\r
178                         return Status.OK_STATUS;\r
179                 }\r
180 \r
181         }\r
182 \r
183 }\r