1 package be
.nikiroo
.fanfix
.library
;
4 import java
.io
.IOException
;
6 import java
.util
.ArrayList
;
8 import java
.util
.TreeSet
;
10 import be
.nikiroo
.fanfix
.Instance
;
11 import be
.nikiroo
.fanfix
.bundles
.UiConfig
;
12 import be
.nikiroo
.fanfix
.bundles
.UiConfigBundle
;
13 import be
.nikiroo
.fanfix
.data
.MetaData
;
14 import be
.nikiroo
.fanfix
.data
.Story
;
15 import be
.nikiroo
.fanfix
.output
.BasicOutput
.OutputType
;
16 import be
.nikiroo
.utils
.Image
;
17 import be
.nikiroo
.utils
.Progress
;
20 * This library will cache another pre-existing {@link BasicLibrary}.
24 public class CacheLibrary
extends BasicLibrary
{
25 private List
<MetaData
> metasReal
;
26 private List
<MetaData
> metasMixed
;
27 private BasicLibrary lib
;
28 private LocalLibrary cacheLib
;
31 * Create a cache library around the given one.
33 * It will return the same result, but those will be saved to disk at the same
34 * time to be fetched quicker the next time.
36 * @param cacheDir the cache directory where to save the files to disk
37 * @param lib the original library to wrap
38 * @param config the configuration used to know which kind of default
39 * {@link OutputType} to use for images and non-images stories
41 public CacheLibrary(File cacheDir
, BasicLibrary lib
, UiConfigBundle config
) {
42 this.cacheLib
= new LocalLibrary(cacheDir
, //
43 config
.getString(UiConfig
.GUI_NON_IMAGES_DOCUMENT_TYPE
),
44 config
.getString(UiConfig
.GUI_IMAGES_DOCUMENT_TYPE
), true);
49 public String
getLibraryName() {
50 return lib
.getLibraryName();
54 public Status
getStatus() {
55 return lib
.getStatus();
59 protected synchronized List
<MetaData
> getMetas(Progress pg
) throws IOException
{
60 // We make sure that cached metas have precedence
66 if (metasMixed
== null) {
67 if (metasReal
== null) {
68 metasReal
= lib
.getMetas(pg
);
71 metasMixed
= new ArrayList
<MetaData
>();
72 TreeSet
<String
> cachedLuids
= new TreeSet
<String
>();
73 for (MetaData cachedMeta
: cacheLib
.getMetas(null)) {
74 metasMixed
.add(cachedMeta
);
75 cachedLuids
.add(cachedMeta
.getLuid());
77 for (MetaData realMeta
: metasReal
) {
78 if (!cachedLuids
.contains(realMeta
.getLuid())) {
79 metasMixed
.add(realMeta
);
85 return new ArrayList
<MetaData
>(metasMixed
);
89 public synchronized Story
getStory(String luid
, MetaData meta
, Progress pg
) throws IOException
{
94 Progress pgImport
= new Progress();
95 Progress pgGet
= new Progress();
98 pg
.addProgress(pgImport
, 3);
99 pg
.addProgress(pgGet
, 1);
101 if (!isCached(luid
)) {
103 cacheLib
.imprt(lib
, luid
, pgImport
);
104 updateMetaCache(metasMixed
, cacheLib
.getInfo(luid
));
106 } catch (IOException e
) {
107 Instance
.getInstance().getTraceHandler().error(e
);
114 String type
= cacheLib
.getOutputType(meta
.isImageDocument());
115 MetaData cachedMeta
= meta
.clone();
116 cachedMeta
.setType(type
);
118 return cacheLib
.getStory(luid
, cachedMeta
, pg
);
122 public synchronized File
getFile(final String luid
, Progress pg
) throws IOException
{
127 Progress pgGet
= new Progress();
128 Progress pgRecall
= new Progress();
131 pg
.addProgress(pgGet
, 4);
132 pg
.addProgress(pgRecall
, 1);
134 if (!isCached(luid
)) {
135 getStory(luid
, pgGet
);
139 File file
= cacheLib
.getFile(luid
, pgRecall
);
147 public Image
getCover(final String luid
) throws IOException
{
148 if (isCached(luid
)) {
149 return cacheLib
.getCover(luid
);
152 // We could update the cache here, but it's not easy
153 return lib
.getCover(luid
);
157 public Image
getSourceCover(String source
) throws IOException
{
158 Image custom
= getCustomSourceCover(source
);
159 if (custom
!= null) {
163 Image cached
= cacheLib
.getSourceCover(source
);
164 if (cached
!= null) {
168 return lib
.getSourceCover(source
);
172 public Image
getAuthorCover(String author
) throws IOException
{
173 Image custom
= getCustomAuthorCover(author
);
174 if (custom
!= null) {
178 Image cached
= cacheLib
.getAuthorCover(author
);
179 if (cached
!= null) {
183 return lib
.getAuthorCover(author
);
187 public Image
getCustomSourceCover(String source
) throws IOException
{
188 Image custom
= cacheLib
.getCustomSourceCover(source
);
189 if (custom
== null) {
190 custom
= lib
.getCustomSourceCover(source
);
191 if (custom
!= null) {
192 cacheLib
.setSourceCover(source
, custom
);
200 public Image
getCustomAuthorCover(String author
) throws IOException
{
201 Image custom
= cacheLib
.getCustomAuthorCover(author
);
202 if (custom
== null) {
203 custom
= lib
.getCustomAuthorCover(author
);
204 if (custom
!= null) {
205 cacheLib
.setAuthorCover(author
, custom
);
213 public void setSourceCover(String source
, String luid
) throws IOException
{
214 lib
.setSourceCover(source
, luid
);
215 cacheLib
.setSourceCover(source
, getCover(luid
));
219 public void setAuthorCover(String author
, String luid
) throws IOException
{
220 lib
.setAuthorCover(author
, luid
);
221 cacheLib
.setAuthorCover(author
, getCover(luid
));
225 * Invalidate the {@link Story} cache (when the content has changed, but we
226 * already have it) with the new given meta.
228 * <b>Make sure to always use {@link MetaData} from the cached library
229 * in priority, here.</b>
232 * the {@link Story} to clear from the cache
234 * @throws IOException
235 * in case of IOException
239 protected void updateInfo(MetaData meta
) throws IOException
{
240 throw new IOException(
241 "This method is not supported in a CacheLibrary, please use updateMetaCache");
244 // relplace the meta in Metas by Meta, add it if needed
245 // return TRUE = added
246 private boolean updateMetaCache(List
<MetaData
> metas
, MetaData meta
) {
247 if (meta
!= null && metas
!= null) {
248 boolean changed
= false;
249 for (int i
= 0; i
< metas
.size(); i
++) {
250 if (metas
.get(i
).getLuid().equals(meta
.getLuid())) {
266 protected void invalidateInfo(String luid
) {
271 invalidateInfo(metasReal
, luid
);
272 invalidateInfo(metasMixed
, luid
);
275 cacheLib
.invalidateInfo(luid
);
276 lib
.invalidateInfo(luid
);
279 // luid cannot be null
280 private void invalidateInfo(List
<MetaData
> metas
, String luid
) {
282 for (int i
= 0; i
< metas
.size(); i
++) {
283 if (metas
.get(i
).getLuid().equals(luid
)) {
291 public synchronized Story
save(Story story
, String luid
, Progress pg
) throws IOException
{
292 Progress pgLib
= new Progress();
293 Progress pgCacheLib
= new Progress();
300 pg
.addProgress(pgLib
, 1);
301 pg
.addProgress(pgCacheLib
, 1);
303 story
= lib
.save(story
, luid
, pgLib
);
304 updateMetaCache(metasReal
, story
.getMeta());
306 story
= cacheLib
.save(story
, story
.getMeta().getLuid(), pgCacheLib
);
307 updateMetaCache(metasMixed
, story
.getMeta());
313 public synchronized void delete(String luid
) throws IOException
{
314 if (isCached(luid
)) {
315 cacheLib
.delete(luid
);
319 invalidateInfo(luid
);
323 protected synchronized void changeSTA(String luid
, String newSource
, String newTitle
, String newAuthor
, Progress pg
)
329 Progress pgCache
= new Progress();
330 Progress pgOrig
= new Progress();
332 pg
.addProgress(pgCache
, 1);
333 pg
.addProgress(pgOrig
, 1);
335 MetaData meta
= getInfo(luid
);
337 throw new IOException("Story not found: " + luid
);
340 if (isCached(luid
)) {
341 cacheLib
.changeSTA(luid
, newSource
, newTitle
, newAuthor
, pgCache
);
345 lib
.changeSTA(luid
, newSource
, newTitle
, newAuthor
, pgOrig
);
348 meta
.setSource(newSource
);
349 meta
.setTitle(newTitle
);
350 meta
.setAuthor(newAuthor
);
353 if (isCached(luid
)) {
354 updateMetaCache(metasMixed
, meta
);
355 updateMetaCache(metasReal
, lib
.getInfo(luid
));
357 updateMetaCache(metasReal
, meta
);
362 public boolean isCached(String luid
) {
364 return cacheLib
.getInfo(luid
) != null;
365 } catch (IOException e
) {
371 public void clearFromCache(String luid
) throws IOException
{
372 if (isCached(luid
)) {
373 cacheLib
.delete(luid
);
378 public synchronized MetaData
imprt(URL url
, Progress pg
) throws IOException
{
383 Progress pgImprt
= new Progress();
384 Progress pgCache
= new Progress();
386 pg
.addProgress(pgImprt
, 7);
387 pg
.addProgress(pgCache
, 3);
389 MetaData meta
= lib
.imprt(url
, pgImprt
);
390 updateMetaCache(metasReal
, meta
);
392 clearFromCache(meta
.getLuid());
398 // All the following methods are only used by Save and Delete in
402 protected int getNextId() {
403 throw new java
.lang
.InternalError("Should not have been called");
407 protected void doDelete(String luid
) throws IOException
{
408 throw new java
.lang
.InternalError("Should not have been called");
412 protected Story
doSave(Story story
, Progress pg
) throws IOException
{
413 throw new java
.lang
.InternalError("Should not have been called");