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