X-Git-Url: http://git.nikiroo.be/?p=nikiroo-utils.git;a=blobdiff_plain;f=library%2FBasicLibrary.java;h=f77d0edcef5ae64b186942be2a6048fa7eca7745;hp=7f286079ed1fe87c88f2ec798a85c26774950089;hb=258e065f81071a861711ef935dca3ec5563f4360;hpb=3b039231be91c50e3d1bd59492205d61a0928494 diff --git a/library/BasicLibrary.java b/library/BasicLibrary.java index 7f28607..f77d0ed 100644 --- a/library/BasicLibrary.java +++ b/library/BasicLibrary.java @@ -4,11 +4,9 @@ import java.io.File; import java.io.IOException; import java.net.URL; import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.TreeMap; import be.nikiroo.fanfix.Instance; import be.nikiroo.fanfix.data.MetaData; @@ -43,11 +41,11 @@ abstract public class BasicLibrary { READ_WRITE, /** The library is ready, but read-only. */ READ_ONLY, - /** The library is invalid (not correctly set up). */ - INVALID, /** You are not allowed to access this library. */ UNAUTHORIZED, - /** The library is currently out of commission. */ + /** The library is invalid, and will never work as is. */ + INVALID, + /** The library is currently out of commission, but may work later. */ UNAVAILABLE; /** @@ -98,7 +96,7 @@ abstract public class BasicLibrary { * Do NOT 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} * @@ -122,13 +120,25 @@ 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 { + /** + * Retrieve the list of {@link MetaData} known by this {@link BasicLibrary} + * in a easy-to-filter version. + * + * @param pg + * the optional {@link Progress} + * @return the list of {@link MetaData} as a {@link MetaResultList} you can + * query + * @throws IOException + * in case of I/O eror + */ + public MetaResultList getList(Progress pg) throws IOException { + // TODO: ensure it is the main used interface + return new MetaResultList(getMetas(pg)); } - - //TODO: make something for (normal and custom) not-story covers - + + // TODO: make something for (normal and custom) non-story covers + /** * Return the cover image associated to this source. *

