Coverage Report - org.crosswire.jsword.versification.BibleNames
 
Classes in this File Line Coverage Branch Coverage Complexity
BibleNames
0%
0/38
0%
0/20
3.143
BibleNames$NameList
0%
0/98
0%
0/46
3.143
 
 1  
 /**
 2  
  * Distribution License:
 3  
  * JSword is free software; you can redistribute it and/or modify it under
 4  
  * the terms of the GNU Lesser General Public License, version 2.1 or later
 5  
  * as published by the Free Software Foundation. This program is distributed
 6  
  * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
 7  
  * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 8  
  * See the GNU Lesser General Public License for more details.
 9  
  *
 10  
  * The License is available on the internet at:
 11  
  *      http://www.gnu.org/copyleft/lgpl.html
 12  
  * or by writing to:
 13  
  *      Free Software Foundation, Inc.
 14  
  *      59 Temple Place - Suite 330
 15  
  *      Boston, MA 02111-1307, USA
 16  
  *
 17  
  * © CrossWire Bible Society, 2005 - 2016
 18  
  *
 19  
  */
 20  
 package org.crosswire.jsword.versification;
 21  
 
 22  
 import java.util.HashMap;
 23  
 import java.util.LinkedHashMap;
 24  
 import java.util.Locale;
 25  
 import java.util.Map;
 26  
 import java.util.MissingResourceException;
 27  
 import java.util.ResourceBundle;
 28  
 
 29  
 import org.crosswire.common.util.CWClassLoader;
 30  
 import org.crosswire.common.util.ClassUtil;
 31  
 import org.crosswire.common.util.StringUtil;
 32  
 import org.crosswire.jsword.internationalisation.LocaleProviderManager;
 33  
 
 34  
 /**
 35  
  * BibleNames deals with locale sensitive BibleBook name lookup conversions.
 36  
  * 
 37  
  * @see gnu.lgpl.License The GNU Lesser General Public License for details.
 38  
  * @author Joe Walker
 39  
  * @author DM Smith
 40  
  */
 41  
 public final class BibleNames {
 42  
     /**
 43  
      * Get the singleton instance of BibleNames.
 44  
      *
 45  
      * @return the singleton
 46  
      */
 47  
     public static BibleNames instance() {
 48  0
         return instance;
 49  
     }
 50  
 
 51  
     /**
 52  
      * Get the BookName.
 53  
      *
 54  
      * @param book the desired book
 55  
      * @return The requested BookName or null if not in this versification
 56  
      */
 57  
     public BookName getBookName(BibleBook book) {
 58  0
         return getLocalizedBibleNames().getBookName(book);
 59  
     }
 60  
 
 61  
     /**
 62  
      * Get the preferred name of a book. Altered by the case setting (see
 63  
      * setBookCase() and isFullBookName())
 64  
      *
 65  
      * @param book the desired book
 66  
      * @return The full name of the book or blank if not in this versification
 67  
      */
 68  
     public String getPreferredName(BibleBook book) {
 69  0
         return getLocalizedBibleNames().getPreferredName(book);
 70  
     }
 71  
 
 72  
     /**
 73  
      * Get the full name of a book (e.g. "Genesis"). Altered by the case setting
 74  
      * (see setBookCase())
 75  
      *
 76  
      * @param book the book
 77  
      * @return The full name of the book or blank if not in this versification
 78  
      */
 79  
     public String getLongName(BibleBook book) {
 80  0
         return getLocalizedBibleNames().getLongName(book);
 81  
     }
 82  
 
 83  
     /**
 84  
      * Get the short name of a book (e.g. "Gen"). Altered by the case setting
 85  
      * (see setBookCase())
 86  
      *
 87  
      * @param book the book
 88  
      * @return The short name of the book or blank if not in this versification
 89  
      */
 90  
     public String getShortName(BibleBook book) {
 91  0
         return getLocalizedBibleNames().getShortName(book);
 92  
     }
 93  
 
 94  
     /**
 95  
      * Get a book from its name.
 96  
      *
 97  
      * @param find
 98  
      *            The string to identify
 99  
      * @return The BibleBook, On error null
 100  
      */
 101  
     public BibleBook getBook(String find) {
 102  0
         BibleBook book = null;
 103  0
         if (containsLetter(find)) {
 104  0
             book = BibleBook.fromOSIS(find);
 105  
 
 106  0
             if (book == null) {
 107  0
                 book = getLocalizedBibleNames().getBook(find, false);
 108  
             }
 109  
 
 110  0
             if (book == null) {
 111  0
                 book = englishBibleNames.getBook(find, false);
 112  
             }
 113  
 
 114  0
             if (book == null) {
 115  0
                 book = getLocalizedBibleNames().getBook(find, true);
 116  
             }
 117  
 
 118  0
             if (book == null) {
 119  0
                 book = englishBibleNames.getBook(find, true);
 120  
             }
 121  
         }
 122  
 
 123  0
         return book;
 124  
     }
 125  
 
 126  
     /**
 127  
      * Is the given string a valid book name. If this method returns true then
 128  
      * getBook() will return a BibleBook and not null.
 129  
      *
 130  
      * @param find
 131  
      *            The string to identify
 132  
      * @return true when the book name is recognized
 133  
      */
 134  
     public boolean isBook(String find) {
 135  0
         return getBook(find) != null;
 136  
     }
 137  
 
 138  
     /**
 139  
      * Load name information for BibleNames for a given locale.
 140  
      * This routine is for testing the underlying NameList.
 141  
      * 
 142  
      * @param locale
 143  
      */
 144  
     void load(Locale locale) {
 145  0
         NameList bibleNames = new NameList(locale);
 146  0
         if (localizedBibleNames.get(locale) == null) {
 147  0
             localizedBibleNames.put(locale, bibleNames);
 148  
         }
 149  0
     }
 150  
 
 151  
     /**
 152  
      * This class is a singleton, enforced by a private constructor.
 153  
      */
 154  0
     private BibleNames() {
 155  0
         localizedBibleNames = new HashMap<Locale, NameList>();
 156  0
         englishBibleNames = getBibleNamesForLocale(Locale.ENGLISH);
 157  0
         localizedBibleNames.put(Locale.ENGLISH, englishBibleNames);
 158  0
     }
 159  
 
 160  
     /**
 161  
      * Gets the localized bible names, based on the {@link LocaleProviderManager}
 162  
      *
 163  
      * @return the localized bible names
 164  
      */
 165  
     private NameList getLocalizedBibleNames() {
 166  
         // Get the current Locale
 167  0
         return getBibleNamesForLocale(LocaleProviderManager.getLocale());
 168  
     }
 169  
 
 170  
     /**
 171  
      * Gets the bible names for a specific locale.
 172  
      *
 173  
      * @param locale the locale
 174  
      * @return the bible names for locale
 175  
      */
 176  
     private NameList getBibleNamesForLocale(Locale locale) {
 177  0
         NameList bibleNames = localizedBibleNames.get(locale);
 178  0
         if (bibleNames == null) {
 179  0
             bibleNames = new NameList(locale);
 180  0
             localizedBibleNames.put(locale, bibleNames);
 181  
         }
 182  
 
 183  0
         return bibleNames;
 184  
     }
 185  
 
 186  
     /**
 187  
      * This is simply a convenience function to wrap Character.isLetter()
 188  
      *
 189  
      * @param text
 190  
      *            The string to be parsed
 191  
      * @return true if the string contains letters
 192  
      */
 193  
     private static boolean containsLetter(String text) {
 194  0
         for (int i = 0; i < text.length(); i++) {
 195  0
             if (Character.isLetter(text.charAt(i))) {
 196  0
                 return true;
 197  
             }
 198  
         }
 199  
 
 200  0
         return false;
 201  
     }
 202  
 
 203  
     /**
 204  
      * NameList is the internal, internationalize list of names
 205  
      * for a locale.
 206  
      *
 207  
      * @see gnu.lgpl.License The GNU Lesser General Public License for details.<br>
 208  
      *      The copyright to this program is held by its authors.
 209  
      * @author DM Smith
 210  
      */
 211  0
     private class NameList {
 212  
         /**
 213  
          * Create NameList for the given locale
 214  
          */
 215  0
         NameList(Locale locale) {
 216  0
             this.locale = locale;
 217  0
             initialize();
 218  0
         }
 219  
 
 220  
         BookName getBookName(BibleBook book) {
 221  0
             return books.get(book);
 222  
         }
 223  
 
 224  
         /**
 225  
          * Get the preferred name of a book. Altered by the case setting (see
 226  
          * setBookCase() and isFullBookName())
 227  
          * 
 228  
          * @param book
 229  
          *            The book of the Bible
 230  
          * @return The full name of the book
 231  
          */
 232  
         String getPreferredName(BibleBook book) {
 233  0
             return getBookName(book).getPreferredName();
 234  
         }
 235  
 
 236  
         /**
 237  
          * Get the full name of a book (e.g. "Genesis"). Altered by the case
 238  
          * setting (see setBookCase())
 239  
          * 
 240  
          * @param book
 241  
          *            The book of the Bible
 242  
          * @return The full name of the book
 243  
          */
 244  
         String getLongName(BibleBook book) {
 245  0
             return getBookName(book).getLongName();
 246  
         }
 247  
 
 248  
         /**
 249  
          * Get the short name of a book (e.g. "Gen"). Altered by the case
 250  
          * setting (see setBookCase())
 251  
          * 
 252  
          * @param book
 253  
          *            The book of the Bible
 254  
          * @return The short name of the book
 255  
          */
 256  
         String getShortName(BibleBook book) {
 257  0
             return getBookName(book).getShortName();
 258  
         }
 259  
 
 260  
         /**
 261  
          * Get a book from its name.
 262  
          * 
 263  
          * @param find
 264  
          *            The string to identify
 265  
          * @param fuzzy
 266  
          *            Whether to also find bible books where only a substring matches
 267  
          * @return The BibleBook, On error null
 268  
          */
 269  
         BibleBook getBook(String find, boolean fuzzy) {
 270  0
             String match = BookName.normalize(find, locale);
 271  
 
 272  0
             BookName bookName = fullNT.get(match);
 273  0
             if (bookName != null) {
 274  0
                 return bookName.getBook();
 275  
             }
 276  
 
 277  0
             bookName = shortNT.get(match);
 278  0
             if (bookName != null) {
 279  0
                 return bookName.getBook();
 280  
             }
 281  
 
 282  0
             bookName = altNT.get(match);
 283  0
             if (bookName != null) {
 284  0
                 return bookName.getBook();
 285  
             }
 286  
 
 287  0
             bookName = fullOT.get(match);
 288  0
             if (bookName != null) {
 289  0
                 return bookName.getBook();
 290  
             }
 291  
 
 292  0
             bookName = shortOT.get(match);
 293  0
             if (bookName != null) {
 294  0
                 return bookName.getBook();
 295  
             }
 296  
 
 297  0
             bookName = altOT.get(match);
 298  0
             if (bookName != null) {
 299  0
                 return bookName.getBook();
 300  
             }
 301  
 
 302  0
             bookName = fullNC.get(match);
 303  0
             if (bookName != null) {
 304  0
                 return bookName.getBook();
 305  
             }
 306  
 
 307  0
             bookName = shortNC.get(match);
 308  0
             if (bookName != null) {
 309  0
                 return bookName.getBook();
 310  
             }
 311  
 
 312  0
             bookName = altNC.get(match);
 313  0
             if (bookName != null) {
 314  0
                 return bookName.getBook();
 315  
             }
 316  
 
 317  0
             if (!fuzzy) {
 318  0
                 return null;
 319  
             }
 320  
 
 321  0
             for (BookName aBook : books.values()) {
 322  0
                 if (aBook.match(match)) {
 323  0
                     return aBook.getBook();
 324  
                 }
 325  
             }
 326  
 
 327  0
             return null;
 328  
         }
 329  
 
 330  
         /**
 331  
          * Load up the resources for Bible book and section names, and cache the
 332  
          * upper and lower versions of them.
 333  
          */
 334  
         private void initialize() {
 335  0
             int ntCount = 0;
 336  0
             int otCount = 0;
 337  0
             int ncCount = 0;
 338  0
             BibleBook[] bibleBooks = BibleBook.values();
 339  0
             for (BibleBook book : bibleBooks) {
 340  0
                 int ordinal = book.ordinal();
 341  0
                 if (ordinal > BibleBook.INTRO_OT.ordinal() && ordinal < BibleBook.INTRO_NT.ordinal()) {
 342  0
                     ++ntCount;
 343  0
                 } else if (ordinal > BibleBook.INTRO_NT.ordinal() && ordinal <= BibleBook.REV.ordinal()) {
 344  0
                     ++otCount;
 345  
                 } else {
 346  0
                     ++ncCount;
 347  
                 }
 348  
             }
 349  
 
 350  
             // Create the book name maps
 351  0
             books = new LinkedHashMap<BibleBook, BookName>(ntCount + otCount + ncCount);
 352  
 
 353  0
             String className = BibleNames.class.getName();
 354  0
             String shortClassName = ClassUtil.getShortClassName(className);
 355  0
             ResourceBundle resources = ResourceBundle.getBundle(shortClassName, locale, CWClassLoader.instance(BibleNames.class));
 356  
 
 357  0
             fullNT = new HashMap<String, BookName>(ntCount);
 358  0
             shortNT = new HashMap<String, BookName>(ntCount);
 359  0
             altNT = new HashMap<String, BookName>(ntCount);
 360  0
             for (int i = BibleBook.MATT.ordinal(); i <= BibleBook.REV.ordinal(); ++i) {
 361  0
                 BibleBook book = bibleBooks[i];
 362  0
                 store(resources, book, fullNT, shortNT, altNT);
 363  
             }
 364  
 
 365  0
             fullOT = new HashMap<String, BookName>(otCount);
 366  0
             shortOT = new HashMap<String, BookName>(otCount);
 367  0
             altOT = new HashMap<String, BookName>(otCount);
 368  0
             for (int i = BibleBook.GEN.ordinal(); i <= BibleBook.MAL.ordinal(); ++i) {
 369  0
                 BibleBook book = bibleBooks[i];
 370  0
                 store(resources, book, fullOT, shortOT, altOT);
 371  
             }
 372  
 
 373  0
             fullNC = new HashMap<String, BookName>(ncCount);
 374  0
             shortNC = new HashMap<String, BookName>(ncCount);
 375  0
             altNC = new HashMap<String, BookName>(ncCount);
 376  0
             store(resources, BibleBook.INTRO_BIBLE, fullNC, shortNC, altNC);
 377  0
             store(resources, BibleBook.INTRO_OT, fullNC, shortNC, altNC);
 378  0
             store(resources, BibleBook.INTRO_NT, fullNC, shortNC, altNC);
 379  0
             for (int i = BibleBook.REV.ordinal() + 1; i < bibleBooks.length; ++i) {
 380  0
                 BibleBook book = bibleBooks[i];
 381  0
                 store(resources, book, fullNC, shortNC, altNC);
 382  
             }
 383  0
         }
 384  
 
 385  
         private void store(ResourceBundle resources, BibleBook book, Map fullMap, Map shortMap, Map altMap) {
 386  0
             String osisName = book.getOSIS();
 387  
 
 388  0
             String fullBook = getString(resources, osisName + FULL_KEY);
 389  
 
 390  0
             String shortBook = getString(resources, osisName + SHORT_KEY);
 391  0
             if (shortBook.length() == 0) {
 392  0
                 shortBook = fullBook;
 393  
             }
 394  
 
 395  0
             String altBook = getString(resources, osisName + ALT_KEY);
 396  
 
 397  0
             BookName bookName = new BookName(locale, BibleBook.fromOSIS(osisName), fullBook, shortBook, altBook);
 398  0
             books.put(book, bookName);
 399  
 
 400  0
             fullMap.put(bookName.getNormalizedLongName(), bookName);
 401  
 
 402  0
             shortMap.put(bookName.getNormalizedShortName(), bookName);
 403  
 
 404  0
             String[] alternates = StringUtil.split(BookName.normalize(altBook, locale), ',');
 405  
 
 406  0
             for (int j = 0; j < alternates.length; j++) {
 407  0
                 altMap.put(alternates[j], bookName);
 408  
             }
 409  0
         }
 410  
 
 411  
         /*
 412  
          * Helper to make the code more readable.
 413  
          */
 414  
         private String getString(ResourceBundle resources, String key) {
 415  
             try {
 416  0
                 return resources.getString(key);
 417  0
             } catch (MissingResourceException e) {
 418  0
                 assert false;
 419  
             }
 420  0
             return null;
 421  
         }
 422  
 
 423  
         private static final String FULL_KEY = ".Full";
 424  
         private static final String SHORT_KEY = ".Short";
 425  
         private static final String ALT_KEY = ".Alt";
 426  
 
 427  
         /** The locale for the Bible Names */
 428  
         private Locale locale;
 429  
 
 430  
         /**
 431  
          * The collection of BookNames by BibleBooks.
 432  
          */
 433  
         private LinkedHashMap<BibleBook, BookName> books;
 434  
 
 435  
         /**
 436  
          * The full names of the New Testament books of the Bible normalized,
 437  
          * generated at runtime
 438  
          */
 439  
         private Map<String, BookName> fullNT;
 440  
 
 441  
         /**
 442  
          * The full names of the Old Testament books of the Bible normalized,
 443  
          * generated at runtime
 444  
          */
 445  
         private Map<String, BookName> fullOT;
 446  
 
 447  
         /**
 448  
          * The full names of the Deuterocanonical books of the Bible normalized,
 449  
          * generated at runtime
 450  
          */
 451  
         private Map<String, BookName> fullNC;
 452  
 
 453  
         /**
 454  
          * Standard shortened names for the New Testament books of the Bible,
 455  
          * normalized, generated at runtime.
 456  
          */
 457  
         private Map<String, BookName> shortNT;
 458  
 
 459  
         /**
 460  
          * Standard shortened names for the Old Testament books of the Bible
 461  
          * normalized, generated at runtime.
 462  
          */
 463  
         private Map<String, BookName> shortOT;
 464  
 
 465  
         /**
 466  
          * Standard shortened names for the Deuterocanonical books of the Bible
 467  
          * normalized, generated at runtime.
 468  
          */
 469  
         private Map<String, BookName> shortNC;
 470  
 
 471  
         /**
 472  
          * Alternative shortened names for the New Testament books of the Bible
 473  
          * normalized, generated at runtime.
 474  
          */
 475  
         private Map<String, BookName> altNT;
 476  
 
 477  
         /**
 478  
          * Alternative shortened names for the Old Testament books of the Bible
 479  
          * normalized, generated at runtime.
 480  
          */
 481  
         private Map<String, BookName> altOT;
 482  
 
 483  
         /**
 484  
          * Alternative shortened names for the Deuterocanonical books of the
 485  
          * Bible normalized, generated at runtime.
 486  
          */
 487  
         private Map<String, BookName> altNC;
 488  
     }
 489  
 
 490  
     /** we cache the Localized Bible Names because there is quite a bit of processing going on for each individual Locale */
 491  
     private transient Map<Locale, NameList> localizedBibleNames;
 492  
 
 493  
     /** English BibleNames, or null when using the program's default locale */
 494  
     private static NameList englishBibleNames;
 495  
 
 496  0
     private static final BibleNames instance = new BibleNames();
 497  
 }