X-Git-Url: http://git.nikiroo.be/?p=fanfix.git;a=blobdiff_plain;f=library%2FLocalLibrary.java;h=f655d4d03bb43b5df69d00fc8b30b2adbad6c113;hp=ffcd8af99d0a482b27e939435fbbd6548f32550d;hb=002972e9de731678035d56304d75a6d9e8233635;hpb=0fc81e6465aa9c1f1dfc19b532082220d609768a diff --git a/library/LocalLibrary.java b/library/LocalLibrary.java index ffcd8af..f655d4d 100644 --- a/library/LocalLibrary.java +++ b/library/LocalLibrary.java @@ -13,16 +13,17 @@ import java.util.Map; import be.nikiroo.fanfix.Instance; import be.nikiroo.fanfix.bundles.Config; +import be.nikiroo.fanfix.bundles.ConfigBundle; import be.nikiroo.fanfix.data.MetaData; import be.nikiroo.fanfix.data.Story; import be.nikiroo.fanfix.output.BasicOutput; import be.nikiroo.fanfix.output.BasicOutput.OutputType; import be.nikiroo.fanfix.output.InfoCover; import be.nikiroo.fanfix.supported.InfoReader; +import be.nikiroo.utils.HashUtils; import be.nikiroo.utils.IOUtils; import be.nikiroo.utils.Image; import be.nikiroo.utils.Progress; -import be.nikiroo.utils.StringUtils; /** * This {@link BasicLibrary} will store the stories locally on disk. @@ -31,6 +32,7 @@ import be.nikiroo.utils.StringUtils; */ public class LocalLibrary extends BasicLibrary { private int lastId; + private Object lock = new Object(); private Map stories; // Files: [ infoFile, TargetFile ] private Map sourceCovers; private Map authorCovers; @@ -44,11 +46,15 @@ public class LocalLibrary extends BasicLibrary { * * @param baseDir * the directory where to find the {@link Story} objects + * @param config + * the configuration used to know which kind of default + * {@link OutputType} to use for images and non-images stories */ - public LocalLibrary(File baseDir) { - this(baseDir, Instance.getConfig().getString( - Config.FILE_FORMAT_NON_IMAGES_DOCUMENT_TYPE), Instance.getConfig() - .getString(Config.FILE_FORMAT_IMAGES_DOCUMENT_TYPE), false); + public LocalLibrary(File baseDir, ConfigBundle config) { + this(baseDir, // + config.getString(Config.FILE_FORMAT_NON_IMAGES_DOCUMENT_TYPE), + config.getString(Config.FILE_FORMAT_IMAGES_DOCUMENT_TYPE), + false); } /** @@ -66,8 +72,9 @@ public class LocalLibrary extends BasicLibrary { */ public LocalLibrary(File baseDir, String text, String image, boolean defaultIsHtml) { - this(baseDir, OutputType.valueOfAllOkUC(text, - defaultIsHtml ? OutputType.HTML : OutputType.INFO_TEXT), + this(baseDir, + OutputType.valueOfAllOkUC(text, + defaultIsHtml ? OutputType.HTML : OutputType.INFO_TEXT), OutputType.valueOfAllOkUC(image, defaultIsHtml ? OutputType.HTML : OutputType.CBZ)); } @@ -101,22 +108,24 @@ public class LocalLibrary extends BasicLibrary { @Override public File getFile(String luid, Progress pg) throws IOException { - Instance.getTraceHandler().trace( + Instance.getInstance().getTraceHandler().trace( this.getClass().getSimpleName() + ": get file for " + luid); File file = null; String mess = "no file found for "; MetaData meta = getInfo(luid); - File[] files = getStories(pg).get(meta); - if (files != null) { - mess = "file retrieved for "; - file = files[1]; + if (meta != null) { + File[] files = getStories(pg).get(meta); + if (files != null) { + mess = "file retrieved for "; + file = files[1]; + } } - Instance.getTraceHandler().trace( - this.getClass().getSimpleName() + ": " + mess + luid + " (" - + meta.getTitle() + ")"); + Instance.getInstance().getTraceHandler() + .trace(this.getClass().getSimpleName() + ": " + mess + luid + + " (" + meta.getTitle() + ")"); return file; } @@ -137,7 +146,7 @@ public class LocalLibrary extends BasicLibrary { meta = InfoReader.readMeta(infoFile, true); return meta.getCover(); } catch (IOException e) { - Instance.getTraceHandler().error(e); + Instance.getInstance().getTraceHandler().error(e); } } } @@ -146,20 +155,25 @@ public class LocalLibrary extends BasicLibrary { } @Override - protected synchronized void updateInfo(MetaData meta) { + protected void updateInfo(MetaData meta) { invalidateInfo(); } @Override protected void invalidateInfo(String luid) { - stories = null; - sourceCovers = null; + synchronized (lock) { + stories = null; + sourceCovers = null; + } } @Override - protected synchronized int getNextId() { + protected String getNextId() { getStories(null); // make sure lastId is set - return ++lastId; + + synchronized (lock) { + return String.format("%03d", ++lastId); + } } @Override @@ -199,13 +213,13 @@ public class LocalLibrary extends BasicLibrary { // Maybe also adding some rollback cleanup if possible if (relatedFile.getName().endsWith(".info")) { try { - String name = relatedFile.getName().replaceFirst( - "\\.info$", ""); + String name = relatedFile.getName().replaceFirst("\\.info$", + ""); relatedFile.delete(); InfoCover.writeInfo(newDir, name, meta); relatedFile.getParentFile().delete(); } catch (IOException e) { - Instance.getTraceHandler().error(e); + Instance.getInstance().getTraceHandler().error(e); } } else { relatedFile.renameTo(new File(newDir, relatedFile.getName())); @@ -213,18 +227,22 @@ public class LocalLibrary extends BasicLibrary { } } - invalidateInfo(); + updateInfo(meta); } @Override - public synchronized Image getCustomSourceCover(String source) { - if (sourceCovers == null) { - sourceCovers = new HashMap(); + public Image getCustomSourceCover(String source) { + synchronized (lock) { + if (sourceCovers == null) { + sourceCovers = new HashMap(); + } } - Image img = sourceCovers.get(source); - if (img != null) { - return img; + synchronized (lock) { + Image img = sourceCovers.get(source); + if (img != null) { + return img; + } } File coverDir = getExpectedDir(source); @@ -235,33 +253,48 @@ public class LocalLibrary extends BasicLibrary { try { in = new FileInputStream(cover); try { - sourceCovers.put(source, new Image(in)); + synchronized (lock) { + Image img = new Image(in); + if (img.getSize() == 0) { + img.close(); + throw new IOException( + "Empty image not accepted"); + } + sourceCovers.put(source, img); + } } finally { in.close(); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { - Instance.getTraceHandler().error( - new IOException( + Instance.getInstance().getTraceHandler() + .error(new IOException( "Cannot load the existing custom source cover: " - + cover, e)); + + cover, + e)); } } } - return sourceCovers.get(source); + synchronized (lock) { + return sourceCovers.get(source); + } } @Override - public synchronized Image getCustomAuthorCover(String author) { - if (authorCovers == null) { - authorCovers = new HashMap(); + public Image getCustomAuthorCover(String author) { + synchronized (lock) { + if (authorCovers == null) { + authorCovers = new HashMap(); + } } - Image img = authorCovers.get(author); - if (img != null) { - return img; + synchronized (lock) { + Image img = authorCovers.get(author); + if (img != null) { + return img; + } } File cover = getAuthorCoverFile(author); @@ -270,21 +303,32 @@ public class LocalLibrary extends BasicLibrary { try { in = new FileInputStream(cover); try { - authorCovers.put(author, new Image(in)); + synchronized (lock) { + Image img = new Image(in); + if (img.getSize() == 0) { + img.close(); + throw new IOException( + "Empty image not accepted"); + } + authorCovers.put(author, img); + } } finally { in.close(); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { - Instance.getTraceHandler().error( - new IOException( + Instance.getInstance().getTraceHandler() + .error(new IOException( "Cannot load the existing custom author cover: " - + cover, e)); + + cover, + e)); } } - return authorCovers.get(author); + synchronized (lock) { + return authorCovers.get(author); + } } @Override @@ -305,17 +349,20 @@ public class LocalLibrary extends BasicLibrary { * @param coverImage * the cover image */ - synchronized void setSourceCover(String source, Image coverImage) { + void setSourceCover(String source, Image coverImage) { File dir = getExpectedDir(source); dir.mkdirs(); File cover = new File(dir, ".cover"); try { - Instance.getCache().saveAsImage(coverImage, cover, true); - if (sourceCovers != null) { - sourceCovers.put(source, coverImage); + Instance.getInstance().getCache().saveAsImage(coverImage, cover, + true); + synchronized (lock) { + if (sourceCovers != null) { + sourceCovers.put(source, coverImage); + } } } catch (IOException e) { - Instance.getTraceHandler().error(e); + Instance.getInstance().getTraceHandler().error(e); } } @@ -327,16 +374,19 @@ public class LocalLibrary extends BasicLibrary { * @param coverImage * the cover image */ - synchronized void setAuthorCover(String author, Image coverImage) { + void setAuthorCover(String author, Image coverImage) { File cover = getAuthorCoverFile(author); cover.getParentFile().mkdirs(); try { - Instance.getCache().saveAsImage(coverImage, cover, true); - if (authorCovers != null) { - authorCovers.put(author, coverImage); + Instance.getInstance().getCache().saveAsImage(coverImage, cover, + true); + synchronized (lock) { + if (authorCovers != null) { + authorCovers.put(author, coverImage); + } } } catch (IOException e) { - Instance.getTraceHandler().error(e); + Instance.getInstance().getTraceHandler().error(e); } } @@ -468,8 +518,8 @@ public class LocalLibrary extends BasicLibrary { if (title.length() > 40) { title = title.substring(0, 40); } - return new File(getExpectedDir(key.getSource()), key.getLuid() + "_" - + title); + return new File(getExpectedDir(key.getSource()), + key.getLuid() + "_" + title); } /** @@ -515,8 +565,9 @@ public class LocalLibrary extends BasicLibrary { */ private File getAuthorCoverFile(String author) { File aDir = new File(baseDir, "_AUTHORS"); - String hash = StringUtils.getMd5Hash(author); - String ext = Instance.getConfig().getString(Config.FILE_FORMAT_IMAGE_FORMAT_COVER); + String hash = HashUtils.md5(author); + String ext = Instance.getInstance().getConfig() + .getString(Config.FILE_FORMAT_IMAGE_FORMAT_COVER); return new File(aDir, hash + "." + ext.toLowerCase()); } @@ -561,14 +612,13 @@ public class LocalLibrary extends BasicLibrary { } } - String coverExt = "." - + Instance.getConfig().getString(Config.FILE_FORMAT_IMAGE_FORMAT_COVER) - .toLowerCase(); + String coverExt = "." + Instance.getInstance().getConfig() + .getString(Config.FILE_FORMAT_IMAGE_FORMAT_COVER).toLowerCase(); File coverFile = new File(path + coverExt); if (!coverFile.exists()) { - coverFile = new File(path.substring(0, - path.length() - fileExt.length()) - + coverExt); + coverFile = new File( + path.substring(0, path.length() - fileExt.length()) + + coverExt); } if (coverFile.exists()) { @@ -591,48 +641,79 @@ public class LocalLibrary extends BasicLibrary { * @return the list of stories (for each item, the first {@link File} is the * info file, the second file is the target {@link File}) */ - private synchronized Map getStories(Progress pg) { + private Map getStories(Progress pg) { if (pg == null) { pg = new Progress(); } else { pg.setMinMax(0, 100); } + Map stories = this.stories; if (stories == null) { - stories = new HashMap(); + stories = getStoriesDo(pg); + synchronized (lock) { + if (this.stories == null) + this.stories = stories; + else + stories = this.stories; + } + } - lastId = 0; + pg.done(); + return stories; - File[] dirs = baseDir.listFiles(new FileFilter() { - @Override - public boolean accept(File file) { - return file != null && file.isDirectory(); - } - }); + } - if (dirs != null) { - Progress pgDirs = new Progress(0, 100 * dirs.length); - pg.addProgress(pgDirs, 100); + /** + * Actually do the work of {@link LocalLibrary#getStories(Progress)} (i.e., + * do not retrieve the cache). + * + * @param pg + * the optional {@link Progress} + * + * @return the list of stories (for each item, the first {@link File} is the + * info file, the second file is the target {@link File}) + */ + private synchronized Map getStoriesDo(Progress pg) { + if (pg == null) { + pg = new Progress(); + } else { + pg.setMinMax(0, 100); + } - for (File dir : dirs) { - Progress pgFiles = new Progress(); - pgDirs.addProgress(pgFiles, 100); - pgDirs.setName("Loading from: " + dir.getName()); + Map stories = new HashMap(); - addToStories(pgFiles, dir); + File[] dirs = baseDir.listFiles(new FileFilter() { + @Override + public boolean accept(File file) { + return file != null && file.isDirectory(); + } + }); - pgFiles.setName(null); - } + if (dirs != null) { + Progress pgDirs = new Progress(0, 100 * dirs.length); + pg.addProgress(pgDirs, 100); + + for (File dir : dirs) { + Progress pgFiles = new Progress(); + pgDirs.addProgress(pgFiles, 100); + pgDirs.setName("Loading from: " + dir.getName()); - pgDirs.setName("Loading directories"); + addToStories(stories, pgFiles, dir); + + pgFiles.setName(null); } + + pgDirs.setName("Loading directories"); } pg.done(); + return stories; } - private void addToStories(Progress pgFiles, File dir) { + private void addToStories(Map stories, Progress pgFiles, + File dir) { File[] infoFilesAndSubdirs = dir.listFiles(new FileFilter() { @Override public boolean accept(File file) { @@ -649,16 +730,12 @@ public class LocalLibrary extends BasicLibrary { } for (File infoFileOrSubdir : infoFilesAndSubdirs) { - if (pgFiles != null) { - pgFiles.setName(infoFileOrSubdir.getName()); - } - if (infoFileOrSubdir.isDirectory()) { - addToStories(null, infoFileOrSubdir); + addToStories(stories, null, infoFileOrSubdir); } else { try { - MetaData meta = InfoReader - .readMeta(infoFileOrSubdir, false); + MetaData meta = InfoReader.readMeta(infoFileOrSubdir, + false); try { int id = Integer.parseInt(meta.getLuid()); if (id > lastId) { @@ -675,7 +752,7 @@ public class LocalLibrary extends BasicLibrary { } catch (IOException e) { // We should not have not-supported files in the // library - Instance.getTraceHandler().error( + Instance.getInstance().getTraceHandler().error( new IOException("Cannot load file from library: " + infoFileOrSubdir, e)); }