@@ -301,7 +311,7 @@ abstract public class BasicLibrary { * * @return the next luid */ - protected abstract int getNextId(); + protected abstract String getNextId(); /** * Delete the target {@link Story}. @@ -338,28 +348,28 @@ 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 true). + * cache (if we have no cache, we default to true). * * @param luid * the Library UID * * @return TRUE if it is */ - public boolean isCached(String luid) { + public boolean isCached(@SuppressWarnings("unused") String luid) { // By default, everything is cached return true; } - + /** * Clear the {@link Story} from the cache, if needed. *

@@ -372,219 +382,57 @@ abstract public class BasicLibrary { * @throws IOException * in case of I/O error */ + @SuppressWarnings("unused") public void clearFromCache(String luid) throws IOException { // By default, this is a noop. } /** - * List all the known types (sources) of stories. - * - * @return the sources - * + * @return the same as getList() * @throws IOException - * in case of IOException + * in case of I/O error + * @deprecated please use {@link BasicLibrary#getList()} and + * {@link MetaResultList#getSources()} instead. */ - public synchronized List getSources() throws IOException { - List list = new ArrayList(); - for (MetaData meta : getMetas(null)) { - String storySource = meta.getSource(); - if (!list.contains(storySource)) { - list.add(storySource); - } - } - - Collections.sort(list); - return list; + @Deprecated + public List getSources() throws IOException { + return getList().getSources(); } /** - * List all the known types (sources) of stories, grouped by directory - * ("Source_1/a" and "Source_1/b" will be grouped into "Source_1"). - *

- * Note that an empty item in the list means a non-grouped source (type) -- - * e.g., you could have for Source_1: - *

- * - * @return the grouped list - * + * @return the same as getList() * @throws IOException - * in case of IOException + * in case of I/O error + * @deprecated please use {@link BasicLibrary#getList()} and + * {@link MetaResultList#getSourcesGrouped()} instead. */ - public synchronized Map> getSourcesGrouped() - throws IOException { - Map> map = new TreeMap>(); - for (String source : getSources()) { - String name; - String subname; - - int pos = source.indexOf('/'); - if (pos > 0 && pos < source.length() - 1) { - name = source.substring(0, pos); - subname = source.substring(pos + 1); - - } else { - name = source; - subname = ""; - } - - List list = map.get(name); - if (list == null) { - list = new ArrayList(); - map.put(name, list); - } - list.add(subname); - } - - return map; + @Deprecated + public Map> getSourcesGrouped() throws IOException { + return getList().getSourcesGrouped(); } /** - * List all the known authors of stories. - * - * @return the authors - * + * @return the same as getList() * @throws IOException - * in case of IOException + * in case of I/O error + * @deprecated please use {@link BasicLibrary#getList()} and + * {@link MetaResultList#getAuthors()} instead. */ - public synchronized List getAuthors() throws IOException { - List list = new ArrayList(); - for (MetaData meta : getMetas(null)) { - String storyAuthor = meta.getAuthor(); - if (!list.contains(storyAuthor)) { - list.add(storyAuthor); - } - } - - Collections.sort(list); - return list; + @Deprecated + public List getAuthors() throws IOException { + return getList().getAuthors(); } /** - * Return the list of authors, grouped by starting letter(s) if needed. - *

- * If the number of author is not too high, only one group with an empty - * name and all the authors will be returned. - *

- * If not, the authors will be separated into groups: - *

    - *
  • *: any author whose name doesn't contain letters nor numbers - *
  • - *
  • 0-9: any authors whose name starts with a number
  • - *
  • A-C (for instance): any author whose name starts with - * A, B or C
  • - *
- * Note that the letters used in the groups can vary (except * and - * 0-9, which may only be present or not). - * - * @return the authors' names, grouped by letter(s) - * + * @return the same as getList() * @throws IOException - * in case of IOException + * in case of I/O error + * @deprecated please use {@link BasicLibrary#getList()} and + * {@link MetaResultList#getAuthorsGrouped()} instead. */ + @Deprecated public Map> getAuthorsGrouped() throws IOException { - int MAX = 20; - - Map> groups = new TreeMap>(); - List authors = getAuthors(); - - // If all authors fit the max, just report them as is - if (authors.size() <= MAX) { - groups.put("", authors); - return groups; - } - - // Create groups A to Z, which can be empty here - for (char car = 'A'; car <= 'Z'; car++) { - groups.put(Character.toString(car), getAuthorsGroup(authors, car)); - } - - // Collapse them - List keys = new ArrayList(groups.keySet()); - for (int i = 0; i + 1 < keys.size(); i++) { - String keyNow = keys.get(i); - String keyNext = keys.get(i + 1); - - List now = groups.get(keyNow); - List next = groups.get(keyNext); - - int currentTotal = now.size() + next.size(); - if (currentTotal <= MAX) { - String key = keyNow.charAt(0) + "-" - + keyNext.charAt(keyNext.length() - 1); - - List all = new ArrayList(); - all.addAll(now); - all.addAll(next); - - groups.remove(keyNow); - groups.remove(keyNext); - groups.put(key, all); - - keys.set(i, key); // set the new key instead of key(i) - keys.remove(i + 1); // remove the next, consumed key - i--; // restart at key(i) - } - } - - // Add "special" groups - groups.put("*", getAuthorsGroup(authors, '*')); - groups.put("0-9", getAuthorsGroup(authors, '0')); - - // Prune empty groups - keys = new ArrayList(groups.keySet()); - for (String key : keys) { - if (groups.get(key).isEmpty()) { - groups.remove(key); - } - } - - return groups; - } - - /** - * Get all the authors that start with the given character: - *
    - *
  • *: any author whose name doesn't contain letters nor numbers - *
  • - *
  • 0: any authors whose name starts with a number
  • - *
  • A (any capital latin letter): any author whose name starts - * with A
  • - *
- * - * @param authors - * the full list of authors - * @param car - * the starting character, *, 0 or a capital - * letter - * - * @return the authors that fulfil the starting letter - */ - private List getAuthorsGroup(List authors, char car) { - List accepted = new ArrayList(); - for (String author : authors) { - char first = '*'; - for (int i = 0; first == '*' && i < author.length(); i++) { - String san = StringUtils.sanitize(author, true, true); - char c = san.charAt(i); - if (c >= '0' && c <= '9') { - first = '0'; - } else if (c >= 'a' && c <= 'z') { - first = (char) (c - 'a' + 'A'); - } else if (c >= 'A' && c <= 'Z') { - first = c; - } - } - - if (first == car) { - accepted.add(author); - } - } - - return accepted; + return getList().getAuthorsGrouped(); } /** @@ -606,14 +454,14 @@ abstract public class BasicLibrary { * cover image MAY 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())) { @@ -627,6 +475,8 @@ abstract public class BasicLibrary { /** * Retrieve a specific {@link Story}. + *

+ * Note that it will update both the cover and the resume in meta. * * @param luid * the Library UID of the story @@ -638,8 +488,7 @@ abstract public class BasicLibrary { * @throws IOException * in case of IOException */ - public synchronized Story getStory(String luid, Progress pg) - throws IOException { + public Story getStory(String luid, Progress pg) throws IOException { Progress pgMetas = new Progress(); Progress pgStory = new Progress(); if (pg != null) { @@ -666,8 +515,12 @@ abstract public class BasicLibrary { /** * Retrieve a specific {@link Story}. + *

+ * Note that it will update both the cover and the resume in meta. * * @param luid + * the LUID of the story + * @param meta * the meta of the story * @param pg * the optional progress reporter @@ -677,8 +530,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 +545,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 +567,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(); @@ -740,6 +599,28 @@ abstract public class BasicLibrary { * in case of I/O error */ public MetaData imprt(URL url, Progress pg) throws IOException { + return imprt(url, null, pg); + } + + /** + * Import the {@link Story} at the given {@link URL} into the + * {@link BasicLibrary}. + * + * @param url + * the {@link URL} to import + * @param luid + * the LUID to use + * @param pg + * the optional progress reporter + * + * @return the imported Story {@link MetaData} + * + * @throws UnknownHostException + * if the host is not supported + * @throws IOException + * in case of I/O error + */ + MetaData imprt(URL url, String luid, Progress pg) throws IOException { if (pg == null) pg = new Progress(); @@ -754,8 +635,7 @@ abstract public class BasicLibrary { throw new UnknownHostException("" + url); } - Story story = save(support.process(pgProcess), pgSave); - pg.setName(story.getMeta().getTitle()); + Story story = save(support.process(pgProcess), luid, pgSave); pg.done(); return story.getMeta(); @@ -876,17 +756,18 @@ 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())); + meta.setLuid(getNextId()); } else { meta.setLuid(luid); } @@ -900,7 +781,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 +799,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 + ")"); } /** @@ -1067,4 +950,49 @@ abstract public class BasicLibrary { pg.done(); } + + /** + * Describe a {@link Story} from its {@link MetaData} and return a list of + * title/value that represent this {@link Story}. + * + * @param meta + * the {@link MetaData} to represent + * + * @return the information, translated and sorted + */ + static public Map getMetaDesc(MetaData meta) { + Map metaDesc = new LinkedHashMap(); + + // TODO: i18n + + StringBuilder tags = new StringBuilder(); + for (String tag : meta.getTags()) { + if (tags.length() > 0) { + tags.append(", "); + } + tags.append(tag); + } + + // TODO: i18n + metaDesc.put("Author", meta.getAuthor()); + metaDesc.put("Published on", meta.getPublisher()); + metaDesc.put("Publication date", meta.getDate()); + metaDesc.put("Creation date", meta.getCreationDate()); + String count = ""; + if (meta.getWords() > 0) { + count = StringUtils.formatNumber(meta.getWords()); + } + if (meta.isImageDocument()) { + metaDesc.put("Number of images", count); + } else { + metaDesc.put("Number of words", count); + } + metaDesc.put("Source", meta.getSource()); + metaDesc.put("Subject", meta.getSubject()); + metaDesc.put("Language", meta.getLang()); + metaDesc.put("Tags", tags.toString()); + metaDesc.put("URL", meta.getUrl()); + + return metaDesc; + } }