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