prepare new system for getting metas in libraries
[fanfix.git] / src / be / nikiroo / fanfix / library / CacheLibrary.java
1 package be.nikiroo.fanfix.library;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.net.URL;
6 import java.util.ArrayList;
7 import java.util.List;
8
9 import be.nikiroo.fanfix.Instance;
10 import be.nikiroo.fanfix.bundles.UiConfig;
11 import be.nikiroo.fanfix.bundles.UiConfigBundle;
12 import be.nikiroo.fanfix.data.MetaData;
13 import be.nikiroo.fanfix.data.Story;
14 import be.nikiroo.fanfix.output.BasicOutput.OutputType;
15 import be.nikiroo.utils.Image;
16 import be.nikiroo.utils.Progress;
17
18 /**
19 * This library will cache another pre-existing {@link BasicLibrary}.
20 *
21 * @author niki
22 */
23 public class CacheLibrary extends BasicLibrary {
24 private List<MetaData> metas;
25 private BasicLibrary lib;
26 private LocalLibrary cacheLib;
27
28 /**
29 * Create a cache library around the given one.
30 * <p>
31 * It will return the same result, but those will be saved to disk at the same
32 * time to be fetched quicker the next time.
33 *
34 * @param cacheDir the cache directory where to save the files to disk
35 * @param lib the original library to wrap
36 * @param config the configuration used to know which kind of default
37 * {@link OutputType} to use for images and non-images stories
38 */
39 public CacheLibrary(File cacheDir, BasicLibrary lib, UiConfigBundle config) {
40 this.cacheLib = new LocalLibrary(cacheDir, //
41 config.getString(UiConfig.GUI_NON_IMAGES_DOCUMENT_TYPE),
42 config.getString(UiConfig.GUI_IMAGES_DOCUMENT_TYPE), true);
43 this.lib = lib;
44 }
45
46 @Override
47 public String getLibraryName() {
48 return lib.getLibraryName();
49 }
50
51 @Override
52 public Status getStatus() {
53 return lib.getStatus();
54 }
55
56 @Override
57 protected List<MetaData> getMetas(Progress pg) throws IOException {
58 if (pg == null) {
59 pg = new Progress();
60 }
61
62 if (metas == null) {
63 metas = lib.getMetas(pg);
64 }
65
66 pg.done();
67 return new ArrayList<MetaData>(metas);
68 }
69
70 @Override
71 public synchronized MetaData getInfo(String luid) throws IOException {
72 MetaData info = cacheLib.getInfo(luid);
73 if (info == null) {
74 info = lib.getInfo(luid);
75 }
76
77 return info;
78 }
79
80 @Override
81 public synchronized Story getStory(String luid, MetaData meta, Progress pg)
82 throws IOException {
83 if (pg == null) {
84 pg = new Progress();
85 }
86
87 Progress pgImport = new Progress();
88 Progress pgGet = new Progress();
89
90 pg.setMinMax(0, 4);
91 pg.addProgress(pgImport, 3);
92 pg.addProgress(pgGet, 1);
93
94 if (!isCached(luid)) {
95 try {
96 cacheLib.imprt(lib, luid, pgImport);
97 updateInfo(cacheLib.getInfo(luid));
98 pgImport.done();
99 } catch (IOException e) {
100 Instance.getInstance().getTraceHandler().error(e);
101 }
102
103 pgImport.done();
104 pgGet.done();
105 }
106
107 String type = cacheLib.getOutputType(meta.isImageDocument());
108 MetaData cachedMeta = meta.clone();
109 cachedMeta.setType(type);
110
111 return cacheLib.getStory(luid, cachedMeta, pg);
112 }
113
114 @Override
115 public synchronized File getFile(final String luid, Progress pg)
116 throws IOException {
117 if (pg == null) {
118 pg = new Progress();
119 }
120
121 Progress pgGet = new Progress();
122 Progress pgRecall = new Progress();
123
124 pg.setMinMax(0, 5);
125 pg.addProgress(pgGet, 4);
126 pg.addProgress(pgRecall, 1);
127
128 if (!isCached(luid)) {
129 getStory(luid, pgGet);
130 pgGet.done();
131 }
132
133 File file = cacheLib.getFile(luid, pgRecall);
134 pgRecall.done();
135
136 pg.done();
137 return file;
138 }
139
140 @Override
141 public Image getCover(final String luid) throws IOException {
142 if (isCached(luid)) {
143 return cacheLib.getCover(luid);
144 }
145
146 // We could update the cache here, but it's not easy
147 return lib.getCover(luid);
148 }
149
150 @Override
151 public Image getSourceCover(String source) throws IOException {
152 Image custom = getCustomSourceCover(source);
153 if (custom != null) {
154 return custom;
155 }
156
157 Image cached = cacheLib.getSourceCover(source);
158 if (cached != null) {
159 return cached;
160 }
161
162 return lib.getSourceCover(source);
163 }
164
165 @Override
166 public Image getAuthorCover(String author) throws IOException {
167 Image custom = getCustomAuthorCover(author);
168 if (custom != null) {
169 return custom;
170 }
171
172 Image cached = cacheLib.getAuthorCover(author);
173 if (cached != null) {
174 return cached;
175 }
176
177 return lib.getAuthorCover(author);
178 }
179
180 @Override
181 public Image getCustomSourceCover(String source) throws IOException {
182 Image custom = cacheLib.getCustomSourceCover(source);
183 if (custom == null) {
184 custom = lib.getCustomSourceCover(source);
185 if (custom != null) {
186 cacheLib.setSourceCover(source, custom);
187 }
188 }
189
190 return custom;
191 }
192
193 @Override
194 public Image getCustomAuthorCover(String author) throws IOException {
195 Image custom = cacheLib.getCustomAuthorCover(author);
196 if (custom == null) {
197 custom = lib.getCustomAuthorCover(author);
198 if (custom != null) {
199 cacheLib.setAuthorCover(author, custom);
200 }
201 }
202
203 return custom;
204 }
205
206 @Override
207 public void setSourceCover(String source, String luid) throws IOException {
208 lib.setSourceCover(source, luid);
209 cacheLib.setSourceCover(source, getCover(luid));
210 }
211
212 @Override
213 public void setAuthorCover(String author, String luid) throws IOException {
214 lib.setAuthorCover(author, luid);
215 cacheLib.setAuthorCover(author, getCover(luid));
216 }
217
218 @Override
219 protected void updateInfo(MetaData meta) throws IOException {
220 if (meta != null && metas != null) {
221 boolean changed = false;
222 for (int i = 0; i < metas.size(); i++) {
223 if (metas.get(i).getLuid().equals(meta.getLuid())) {
224 metas.set(i, meta);
225 changed = true;
226 }
227 }
228
229 if (!changed) {
230 metas.add(meta);
231 }
232 }
233
234 cacheLib.updateInfo(meta);
235 lib.updateInfo(meta);
236 }
237
238 @Override
239 protected void invalidateInfo(String luid) {
240 if (luid == null) {
241 metas = null;
242 } else if (metas != null) {
243 for (int i = 0; i < metas.size(); i++) {
244 if (metas.get(i).getLuid().equals(luid)) {
245 metas.remove(i--);
246 }
247 }
248 }
249
250 cacheLib.invalidateInfo(luid);
251 lib.invalidateInfo(luid);
252 }
253
254 @Override
255 public synchronized Story save(Story story, String luid, Progress pg)
256 throws IOException {
257 Progress pgLib = new Progress();
258 Progress pgCacheLib = new Progress();
259
260 if (pg == null) {
261 pg = new Progress();
262 }
263
264 pg.setMinMax(0, 2);
265 pg.addProgress(pgLib, 1);
266 pg.addProgress(pgCacheLib, 1);
267
268 story = lib.save(story, luid, pgLib);
269 story = cacheLib.save(story, story.getMeta().getLuid(), pgCacheLib);
270
271 updateInfo(story.getMeta());
272
273 return story;
274 }
275
276 @Override
277 public synchronized void delete(String luid) throws IOException {
278 if (isCached(luid)) {
279 cacheLib.delete(luid);
280 }
281 lib.delete(luid);
282
283 invalidateInfo(luid);
284 }
285
286 @Override
287 protected synchronized void changeSTA(String luid, String newSource,
288 String newTitle, String newAuthor, Progress pg) throws IOException {
289 if (pg == null) {
290 pg = new Progress();
291 }
292
293 Progress pgCache = new Progress();
294 Progress pgOrig = new Progress();
295 pg.setMinMax(0, 2);
296 pg.addProgress(pgCache, 1);
297 pg.addProgress(pgOrig, 1);
298
299 MetaData meta = getInfo(luid);
300 if (meta == null) {
301 throw new IOException("Story not found: " + luid);
302 }
303
304 if (isCached(luid)) {
305 cacheLib.changeSTA(luid, newSource, newTitle, newAuthor, pgCache);
306 }
307 pgCache.done();
308
309 lib.changeSTA(luid, newSource, newTitle, newAuthor, pgOrig);
310 pgOrig.done();
311
312 meta.setSource(newSource);
313 meta.setTitle(newTitle);
314 meta.setAuthor(newAuthor);
315 pg.done();
316
317 invalidateInfo(luid);
318 }
319
320 /**
321 * Check if the {@link Story} denoted by this Library UID is present in the
322 * cache.
323 *
324 * @param luid
325 * the Library UID
326 *
327 * @return TRUE if it is
328 */
329 public boolean isCached(String luid) {
330 try {
331 return cacheLib.getInfo(luid) != null;
332 } catch (IOException e) {
333 return false;
334 }
335 }
336
337 /**
338 * Clear the {@link Story} from the cache.
339 * <p>
340 * The next time we try to retrieve the {@link Story}, it may be required to
341 * cache it again.
342 *
343 * @param luid
344 * the story to clear
345 *
346 * @throws IOException
347 * in case of I/O error
348 */
349 public void clearFromCache(String luid) throws IOException {
350 if (isCached(luid)) {
351 cacheLib.delete(luid);
352 }
353 }
354
355 @Override
356 public MetaData imprt(URL url, Progress pg) throws IOException {
357 if (pg == null) {
358 pg = new Progress();
359 }
360
361 Progress pgImprt = new Progress();
362 Progress pgCache = new Progress();
363 pg.setMinMax(0, 10);
364 pg.addProgress(pgImprt, 7);
365 pg.addProgress(pgCache, 3);
366
367 MetaData meta = lib.imprt(url, pgImprt);
368 updateInfo(meta);
369
370 clearFromCache(meta.getLuid());
371
372 pg.done();
373 return meta;
374 }
375
376 // All the following methods are only used by Save and Delete in
377 // BasicLibrary:
378
379 @Override
380 protected int getNextId() {
381 throw new java.lang.InternalError("Should not have been called");
382 }
383
384 @Override
385 protected void doDelete(String luid) throws IOException {
386 throw new java.lang.InternalError("Should not have been called");
387 }
388
389 @Override
390 protected Story doSave(Story story, Progress pg) throws IOException {
391 throw new java.lang.InternalError("Should not have been called");
392 }
393 }