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