import java.net.MalformedURLException;
import java.net.URL;
+import be.nikiroo.fanfix.bundles.Config;
import be.nikiroo.fanfix.bundles.StringId;
import be.nikiroo.fanfix.data.Chapter;
import be.nikiroo.fanfix.data.Story;
+import be.nikiroo.fanfix.library.BasicLibrary;
+import be.nikiroo.fanfix.library.CacheLibrary;
import be.nikiroo.fanfix.library.LocalLibrary;
import be.nikiroo.fanfix.library.RemoteLibrary;
import be.nikiroo.fanfix.library.RemoteLibraryServer;
host = args[i];
} else if (port == null) {
port = Integer.parseInt(args[i]);
- BasicReader
- .setDefaultLibrary(new RemoteLibrary(host, port));
+
+ File remoteCacheDir = Instance.getRemoteDir(host);
+ BasicLibrary lib = new RemoteLibrary(host, port);
+ lib = new CacheLibrary(remoteCacheDir, lib);
+
+ BasicReader.setDefaultLibrary(lib);
+
action = MainAction.START;
} else {
exitCode = 255;
*
* @param luid
* the Library UID of the story
+ * @param pg
+ * the optional {@link Progress}
*
* @return the corresponding {@link Story}
*/
- public abstract File getFile(String luid);
+ public abstract File getFile(String luid, Progress pg);
/**
* Return the cover image associated to this story.
* @return the corresponding {@link Story} or NULL if not found
*/
public synchronized Story getStory(String luid, Progress pg) {
- // TODO: pg
if (pg == null) {
pg = new Progress();
}
+ Progress pgGet = new Progress();
+ Progress pgProcess = new Progress();
+
+ pg.setMinMax(0, 2);
+ pg.addProgress(pgGet, 1);
+ pg.addProgress(pgProcess, 1);
+
Story story = null;
for (MetaData meta : getMetas(null)) {
if (meta.getLuid().equals(luid)) {
- File file = getFile(luid);
+ File file = getFile(luid, pgGet);
+ pgGet.done();
try {
SupportType type = SupportType.valueOfAllOkUC(meta
.getType());
URL url = file.toURI().toURL();
if (type != null) {
- story = BasicSupport.getSupport(type).process(url, pg);
+ story = BasicSupport.getSupport(type).process(url,
+ pgProcess);
} else {
throw new IOException("Unknown type: " + meta.getType());
}
Instance.syserr(new IOException(
"Cannot load file from library: " + file, e));
} finally {
+ pgProcess.done();
pg.done();
}
--- /dev/null
+package be.nikiroo.fanfix.library;
+
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import be.nikiroo.fanfix.Instance;
+import be.nikiroo.fanfix.bundles.UiConfig;
+import be.nikiroo.fanfix.data.MetaData;
+import be.nikiroo.fanfix.data.Story;
+import be.nikiroo.utils.Progress;
+
+/**
+ * This library will cache another pre-existing {@link BasicLibrary}.
+ *
+ * @author niki
+ */
+public class CacheLibrary extends BasicLibrary {
+ private List<MetaData> metas;
+ 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.
+ *
+ * @param cacheDir
+ * the cache directory where to save the files to disk
+ * @param lib
+ * the original library to wrap
+ */
+ public CacheLibrary(File cacheDir, BasicLibrary lib) {
+ this.cacheLib = new LocalLibrary(cacheDir, Instance.getUiConfig()
+ .getString(UiConfig.GUI_NON_IMAGES_DOCUMENT_TYPE), Instance
+ .getUiConfig().getString(UiConfig.GUI_IMAGES_DOCUMENT_TYPE),
+ true);
+ this.lib = lib;
+ }
+
+ @Override
+ public String getLibraryName() {
+ return lib.getLibraryName();
+ }
+
+ @Override
+ protected List<MetaData> getMetas(Progress pg) {
+ if (pg == null) {
+ pg = new Progress();
+ }
+
+ if (metas == null) {
+ metas = lib.getMetas(pg);
+ }
+
+ pg.done();
+ return metas;
+ }
+
+ @Override
+ public synchronized File getFile(final String luid, Progress pg) {
+ if (pg == null) {
+ pg = new Progress();
+ }
+
+ Progress pgImport = new Progress();
+ Progress pgGet = new Progress();
+ Progress pgRecall = new Progress();
+
+ pg.setMinMax(0, 5);
+ pg.addProgress(pgImport, 3);
+ pg.addProgress(pgGet, 1);
+ pg.addProgress(pgRecall, 1);
+
+ if (!isCached(luid)) {
+ try {
+ cacheLib.imprt(lib, luid, pgImport);
+ pgImport.done();
+ Story story = cacheLib.getStory(luid, pgGet);
+ metas.remove(story.getMeta());
+ metas.add(story.getMeta());
+ } catch (IOException e) {
+ Instance.syserr(e);
+ }
+
+ pgImport.done();
+ pgGet.done();
+ }
+
+ File file = cacheLib.getFile(luid, pgRecall);
+ pgRecall.done();
+
+ pg.done();
+ return file;
+ }
+
+ @Override
+ public BufferedImage getCover(final String luid) {
+ // Retrieve it from the cache if possible:
+ if (isCached(luid)) {
+ return cacheLib.getCover(luid);
+ }
+
+ return lib.getCover(luid);
+ }
+
+ @Override
+ protected void clearCache() {
+ metas = null;
+ cacheLib.clearCache();
+ lib.clearCache();
+ }
+
+ @Override
+ public synchronized Story save(Story story, String luid, Progress pg)
+ throws IOException {
+ story = lib.save(story, luid, pg);
+ clearCache();
+ return story;
+ }
+
+ @Override
+ public synchronized void delete(String luid) throws IOException {
+ cacheLib.delete(luid);
+ lib.delete(luid);
+ clearCache();
+ }
+
+ @Override
+ public void setSourceCover(String source, String luid) {
+ cacheLib.setSourceCover(source, luid);
+ lib.setSourceCover(source, luid);
+ }
+
+ @Override
+ public synchronized void changeSource(String luid, String newSource,
+ Progress pg) throws IOException {
+ if (pg == null) {
+ pg = new Progress();
+ }
+
+ Progress pgCache = new Progress();
+ Progress pgOrig = new Progress();
+ pg.setMinMax(0, 2);
+ pg.addProgress(pgCache, 1);
+ pg.addProgress(pgOrig, 1);
+
+ cacheLib.changeSource(luid, newSource, pgCache);
+ pgCache.done();
+ lib.changeSource(luid, newSource, pgOrig);
+ pgOrig.done();
+
+ pg.done();
+ }
+
+ /**
+ * Check if the {@link Story} denoted by this Library UID is present in the
+ * cache.
+ *
+ * @param luid
+ * the Library UID
+ *
+ * @return TRUE if it is
+ */
+ public boolean isCached(String luid) {
+ return cacheLib.getInfo(luid) != null;
+ }
+
+ /**
+ * Clear the {@link Story} from the cache.
+ *
+ * @param luid
+ * the story to clear
+ *
+ * @throws IOException
+ * in case of I/O error
+ */
+ public void clearFromCache(String luid) throws IOException {
+ cacheLib.delete(luid);
+ clearCache();
+ }
+
+ // All the following methods are only used by Save and Delete in
+ // BasicLibrary:
+
+ @Override
+ protected int getNextId() {
+ throw new java.lang.InternalError("Should not have been called");
+ }
+
+ @Override
+ protected void doDelete(String luid) throws IOException {
+ throw new java.lang.InternalError("Should not have been called");
+ }
+
+ @Override
+ protected Story doSave(Story story, Progress pg) throws IOException {
+ throw new java.lang.InternalError("Should not have been called");
+ }
+}
*
* @param baseDir
* the directory where to find the {@link Story} objects
+ * @param text
+ * the {@link OutputType} to use for non-image documents
+ * @param image
+ * the {@link OutputType} to use for image documents
+ * @param defaultIsHtml
+ * if the given text or image is invalid, use HTML by default (if
+ * not, it will be INFO_TEXT/CBZ by default)
*/
public LocalLibrary(File baseDir, String text, String image,
boolean defaultIsHtml) {
- this(baseDir, OutputType.valueOfNullOkUC(text,
+ this(baseDir, OutputType.valueOfAllOkUC(text,
defaultIsHtml ? OutputType.HTML : OutputType.INFO_TEXT),
- OutputType.valueOfNullOkUC(image,
+ OutputType.valueOfAllOkUC(image,
defaultIsHtml ? OutputType.HTML : OutputType.CBZ));
}
}
@Override
- public File getFile(String luid) {
- File[] files = getStories(null).get(getInfo(luid));
+ public File getFile(String luid, Progress pg) {
+ File[] files = getStories(pg).get(getInfo(luid));
if (files != null) {
return files[1];
}
pg = new Progress();
}
- LocalLibrary otherLocalLibrary = null;
- if (other instanceof RemoteLibrary) {
- otherLocalLibrary = ((RemoteLibrary) other).getLocalLibrary();
- }
-
+ // Check if we can simply copy the files instead of the whole process
if (other instanceof LocalLibrary) {
- otherLocalLibrary = (LocalLibrary) other;
- }
+ LocalLibrary otherLocalLibrary = (LocalLibrary) other;
- // Check if we can simply copy the files instead of the whole process
- if (otherLocalLibrary != null) {
MetaData meta = otherLocalLibrary.getInfo(luid);
String expectedType = ""
+ (meta != null && meta.isImageDocument() ? image : text);
public class RemoteLibrary extends BasicLibrary {
private String host;
private int port;
- private File baseDir;
-
- private LocalLibrary lib;
- private List<MetaData> metas;
/**
* Create a {@link RemoteLibrary} linked to the given server.
public RemoteLibrary(String host, int port) {
this.host = host;
this.port = port;
-
- this.baseDir = Instance.getRemoteDir(host);
- this.baseDir.mkdirs();
-
- this.lib = new LocalLibrary(baseDir);
}
@Override
@Override
protected List<MetaData> getMetas(Progress pg) {
// TODO: progress
+ final List<MetaData> metas = new ArrayList<MetaData>();
+ MetaData[] fromNetwork = this
+ .<MetaData[]> getRemoteObject("GET_METADATA *");
- if (metas == null) {
- metas = new ArrayList<MetaData>();
-
- try {
- new ConnectActionClient(host, port, true) {
- @Override
- public void action(Version serverVersion) throws Exception {
- try {
- Object rep = send("GET_METADATA *");
- for (MetaData meta : (MetaData[]) rep) {
- metas.add(meta);
- }
- } catch (Exception e) {
- Instance.syserr(e);
- }
- }
- }.connect();
- } catch (IOException e) {
- Instance.syserr(e);
- }
-
- List<String> test = new ArrayList<String>();
- for (MetaData meta : metas) {
- if (test.contains(meta.getLuid())) {
- throw new RuntimeException("wwops");
- }
- test.add(meta.getLuid());
+ if (fromNetwork != null) {
+ for (MetaData meta : fromNetwork) {
+ metas.add(meta);
}
}
}
@Override
- public synchronized File getFile(final String luid) {
- File file = lib.getFile(luid);
- if (file == null) {
- final File[] tmp = new File[1];
- try {
- new ConnectActionClient(host, port, true) {
- @Override
- public void action(Version serverVersion) throws Exception {
- try {
- Object rep = send("GET_STORY " + luid);
- Story story = (Story) rep;
- if (story != null) {
- lib.save(story, luid, null);
- tmp[0] = lib.getFile(luid);
- }
- } catch (Exception e) {
- Instance.syserr(e);
- }
- }
- }.connect();
- } catch (IOException e) {
- Instance.syserr(e);
- }
-
- file = tmp[0];
- }
-
- if (file != null) {
- MetaData meta = getInfo(luid);
- metas.add(meta);
- }
-
- return file;
+ public BufferedImage getCover(final String luid) {
+ return this.<BufferedImage> getRemoteObject("GET_COVER " + luid);
}
@Override
- public BufferedImage getCover(final String luid) {
- // Retrieve it from the cache if possible:
- if (lib.getInfo(luid) != null) {
- return lib.getCover(luid);
- }
-
- final BufferedImage[] result = new BufferedImage[1];
- try {
- new ConnectActionClient(host, port, true) {
- @Override
- public void action(Version serverVersion) throws Exception {
- try {
- Object rep = send("GET_COVER " + luid);
- result[0] = (BufferedImage) rep;
- } catch (Exception e) {
- Instance.syserr(e);
- }
- }
- }.connect();
- } catch (IOException e) {
- Instance.syserr(e);
- }
-
- return result[0];
+ public synchronized Story getStory(final String luid, Progress pg) {
+ return this.<Story> getRemoteObject("GET_STORY " + luid);
}
@Override
protected void clearCache() {
- metas = null;
- lib.clearCache();
}
@Override
"No write support allowed on remote Libraries");
}
- // All the following methods are only used by Save and Delete in
- // BasicLibrary:
+ @Override
+ public synchronized File getFile(final String luid) {
+ throw new java.lang.InternalError(
+ "Operation not supportorted on remote Libraries");
+ }
+
+ // The following methods are only used by Save and Delete in BasicLibrary:
@Override
protected int getNextId() {
}
/**
- * Return the backing local library.
+ * Return an object from the server.
+ *
+ * @param <T>
+ * the expected type of object
+ * @param command
+ * the command to send
*
- * @return the library
+ * @return the object or NULL
*/
- LocalLibrary getLocalLibrary() {
- return lib;
+ @SuppressWarnings("unchecked")
+ private <T> T getRemoteObject(final String command) {
+ final Object[] result = new Object[1];
+ try {
+ new ConnectActionClient(host, port, true) {
+ @Override
+ public void action(Version serverVersion) throws Exception {
+ try {
+ Object rep = send(command);
+ result[0] = rep;
+ } catch (Exception e) {
+ Instance.syserr(e);
+ }
+ }
+ }.connect();
+ } catch (IOException e) {
+ Instance.syserr(e);
+ }
+
+ try {
+ return (T) result[0];
+ } catch (Exception e) {
+ Instance.syserr(e);
+ return null;
+ }
}
}
public static void openExternal(BasicLibrary lib, String luid)
throws IOException {
MetaData meta = lib.getInfo(luid);
- File target = lib.getFile(luid);
+ File target = lib.getFile(luid, null);
openExternal(meta, target);
}
import be.nikiroo.fanfix.Instance;
import be.nikiroo.fanfix.VersionCheck;
-import be.nikiroo.fanfix.bundles.UiConfig;
import be.nikiroo.fanfix.data.MetaData;
import be.nikiroo.fanfix.data.Story;
+import be.nikiroo.fanfix.library.BasicLibrary;
+import be.nikiroo.fanfix.library.CacheLibrary;
import be.nikiroo.fanfix.library.LocalLibrary;
import be.nikiroo.utils.Progress;
import be.nikiroo.utils.Version;
class GuiReader extends BasicReader {
static private boolean nativeLookLoaded;
- private LocalLibrary localLibrary;
+ private CacheLibrary cacheLib;
+
+ private File cacheDir;
public GuiReader() throws IOException {
if (!nativeLookLoaded) {
nativeLookLoaded = true;
}
- File dir = Instance.getReaderDir();
- dir.mkdirs();
- if (!dir.exists()) {
+ cacheDir = Instance.getReaderDir();
+ cacheDir.mkdirs();
+ if (!cacheDir.exists()) {
throw new IOException(
- "Cannote create cache directory for local reader: " + dir);
+ "Cannote create cache directory for local reader: "
+ + cacheDir);
+ }
+ }
+
+ @Override
+ public synchronized BasicLibrary getLibrary() {
+ if (cacheLib == null) {
+ BasicLibrary lib = super.getLibrary();
+ if (lib instanceof CacheLibrary) {
+ cacheLib = (CacheLibrary) lib;
+ } else {
+ cacheLib = new CacheLibrary(cacheDir, lib);
+ }
}
- localLibrary = new LocalLibrary(dir, Instance.getUiConfig().getString(
- UiConfig.GUI_NON_IMAGES_DOCUMENT_TYPE), Instance.getUiConfig()
- .getString(UiConfig.GUI_IMAGES_DOCUMENT_TYPE), true);
+ return cacheLib;
}
@Override
read(meta.getLuid(), null);
}
- /**
- * Import the story into the local reader library, and keep the same LUID.
- *
- * @param luid
- * the Library UID
- * @param pg
- * the optional progress reporter
- *
- * @throws IOException
- * in case of I/O error
- */
- public void imprt(String luid, Progress pg) throws IOException {
- try {
- localLibrary.imprt(getLibrary(), luid, pg);
- } catch (IOException e) {
- throw new IOException(
- "Cannot import story from library to LocalReader library: "
- + luid, e);
- }
- }
-
/**
* Check if the {@link Story} denoted by this Library UID is present in the
* {@link GuiReader} cache.
* @return TRUE if it is
*/
public boolean isCached(String luid) {
- return localLibrary.getInfo(luid) != null;
+ return cacheLib.isCached(luid);
}
@Override
// delete from local reader library
void clearLocalReaderCache(String luid) {
try {
- localLibrary.delete(luid);
+ cacheLib.clearFromCache(luid);
} catch (IOException e) {
Instance.syserr(e);
}
// delete from main library
void delete(String luid) {
try {
- if (localLibrary.getInfo(luid) != null) {
- localLibrary.delete(luid);
- }
- getLibrary().delete(luid);
+ cacheLib.delete(luid);
} catch (IOException e) {
Instance.syserr(e);
}
// open the given book
void read(String luid, Progress pg) throws IOException {
- File file = localLibrary.getFile(luid);
- if (file == null) {
- imprt(luid, pg);
- file = localLibrary.getFile(luid);
- }
+ File file = cacheLib.getFile(luid, pg);
// TODO: show a special page for the chapter?
openExternal(getLibrary().getInfo(luid), file);
void changeType(String luid, String newSource) {
try {
- if (localLibrary.getInfo(luid) != null) {
- localLibrary.changeSource(luid, newSource, null);
- }
- getLibrary().changeSource(luid, newSource, null);
+ cacheLib.changeSource(luid, newSource, null);
} catch (IOException e) {
Instance.syserr(e);
}