allow getMetas without synchronized
authorNiki Roo <niki@nikiroo.be>
Sat, 18 Apr 2020 20:55:16 +0000 (22:55 +0200)
committerNiki Roo <niki@nikiroo.be>
Sat, 18 Apr 2020 20:55:16 +0000 (22:55 +0200)
library/BasicLibrary.java
library/CacheLibrary.java
library/LocalLibrary.java
library/RemoteLibrary.java

index 7f286079ed1fe87c88f2ec798a85c26774950089..586c4ef17e11ff4d8c7eefa1cf6c689dac71ce59 100644 (file)
@@ -98,7 +98,7 @@ abstract public class BasicLibrary {
         * Do <b>NOT</b> alter this file.
         * 
         * @param luid
-        *            the Library UID of the story
+        *            the Library UID of the story, can be NULL
         * @param pg
         *            the optional {@link Progress}
         * 
@@ -123,12 +123,12 @@ abstract public class BasicLibrary {
        public abstract Image getCover(String luid) throws IOException;
 
        // TODO: ensure it is the main used interface
-       public synchronized MetaResultList getList(Progress pg) throws IOException {
+       public MetaResultList getList(Progress pg) throws IOException {
                return new MetaResultList(getMetas(pg));
        }
-       
-       //TODO: make something for (normal and custom) not-story covers
-       
+
+       // TODO: make something for (normal and custom) not-story covers
+
        /**
         * Return the cover image associated to this source.
         * <p>
@@ -338,14 +338,14 @@ abstract public class BasicLibrary {
         * @param pg
         *            the optional progress reporter
         */
-       public synchronized void refresh(Progress pg) {
+       public void refresh(Progress pg) {
                try {
                        getMetas(pg);
                } catch (IOException e) {
                        // We will let it fail later
                }
        }
-       
+
        /**
         * Check if the {@link Story} denoted by this Library UID is present in the
         * cache (if we have no cache, we default to </t>true</tt>).
@@ -359,7 +359,7 @@ abstract public class BasicLibrary {
                // By default, everything is cached
                return true;
        }
-       
+
        /**
         * Clear the {@link Story} from the cache, if needed.
         * <p>
@@ -384,7 +384,7 @@ abstract public class BasicLibrary {
         * @throws IOException
         *             in case of IOException
         */
-       public synchronized List<String> getSources() throws IOException {
+       public List<String> getSources() throws IOException {
                List<String> list = new ArrayList<String>();
                for (MetaData meta : getMetas(null)) {
                        String storySource = meta.getSource();
@@ -414,8 +414,7 @@ abstract public class BasicLibrary {
         * @throws IOException
         *             in case of IOException
         */
-       public synchronized Map<String, List<String>> getSourcesGrouped()
-                       throws IOException {
+       public Map<String, List<String>> getSourcesGrouped() throws IOException {
                Map<String, List<String>> map = new TreeMap<String, List<String>>();
                for (String source : getSources()) {
                        String name;
@@ -450,7 +449,7 @@ abstract public class BasicLibrary {
         * @throws IOException
         *             in case of IOException
         */
-       public synchronized List<String> getAuthors() throws IOException {
+       public List<String> getAuthors() throws IOException {
                List<String> list = new ArrayList<String>();
                for (MetaData meta : getMetas(null)) {
                        String storyAuthor = meta.getAuthor();
@@ -606,14 +605,14 @@ abstract public class BasicLibrary {
         * cover image <b>MAY</b> not be included.
         * 
         * @param luid
-        *            the Library UID of the story
+        *            the Library UID of the story, can be NULL
         * 
-        * @return the corresponding {@link Story}
+        * @return the corresponding {@link Story} or NULL if not found
         * 
         * @throws IOException
         *             in case of IOException
         */
-       public synchronized MetaData getInfo(String luid) throws IOException {
+       public MetaData getInfo(String luid) throws IOException {
                if (luid != null) {
                        for (MetaData meta : getMetas(null)) {
                                if (luid.equals(meta.getLuid())) {
@@ -668,6 +667,8 @@ abstract public class BasicLibrary {
         * Retrieve a specific {@link Story}.
         * 
         * @param luid
+        *            the LUID of the story
+        * @param meta
         *            the meta of the story
         * @param pg
         *            the optional progress reporter
@@ -677,8 +678,7 @@ abstract public class BasicLibrary {
         * @throws IOException
         *             in case of IOException
         */
-       public synchronized Story getStory(String luid,
-                       @SuppressWarnings("javadoc") MetaData meta, Progress pg)
+       public synchronized Story getStory(String luid, MetaData meta, Progress pg)
                        throws IOException {
 
                if (pg == null) {
@@ -693,12 +693,21 @@ abstract public class BasicLibrary {
                pg.addProgress(pgProcess, 1);
 
                Story story = null;
-               File file = getFile(luid, pgGet);
+               File file = null;
+
+               if (luid != null && meta != null) {
+                       file = getFile(luid, pgGet);
+               }
+
                pgGet.done();
                try {
-                       SupportType type = SupportType.valueOfAllOkUC(meta.getType());
-                       URL url = file.toURI().toURL();
-                       if (type != null) {
+                       if (file != null) {
+                               SupportType type = SupportType.valueOfAllOkUC(meta.getType());
+                               if (type == null) {
+                                       throw new IOException("Unknown type: " + meta.getType());
+                               }
+
+                               URL url = file.toURI().toURL();
                                story = BasicSupport.getSupport(type, url) //
                                                .process(pgProcess);
 
@@ -706,15 +715,13 @@ abstract public class BasicLibrary {
                                meta.setCover(story.getMeta().getCover());
                                meta.setResume(story.getMeta().getResume());
                                story.setMeta(meta);
-                               //
-                       } else {
-                               throw new IOException("Unknown type: " + meta.getType());
                        }
                } catch (IOException e) {
-                       // We should not have not-supported files in the
-                       // library
-                       Instance.getInstance().getTraceHandler().error(new IOException(
-                                       String.format("Cannot load file of type '%s' from library: %s", meta.getType(), file), e));
+                       // We should not have not-supported files in the library
+                       Instance.getInstance().getTraceHandler()
+                                       .error(new IOException(String.format(
+                                                       "Cannot load file of type '%s' from library: %s",
+                                                       meta.getType(), file), e));
                } finally {
                        pgProcess.done();
                        pg.done();
@@ -876,15 +883,16 @@ abstract public class BasicLibrary {
                if (pg == null) {
                        pg = new Progress();
                }
-               
-               Instance.getInstance().getTraceHandler().trace(this.getClass().getSimpleName() + ": saving story " + luid);
+
+               Instance.getInstance().getTraceHandler().trace(
+                               this.getClass().getSimpleName() + ": saving story " + luid);
 
                // Do not change the original metadata, but change the original story
                MetaData meta = story.getMeta().clone();
                story.setMeta(meta);
 
                pg.setName("Saving story");
-               
+
                if (luid == null || luid.isEmpty()) {
                        meta.setLuid(String.format("%03d", getNextId()));
                } else {
@@ -900,7 +908,8 @@ abstract public class BasicLibrary {
                updateInfo(story.getMeta());
 
                Instance.getInstance().getTraceHandler()
-                               .trace(this.getClass().getSimpleName() + ": story saved (" + luid + ")");
+                               .trace(this.getClass().getSimpleName() + ": story saved ("
+                                               + luid + ")");
 
                pg.setName(meta.getTitle());
                pg.done();
@@ -917,14 +926,15 @@ abstract public class BasicLibrary {
         *             in case of I/O error
         */
        public synchronized void delete(String luid) throws IOException {
-               Instance.getInstance().getTraceHandler().trace(this.getClass().getSimpleName() + ": deleting story " + luid);
+               Instance.getInstance().getTraceHandler().trace(
+                               this.getClass().getSimpleName() + ": deleting story " + luid);
 
                doDelete(luid);
                invalidateInfo(luid);
 
                Instance.getInstance().getTraceHandler()
-                               .trace(this.getClass().getSimpleName() + ": story deleted (" + luid
-                                               + ")");
+                               .trace(this.getClass().getSimpleName() + ": story deleted ("
+                                               + luid + ")");
        }
 
        /**
index 694f9ec267501d546ba8b44413cfeb346ef8963d..23f19a9ed323de88cb2202c6cde7462bf53219de 100644 (file)
@@ -24,21 +24,27 @@ import be.nikiroo.utils.Progress;
 public class CacheLibrary extends BasicLibrary {
        private List<MetaData> metasReal;
        private List<MetaData> metasMixed;
+       private Object metasLock = new Object();
+
        private BasicLibrary lib;
        private LocalLibrary cacheLib;
 
        /**
         * Create a cache library around the given one.
         * <p>
-        * It will return the same result, but those will be saved to disk at the same
-        * time to be fetched quicker the next time.
+        * It will return the same result, but those will be saved to disk at the
+        * same time to be fetched quicker the next time.
         * 
-        * @param cacheDir the cache directory where to save the files to disk
-        * @param lib      the original library to wrap
-        * @param config   the configuration used to know which kind of default
-        *                 {@link OutputType} to use for images and non-images stories
+        * @param cacheDir
+        *            the cache directory where to save the files to disk
+        * @param lib
+        *            the original library to wrap
+        * @param config
+        *            the configuration used to know which kind of default
+        *            {@link OutputType} to use for images and non-images stories
         */
-       public CacheLibrary(File cacheDir, BasicLibrary lib, UiConfigBundle config) {
+       public CacheLibrary(File cacheDir, BasicLibrary lib,
+                       UiConfigBundle config) {
                this.cacheLib = new LocalLibrary(cacheDir, //
                                config.getString(UiConfig.GUI_NON_IMAGES_DOCUMENT_TYPE),
                                config.getString(UiConfig.GUI_IMAGES_DOCUMENT_TYPE), true);
@@ -56,27 +62,28 @@ public class CacheLibrary extends BasicLibrary {
        }
 
        @Override
-       protected synchronized List<MetaData> getMetas(Progress pg) throws IOException {
-               // We make sure that cached metas have precedence
-
+       protected List<MetaData> getMetas(Progress pg) throws IOException {
                if (pg == null) {
                        pg = new Progress();
                }
 
-               if (metasMixed == null) {
-                       if (metasReal == null) {
-                               metasReal = lib.getMetas(pg);
-                       }
-                       
-                       metasMixed = new ArrayList<MetaData>();
-                       TreeSet<String> cachedLuids = new TreeSet<String>();
-                       for (MetaData cachedMeta : cacheLib.getMetas(null)) {
-                               metasMixed.add(cachedMeta);
-                               cachedLuids.add(cachedMeta.getLuid());
-                       }
-                       for (MetaData realMeta : metasReal) {
-                               if (!cachedLuids.contains(realMeta.getLuid())) {
-                                       metasMixed.add(realMeta);
+               synchronized (metasLock) {
+                       // We make sure that cached metas have precedence
+                       if (metasMixed == null) {
+                               if (metasReal == null) {
+                                       metasReal = lib.getMetas(pg);
+                               }
+
+                               metasMixed = new ArrayList<MetaData>();
+                               TreeSet<String> cachedLuids = new TreeSet<String>();
+                               for (MetaData cachedMeta : cacheLib.getMetas(null)) {
+                                       metasMixed.add(cachedMeta);
+                                       cachedLuids.add(cachedMeta.getLuid());
+                               }
+                               for (MetaData realMeta : metasReal) {
+                                       if (!cachedLuids.contains(realMeta.getLuid())) {
+                                               metasMixed.add(realMeta);
+                                       }
                                }
                        }
                }
@@ -86,7 +93,8 @@ public class CacheLibrary extends BasicLibrary {
        }
 
        @Override
-       public synchronized Story getStory(String luid, MetaData meta, Progress pg) throws IOException {
+       public synchronized Story getStory(String luid, MetaData meta, Progress pg)
+                       throws IOException {
                if (pg == null) {
                        pg = new Progress();
                }
@@ -119,7 +127,8 @@ public class CacheLibrary extends BasicLibrary {
        }
 
        @Override
-       public synchronized File getFile(final String luid, Progress pg) throws IOException {
+       public synchronized File getFile(final String luid, Progress pg)
+                       throws IOException {
                if (pg == null) {
                        pg = new Progress();
                }
@@ -225,8 +234,8 @@ public class CacheLibrary extends BasicLibrary {
         * Invalidate the {@link Story} cache (when the content has changed, but we
         * already have it) with the new given meta.
         * <p>
-        * <b>Make sure to always use {@link MetaData} from the cached library 
-        * in priority, here.</b>
+        * <b>Make sure to always use {@link MetaData} from the cached library in
+        * priority, here.</b>
         * 
         * @param meta
         *            the {@link Story} to clear from the cache
@@ -240,33 +249,37 @@ public class CacheLibrary extends BasicLibrary {
                throw new IOException(
                                "This method is not supported in a CacheLibrary, please use updateMetaCache");
        }
-       
+
        // relplace the meta in Metas by Meta, add it if needed
        // return TRUE = added
        private boolean updateMetaCache(List<MetaData> metas, MetaData meta) {
                if (meta != null && metas != null) {
-                       boolean changed = false;
-                       for (int i = 0; i < metas.size(); i++) {
-                               if (metas.get(i).getLuid().equals(meta.getLuid())) {
-                                       metas.set(i, meta);
-                                       changed = true;
+                       synchronized (metasLock) {
+                               boolean changed = false;
+                               for (int i = 0; i < metas.size(); i++) {
+                                       if (metas.get(i).getLuid().equals(meta.getLuid())) {
+                                               metas.set(i, meta);
+                                               changed = true;
+                                       }
                                }
-                       }
 
-                       if (!changed) {
-                               metas.add(meta);
-                               return true;
+                               if (!changed) {
+                                       metas.add(meta);
+                                       return true;
+                               }
                        }
                }
-               
+
                return false;
        }
 
        @Override
        protected void invalidateInfo(String luid) {
                if (luid == null) {
-                       metasReal = null;
-                       metasMixed = null;
+                       synchronized (metasLock) {
+                               metasReal = null;
+                               metasMixed = null;
+                       }
                } else {
                        invalidateInfo(metasReal, luid);
                        invalidateInfo(metasMixed, luid);
@@ -279,16 +292,19 @@ public class CacheLibrary extends BasicLibrary {
        // luid cannot be null
        private void invalidateInfo(List<MetaData> metas, String luid) {
                if (metas != null) {
-                       for (int i = 0; i < metas.size(); i++) {
-                               if (metas.get(i).getLuid().equals(luid)) {
-                                       metas.remove(i--);
+                       synchronized (metasLock) {
+                               for (int i = 0; i < metas.size(); i++) {
+                                       if (metas.get(i).getLuid().equals(luid)) {
+                                               metas.remove(i--);
+                                       }
                                }
                        }
                }
        }
 
        @Override
-       public synchronized Story save(Story story, String luid, Progress pg) throws IOException {
+       public synchronized Story save(Story story, String luid, Progress pg)
+                       throws IOException {
                Progress pgLib = new Progress();
                Progress pgCacheLib = new Progress();
 
@@ -302,7 +318,7 @@ public class CacheLibrary extends BasicLibrary {
 
                story = lib.save(story, luid, pgLib);
                updateMetaCache(metasReal, story.getMeta());
-               
+
                story = cacheLib.save(story, story.getMeta().getLuid(), pgCacheLib);
                updateMetaCache(metasMixed, story.getMeta());
 
@@ -310,7 +326,7 @@ public class CacheLibrary extends BasicLibrary {
        }
 
        @Override
-       public synchronized void delete(String luid) throws IOException {
+       public void delete(String luid) throws IOException {
                if (isCached(luid)) {
                        cacheLib.delete(luid);
                }
@@ -320,8 +336,8 @@ public class CacheLibrary extends BasicLibrary {
        }
 
        @Override
-       protected synchronized void changeSTA(String luid, String newSource, String newTitle, String newAuthor, Progress pg)
-                       throws IOException {
+       protected synchronized void changeSTA(String luid, String newSource,
+                       String newTitle, String newAuthor, Progress pg) throws IOException {
                if (pg == null) {
                        pg = new Progress();
                }
@@ -375,7 +391,7 @@ public class CacheLibrary extends BasicLibrary {
        }
 
        @Override
-       public synchronized MetaData imprt(URL url, Progress pg) throws IOException {
+       public MetaData imprt(URL url, Progress pg) throws IOException {
                if (pg == null) {
                        pg = new Progress();
                }
@@ -388,7 +404,10 @@ public class CacheLibrary extends BasicLibrary {
 
                MetaData meta = lib.imprt(url, pgImprt);
                updateMetaCache(metasReal, meta);
-               metasMixed = null;
+               synchronized (metasLock) {
+                       metasMixed = null;
+               }
+
                clearFromCache(meta.getLuid());
 
                pg.done();
index 80d216b84c216fd32a5dc8cf26f9e4dc2a28353c..3cf5a25bc232baddd6ed34df9faabbaa3d82281f 100644 (file)
@@ -14,7 +14,6 @@ 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.bundles.UiConfigBundle;
 import be.nikiroo.fanfix.data.MetaData;
 import be.nikiroo.fanfix.data.Story;
 import be.nikiroo.fanfix.output.BasicOutput;
@@ -33,6 +32,7 @@ import be.nikiroo.utils.StringUtils;
  */
 public class LocalLibrary extends BasicLibrary {
        private int lastId;
+       private Object lock = new Object();
        private Map<MetaData, File[]> stories; // Files: [ infoFile, TargetFile ]
        private Map<String, Image> sourceCovers;
        private Map<String, Image> authorCovers;
@@ -44,14 +44,17 @@ public class LocalLibrary extends BasicLibrary {
        /**
         * Create a new {@link LocalLibrary} with the given back-end directory.
         * 
-        * @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
+        * @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, ConfigBundle config) {
                this(baseDir, //
                                config.getString(Config.FILE_FORMAT_NON_IMAGES_DOCUMENT_TYPE),
-                               config.getString(Config.FILE_FORMAT_IMAGES_DOCUMENT_TYPE), false);
+                               config.getString(Config.FILE_FORMAT_IMAGES_DOCUMENT_TYPE),
+                               false);
        }
 
        /**
@@ -69,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));
        }
@@ -98,26 +102,30 @@ public class LocalLibrary extends BasicLibrary {
        }
 
        @Override
-       protected synchronized List<MetaData> getMetas(Progress pg) {
+       protected List<MetaData> getMetas(Progress pg) {
                return new ArrayList<MetaData>(getStories(pg).keySet());
        }
 
        @Override
        public File getFile(String luid, Progress pg) throws IOException {
-               Instance.getInstance().getTraceHandler().trace(this.getClass().getSimpleName() + ": get file for " + luid);
+               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.getInstance().getTraceHandler()
-                               .trace(this.getClass().getSimpleName() + ": " + mess + luid + " (" + meta.getTitle() + ")");
+                               .trace(this.getClass().getSimpleName() + ": " + mess + luid
+                                               + " (" + meta.getTitle() + ")");
 
                return file;
        }
@@ -147,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 int getNextId() {
                getStories(null); // make sure lastId is set
-               return ++lastId;
+
+               synchronized (lock) {
+                       return ++lastId;
+               }
        }
 
        @Override
@@ -200,8 +213,8 @@ 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();
@@ -218,14 +231,18 @@ public class LocalLibrary extends BasicLibrary {
        }
 
        @Override
-       public synchronized Image getCustomSourceCover(String source) {
-               if (sourceCovers == null) {
-                       sourceCovers = new HashMap<String, Image>();
+       public Image getCustomSourceCover(String source) {
+               synchronized (lock) {
+                       if (sourceCovers == null) {
+                               sourceCovers = new HashMap<String, Image>();
+                       }
                }
 
-               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);
@@ -236,7 +253,9 @@ public class LocalLibrary extends BasicLibrary {
                                try {
                                        in = new FileInputStream(cover);
                                        try {
-                                               sourceCovers.put(source, new Image(in));
+                                               synchronized (lock) {
+                                                       sourceCovers.put(source, new Image(in));
+                                               }
                                        } finally {
                                                in.close();
                                        }
@@ -244,23 +263,32 @@ public class LocalLibrary extends BasicLibrary {
                                        e.printStackTrace();
                                } catch (IOException e) {
                                        Instance.getInstance().getTraceHandler()
-                                                       .error(new IOException("Cannot load the existing custom source cover: " + cover, e));
+                                                       .error(new IOException(
+                                                                       "Cannot load the existing custom source cover: "
+                                                                                       + 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<String, Image>();
+       public Image getCustomAuthorCover(String author) {
+               synchronized (lock) {
+                       if (authorCovers == null) {
+                               authorCovers = new HashMap<String, Image>();
+                       }
                }
 
-               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);
@@ -269,7 +297,9 @@ public class LocalLibrary extends BasicLibrary {
                        try {
                                in = new FileInputStream(cover);
                                try {
-                                       authorCovers.put(author, new Image(in));
+                                       synchronized (lock) {
+                                               authorCovers.put(author, new Image(in));
+                                       }
                                } finally {
                                        in.close();
                                }
@@ -277,11 +307,16 @@ public class LocalLibrary extends BasicLibrary {
                                e.printStackTrace();
                        } catch (IOException e) {
                                Instance.getInstance().getTraceHandler()
-                                               .error(new IOException("Cannot load the existing custom author cover: " + cover, e));
+                                               .error(new IOException(
+                                                               "Cannot load the existing custom author cover: "
+                                                                               + cover,
+                                                               e));
                        }
                }
 
-               return authorCovers.get(author);
+               synchronized (lock) {
+                       return authorCovers.get(author);
+               }
        }
 
        @Override
@@ -302,14 +337,17 @@ 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.getInstance().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.getInstance().getTraceHandler().error(e);
@@ -324,13 +362,16 @@ 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.getInstance().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.getInstance().getTraceHandler().error(e);
@@ -465,8 +506,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);
        }
 
        /**
@@ -513,7 +554,8 @@ public class LocalLibrary extends BasicLibrary {
        private File getAuthorCoverFile(String author) {
                File aDir = new File(baseDir, "_AUTHORS");
                String hash = StringUtils.getMd5Hash(author);
-               String ext = Instance.getInstance().getConfig().getString(Config.FILE_FORMAT_IMAGE_FORMAT_COVER);
+               String ext = Instance.getInstance().getConfig()
+                               .getString(Config.FILE_FORMAT_IMAGE_FORMAT_COVER);
                return new File(aDir, hash + "." + ext.toLowerCase());
        }
 
@@ -558,13 +600,13 @@ public class LocalLibrary extends BasicLibrary {
                        }
                }
 
-               String coverExt = "."
-                               + Instance.getInstance().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()) {
@@ -587,48 +629,76 @@ 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<MetaData, File[]> getStories(Progress pg) {
+       private Map<MetaData, File[]> getStories(Progress pg) {
                if (pg == null) {
                        pg = new Progress();
                } else {
                        pg.setMinMax(0, 100);
                }
 
-               if (stories == null) {
-                       stories = new HashMap<MetaData, File[]>();
+               Map<MetaData, File[]> stories = this.stories;
+               synchronized (lock) {
+                       if (stories == null) {
+                               stories = getStoriesDo(pg);
+                               this.stories = 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<MetaData, File[]> 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<MetaData, File[]> stories = new HashMap<MetaData, File[]>();
 
-                                       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);
 
-                               pgDirs.setName("Loading directories");
+                       for (File dir : dirs) {
+                               Progress pgFiles = new Progress();
+                               pgDirs.addProgress(pgFiles, 100);
+                               pgDirs.setName("Loading from: " + dir.getName());
+
+                               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<MetaData, File[]> stories, Progress pgFiles,
+                       File dir) {
                File[] infoFilesAndSubdirs = dir.listFiles(new FileFilter() {
                        @Override
                        public boolean accept(File file) {
@@ -650,11 +720,11 @@ public class LocalLibrary extends BasicLibrary {
                        }
 
                        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) {
@@ -671,8 +741,9 @@ public class LocalLibrary extends BasicLibrary {
                                } catch (IOException e) {
                                        // We should not have not-supported files in the
                                        // library
-                                       Instance.getInstance().getTraceHandler()
-                                                       .error(new IOException("Cannot load file from library: " + infoFileOrSubdir, e));
+                                       Instance.getInstance().getTraceHandler().error(
+                                                       new IOException("Cannot load file from library: "
+                                                                       + infoFileOrSubdir, e));
                                }
                        }
 
index 65be7b1759e4893b2412f2c74cc00c0b3a95a2a7..bbe772a8c90168c658fa985461e92c58f13bb8d0 100644 (file)
@@ -426,7 +426,7 @@ public class RemoteLibrary extends BasicLibrary {
        }
 
        @Override
-       public synchronized File getFile(final String luid, Progress pg) {
+       public File getFile(final String luid, Progress pg) {
                throw new java.lang.InternalError(
                                "Operation not supportorted on remote Libraries");
        }
@@ -449,7 +449,7 @@ public class RemoteLibrary extends BasicLibrary {
        }
 
        @Override
-       public synchronized MetaData getInfo(String luid) throws IOException {
+       public MetaData getInfo(String luid) throws IOException {
                List<MetaData> metas = getMetasList(luid, null);
                if (!metas.isEmpty()) {
                        return metas.get(0);
@@ -459,7 +459,7 @@ public class RemoteLibrary extends BasicLibrary {
        }
 
        @Override
-       protected synchronized List<MetaData> getMetas(Progress pg) throws IOException {
+       protected List<MetaData> getMetas(Progress pg) throws IOException {
                return getMetasList("*", pg);
        }