OSDN Git Service

キャンセル要求が成功した場合は一旦キャンセル表示を行う(cancelledイベントが飛ばない場合があるので)
[coroid/inqubus.git] / frontend / src / yukihane / inqubus / manager / TaskManage.java
1 package yukihane.inqubus.manager;
2
3 import java.io.File;
4 import java.util.HashMap;
5 import java.util.Map;
6 import java.util.concurrent.ExecutorService;
7 import java.util.concurrent.Executors;
8 import java.util.concurrent.Future;
9 import java.util.logging.Level;
10 import java.util.logging.Logger;
11 import saccubus.worker.WorkerListener;
12 import saccubus.worker.impl.MessageReportable;
13 import saccubus.worker.impl.PercentageReportable;
14 import saccubus.worker.impl.convert.Convert;
15 import saccubus.worker.impl.convert.ConvertProgress;
16 import saccubus.worker.impl.convert.ConvertResult;
17 import saccubus.worker.impl.download.Download;
18 import saccubus.worker.impl.download.DownloadProgress;
19 import saccubus.worker.impl.download.DownloadResult;
20 import saccubus.worker.profile.ConvertProfile;
21 import saccubus.worker.profile.DownloadProfile;
22
23 /**
24  *
25  * @author yuki
26  */
27 public class TaskManage {
28
29     private static final Logger logger = Logger.getLogger(TaskManage.class.getName());
30     private final ExecutorService downloadExecutorService;
31     private final ExecutorService convertExecutorService;
32     private final Map<Integer, ManageTarget<DownloadResult>> downloadTargets = new HashMap<>();
33     private final Map<Integer, ManageTarget<ConvertResult>> convertTargets = new HashMap<>();
34     private final TaskManageListener clientListener;
35     private final int waitDownload;
36
37     public TaskManage() {
38         this(1, 30, 1, null);
39     }
40
41     public TaskManage(int maxDownload, int maxConvert) {
42         this(maxDownload, 30, maxConvert, null);
43     }
44
45     public TaskManage(int maxDownload, int waitDownload, int maxConvert, TaskManageListener listener) {
46         downloadExecutorService = Executors.newFixedThreadPool(maxDownload);
47         convertExecutorService = Executors.newFixedThreadPool(maxConvert);
48         this.waitDownload = waitDownload;
49         this.clientListener = listener;
50     }
51
52     public synchronized boolean add(RequestProcess request) {
53         final DownloadProfile dp = request.getDownloadProfile();
54         final ConvertProfile cp = request.getConvertProfile();
55         if (dp != null && (dp.getVideoProfile().isDownload() || dp.getCommentProfile().isDownload())) {
56             // ダウンロードするものがあればまずダウンロード処理
57             final Download task = new Download(dp, request.getVideoId(),
58                     new DownloadListener(request.getRowId()), waitDownload);
59             final Future<DownloadResult> future = downloadExecutorService.submit(task);
60             downloadTargets.put(request.getRowId(), new ManageTarget<>(request, future));
61             return true;
62
63         } else if (cp != null && cp.isConvert()) {
64             final Convert task = new Convert(cp, dp.getVideoProfile().getLocalFile(), dp.getCommentProfile().
65                     getLocalFile(), new ConvertListener(request.getRowId()));
66             final Future<ConvertResult> future = convertExecutorService.submit(task);
67             convertTargets.put(request.getRowId(), new ManageTarget<>(request, future));
68             return true;
69         }
70         return false;
71     }
72
73     public synchronized boolean cancel(int rowId) {
74         // FIXME 実行前にキャンセルした場合にはcancelledイベントが飛ばないのでMapからリクエストを削除できない
75         final ManageTarget<DownloadResult> down = downloadTargets.get(rowId);
76         if (down != null) {
77             return down.getFuture().cancel(true);
78         }
79         final ManageTarget<ConvertResult> conv = convertTargets.get(rowId);
80         if (conv != null) {
81             return conv.getFuture().cancel(true);
82         }
83
84         return false;
85     }
86
87     private class DownloadListener extends TaskManageInnerListener<DownloadResult, DownloadProgress> {
88
89         private DownloadListener(int rowId) {
90             super(rowId);
91         }
92
93         @Override
94         public void done(DownloadResult result) {
95             super.done(result);
96             synchronized (TaskManage.this) {
97                 final ManageTarget<DownloadResult> mt = removeRequest(getRowId());
98                 final RequestProcess request = mt.getRequest();
99                 if (request.getConvertProfile().isConvert()) {
100                     final DownloadProfile dp = request.getDownloadProfile();
101                     final File video = (dp.getVideoProfile().isDownload()) ? result.getDownloadVideo() : dp.
102                             getVideoProfile().getLocalFile();
103                     final File comment = (dp.getCommentProfile().isDownload()) ? result.getDownloadComment() : dp.
104                             getCommentProfile().getLocalFile();
105                     final ConvertProfile cp = request.getConvertProfile();
106                     final Convert task = new Convert(cp, video, comment, new ConvertListener(getRowId()));
107                     final Future<ConvertResult> future = convertExecutorService.submit(task);
108                     convertTargets.put(request.getRowId(), new ManageTarget<>(request, future));
109                 }
110                 // TODO 変換が必要なら変換キューに入れる
111             }
112
113         }
114
115         @Override
116         protected TaskKind getKind() {
117             return TaskKind.DOWNLOAD;
118         }
119
120         @Override
121         protected ManageTarget<DownloadResult> removeRequest(int rowId) {
122             return downloadTargets.remove(rowId);
123         }
124     }
125
126     private class ConvertListener extends TaskManageInnerListener<ConvertResult, ConvertProgress> {
127
128         private ConvertListener(int rowId) {
129             super(rowId);
130         }
131
132         @Override
133         protected TaskKind getKind() {
134             return TaskKind.CONVERT;
135         }
136
137         @Override
138         public void done(ConvertResult result) {
139             super.done(result);
140             synchronized (TaskManage.this) {
141                 removeRequest(getRowId());
142             }
143         }
144
145         @Override
146         protected ManageTarget<ConvertResult> removeRequest(int rowId) {
147             return convertTargets.remove(rowId);
148         }
149     }
150
151     abstract class TaskManageInnerListener<T, V extends PercentageReportable & MessageReportable> implements WorkerListener<T, V> {
152
153         private final int rowId;
154
155         protected TaskManageInnerListener(int rowId) {
156             this.rowId = rowId;
157         }
158
159         protected int getRowId() {
160             return rowId;
161         }
162
163         private void notify(TaskStatus status) {
164             notify(status, -1.0, "");
165         }
166
167         private void notify(TaskStatus status, double percentage, String message) {
168             if (getListener() == null) {
169                 return;
170             }
171             getListener().process(rowId, getKind(), status, percentage, message);
172         }
173
174         private TaskManageListener getListener() {
175             return clientListener;
176         }
177
178         protected abstract TaskKind getKind();
179
180         @Override
181         public void process(V progress) {
182             logger.log(Level.FINEST, "process: {0}", progress);
183             notify(TaskStatus.DOING, progress.getPercentage(), progress.getMessage());
184         }
185
186         @Override
187         public final void cancelled() {
188             logger.log(Level.FINE, "cancelled: {0}", toString());
189             synchronized (TaskManage.this) {
190                 removeRequest(rowId);
191             }
192             notify(TaskStatus.CANCELLED);
193         }
194
195         /**
196          * この処理をオーバライドしてキューからリクエストを削除する必要があります.
197          * @param result 処理結果.
198          */
199         @Override
200         public void done(T result) {
201             logger.log(Level.FINE, "done: {0}", result);
202             notify(TaskStatus.DONE);
203         }
204
205         @Override
206         public final void error(Throwable th) {
207             logger.log(Level.SEVERE, "error", th);
208             synchronized (TaskManage.this) {
209                 removeRequest(rowId);
210             }
211             notify(TaskStatus.ERROR, 0.0, th.getMessage());
212         }
213
214         protected abstract ManageTarget<T> removeRequest(int rowId);
215     }
216
217     class ManageTarget<T> {
218
219         private final RequestProcess request;
220         private final Future<T> future;
221
222         ManageTarget(RequestProcess request, Future<T> future) {
223             this.request = request;
224             this.future = future;
225         }
226
227         Future<T> getFuture() {
228             return future;
229         }
230
231         RequestProcess getRequest() {
232             return request;
233         }
234     }
235 }