java 1.6 compat fix
[nikiroo-utils.git] / src / be / nikiroo / fanfix / library / RemoteLibrary.java
CommitLineData
e42573a0 1package be.nikiroo.fanfix.library;
b0e88ebd
NR
2
3import java.io.File;
4import java.io.IOException;
edf79e5e 5import java.net.URL;
e6249b0f 6import java.net.UnknownHostException;
68e2c6d2
NR
7import java.util.ArrayList;
8import java.util.List;
b0e88ebd 9
e42573a0 10import be.nikiroo.fanfix.Instance;
b0e88ebd
NR
11import be.nikiroo.fanfix.data.MetaData;
12import be.nikiroo.fanfix.data.Story;
16a81ef7 13import be.nikiroo.utils.Image;
b0e88ebd 14import be.nikiroo.utils.Progress;
416c54f8 15import be.nikiroo.utils.StringUtils;
b0e88ebd 16import be.nikiroo.utils.Version;
62c63b07 17import be.nikiroo.utils.serial.server.ConnectActionClientObject;
b0e88ebd 18
68e2c6d2
NR
19/**
20 * This {@link BasicLibrary} will access a remote server to list the available
a85e8077 21 * stories, and download the ones you try to load to the local directory
68e2c6d2
NR
22 * specified in the configuration.
23 *
24 * @author niki
25 */
26public class RemoteLibrary extends BasicLibrary {
b0e88ebd
NR
27 private String host;
28 private int port;
416c54f8 29 private final String md5;
68e2c6d2
NR
30
31 /**
32 * Create a {@link RemoteLibrary} linked to the given server.
33 *
2070ced5
NR
34 * @param key
35 * the key that will allow us to exchange information with the
36 * server
68e2c6d2
NR
37 * @param host
38 * the host to contact or NULL for localhost
39 * @param port
40 * the port to contact it on
41 */
2070ced5 42 public RemoteLibrary(String key, String host, int port) {
416c54f8 43 this.md5 = StringUtils.getMd5Hash(key);
b0e88ebd
NR
44 this.host = host;
45 this.port = port;
b0e88ebd
NR
46 }
47
99ccbdf6
NR
48 @Override
49 public String getLibraryName() {
50 return host + ":" + port;
51 }
52
e6249b0f
NR
53 @Override
54 public Status getStatus() {
55 final Status[] result = new Status[1];
56
57 result[0] = Status.INVALID;
58
59 ConnectActionClientObject action = null;
60 try {
41029926 61 Instance.getTraceHandler().trace("Getting remote lib status...");
e6249b0f
NR
62 action = new ConnectActionClientObject(host, port, true) {
63 @Override
64 public void action(Version serverVersion) throws Exception {
416c54f8 65 Object rep = send(new Object[] { md5, "PING" });
e6249b0f
NR
66 if ("PONG".equals(rep)) {
67 result[0] = Status.READY;
68 } else {
69 result[0] = Status.UNAUTORIZED;
70 }
71 }
72
73 @Override
74 protected void onError(Exception e) {
75 result[0] = Status.UNAVAILABLE;
76 }
77 };
78
79 } catch (UnknownHostException e) {
80 result[0] = Status.INVALID;
81 } catch (IllegalArgumentException e) {
82 result[0] = Status.INVALID;
83 } catch (Exception e) {
84 result[0] = Status.UNAVAILABLE;
85 }
86
87 if (action != null) {
88 try {
89 action.connect();
90 } catch (Exception e) {
91 result[0] = Status.UNAVAILABLE;
92 }
93 }
94
41029926 95 Instance.getTraceHandler().trace("Remote lib status: " + result[0]);
e6249b0f
NR
96 return result[0];
97 }
98
b0e88ebd 99 @Override
16a81ef7
NR
100 public Image getCover(final String luid) {
101 final Image[] result = new Image[1];
b0e88ebd 102
b9ce9cad
NR
103 try {
104 new ConnectActionClientObject(host, port, true) {
105 @Override
106 public void action(Version serverVersion) throws Exception {
416c54f8 107 Object rep = send(new Object[] { md5, "GET_COVER", luid });
16a81ef7 108 result[0] = (Image) rep;
b9ce9cad 109 }
b0e88ebd 110
b9ce9cad
NR
111 @Override
112 protected void onError(Exception e) {
113 Instance.getTraceHandler().error(e);
114 }
115 }.connect();
116 } catch (Exception e) {
117 Instance.getTraceHandler().error(e);
118 }
b0e88ebd 119
b9ce9cad 120 return result[0];
085a2f9a
NR
121 }
122
123 @Override
e1de8087 124 public Image getCustomSourceCover(final String source) {
3989dfc5
NR
125 return getCustomCover(source, "SOURCE");
126 }
127
128 @Override
129 public Image getCustomAuthorCover(final String author) {
130 return getCustomCover(author, "AUTHOR");
131 }
132
133 // type: "SOURCE" or "AUTHOR"
134 private Image getCustomCover(final String source, final String type) {
16a81ef7 135 final Image[] result = new Image[1];
b9ce9cad
NR
136
137 try {
138 new ConnectActionClientObject(host, port, true) {
139 @Override
140 public void action(Version serverVersion) throws Exception {
3989dfc5
NR
141 Object rep = send(new Object[] { md5, "GET_CUSTOM_COVER",
142 type, source });
16a81ef7 143 result[0] = (Image) rep;
b9ce9cad
NR
144 }
145
146 @Override
147 protected void onError(Exception e) {
148 Instance.getTraceHandler().error(e);
149 }
150 }.connect();
151 } catch (Exception e) {
152 Instance.getTraceHandler().error(e);
153 }
154
155 return result[0];
b0e88ebd 156 }
68e2c6d2
NR
157
158 @Override
ff05b828 159 public synchronized Story getStory(final String luid, Progress pg) {
b9ce9cad
NR
160 final Progress pgF = pg;
161 final Story[] result = new Story[1];
68e2c6d2 162
b9ce9cad
NR
163 try {
164 new ConnectActionClientObject(host, port, true) {
165 @Override
166 public void action(Version serverVersion) throws Exception {
167 Progress pg = pgF;
168 if (pg == null) {
169 pg = new Progress();
170 }
171
416c54f8 172 Object rep = send(new Object[] { md5, "GET_STORY", luid });
b9ce9cad
NR
173
174 MetaData meta = null;
175 if (rep instanceof MetaData) {
176 meta = (MetaData) rep;
177 if (meta.getWords() <= Integer.MAX_VALUE) {
178 pg.setMinMax(0, (int) meta.getWords());
179 }
180 }
181
182 List<Object> list = new ArrayList<Object>();
183 for (Object obj = send(null); obj != null; obj = send(null)) {
184 list.add(obj);
185 pg.add(1);
186 }
187
188 result[0] = RemoteLibraryServer.rebuildStory(list);
189 pg.done();
190 }
191
192 @Override
193 protected void onError(Exception e) {
194 Instance.getTraceHandler().error(e);
195 }
196 }.connect();
197 } catch (Exception e) {
198 Instance.getTraceHandler().error(e);
199 }
200
201 return result[0];
68e2c6d2
NR
202 }
203
204 @Override
b9ce9cad
NR
205 public synchronized Story save(final Story story, final String luid,
206 Progress pg) throws IOException {
0fa0fe95
NR
207 final String[] luidSaved = new String[1];
208 Progress pgSave = new Progress();
209 Progress pgRefresh = new Progress();
210 if (pg == null) {
211 pg = new Progress();
212 }
213
214 pg.setMinMax(0, 10);
215 pg.addProgress(pgSave, 9);
216 pg.addProgress(pgRefresh, 1);
217
218 final Progress pgF = pgSave;
b9ce9cad
NR
219
220 new ConnectActionClientObject(host, port, true) {
221 @Override
222 public void action(Version serverVersion) throws Exception {
223 Progress pg = pgF;
b9ce9cad
NR
224 if (story.getMeta().getWords() <= Integer.MAX_VALUE) {
225 pg.setMinMax(0, (int) story.getMeta().getWords());
226 }
227
416c54f8 228 send(new Object[] { md5, "SAVE_STORY", luid });
b9ce9cad
NR
229
230 List<Object> list = RemoteLibraryServer.breakStory(story);
231 for (Object obj : list) {
232 send(obj);
233 pg.add(1);
234 }
235
edf79e5e 236 luidSaved[0] = (String) send(null);
0fa0fe95 237
b9ce9cad
NR
238 pg.done();
239 }
240
241 @Override
242 protected void onError(Exception e) {
243 Instance.getTraceHandler().error(e);
244 }
245 }.connect();
085a2f9a
NR
246
247 // because the meta changed:
edf79e5e 248 MetaData meta = getInfo(luidSaved[0]);
efa3c511
NR
249 if (story.getMeta().getClass() != null) {
250 // If already available locally:
251 meta.setCover(story.getMeta().getCover());
252 } else {
253 // If required:
254 meta.setCover(getCover(meta.getLuid()));
255 }
edf79e5e 256 story.setMeta(meta);
0fa0fe95
NR
257
258 pg.done();
085a2f9a
NR
259
260 return story;
68e2c6d2
NR
261 }
262
263 @Override
b9ce9cad
NR
264 public synchronized void delete(final String luid) throws IOException {
265 new ConnectActionClientObject(host, port, true) {
266 @Override
267 public void action(Version serverVersion) throws Exception {
416c54f8 268 send(new Object[] { md5, "DELETE_STORY", luid });
b9ce9cad
NR
269 }
270
271 @Override
272 protected void onError(Exception e) {
273 Instance.getTraceHandler().error(e);
274 }
275 }.connect();
68e2c6d2
NR
276 }
277
278 @Override
b9ce9cad 279 public void setSourceCover(final String source, final String luid) {
3989dfc5
NR
280 setCover(source, luid, "SOURCE");
281 }
282
283 @Override
284 public void setAuthorCover(final String author, final String luid) {
285 setCover(author, luid, "AUTHOR");
286 }
287
288 // type = "SOURCE" | "AUTHOR"
289 private void setCover(final String value, final String luid,
290 final String type) {
b9ce9cad
NR
291 try {
292 new ConnectActionClientObject(host, port, true) {
293 @Override
294 public void action(Version serverVersion) throws Exception {
3989dfc5 295 send(new Object[] { md5, "SET_COVER", type, value, luid });
b9ce9cad
NR
296 }
297
298 @Override
299 protected void onError(Exception e) {
300 Instance.getTraceHandler().error(e);
301 }
302 }.connect();
303 } catch (IOException e) {
304 Instance.getTraceHandler().error(e);
edf79e5e
NR
305 }
306 }
307
308 @Override
309 // Could work (more slowly) without it
310 public Story imprt(final URL url, Progress pg) throws IOException {
00f6344a
NR
311 // Import the file locally if it is actually a file
312 if (url == null || url.getProtocol().equalsIgnoreCase("file")) {
313 return super.imprt(url, pg);
314 }
315
316 // Import it remotely if it is an URL
317
edf79e5e
NR
318 if (pg == null) {
319 pg = new Progress();
320 }
321
322 pg.setMinMax(0, 2);
323 Progress pgImprt = new Progress();
324 Progress pgGet = new Progress();
325 pg.addProgress(pgImprt, 1);
326 pg.addProgress(pgGet, 1);
327
328 final Progress pgF = pgImprt;
329 final String[] luid = new String[1];
330
331 try {
332 new ConnectActionClientObject(host, port, true) {
333 @Override
334 public void action(Version serverVersion) throws Exception {
335 Progress pg = pgF;
336
337 Object rep = send(new Object[] { md5, "IMPORT",
338 url.toString() });
339
340 while (true) {
341 if (!RemoteLibraryServer.updateProgress(pg, rep)) {
342 break;
343 }
344
345 rep = send(null);
346 }
347
348 pg.done();
349 luid[0] = (String) rep;
350 }
351
352 @Override
353 protected void onError(Exception e) {
354 Instance.getTraceHandler().error(e);
355 }
356 }.connect();
357 } catch (IOException e) {
358 Instance.getTraceHandler().error(e);
359 }
360
361 if (luid[0] == null) {
362 throw new IOException("Remote failure");
363 }
364
365 Story story = getStory(luid[0], pgGet);
366 pgGet.done();
367
368 pg.done();
369 return story;
370 }
371
372 @Override
373 // Could work (more slowly) without it
c8d48938
NR
374 protected synchronized void changeSTA(final String luid,
375 final String newSource, final String newTitle,
376 final String newAuthor, Progress pg) throws IOException {
edf79e5e
NR
377 final Progress pgF = pg == null ? new Progress() : pg;
378
379 try {
380 new ConnectActionClientObject(host, port, true) {
381 @Override
382 public void action(Version serverVersion) throws Exception {
383 Progress pg = pgF;
384
c8d48938
NR
385 Object rep = send(new Object[] { md5, "CHANGE_STA", luid,
386 newSource, newTitle, newAuthor });
edf79e5e
NR
387 while (true) {
388 if (!RemoteLibraryServer.updateProgress(pg, rep)) {
389 break;
390 }
391
392 rep = send(null);
393 }
394 }
395
396 @Override
397 protected void onError(Exception e) {
398 Instance.getTraceHandler().error(e);
399 }
400 }.connect();
401 } catch (IOException e) {
402 Instance.getTraceHandler().error(e);
b9ce9cad 403 }
68e2c6d2
NR
404 }
405
ff05b828 406 @Override
2249988a 407 public synchronized File getFile(final String luid, Progress pg) {
ff05b828
NR
408 throw new java.lang.InternalError(
409 "Operation not supportorted on remote Libraries");
410 }
411
468b960b
NR
412 /**
413 * Stop the server.
414 */
415 public void exit() {
416 try {
417 new ConnectActionClientObject(host, port, true) {
418 @Override
419 public void action(Version serverVersion) throws Exception {
420 send(new Object[] { md5, "EXIT" });
421 }
422
423 @Override
424 protected void onError(Exception e) {
425 Instance.getTraceHandler().error(e);
426 }
427 }.connect();
428 } catch (IOException e) {
429 Instance.getTraceHandler().error(e);
430 }
431 }
432
e272f05f
NR
433 @Override
434 public synchronized MetaData getInfo(String luid) {
435 List<MetaData> metas = getMetasList(luid, null);
436 if (!metas.isEmpty()) {
437 return metas.get(0);
438 }
439
440 return null;
441 }
442
14b57448 443 @Override
b9ce9cad 444 protected List<MetaData> getMetas(Progress pg) {
e272f05f
NR
445 return getMetasList("*", pg);
446 }
447
448 @Override
efa3c511
NR
449 protected void updateInfo(MetaData meta) {
450 // Will be taken care of directly server side
451 }
452
453 @Override
c8d48938 454 protected void invalidateInfo(String luid) {
efa3c511 455 // Will be taken care of directly server side
e272f05f
NR
456 }
457
458 // The following methods are only used by Save and Delete in BasicLibrary:
459
460 @Override
461 protected int getNextId() {
462 throw new java.lang.InternalError("Should not have been called");
463 }
464
465 @Override
466 protected void doDelete(String luid) throws IOException {
467 throw new java.lang.InternalError("Should not have been called");
468 }
469
470 @Override
471 protected Story doSave(Story story, Progress pg) throws IOException {
472 throw new java.lang.InternalError("Should not have been called");
473 }
474
475 //
476
477 /**
478 * Return the meta of the given story or a list of all known metas if the
479 * luid is "*".
9f51d8ab
NR
480 * <p>
481 * Will not get the covers.
e272f05f
NR
482 *
483 * @param luid
484 * the luid of the story or *
485 * @param pg
486 * the optional progress
487 *
488 *
489 * @return the metas
490 */
491 private List<MetaData> getMetasList(final String luid, Progress pg) {
b9ce9cad
NR
492 final Progress pgF = pg;
493 final List<MetaData> metas = new ArrayList<MetaData>();
74a40dfb 494
ff05b828 495 try {
62c63b07 496 new ConnectActionClientObject(host, port, true) {
ff05b828
NR
497 @Override
498 public void action(Version serverVersion) throws Exception {
b9ce9cad
NR
499 Progress pg = pgF;
500 if (pg == null) {
501 pg = new Progress();
851dd538 502 }
74a40dfb 503
e272f05f 504 Object rep = send(new Object[] { md5, "GET_METADATA", luid });
74a40dfb 505
b9ce9cad
NR
506 while (true) {
507 if (!RemoteLibraryServer.updateProgress(pg, rep)) {
508 break;
509 }
74a40dfb 510
b9ce9cad 511 rep = send(null);
ff05b828 512 }
851dd538 513
e272f05f
NR
514 if (rep instanceof MetaData[]) {
515 for (MetaData meta : (MetaData[]) rep) {
516 metas.add(meta);
517 }
518 } else if (rep != null) {
519 metas.add((MetaData) rep);
b9ce9cad 520 }
851dd538
NR
521 }
522
523 @Override
524 protected void onError(Exception e) {
525 Instance.getTraceHandler().error(e);
ff05b828
NR
526 }
527 }.connect();
ff05b828 528 } catch (Exception e) {
62c63b07 529 Instance.getTraceHandler().error(e);
ff05b828 530 }
b9ce9cad
NR
531
532 return metas;
533 }
b0e88ebd 534}