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

index 215bd1a7d1b466b68180580e16d975187119090e..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,7 +123,7 @@ 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));
        }
 
@@ -338,7 +338,7 @@ 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) {
@@ -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,13 +715,9 @@ 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
+                       // 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",
index 56558452ea47a11a33250ca94cdd61fb1b01012e..23f19a9ed323de88cb2202c6cde7462bf53219de 100644 (file)
@@ -24,6 +24,8 @@ 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;
 
@@ -60,28 +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);
-                       }
+               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);
+                               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);
+                                       }
                                }
                        }
                }
@@ -252,17 +254,19 @@ public class CacheLibrary extends BasicLibrary {
        // 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;
+                               }
                        }
                }
 
@@ -272,8 +276,10 @@ public class CacheLibrary extends BasicLibrary {
        @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);
@@ -286,9 +292,11 @@ 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--);
+                                       }
                                }
                        }
                }
@@ -318,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);
                }
@@ -383,8 +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();
                }
@@ -397,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 0300b9e4ec1fd6fcb028e576d4d0cc29b9e0e2ea..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;
@@ -102,7 +102,7 @@ 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());
        }
 
@@ -115,10 +115,12 @@ public class LocalLibrary extends BasicLibrary {
                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()
@@ -153,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
@@ -224,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);
@@ -242,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();
                                        }
@@ -258,18 +271,24 @@ public class LocalLibrary extends BasicLibrary {
                        }
                }
 
-               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);
@@ -278,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();
                                }
@@ -293,7 +314,9 @@ public class LocalLibrary extends BasicLibrary {
                        }
                }
 
-               return authorCovers.get(author);
+               synchronized (lock) {
+                       return authorCovers.get(author);
+               }
        }
 
        @Override
@@ -314,15 +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);
+                       synchronized (lock) {
+                               if (sourceCovers != null) {
+                                       sourceCovers.put(source, coverImage);
+                               }
                        }
                } catch (IOException e) {
                        Instance.getInstance().getTraceHandler().error(e);
@@ -337,14 +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);
+                       synchronized (lock) {
+                               if (authorCovers != null) {
+                                       authorCovers.put(author, coverImage);
+                               }
                        }
                } catch (IOException e) {
                        Instance.getInstance().getTraceHandler().error(e);
@@ -602,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);
+
+                       for (File dir : dirs) {
+                               Progress pgFiles = new Progress();
+                               pgDirs.addProgress(pgFiles, 100);
+                               pgDirs.setName("Loading from: " + dir.getName());
+
+                               addToStories(stories, pgFiles, dir);
 
-                               pgDirs.setName("Loading directories");
+                               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) {
@@ -665,7 +720,7 @@ public class LocalLibrary extends BasicLibrary {
                        }
 
                        if (infoFileOrSubdir.isDirectory()) {
-                               addToStories(null, infoFileOrSubdir);
+                               addToStories(stories, null, infoFileOrSubdir);
                        } else {
                                try {
                                        MetaData meta = InfoReader.readMeta(infoFileOrSubdir,
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);
        }