[jsword-svn] r1789 - in trunk: common/.settings common/src/main/java/org/crosswire/common/util jsword/src/main/java/org/crosswire/jsword/book jsword/src/main/java/org/crosswire/jsword/bridge jsword/src/main/java/org/crosswire/jsword/examples jsword/src/main/java/org/crosswire/jsword/passage jsword/src/test/java/org/crosswire/jsword jsword/src/test/java/org/crosswire/jsword/bridge

dmsmith at www.crosswire.org dmsmith at www.crosswire.org
Wed Apr 9 14:48:08 MST 2008


Author: dmsmith
Date: 2008-04-09 14:48:06 -0700 (Wed, 09 Apr 2008)
New Revision: 1789

Added:
   trunk/common/src/main/java/org/crosswire/common/util/ItemIterator.java
   trunk/jsword/src/main/java/org/crosswire/jsword/bridge/BookExporter.java
   trunk/jsword/src/main/java/org/crosswire/jsword/bridge/BookIndexer.java
   trunk/jsword/src/main/java/org/crosswire/jsword/bridge/BookInstaller.java
   trunk/jsword/src/test/java/org/crosswire/jsword/bridge/
   trunk/jsword/src/test/java/org/crosswire/jsword/bridge/DwrBridgeTest.java
Removed:
   trunk/jsword/src/main/java/org/crosswire/jsword/examples/BookExporter.java
   trunk/jsword/src/main/java/org/crosswire/jsword/examples/BookIndexer.java
   trunk/jsword/src/main/java/org/crosswire/jsword/examples/BookInstaller.java
Modified:
   trunk/common/.settings/org.eclipse.jdt.ui.prefs
   trunk/jsword/src/main/java/org/crosswire/jsword/book/Books.java
   trunk/jsword/src/main/java/org/crosswire/jsword/bridge/DwrBridge.java
   trunk/jsword/src/main/java/org/crosswire/jsword/examples/APIExamples.java
   trunk/jsword/src/main/java/org/crosswire/jsword/passage/DefaultLeafKeyList.java
   trunk/jsword/src/main/java/org/crosswire/jsword/passage/Verse.java
   trunk/jsword/src/main/java/org/crosswire/jsword/passage/VerseRange.java
Log:
Added an adapter for DWR called DwrBridge.

Modified: trunk/common/.settings/org.eclipse.jdt.ui.prefs
===================================================================
--- trunk/common/.settings/org.eclipse.jdt.ui.prefs	2008-04-08 15:32:33 UTC (rev 1788)
+++ trunk/common/.settings/org.eclipse.jdt.ui.prefs	2008-04-09 21:48:06 UTC (rev 1789)
@@ -1,4 +1,4 @@
-#Tue Jul 03 08:56:45 EDT 2007
+#Fri Apr 04 09:24:53 GMT-05:00 2008
 cleanup.add_default_serial_version_id=false
 cleanup.add_generated_serial_version_id=true
 cleanup.add_missing_annotations=true
@@ -54,4 +54,4 @@
 org.eclipse.jdt.ui.exception.name=e
 org.eclipse.jdt.ui.gettersetter.use.is=true
 org.eclipse.jdt.ui.overrideannotation=true
-org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/**\n * Distribution License\:\n * JSword is free software; you can redistribute it and/or modify it under\n * the terms of the GNU Lesser General Public License, version 2.1 as published by\n * the Free Software Foundation. This program is distributed in the hope\n * that it will be useful, but WITHOUT ANY WARRANTY; without even the\n * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n * See the GNU Lesser General Public License for more details.\n *\n * The License is available on the internet at\:\n *       http\://www.gnu.org/copyleft/lgpl.html\n * or by writing to\:\n *      Free Software Foundation, Inc.\n *      59 Temple Place - Suite 330\n *      Boston, MA 02111-1307, USA\n *\n * Copyright\: 2007\n *     The copyright to this program is held by it's authors.\n *\n * ID\: $$Id\: org.eclipse.jdt.ui.prefs 1178 2006-11-06 12\:48\:02Z dmsmith $$\n */\n</templ!
 ate><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n *\n *\n * @see gnu.lgpl.License for license details.&lt;br&gt;\n *      The copyright to this program is held by it's authors.\n * @author DM Smith [dmsmith555 at yahoo dot com]\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="true" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment">/* (non-Javadoc)\n * ${see_to_overridden}\n */</template><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="true" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" descri!
 ption\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8"?>\n<templates><template id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment" description\="Comment for getter method" context\="gettercomment_context" enabled\="true" deleted\="false" autoinsert\="true">/**\n * @return the ${bare_field_name}\n */</template><template id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment" description\="Comment for setter method" context\="settercomment_context" enabled\="true" deleted\="false" autoinsert\="true">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment" description\="Comment for created constructors" context\="constructorcomment_context" enabled\="true" deleted\="false" autoinsert\="true">/**\n * ${tags}\n */</template><template id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment" description\="Comment for created Java files" context\="filecomment_context" enabled\="true" deleted\="false" autoinsert\="false">/**\n * Distribution License\:\n * JSword is free software; you can redistribute it and/or modify it under\n * the terms of the GNU Lesser General Public License, version 2.1 as published by\n * the Free Software Foundation. This program is distributed in the hope\n * that it will be useful, but WITHOUT ANY WARRANTY; without even the\n * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n * See the GNU Lesser General Public License for more details.\n *\n * The License is available on the internet at\:\n *       http\://www.gnu.org/copyleft/lgpl.html\n * or by writing to\:\n *      Free Software Foundation, Inc.\n *      59 Temple Place - Suite 330\n *      Boston, MA 02111-1307, USA\n *\n * Copyright\: 2007\n *     The copyright to this program is held by it's authors.\n *\n * ID\: $$Id\: org.eclipse.jdt.ui.prefs 1178 2006-11-06 12\:48\:02Z dmsmith $$\n */\n</tem!
 plate><template id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment" description\="Comment for created types" context\="typecomment_context" enabled\="true" deleted\="false" autoinsert\="false">/**\n *\n *\n * @see gnu.lgpl.License for license details.&lt;br&gt;\n *      The copyright to this program is held by it's authors.\n * @author DM Smith [dmsmith555 at yahoo dot com]\n */</template><template id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment" description\="Comment for fields" context\="fieldcomment_context" enabled\="true" deleted\="false" autoinsert\="true">/**\n * \n */</template><template id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment" description\="Comment for non-overriding methods" context\="methodcomment_context" enabled\="true" deleted\="false" autoinsert\="true">/**\n * ${tags}\n */</template><template id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment" description\="Comment for overriding methods" context\="overridecomment_context" enabled\="true" deleted\="false" autoinsert\="true">/* (non-Javadoc)\n * ${see_to_overridden}\n */</template><template id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment" description\="Comment for delegate methods" context\="delegatecomment_context" enabled\="true" deleted\="false" autoinsert\="true">/**\n * ${tags}\n * ${see_to_target}\n */</template><template id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype" description\="Newly created files" context\="newtype_context" enabled\="true" deleted\="false" autoinsert\="true">${filecomment}\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody" description\="Code in new class type bodies" context\="classbody_context" enabled\="true" deleted\="false" autoinsert\="true">\n</template><template id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfac!
 ebody" description\="Code in new interface type bodies" context\="interfacebody_context" enabled\="true" deleted\="false" autoinsert\="true">\n</template><template id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody" description\="Code in new enum type bodies" context\="enumbody_context" enabled\="true" deleted\="false" autoinsert\="true">\n</template><template id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody" description\="Code in new annotation type bodies" context\="annotationbody_context" enabled\="true" deleted\="false" autoinsert\="true">\n</template><template id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock" description\="Code in new catch blocks" context\="catchblock_context" enabled\="true" deleted\="false" autoinsert\="true">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody" description\="Code in created method stubs" context\="methodbody_context" enabled\="true" deleted\="false" autoinsert\="true">// ${todo} Auto-generated method stub\n${body_statement}</template><template id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody" description\="Code in created constructor stubs" context\="constructorbody_context" enabled\="true" deleted\="false" autoinsert\="true">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody" description\="Code in created getters" context\="getterbody_context" enabled\="true" deleted\="false" autoinsert\="true">return ${field};</template><template id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody" description\="Code in created setters" context\="setterbody_context" enabled\="true" deleted\="false" autoinsert\="true">${field} \= ${param};</template></templates>

Added: trunk/common/src/main/java/org/crosswire/common/util/ItemIterator.java
===================================================================
--- trunk/common/src/main/java/org/crosswire/common/util/ItemIterator.java	                        (rev 0)
+++ trunk/common/src/main/java/org/crosswire/common/util/ItemIterator.java	2008-04-09 21:48:06 UTC (rev 1789)
@@ -0,0 +1,76 @@
+/**
+ * Distribution License:
+ * JSword is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License, version 2.1 as published by
+ * the Free Software Foundation. This program is distributed in the hope
+ * that it will be useful, but WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The License is available on the internet at:
+ *       http://www.gnu.org/copyleft/lgpl.html
+ * or by writing to:
+ *      Free Software Foundation, Inc.
+ *      59 Temple Place - Suite 330
+ *      Boston, MA 02111-1307, USA
+ *
+ * Copyright: 2008
+ *     The copyright to this program is held by it's authors.
+ *
+ * ID: $Id: ItemIterator.java 1462 2007-07-02 02:32:23Z dmsmith $
+ */
+package org.crosswire.common.util;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+
+/**
+ * An <code>ItemIterator</code> is an <code>Iterator</code> that iterates
+ * a single item.
+ *
+ *
+ * @see gnu.lgpl.License for license details.<br>
+ *      The copyright to this program is held by it's authors.
+ * @author DM Smith [ dmsmith555 at yahoo dot com]
+ */
+public class ItemIterator implements Iterator
+{
+    public ItemIterator(Object item)
+    {
+        this.item = item;
+    }
+
+    /* (non-Javadoc)
+     * @see java.util.Iterator#hasNext()
+     */
+    public boolean hasNext()
+    {
+        return !done;
+    }
+
+    /* (non-Javadoc)
+     * @see java.util.Iterator#next()
+     */
+    public Object next()
+    {
+        if (done)
+        {
+            throw new NoSuchElementException();
+        }
+
+        done = true;
+        return item;
+    }
+
+    /* (non-Javadoc)
+     * @see java.util.Iterator#remove()
+     */
+    public void remove() throws UnsupportedOperationException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    private Object  item;
+    private boolean done;
+}

Modified: trunk/jsword/src/main/java/org/crosswire/jsword/book/Books.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/book/Books.java	2008-04-08 15:32:33 UTC (rev 1788)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/book/Books.java	2008-04-09 21:48:06 UTC (rev 1789)
@@ -84,6 +84,11 @@
      */
     public synchronized Book getBook(String name)
     {
+        if (name == null)
+        {
+            return null;
+        }
+
         // Check name first
         // First check for exact matches
         Iterator iter = books.iterator();

Copied: trunk/jsword/src/main/java/org/crosswire/jsword/bridge/BookExporter.java (from rev 1785, trunk/jsword/src/main/java/org/crosswire/jsword/examples/BookExporter.java)
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/bridge/BookExporter.java	                        (rev 0)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/bridge/BookExporter.java	2008-04-09 21:48:06 UTC (rev 1789)
@@ -0,0 +1,122 @@
+/**
+ * Distribution License:
+ * JSword is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License, version 2.1 as published by
+ * the Free Software Foundation. This program is distributed in the hope
+ * that it will be useful, but WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The License is available on the internet at:
+ *       http://www.gnu.org/copyleft/lgpl.html
+ * or by writing to:
+ *      Free Software Foundation, Inc.
+ *      59 Temple Place - Suite 330
+ *      Boston, MA 02111-1307, USA
+ *
+ * Copyright: 2008
+ *     The copyright to this program is held by it's authors.
+ *
+ * ID: $Id: BookIndexer.java 1466 2007-07-02 02:48:09Z dmsmith $
+ */
+package org.crosswire.jsword.bridge;
+
+import java.util.Iterator;
+
+import org.crosswire.jsword.book.Book;
+import org.crosswire.jsword.book.BookCategory;
+import org.crosswire.jsword.book.BookException;
+import org.crosswire.jsword.book.Books;
+import org.crosswire.jsword.passage.Key;
+import org.crosswire.jsword.versification.BibleInfo;
+
+/**
+ * Exports the Book in SWORD's imp format.
+ * This is identical to SWORD's mod2imp.
+ * Note: it does not work with GenBook.
+ * 
+ * @see gnu.lgpl.License for license details.
+ *      The copyright to this program is held by it's authors.
+ * @author DM Smith [dmsmith555 at yahoo dot com]
+ */
+public class BookExporter
+{
+
+    public BookExporter(Book book)
+    {
+        this.book = book;
+    }
+
+    public void mod2imp() throws BookException
+    {
+        // Use short key names for Bibles.
+        if (BookCategory.BIBLE.equals(book.getBookCategory()))
+        {
+            BibleInfo.setFullBookName(false);
+        }
+
+        Key keys = book.getGlobalKeyList();
+
+        Iterator iter = keys.iterator();
+        StringBuffer buf = new StringBuffer();
+        while (iter.hasNext())
+        {
+            Key key = (Key) iter.next();
+            String rawText = book.getRawText(key);
+            if (rawText != null && rawText.trim().length() > 0)
+            {
+                buf.delete(0, buf.length());
+                buf.append("$$$").append(key).append('\n').append(rawText); //$NON-NLS-1$
+                System.out.println(buf.toString());
+            }
+        }
+    }
+
+    private Book book;
+
+    /**
+     * Call with &lt;operation&gt; book.
+     * Where operation can be one of:
+     * <ul>
+     * <li>check - returns "TRUE" or "FALSE" indicating whether the index exists or not</li>
+     * <li>create - (re)create the index</li>
+     * <li>delete - delete the index if it exists</li>
+     * </ul>
+     * And book is the initials of a book, e.g. KJV.
+     * 
+     * @param args
+     */
+    public static void main(String[] args)
+    {
+        if (args.length != 1)
+        {
+            usage();
+        }
+
+        System.err.println("BookExporter " + args[0]); //$NON-NLS-1$
+
+        Book b = Books.installed().getBook(args[0]);
+        if (b == null)
+        {
+            System.err.println("Book not found"); //$NON-NLS-1$
+            System.exit(1);
+        }
+
+        BookExporter exporter = new BookExporter(b);
+        try
+        {
+            exporter.mod2imp();
+        }
+        catch (BookException e)
+        {
+            System.err.println("Error while exporting"); //$NON-NLS-1$
+            e.printStackTrace();
+        }
+    }
+
+    public static void usage()
+    {
+        System.err.println("Usage: BookExporter book"); //$NON-NLS-1$
+        System.exit(1);
+    }
+}

Copied: trunk/jsword/src/main/java/org/crosswire/jsword/bridge/BookIndexer.java (from rev 1785, trunk/jsword/src/main/java/org/crosswire/jsword/examples/BookIndexer.java)
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/bridge/BookIndexer.java	                        (rev 0)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/bridge/BookIndexer.java	2008-04-09 21:48:06 UTC (rev 1789)
@@ -0,0 +1,202 @@
+/**
+ * Distribution License:
+ * JSword is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License, version 2.1 as published by
+ * the Free Software Foundation. This program is distributed in the hope
+ * that it will be useful, but WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The License is available on the internet at:
+ *       http://www.gnu.org/copyleft/lgpl.html
+ * or by writing to:
+ *      Free Software Foundation, Inc.
+ *      59 Temple Place - Suite 330
+ *      Boston, MA 02111-1307, USA
+ *
+ * Copyright: 2008
+ *     The copyright to this program is held by it's authors.
+ *
+ * ID: $Id: BookIndexer.java 1466 2007-07-02 02:48:09Z dmsmith $
+ */
+package org.crosswire.jsword.bridge;
+
+import org.crosswire.jsword.book.Book;
+import org.crosswire.jsword.book.BookException;
+import org.crosswire.jsword.book.Books;
+import org.crosswire.jsword.index.IndexManager;
+import org.crosswire.jsword.index.IndexManagerFactory;
+import org.crosswire.jsword.index.IndexStatusEvent;
+import org.crosswire.jsword.index.IndexStatusListener;
+
+/**
+ * BookIndexer allows one to check the status of an index, build an index or delete an index.
+ * This is similar to SWORD's mkfastmod.
+ * 
+ * @see gnu.lgpl.License for license details.
+ *      The copyright to this program is held by it's authors.
+ * @author DM Smith [dmsmith555 at yahoo dot com]
+ */
+public class BookIndexer
+{
+
+    public BookIndexer(Book book)
+    {
+        this.book = book;
+        done = true; // not busy
+        indexManager = IndexManagerFactory.getIndexManager();
+        isl = new StatusListener(this);
+    }
+
+    public boolean isIndexed()
+    {
+        // If we are busy then the index is being created
+        // or it is being deleted. So for all practical purposes
+        // it is not indexed.
+        return done && indexManager.isIndexed(book);
+    }
+
+    public void deleteIndex() throws BookException
+    {
+        if (done)
+        {
+            done = false;
+            book.addIndexStatusListener(isl);
+            indexManager.deleteIndex(book);
+            while (!done)
+            {
+                try
+                {
+                    Thread.sleep(100);
+                }
+                catch (InterruptedException e)
+                {
+                    // ok to be interrupted
+                }
+            }
+            book.removeIndexStatusListener(isl);
+        }
+    }
+
+    public void createIndex() throws BookException
+    {
+        if (done)
+        {
+            done = false;
+            book.addIndexStatusListener(isl);
+            if (isIndexed())
+            {
+                deleteIndex();
+            }
+            indexManager.scheduleIndexCreation(book);
+            while (!done)
+            {
+                try
+                {
+                    Thread.sleep(100);
+                }
+                catch (InterruptedException e)
+                {
+                    // ok to be interrupted
+                }
+            }
+            book.removeIndexStatusListener(isl);
+        }
+    }
+
+    protected void setDone(boolean state)
+    {
+        done = state;
+    }
+
+    private Book book;
+    private IndexManager indexManager;
+    private IndexStatusListener isl;
+    private boolean done;
+
+    public static final class StatusListener implements IndexStatusListener
+    {
+        public StatusListener(BookIndexer indexer)
+        {
+            this.indexer = indexer;
+        }
+
+        public void statusChanged(IndexStatusEvent ev)
+        {
+            indexer.setDone(true);
+        }
+
+        BookIndexer indexer;
+        
+    }
+
+    /**
+     * Call with &lt;operation&gt; book.
+     * Where operation can be one of:
+     * <ul>
+     * <li>check - returns "TRUE" or "FALSE" indicating whether the index exists or not</li>
+     * <li>create - (re)create the index</li>
+     * <li>delete - delete the index if it exists</li>
+     * </ul>
+     * And book is the initials of a book, e.g. KJV.
+     * 
+     * @param args
+     */
+    public static void main(String[] args)
+    {
+        if (args.length != 2)
+        {
+            usage();
+        }
+
+        System.err.println("BookIndexer " + args[0] + " " + args[1]); //$NON-NLS-1$ //$NON-NLS-2$
+
+        String operation = args[0];
+        Book b = Books.installed().getBook(args[1]);
+        if (b == null)
+        {
+            System.err.println("Book not found"); //$NON-NLS-1$
+            System.exit(1);
+        }
+
+        BookIndexer indexer = new BookIndexer(b);
+        if (operation.equalsIgnoreCase("create")) //$NON-NLS-1$
+        {
+            try
+            {
+                indexer.createIndex();
+            }
+            catch (BookException e)
+            {
+                System.err.println("Unable to re-index book."); //$NON-NLS-1$
+                e.printStackTrace();
+            }
+        }
+        else if (operation.equalsIgnoreCase("delete")) //$NON-NLS-1$
+        {
+            try
+            {
+                indexer.deleteIndex();
+            }
+            catch (BookException e)
+            {
+                System.err.println("Unable to delete index for book."); //$NON-NLS-1$
+                e.printStackTrace();
+            }
+        }
+        else if (operation.equalsIgnoreCase("check")) //$NON-NLS-1$
+        {
+            System.err.println(indexer.isIndexed());
+        }
+        else
+        {
+            usage();
+        }
+    }
+
+    public static void usage()
+    {
+        System.err.println("Usage: BookIndexer operation book"); //$NON-NLS-1$
+        System.exit(1);
+    }
+}

Copied: trunk/jsword/src/main/java/org/crosswire/jsword/bridge/BookInstaller.java (from rev 1785, trunk/jsword/src/main/java/org/crosswire/jsword/examples/BookInstaller.java)
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/bridge/BookInstaller.java	                        (rev 0)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/bridge/BookInstaller.java	2008-04-09 21:48:06 UTC (rev 1789)
@@ -0,0 +1,366 @@
+/**
+ * Distribution License:
+ * JSword is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License, version 2.1 as published by
+ * the Free Software Foundation. This program is distributed in the hope
+ * that it will be useful, but WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The License is available on the internet at:
+ *       http://www.gnu.org/copyleft/lgpl.html
+ * or by writing to:
+ *      Free Software Foundation, Inc.
+ *      59 Temple Place - Suite 330
+ *      Boston, MA 02111-1307, USA
+ *
+ * Copyright: 2008
+ *     The copyright to this program is held by it's authors.
+ *
+ * ID: $Id: BookIndexer.java 1466 2007-07-02 02:48:09Z dmsmith $
+ */
+package org.crosswire.jsword.bridge;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.crosswire.jsword.book.Book;
+import org.crosswire.jsword.book.BookException;
+import org.crosswire.jsword.book.BookFilter;
+import org.crosswire.jsword.book.BookFilters;
+import org.crosswire.jsword.book.Books;
+import org.crosswire.jsword.book.install.InstallException;
+import org.crosswire.jsword.book.install.InstallManager;
+import org.crosswire.jsword.book.install.Installer;
+
+/**
+ * Exports the Book in SWORD's imp format.
+ * This is identical to SWORD's mod2imp.
+ * Note: it does not work with GenBook.
+ * 
+ * @see gnu.lgpl.License for license details.
+ *      The copyright to this program is held by it's authors.
+ * @author DM Smith [dmsmith555 at yahoo dot com]
+ */
+public class BookInstaller
+{
+
+    public BookInstaller()
+    {
+        installManager = new InstallManager();
+    }
+
+    /**
+     * Uninstall a book.
+     * @param book the book to delete
+     * @throws BookException 
+     */
+    public void deleteBook(Book book) throws BookException
+    {
+        // Make the book unavailable.
+        // This is normally done via listeners.
+        Books.installed().removeBook(book);
+
+        // Actually do the delete
+        // This should be a call on installer.
+        book.getDriver().delete(book);
+
+    }
+
+    /**
+     * Get a list of all know installers.
+     * 
+     * @return
+     */
+    public Map getInstallers()
+    {
+        // Ask the Install Manager for a map of all known remote repositories sites
+        return installManager.getInstallers();
+    }
+
+    /**
+     * Get a list of all installed books.
+     * @return the list of installed books
+     */
+    public static List getInstalledBooks()
+    {
+        return Books.installed().getBooks();
+    }
+
+    /**
+     * Get a list of installed books by BookFilter.
+     * @param filter The book filter
+     * @see BookFilter
+     * @see Books
+     */
+    public static List getInstalledBooks(BookFilter filter)
+    {
+        return Books.installed().getBooks(filter);
+    }
+
+    /**
+     * Get a list of books by CustomFilter specification
+     * @param filter The filter string
+     * @see BookFilters#getCustom(java.lang.String)
+     * @see Books
+     */
+    public static List getInstalledBooks(String filterSpec)
+    {
+        return getInstalledBooks(BookFilters.getCustom(filterSpec));
+    }
+
+    /**
+     * Get a particular installed book by initials.
+     * 
+     * @param bookInitials The book name to search for
+     * @return The found book. Null otherwise.
+     */
+    public static Book getInstalledBook(String bookInitials)
+    {
+        return Books.installed().getBook(bookInitials);
+    }
+
+    /**
+     * Get a list of all known books for an installer.
+     * @param repositoryName
+     * @return the list of books at that repository
+     */
+    public List getRepositoryBooks(String repositoryName)
+    {
+        return installManager.getInstaller(repositoryName).getBooks();
+    }
+
+    /**
+     * Get a list of books in a repository by BookFilter.
+     * @param filter The book filter
+     * @see BookFilter
+     * @see Books
+     */
+    public List getRepositoryBooks(String repositoryName, BookFilter filter)
+    {
+        return installManager.getInstaller(repositoryName).getBooks(filter);
+    }
+
+    /**
+     * Get a list of books in a repository by CustomFilter specification
+     * @param filter The filter string
+     * @see BookFilters#getCustom(java.lang.String)
+     * @see Books
+     */
+    public List getRepositoryBooks(String repositoryName, String filterSpec)
+    {
+        return getRepositoryBooks(repositoryName, BookFilters.getCustom(filterSpec));
+    }
+
+    /**
+     * Get a particular installed book by initials.
+     * 
+     * @param bookInitials The book name to search for
+     * @return The found book. Null otherwise.
+     */
+    public Book getRepositoryBook(String repositoryName, String bookInitials)
+    {
+        return installManager.getInstaller(repositoryName).getBook(bookInitials);
+    }
+
+    /**
+     * Reload the local cache for a remote repository.
+     * 
+     * @param repositoryName
+     * @throws InstallException 
+     */
+    public void reloadBookList(String repositoryName) throws InstallException
+    {
+        installManager.getInstaller(repositoryName).reloadBookList();
+    }
+
+    /**
+     * Get a Book from the repository. Note this does not install it.
+     * 
+     * @param repositoryName the repository from which to get the book
+     * @param bookName the name of the book to get
+     * @return
+     */
+    public Book getBook(String repositoryName, String bookName)
+    {
+        return installManager.getInstaller(repositoryName).getBook(bookName);     
+    }
+
+    /**
+     * Install a book, overwriting it if the book to be installed is newer.
+     * 
+     * @param repositoryName the name of the repository from which to get the book
+     * @param bookName the book to get
+     * @throws BookException 
+     * @throws InstallException 
+     */
+    public void installBook(String repositoryName, Book book) throws BookException, InstallException
+    {
+        // An installer knows how to install books
+        Installer installer = installManager.getInstaller(repositoryName);
+
+        // Delete the book, if present
+        // At the moment, JSword will not re-install. Later it will, if the
+        // remote version is greater.
+        if (Books.installed().getBook(book.getInitials()) != null)
+        {
+            deleteBook(book);
+        }
+
+        // Now install it. Note this is a background task.
+        installer.install(book);
+    }
+
+    private InstallManager installManager;
+
+    /**
+     * BookInstaller can manage the installation of books with the following capabilities.
+     * 
+     * Usage: BookInstaller [option]<br/>
+     * Options:
+     * <table border="0">
+     * <tr><td>uninstall</td><td>bookName               </td><td>Uninstall book</td></tr>
+     * <tr><td>sources  </td><td>&nbsp;                 </td><td>List source repositories</td></tr>
+     * <tr><td>list     </td><td>&nbsp;                 </td><td>List installed books</td></tr>
+     * <tr><td>list     </td><td>repositoryName         </td><td>list available books from a repository</td></tr>
+     * <tr><td>reload   </td><td>repositoryName         </td><td>Reload the local cache for a repository</td></tr>
+     * <tr><td>install  </td><td>repositoryName bookName</td><td>Install a book from a repository</td></tr>
+     * </table>
+     * 
+     * @param args
+     */
+    public static void main(String[] args)
+    {
+        if (args.length < 1)
+        {
+            usage();
+        }
+
+        System.err.print("BookExporter" + args[0]); //$NON-NLS-1$
+        for (int i = 1; i < args.length; i++)
+        {
+            System.err.print(' ');
+            System.err.print(args[i]);
+        }
+
+        BookInstaller installer = new BookInstaller();
+
+        String operation = args[0];
+        if (operation.equalsIgnoreCase("uninstall")) //$NON-NLS-1$
+        {
+            Book b = Books.installed().getBook(args[1]);
+            if (b == null)
+            {
+                System.err.println("Book not found"); //$NON-NLS-1$
+                System.exit(1);
+            }
+            try
+            {
+                installer.deleteBook(b);
+            }
+            catch (BookException e)
+            {
+                e.printStackTrace();
+            }
+        }
+        else if (operation.equalsIgnoreCase("sources")) //$NON-NLS-1$
+        {
+            // Get all the installers one after the other
+            Map installers = installer.getInstallers();
+            Iterator iter = installers.keySet().iterator();
+            while (iter.hasNext())
+            {
+                System.out.println(iter.next());
+            }
+        }
+        else if (operation.equalsIgnoreCase("list")) //$NON-NLS-1$
+        {
+            if (args.length == 1)
+            {
+                Iterator iter = BookInstaller.getInstalledBooks().iterator();
+                while (iter.hasNext())
+                {
+                    Book book = (Book) iter.next();
+                    System.out.println(book.getInitials());
+                }
+            }
+            else if (args.length == 2)
+            {
+                Iterator iter =  installer.getRepositoryBooks(args[1]).iterator();
+                while (iter.hasNext())
+                {
+                    Book book = (Book) iter.next();
+                    System.out.println(book.getInitials());
+                }                
+            }
+            else
+            {
+                usage();
+            }
+        }
+        else if (operation.equalsIgnoreCase("reload")) //$NON-NLS-1$
+        {
+           if (args.length == 2)
+           {
+               try
+               {
+                   installer.reloadBookList(args[1]);
+               }
+               catch (InstallException e)
+               {
+                   e.printStackTrace();
+               }
+            }
+            else
+            {
+                usage();
+            }
+        }
+        else if (operation.equalsIgnoreCase("install")) //$NON-NLS-1$
+        {
+            if (args.length == 3)
+            {
+                Book b = installer.getBook(args[1], args[2]);
+                if (b == null)
+                {
+                    System.err.println("Book not found"); //$NON-NLS-1$
+                    System.exit(1);
+                }
+                try
+                {
+                    installer.installBook(args[1], b);
+                }
+                catch (BookException e)
+                {
+                    e.printStackTrace();
+                }
+                catch (InstallException e)
+                {
+                    e.printStackTrace();
+                }
+            }
+            else
+            {
+                usage();
+            }
+        }
+        else
+        {
+            usage();
+        }
+    }
+
+    public static void usage()
+    {
+        System.err.println("usage: BookInstaller <option>"); //$NON-NLS-1$
+        System.err.println("Options:"); //$NON-NLS-1$
+        System.err.println("    uninstall bookName                 Uninstall book"); //$NON-NLS-1$
+        System.err.println("    sources                            List remote source repositories"); //$NON-NLS-1$
+        System.err.println("    list                               List installed books"); //$NON-NLS-1$
+        System.err.println("    list      repositoryName           List available books from a repository"); //$NON-NLS-1$
+        System.err.println("    refresh   repositoryName           Reload local cache for a repository"); //$NON-NLS-1$
+        System.err.println("    install   repositoryName bookName  Install a book from a repository"); //$NON-NLS-1$
+        System.exit(1);
+    }
+}

Modified: trunk/jsword/src/main/java/org/crosswire/jsword/bridge/DwrBridge.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/bridge/DwrBridge.java	2008-04-08 15:32:33 UTC (rev 1788)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/bridge/DwrBridge.java	2008-04-09 21:48:06 UTC (rev 1789)
@@ -21,21 +21,28 @@
  */
 package org.crosswire.jsword.bridge;
 
+import java.io.File;
+import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Locale;
 
 import org.crosswire.common.xml.SAXEventProvider;
+import org.crosswire.common.xml.SerializingContentHandler;
 import org.crosswire.jsword.book.Book;
 import org.crosswire.jsword.book.BookCategory;
 import org.crosswire.jsword.book.BookData;
 import org.crosswire.jsword.book.BookException;
-import org.crosswire.jsword.book.BookFilter;
 import org.crosswire.jsword.book.BookFilters;
 import org.crosswire.jsword.book.Books;
-import org.crosswire.jsword.book.OSISUtil;
+import org.crosswire.jsword.book.sword.SwordBookPath;
+import org.crosswire.jsword.index.IndexManagerFactory;
 import org.crosswire.jsword.passage.Key;
 import org.crosswire.jsword.passage.NoSuchKeyException;
 import org.crosswire.jsword.passage.Passage;
+import org.crosswire.jsword.versification.BibleInfo;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
 
 /**
  * The DWR DwrBridge adapts JSword to DWR. This is based upon APIExamples.
@@ -47,107 +54,245 @@
 public class DwrBridge
 {
     /**
-     * Get just the canonical text of one or more book entries without any markup.
-     *
-     * @param bookInitials the book to use
-     * @param reference a reference, appropriate for the book, of one or more entries
+     * Get a listing of all the available books.
+     * 
+     * @param filter The custom filter specification string
+     * @return a list of (initial, name) string pairs
+     * @see BookFilters#getCustom(java.lang.String)
+     * @see Books
      */
-    public String getPlainText(String bookInitials, String reference) throws BookException, NoSuchKeyException
+    public String[][] getInstalledBooks(String filter)
     {
-        Book book = getInstalledBook(bookInitials);
-        if (book == null)
+        List reply = new ArrayList();        
+
+        List books = BookInstaller.getInstalledBooks(filter);
+
+        Iterator iter = books.iterator();
+        while (iter.hasNext())
         {
-            return ""; //$NON-NLS-1$
+            Book book = (Book) iter.next();
+            String[] rbook = new String[]
+            {
+                            book.getInitials(), book.getName()
+            };
+            reply.add(rbook);
         }
 
-        Key      key  = book.getKey(reference);
-        BookData data = new BookData(book, key);
-        return OSISUtil.getCanonicalText(data.getOsisFragment());
+        // If we can't find a book, indicate that.
+        if (reply.size() == 0)
+        {
+            reply.add(new String[] { "", "No Books installed" }); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+
+        return (String[][]) reply.toArray(new String[reply.size()][]);
     }
 
     /**
-     * Obtain a SAX event provider for the OSIS document representation of one or more book entries.
+     * Determine whether the named book can be searched, that is, whether
+     * the book is indexed.
+     * 
+     * @param bookInitials the named book to check.
+     * @return true if searching can be performed
+     */
+    public boolean isIndexed(String bookInitials)
+    {
+        return isIndexed(BookInstaller.getInstalledBook(bookInitials));
+    }
+
+    /**
+     * Obtain the OSIS representation from a book for a reference, pruning a reference to a limited number of keys.
      *
      * @param bookInitials the book to use
-     * @param reference a reference, appropriate for the book, of one or more entries
+     * @param reference a reference, appropriate for the book, for one or more keys
      */
-    private SAXEventProvider getOSIS(String bookInitials, String reference, int maxKeyCount) throws BookException, NoSuchKeyException
+    public String getOSISString(String bookInitials, String reference, int maxKeyCount) throws BookException, NoSuchKeyException
     {
-        if (bookInitials == null || reference == null)
+        String result = ""; //$NON-NLS-1$
+        try
         {
-            return null;
+            SAXEventProvider sep = getOSISProvider(bookInitials, reference, maxKeyCount);
+            if (sep != null)
+            {
+                ContentHandler ser = new SerializingContentHandler();
+                sep.provideSAXEvents(ser);
+                result = ser.toString();
+            }
+            return result;
         }
+        catch (SAXException ex)
+        {
+//            throw new BookException(Msg.JSWORD_SAXPARSE, ex);
+        }
+        return result;
+    }
 
-        Book book = getInstalledBook(bookInitials);
+    /**
+     * @param bookInitials
+     * @param searchRequest
+     * @return
+     * @throws BookException
+     */
+    public String search(String bookInitials, String searchRequest) throws BookException
+    {
+        Book book = BookInstaller.getInstalledBook(bookInitials);
+        if (isIndexed(book) && searchRequest != null)
+        {
+            if (BookCategory.BIBLE.equals(book.getBookCategory()))
+            {
+                BibleInfo.setFullBookName(false);
+            }
+            return book.find(searchRequest).getName();
+        }
+        return ""; //$NON-NLS-1$
+    }
 
-        Key key = null;
-        if (BookCategory.BIBLE.equals(book.getBookCategory()))
+    /**
+     * Get close matches for a target in a book whose keys have a meaningful sort. This is not true of
+     * keys that are numeric or contain numbers. (unless the numbers are 0 filled.)
+     */
+    public String[] match(String bookInitials, String searchRequest, int maxMatchCount)
+    {
+        Book book = BookInstaller.getInstalledBook(bookInitials);
+        if (book == null || searchRequest == null || maxMatchCount < 1)
         {
-            key = book.getKey(reference);
-            key = ((Passage) key).trimVerses(maxKeyCount);
+            return new String[0];
         }
-        else
+
+        // Need to use the locale of the book so that we can find stuff in the proper order
+        Locale sortLocale = new Locale(book.getLanguage().getCode());
+        String target = searchRequest.toLowerCase(sortLocale);
+
+        // Get everything with target as the prefix.
+        // In Unicode \uFFFF is reserved for internal use
+        // and is greater than every character defined in Unicode
+        String endTarget = target + '\uffff';
+
+        // This whole getGlobalKeyList is messy.
+        // 1) Some drivers cache the list which is slow.
+        // 2) Binary lookup would be much better.
+        // 3) Caching the whole list here is dumb.
+        // What is needed is that all this be pushed into JSword proper.
+        // TODO(dms): Push this into Book interface.
+        List result = new ArrayList();
+        Iterator iter = book.getGlobalKeyList().iterator();
+        int count = 0;
+        while (iter.hasNext())
         {
-            key = book.createEmptyKeyList();
-            
-            Iterator iter = book.getKey(reference).iterator();
-            int count = 0;
-            while (iter.hasNext())
+            Key key = (Key) iter.next();
+            String entry = key.getName().toLowerCase(sortLocale);
+            if (entry.compareTo(target) >= 0)
             {
-                if (++count >= maxKeyCount)
+                if (entry.compareTo(endTarget) < 0)
                 {
+                    result.add(entry);
+                    count++;
+                }
+
+                // Have we seen enough?
+                if (count >= maxMatchCount)
+                {
                     break;
                 }
-                key.addAll((Key) iter.next());
             }
         }
 
-        BookData data = new BookData(book, key);
-
-        return data.getSAXEventProvider();
+        return (String[]) result.toArray(new String[result.size()]);
     }
 
     /**
-     * Get a list of all installed books.
-     * @return the list of installed books
+     * For the sake of diagnostics, return the locations that JSword will look for books.
+     * @return
      */
-    private List getInstalledBooks()
+    public String[] getSwordPath()
     {
-        return Books.installed().getBooks();
+        File[] filePath = SwordBookPath.getSwordPath();
+        if (filePath.length == 0)
+        {
+            return new String[] { "No path" } ; //$NON-NLS-1$
+        }
+        String[] path = new String[filePath.length];
+        for (int i = 0; i < filePath.length; i++)
+        {
+            path[i] = filePath[i].getAbsolutePath();
+        }
+        return path;
     }
 
     /**
-     * Get a list of installed books by BookFilter.
-     * @param filter The book filter
-     * @see BookFilter
-     * @see Books
+     * Determine whether the book can be searched, that is, whether
+     * the book is indexed.
+     * 
+     * @param book the book to check.
+     * @return true if searching can be performed
      */
-    private List getInstalledBooks(BookFilter filter)
+    private boolean isIndexed(Book book)
     {
-        return Books.installed().getBooks(filter);
+        return book != null && IndexManagerFactory.getIndexManager().isIndexed(book);
     }
 
     /**
-     * Get a list of books by CustomFilter specification
-     * @param filter The filter string
-     * @see BookFilters#getCustom(java.lang.String)
-     * @see Books
+     * Get BookData representing one or more Book entries, but capped to a maximum number of entries.
+     * 
+     * @param bookInitials the book to use
+     * @param reference a reference, appropriate for the book, of one or more entries
+     * @param maxKeyCount the maximum number of entries to use
+     * 
+     * @throws NoSuchKeyException 
      */
-    private List getInstalledBooks(String filterSpec)
+    private BookData getBookData(String bookInitials, String reference, int maxKeyCount) throws NoSuchKeyException
     {
-        return getInstalledBooks(BookFilters.getCustom(filterSpec));
+        Book book = BookInstaller.getInstalledBook(bookInitials);
+        if (book == null || reference == null || maxKeyCount < 1)
+        {
+            return null;
+        }
+
+        // TODO(dms): add trim to the key interface.
+        Key key = null;
+        if (BookCategory.BIBLE.equals(book.getBookCategory()))
+        {
+            key = book.getKey(reference);
+            ((Passage) key).trimVerses(maxKeyCount);
+        }
+        else if (BookCategory.GENERAL_BOOK.equals(book.getBookCategory()))
+        {
+            // At this time we cannot trim a General Book
+            key = book.getKey(reference);
+        }
+        else
+        {
+            key = book.createEmptyKeyList();
+            
+            Iterator iter = book.getKey(reference).iterator();
+            int count = 0;
+            while (iter.hasNext())
+            {
+                if (++count >= maxKeyCount)
+                {
+                    break;
+                }
+                key.addAll((Key) iter.next());
+            }
+        }
+
+        return new BookData(book, key);        
     }
 
     /**
-     * Get a particular installed book by initials.
-     * 
-     * @param bookInitials The book name to search for
-     * @return The found book. Null otherwise.
+     * Obtain a SAX event provider for the OSIS document representation of one or more book entries.
+     *
+     * @param bookInitials the book to use
+     * @param reference a reference, appropriate for the book, of one or more entries
      */
-    private Book getInstalledBook(String bookInitials)
+    private SAXEventProvider getOSISProvider(String bookInitials, String reference, int maxKeyCount) throws BookException, NoSuchKeyException
     {
-        return Books.installed().getBook(bookInitials);
+        BookData data = getBookData(bookInitials, reference, maxKeyCount);
+        SAXEventProvider provider = null;
+        if (data != null)
+        {
+            provider = data.getSAXEventProvider();
+        }
+        return provider;
     }
 
-
 }

Modified: trunk/jsword/src/main/java/org/crosswire/jsword/examples/APIExamples.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/examples/APIExamples.java	2008-04-08 15:32:33 UTC (rev 1788)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/examples/APIExamples.java	2008-04-09 21:48:06 UTC (rev 1789)
@@ -35,6 +35,7 @@
 import org.crosswire.common.xml.TransformingSAXEventProvider;
 import org.crosswire.common.xml.XMLUtil;
 import org.crosswire.jsword.book.Book;
+import org.crosswire.jsword.book.BookCategory;
 import org.crosswire.jsword.book.BookData;
 import org.crosswire.jsword.book.BookException;
 import org.crosswire.jsword.book.BookFilter;
@@ -72,53 +73,108 @@
     private static final String BIBLE_NAME = "KJV"; //$NON-NLS-1$
 
     /**
-     * The source to this method is an example of how to read the plain text of
-     * a verse, and print it to stdout. Reading from a Commentary is just the
-     * same as reading from a Bible.
-     * @see Book
+     * Get a particular installed book by initials.
+     * 
+     * @param bookInitials The book name to search for
+     * @return The found book. Null otherwise.
      */
-    public void readPlainText() throws BookException, NoSuchKeyException
+    public Book getBook(String bookInitials)
     {
-        Books books = Books.installed();
-        Book bible = books.getBook(BIBLE_NAME);
+        return Books.installed().getBook(bookInitials);
+    }
 
-        Key key = bible.getKey("Gen 1 1"); //$NON-NLS-1$
-        BookData data = new BookData(bible, key);
-        String text = OSISUtil.getCanonicalText(data.getOsisFragment());
+    /**
+     * Get just the canonical text of one or more book entries without any markup.
+     *
+     * @param bookInitials the book to use
+     * @param reference a reference, appropriate for the book, of one or more entries
+     */
+    public String getPlainText(String bookInitials, String reference) throws BookException, NoSuchKeyException
+    {
+        Book book = getBook(bookInitials);
+        if (book == null)
+        {
+            return ""; //$NON-NLS-1$
+        }
 
-        System.out.println("The plain text of Gen 1:1 is " + text); //$NON-NLS-1$
+        Key      key  = book.getKey(reference);
+        BookData data = new BookData(book, key);
+        return OSISUtil.getCanonicalText(data.getOsisFragment());
     }
 
     /**
-     * This method demonstrates how to get styled text (in this case HTML) from
-     * a verse, and print it to stdout. Reading from a Commentary is just the
-     * same as reading from a Bible.
+     * Obtain a SAX event provider for the OSIS document representation of one or more book entries.
+     *
+     * @param bookInitials the book to use
+     * @param reference a reference, appropriate for the book, of one or more entries
+     */
+    public SAXEventProvider getOSIS(String bookInitials, String reference, int maxKeyCount) throws BookException, NoSuchKeyException
+    {
+        if (bookInitials == null || reference == null)
+        {
+            return null;
+        }
+
+        Book book = getBook(bookInitials);
+
+        Key key = null;
+        if (BookCategory.BIBLE.equals(book.getBookCategory()))
+        {
+            key = book.getKey(reference);
+            key = ((Passage) key).trimVerses(maxKeyCount);
+        }
+        else
+        {
+            key = book.createEmptyKeyList();
+            
+            Iterator iter = book.getKey(reference).iterator();
+            int count = 0;
+            while (iter.hasNext())
+            {
+                if (++count >= maxKeyCount)
+                {
+                    break;
+                }
+                key.addAll((Key) iter.next());
+            }
+        }
+
+        BookData data = new BookData(book, key);
+
+        return data.getSAXEventProvider();
+    }
+
+    /**
+     * Obtain styled text (in this case HTML) for a book reference.
+     * 
+     * @param bookInitials the book to use
+     * @param reference a reference, appropriate for the book, of one or more entries
+     * @return the styled text
      * @see Book
      * @see SAXEventProvider
      */
-    public void readStyledText() throws NoSuchKeyException, BookException, TransformerException, SAXException
+    public String readStyledText(String bookInitials, String reference, int maxKeyCount) throws NoSuchKeyException, BookException, TransformerException, SAXException
     {
-        Book bible = Books.installed().getBook(BIBLE_NAME);
+        Book book = getBook(bookInitials);
+        SAXEventProvider osissep = getOSIS(bookInitials, reference, maxKeyCount);
+        if (osissep == null)
+        {
+            return ""; //$NON-NLS-1$
+        }
 
-        Key key = bible.getKey("Gen 1 1"); //$NON-NLS-1$
-        BookData data = new BookData(bible, key);
-        SAXEventProvider osissep = data.getSAXEventProvider();
-
         Converter styler = ConverterFactory.getConverter();
 
         TransformingSAXEventProvider htmlsep = (TransformingSAXEventProvider) styler.convert(osissep);
 
-        // You can also pass parameters to the xslt. What you pass depends upon what the xslt can use.
-        BookMetaData bmd = bible.getBookMetaData();
+        // You can also pass parameters to the XSLT. What you pass depends upon what the XSLT can use.
+        BookMetaData bmd = book.getBookMetaData();
         boolean direction = bmd.isLeftToRight();
         htmlsep.setParameter("direction", direction ? "ltr" : "rtl"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 
         // Finally you can get the styled text.
-        String text = XMLUtil.writeToString(htmlsep);
-
-        System.out.println("The html text of Gen 1:1 is " + text); //$NON-NLS-1$
+        return XMLUtil.writeToString(htmlsep);
     }
-
+    
     /**
      * While Bible and Commentary are very similar, a Dictionary is read in a
      * slightly different way. It is also worth looking at the JavaDoc for
@@ -350,6 +406,7 @@
             }
         }
     }
+
     /**
      * A simple BookFilter that looks for a Bible by name.
      */
@@ -400,8 +457,8 @@
         APIExamples examples = new APIExamples();
 
         examples.installBook();
-        examples.readPlainText();
-        examples.readStyledText();
+        System.out.println("The plain text of Gen 1:1 is " + examples.getPlainText(BIBLE_NAME, "Gen 1:1")); //$NON-NLS-1$ //$NON-NLS-2$
+        System.out.println("The html text of Gen 1:1 is " + examples.readStyledText(BIBLE_NAME, "Gen 1:1", 100)); //$NON-NLS-1$ //$NON-NLS-2$
         examples.readDictionary();
         examples.search();
         examples.rankedSearch();

Deleted: trunk/jsword/src/main/java/org/crosswire/jsword/examples/BookExporter.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/examples/BookExporter.java	2008-04-08 15:32:33 UTC (rev 1788)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/examples/BookExporter.java	2008-04-09 21:48:06 UTC (rev 1789)
@@ -1,122 +0,0 @@
-/**
- * Distribution License:
- * JSword is free software; you can redistribute it and/or modify it under
- * the terms of the GNU Lesser General Public License, version 2.1 as published by
- * the Free Software Foundation. This program is distributed in the hope
- * that it will be useful, but WITHOUT ANY WARRANTY; without even the
- * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The License is available on the internet at:
- *       http://www.gnu.org/copyleft/lgpl.html
- * or by writing to:
- *      Free Software Foundation, Inc.
- *      59 Temple Place - Suite 330
- *      Boston, MA 02111-1307, USA
- *
- * Copyright: 2008
- *     The copyright to this program is held by it's authors.
- *
- * ID: $Id: BookIndexer.java 1466 2007-07-02 02:48:09Z dmsmith $
- */
-package org.crosswire.jsword.examples;
-
-import java.util.Iterator;
-
-import org.crosswire.jsword.book.Book;
-import org.crosswire.jsword.book.BookCategory;
-import org.crosswire.jsword.book.BookException;
-import org.crosswire.jsword.book.Books;
-import org.crosswire.jsword.passage.Key;
-import org.crosswire.jsword.versification.BibleInfo;
-
-/**
- * Exports the Book in SWORD's imp format.
- * This is identical to SWORD's mod2imp.
- * Note: it does not work with GenBook.
- * 
- * @see gnu.lgpl.License for license details.
- *      The copyright to this program is held by it's authors.
- * @author DM Smith [dmsmith555 at yahoo dot com]
- */
-public class BookExporter
-{
-
-    public BookExporter(Book book)
-    {
-        this.book = book;
-    }
-
-    public void mod2imp() throws BookException
-    {
-        // Use short key names for Bibles.
-        if (BookCategory.BIBLE.equals(book.getBookCategory()))
-        {
-            BibleInfo.setFullBookName(false);
-        }
-
-        Key keys = book.getGlobalKeyList();
-
-        Iterator iter = keys.iterator();
-        StringBuffer buf = new StringBuffer();
-        while (iter.hasNext())
-        {
-            Key key = (Key) iter.next();
-            String rawText = book.getRawText(key);
-            if (rawText != null && rawText.trim().length() > 0)
-            {
-                buf.delete(0, buf.length());
-                buf.append("$$$").append(key).append('\n').append(rawText); //$NON-NLS-1$
-                System.out.println(buf.toString());
-            }
-        }
-    }
-
-    private Book book;
-
-    /**
-     * Call with &lt;operation&gt; book.
-     * Where operation can be one of:
-     * <ul>
-     * <li>check - returns "TRUE" or "FALSE" indicating whether the index exists or not</li>
-     * <li>create - (re)create the index</li>
-     * <li>delete - delete the index if it exists</li>
-     * </ul>
-     * And book is the initials of a book, e.g. KJV.
-     * 
-     * @param args
-     */
-    public static void main(String[] args)
-    {
-        if (args.length != 1)
-        {
-            usage();
-        }
-
-        System.err.println("BookExporter " + args[0]); //$NON-NLS-1$
-
-        Book b = Books.installed().getBook(args[0]);
-        if (b == null)
-        {
-            System.err.println("Book not found"); //$NON-NLS-1$
-            System.exit(1);
-        }
-
-        BookExporter exporter = new BookExporter(b);
-        try
-        {
-            exporter.mod2imp();
-        }
-        catch (BookException e)
-        {
-            System.err.println("Error while exporting"); //$NON-NLS-1$
-            e.printStackTrace();
-        }
-    }
-
-    public static void usage()
-    {
-        System.err.println("Usage: BookExporter book"); //$NON-NLS-1$
-        System.exit(1);
-    }
-}

Deleted: trunk/jsword/src/main/java/org/crosswire/jsword/examples/BookIndexer.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/examples/BookIndexer.java	2008-04-08 15:32:33 UTC (rev 1788)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/examples/BookIndexer.java	2008-04-09 21:48:06 UTC (rev 1789)
@@ -1,202 +0,0 @@
-/**
- * Distribution License:
- * JSword is free software; you can redistribute it and/or modify it under
- * the terms of the GNU Lesser General Public License, version 2.1 as published by
- * the Free Software Foundation. This program is distributed in the hope
- * that it will be useful, but WITHOUT ANY WARRANTY; without even the
- * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The License is available on the internet at:
- *       http://www.gnu.org/copyleft/lgpl.html
- * or by writing to:
- *      Free Software Foundation, Inc.
- *      59 Temple Place - Suite 330
- *      Boston, MA 02111-1307, USA
- *
- * Copyright: 2008
- *     The copyright to this program is held by it's authors.
- *
- * ID: $Id: BookIndexer.java 1466 2007-07-02 02:48:09Z dmsmith $
- */
-package org.crosswire.jsword.examples;
-
-import org.crosswire.jsword.book.Book;
-import org.crosswire.jsword.book.BookException;
-import org.crosswire.jsword.book.Books;
-import org.crosswire.jsword.index.IndexManager;
-import org.crosswire.jsword.index.IndexManagerFactory;
-import org.crosswire.jsword.index.IndexStatusEvent;
-import org.crosswire.jsword.index.IndexStatusListener;
-
-/**
- * BookIndexer allows one to check the status of an index, build an index or delete an index.
- * This is similar to SWORD's mkfastmod.
- * 
- * @see gnu.lgpl.License for license details.
- *      The copyright to this program is held by it's authors.
- * @author DM Smith [dmsmith555 at yahoo dot com]
- */
-public class BookIndexer
-{
-
-    public BookIndexer(Book book)
-    {
-        this.book = book;
-        done = true; // not busy
-        indexManager = IndexManagerFactory.getIndexManager();
-        isl = new StatusListener(this);
-    }
-
-    public boolean isIndexed()
-    {
-        // If we are busy then the index is being created
-        // or it is being deleted. So for all practical purposes
-        // it is not indexed.
-        return done && indexManager.isIndexed(book);
-    }
-
-    public void deleteIndex() throws BookException
-    {
-        if (done)
-        {
-            done = false;
-            book.addIndexStatusListener(isl);
-            indexManager.deleteIndex(book);
-            while (!done)
-            {
-                try
-                {
-                    Thread.sleep(100);
-                }
-                catch (InterruptedException e)
-                {
-                    // ok to be interrupted
-                }
-            }
-            book.removeIndexStatusListener(isl);
-        }
-    }
-
-    public void createIndex() throws BookException
-    {
-        if (done)
-        {
-            done = false;
-            book.addIndexStatusListener(isl);
-            if (isIndexed())
-            {
-                deleteIndex();
-            }
-            indexManager.scheduleIndexCreation(book);
-            while (!done)
-            {
-                try
-                {
-                    Thread.sleep(100);
-                }
-                catch (InterruptedException e)
-                {
-                    // ok to be interrupted
-                }
-            }
-            book.removeIndexStatusListener(isl);
-        }
-    }
-
-    protected void setDone(boolean state)
-    {
-        done = state;
-    }
-
-    private Book book;
-    private IndexManager indexManager;
-    private IndexStatusListener isl;
-    private boolean done;
-
-    public static final class StatusListener implements IndexStatusListener
-    {
-        public StatusListener(BookIndexer indexer)
-        {
-            this.indexer = indexer;
-        }
-
-        public void statusChanged(IndexStatusEvent ev)
-        {
-            indexer.setDone(true);
-        }
-
-        BookIndexer indexer;
-        
-    }
-
-    /**
-     * Call with &lt;operation&gt; book.
-     * Where operation can be one of:
-     * <ul>
-     * <li>check - returns "TRUE" or "FALSE" indicating whether the index exists or not</li>
-     * <li>create - (re)create the index</li>
-     * <li>delete - delete the index if it exists</li>
-     * </ul>
-     * And book is the initials of a book, e.g. KJV.
-     * 
-     * @param args
-     */
-    public static void main(String[] args)
-    {
-        if (args.length != 2)
-        {
-            usage();
-        }
-
-        System.err.println("BookIndexer " + args[0] + " " + args[1]); //$NON-NLS-1$ //$NON-NLS-2$
-
-        String operation = args[0];
-        Book b = Books.installed().getBook(args[1]);
-        if (b == null)
-        {
-            System.err.println("Book not found"); //$NON-NLS-1$
-            System.exit(1);
-        }
-
-        BookIndexer indexer = new BookIndexer(b);
-        if (operation.equalsIgnoreCase("create")) //$NON-NLS-1$
-        {
-            try
-            {
-                indexer.createIndex();
-            }
-            catch (BookException e)
-            {
-                System.err.println("Unable to re-index book."); //$NON-NLS-1$
-                e.printStackTrace();
-            }
-        }
-        else if (operation.equalsIgnoreCase("delete")) //$NON-NLS-1$
-        {
-            try
-            {
-                indexer.deleteIndex();
-            }
-            catch (BookException e)
-            {
-                System.err.println("Unable to delete index for book."); //$NON-NLS-1$
-                e.printStackTrace();
-            }
-        }
-        else if (operation.equalsIgnoreCase("check")) //$NON-NLS-1$
-        {
-            System.err.println(indexer.isIndexed());
-        }
-        else
-        {
-            usage();
-        }
-    }
-
-    public static void usage()
-    {
-        System.err.println("Usage: BookIndexer operation book"); //$NON-NLS-1$
-        System.exit(1);
-    }
-}

Deleted: trunk/jsword/src/main/java/org/crosswire/jsword/examples/BookInstaller.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/examples/BookInstaller.java	2008-04-08 15:32:33 UTC (rev 1788)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/examples/BookInstaller.java	2008-04-09 21:48:06 UTC (rev 1789)
@@ -1,298 +0,0 @@
-/**
- * Distribution License:
- * JSword is free software; you can redistribute it and/or modify it under
- * the terms of the GNU Lesser General Public License, version 2.1 as published by
- * the Free Software Foundation. This program is distributed in the hope
- * that it will be useful, but WITHOUT ANY WARRANTY; without even the
- * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The License is available on the internet at:
- *       http://www.gnu.org/copyleft/lgpl.html
- * or by writing to:
- *      Free Software Foundation, Inc.
- *      59 Temple Place - Suite 330
- *      Boston, MA 02111-1307, USA
- *
- * Copyright: 2008
- *     The copyright to this program is held by it's authors.
- *
- * ID: $Id: BookIndexer.java 1466 2007-07-02 02:48:09Z dmsmith $
- */
-package org.crosswire.jsword.examples;
-
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-import org.crosswire.jsword.book.Book;
-import org.crosswire.jsword.book.BookException;
-import org.crosswire.jsword.book.Books;
-import org.crosswire.jsword.book.install.InstallException;
-import org.crosswire.jsword.book.install.InstallManager;
-import org.crosswire.jsword.book.install.Installer;
-
-/**
- * Exports the Book in SWORD's imp format.
- * This is identical to SWORD's mod2imp.
- * Note: it does not work with GenBook.
- * 
- * @see gnu.lgpl.License for license details.
- *      The copyright to this program is held by it's authors.
- * @author DM Smith [dmsmith555 at yahoo dot com]
- */
-public class BookInstaller
-{
-
-    public BookInstaller()
-    {
-        installManager = new InstallManager();
-    }
-
-    /**
-     * Uninstall a book.
-     * @param book the book to delete
-     * @throws BookException 
-     */
-    public void deleteBook(Book book) throws BookException
-    {
-        // Make the book unavailable.
-        // This is normally done via listeners.
-        Books.installed().removeBook(book);
-
-        // Actually do the delete
-        // This should be a call on installer.
-        book.getDriver().delete(book);
-
-    }
-
-    /**
-     * Get a list of all know installers.
-     * 
-     * @return
-     */
-    public Map getInstallers()
-    {
-        // Ask the Install Manager for a map of all known remote repositories sites
-        return installManager.getInstallers();
-    }
-
-    /**
-     * Get a list of all installed books.
-     * @return the list of installed books
-     */
-    public List getInstalledBooks()
-    {
-        return Books.installed().getBooks();
-    }
-
-    /**
-     * Get a list of all known books for an installer.
-     * @param repositoryName
-     * @return the list of books at that repository
-     */
-    public List getRepositoryBooks(String repositoryName)
-    {
-        return installManager.getInstaller(repositoryName).getBooks();
-    }
-
-    /**
-     * Reload the local cache for a remote repository.
-     * 
-     * @param repositoryName
-     * @throws InstallException 
-     */
-    public void reloadBookList(String repositoryName) throws InstallException
-    {
-        installManager.getInstaller(repositoryName).reloadBookList();
-    }
-
-    /**
-     * Get a Book from the repository. Note this does not install it.
-     * 
-     * @param repositoryName the repository from which to get the book
-     * @param bookName the name of the book to get
-     * @return
-     */
-    public Book getBook(String repositoryName, String bookName)
-    {
-        return installManager.getInstaller(repositoryName).getBook(bookName);     
-    }
-
-    /**
-     * Install a book, overwriting it if the book to be installed is newer.
-     * 
-     * @param repositoryName the name of the repository from which to get the book
-     * @param bookName the book to get
-     * @throws BookException 
-     * @throws InstallException 
-     */
-    public void installBook(String repositoryName, Book book) throws BookException, InstallException
-    {
-        // An installer knows how to install books
-        Installer installer = installManager.getInstaller(repositoryName);
-
-        // Delete the book, if present
-        // At the moment, JSword will not re-install. Later it will, if the
-        // remote version is greater.
-        if (Books.installed().getBook(book.getInitials()) != null)
-        {
-            deleteBook(book);
-        }
-
-        // Now install it. Note this is a background task.
-        installer.install(book);
-    }
-
-    private InstallManager installManager;
-
-    /**
-     * BookInstaller can manage the installation of books with the following capabilities.
-     * 
-     * Usage: BookInstaller [option]<br/>
-     * Options:
-     * <table border="0">
-     * <tr><td>uninstall</td><td>bookName               </td><td>Uninstall book</td></tr>
-     * <tr><td>sources  </td><td>&nbsp;                 </td><td>List source repositories</td></tr>
-     * <tr><td>list     </td><td>&nbsp;                 </td><td>List installed books</td></tr>
-     * <tr><td>list     </td><td>repositoryName         </td><td>list available books from a repository</td></tr>
-     * <tr><td>reload   </td><td>repositoryName         </td><td>Reload the local cache for a repository</td></tr>
-     * <tr><td>install  </td><td>repositoryName bookName</td><td>Install a book from a repository</td></tr>
-     * </table>
-     * 
-     * @param args
-     */
-    public static void main(String[] args)
-    {
-        if (args.length < 1)
-        {
-            usage();
-        }
-
-        System.err.print("BookExporter" + args[0]); //$NON-NLS-1$
-        for (int i = 1; i < args.length; i++)
-        {
-            System.err.print(' ');
-            System.err.print(args[i]);
-        }
-
-        BookInstaller installer = new BookInstaller();
-
-        String operation = args[0];
-        if (operation.equalsIgnoreCase("uninstall")) //$NON-NLS-1$
-        {
-            Book b = Books.installed().getBook(args[1]);
-            if (b == null)
-            {
-                System.err.println("Book not found"); //$NON-NLS-1$
-                System.exit(1);
-            }
-            try
-            {
-                installer.deleteBook(b);
-            }
-            catch (BookException e)
-            {
-                e.printStackTrace();
-            }
-        }
-        else if (operation.equalsIgnoreCase("sources")) //$NON-NLS-1$
-        {
-            // Get all the installers one after the other
-            Map installers = installer.getInstallers();
-            Iterator iter = installers.keySet().iterator();
-            while (iter.hasNext())
-            {
-                System.out.println(iter.next());
-            }
-        }
-        else if (operation.equalsIgnoreCase("list")) //$NON-NLS-1$
-        {
-            if (args.length == 1)
-            {
-                Iterator iter = installer.getInstalledBooks().iterator();
-                while (iter.hasNext())
-                {
-                    Book book = (Book) iter.next();
-                    System.out.println(book.getInitials());
-                }
-            }
-            else if (args.length == 2)
-            {
-                Iterator iter =  installer.getRepositoryBooks(args[1]).iterator();
-                while (iter.hasNext())
-                {
-                    Book book = (Book) iter.next();
-                    System.out.println(book.getInitials());
-                }                
-            }
-            else
-            {
-                usage();
-            }
-        }
-        else if (operation.equalsIgnoreCase("reload")) //$NON-NLS-1$
-        {
-           if (args.length == 2)
-           {
-               try
-               {
-                   installer.reloadBookList(args[1]);
-               }
-               catch (InstallException e)
-               {
-                   e.printStackTrace();
-               }
-            }
-            else
-            {
-                usage();
-            }
-        }
-        else if (operation.equalsIgnoreCase("install")) //$NON-NLS-1$
-        {
-            if (args.length == 3)
-            {
-                Book b = installer.getBook(args[1], args[2]);
-                if (b == null)
-                {
-                    System.err.println("Book not found"); //$NON-NLS-1$
-                    System.exit(1);
-                }
-                try
-                {
-                    installer.installBook(args[1], b);
-                }
-                catch (BookException e)
-                {
-                    e.printStackTrace();
-                }
-                catch (InstallException e)
-                {
-                    e.printStackTrace();
-                }
-            }
-            else
-            {
-                usage();
-            }
-        }
-        else
-        {
-            usage();
-        }
-    }
-
-    public static void usage()
-    {
-        System.err.println("usage: BookInstaller <option>"); //$NON-NLS-1$
-        System.err.println("Options:"); //$NON-NLS-1$
-        System.err.println("    uninstall bookName                 Uninstall book"); //$NON-NLS-1$
-        System.err.println("    sources                            List remote source repositories"); //$NON-NLS-1$
-        System.err.println("    list                               List installed books"); //$NON-NLS-1$
-        System.err.println("    list      repositoryName           List available books from a repository"); //$NON-NLS-1$
-        System.err.println("    refresh   repositoryName           Reload local cache for a repository"); //$NON-NLS-1$
-        System.err.println("    install   repositoryName bookName  Install a book from a repository"); //$NON-NLS-1$
-        System.exit(1);
-    }
-}

Modified: trunk/jsword/src/main/java/org/crosswire/jsword/passage/DefaultLeafKeyList.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/passage/DefaultLeafKeyList.java	2008-04-08 15:32:33 UTC (rev 1788)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/passage/DefaultLeafKeyList.java	2008-04-09 21:48:06 UTC (rev 1789)
@@ -23,7 +23,7 @@
 
 import java.util.Iterator;
 
-import org.crosswire.common.util.EmptyIterator;
+import org.crosswire.common.util.ItemIterator;
 
 /**
  * A simple default implementation of the Key interface.
@@ -129,7 +129,7 @@
      */
     public boolean isEmpty()
     {
-        return true;
+        return false;
     }
 
     /* (non-Javadoc)
@@ -137,7 +137,7 @@
      */
     public boolean contains(Key key)
     {
-        return false;
+        return this.equals(key);
     }
 
     /* (non-Javadoc)
@@ -145,7 +145,7 @@
      */
     public Iterator iterator()
     {
-        return new EmptyIterator();
+        return new ItemIterator(this);
     }
 
     /* (non-Javadoc)
@@ -184,6 +184,10 @@
      */
     public Key get(int index)
     {
+        if (index == 0)
+        {
+            return this;
+        }
         return null;
     }
 
@@ -192,6 +196,10 @@
      */
     public int indexOf(Key that)
     {
+        if (this.equals(that))
+        {
+            return 0;
+        }
         return -1;
     }
 

Modified: trunk/jsword/src/main/java/org/crosswire/jsword/passage/Verse.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/passage/Verse.java	2008-04-08 15:32:33 UTC (rev 1788)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/passage/Verse.java	2008-04-09 21:48:06 UTC (rev 1789)
@@ -26,9 +26,9 @@
 import java.io.ObjectOutputStream;
 import java.io.Serializable;
 import java.util.Iterator;
-import java.util.NoSuchElementException;
 
 import org.crosswire.common.icu.NumberShaper;
+import org.crosswire.common.util.ItemIterator;
 import org.crosswire.common.util.Logger;
 import org.crosswire.jsword.versification.BibleInfo;
 
@@ -820,44 +820,6 @@
         // default ctor so I will ignore it here.
     }
 
-    /**
-     * Iterator over 1 verse - For being a VerseBase.
-     */
-    class VerseIterator implements Iterator
-    {
-        /* (non-Javadoc)
-         * @see java.util.Iterator#hasNext()
-         */
-        public boolean hasNext()
-        {
-            return !done;
-        }
-
-        /* (non-Javadoc)
-         * @see java.util.Iterator#next()
-         */
-        public Object next()
-        {
-            if (done)
-            {
-                throw new NoSuchElementException();
-            }
-
-            done = true;
-            return Verse.this;
-        }
-
-        /* (non-Javadoc)
-         * @see java.util.Iterator#remove()
-         */
-        public void remove() throws UnsupportedOperationException
-        {
-            throw new UnsupportedOperationException();
-        }
-
-        private boolean done;
-    }
-
     /* (non-Javadoc)
      * @see org.crosswire.jsword.passage.Key#canHaveChildren()
      */
@@ -887,7 +849,7 @@
      */
     public boolean isEmpty()
     {
-        return true;
+        return false;
     }
 
     /* (non-Javadoc)
@@ -895,7 +857,7 @@
      */
     public boolean contains(Key key)
     {
-        return false;
+        return this.equals(key);
     }
 
     /* (non-Javadoc)
@@ -903,7 +865,7 @@
      */
     public Iterator iterator()
     {
-        return new VerseIterator();
+        return new ItemIterator(this);
     }
 
     /* (non-Javadoc)
@@ -942,6 +904,10 @@
      */
     public Key get(int index)
     {
+        if (index == 0)
+        {
+            return this;
+        }
         return null;
     }
 
@@ -950,6 +916,10 @@
      */
     public int indexOf(Key that)
     {
+        if (this.equals(that))
+        {
+            return 0;
+        }
         return -1;
     }
 

Modified: trunk/jsword/src/main/java/org/crosswire/jsword/passage/VerseRange.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/passage/VerseRange.java	2008-04-08 15:32:33 UTC (rev 1788)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/passage/VerseRange.java	2008-04-09 21:48:06 UTC (rev 1789)
@@ -1128,7 +1128,7 @@
      */
     public boolean isEmpty()
     {
-        return true;
+        return verseCount == 0;
     }
 
     /* (non-Javadoc)

Added: trunk/jsword/src/test/java/org/crosswire/jsword/bridge/DwrBridgeTest.java
===================================================================
--- trunk/jsword/src/test/java/org/crosswire/jsword/bridge/DwrBridgeTest.java	                        (rev 0)
+++ trunk/jsword/src/test/java/org/crosswire/jsword/bridge/DwrBridgeTest.java	2008-04-09 21:48:06 UTC (rev 1789)
@@ -0,0 +1,98 @@
+/**
+ * Distribution License:
+ * JSword is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License, version 2.1 as published by
+ * the Free Software Foundation. This program is distributed in the hope
+ * that it will be useful, but WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The License is available on the internet at:
+ *       http://www.gnu.org/copyleft/lgpl.html
+ * or by writing to:
+ *      Free Software Foundation, Inc.
+ *      59 Temple Place - Suite 330
+ *      Boston, MA 02111-1307, USA
+ *
+ * Copyright: 2008
+ *     The copyright to this program is held by it's authors.
+ *
+ * ID: $Id: org.eclipse.jdt.ui.prefs 1178 2006-11-06 12:48:02Z dmsmith $
+ */
+package org.crosswire.jsword.bridge;
+
+import org.crosswire.jsword.book.BookException;
+import org.crosswire.jsword.passage.NoSuchKeyException;
+
+import junit.framework.TestCase;
+
+/**
+ * Test of functionality for use with DWR. This test assumes, at a minimum,
+ * that KJV, Strong's Greek and Hebrew Dictionaries, Robinson's morphological codes, ... are installed
+ * and that the KJV is indexed.
+ *
+ * @see gnu.lgpl.License for license details.<br>
+ *      The copyright to this program is held by it's authors.
+ * @author DM Smith [dmsmith555 at yahoo dot com]
+ */
+public class DwrBridgeTest extends TestCase
+{
+    DwrBridge dwrBridge = new DwrBridge();
+
+    protected void setUp()
+    {
+    }
+
+    public void testGetBooks()
+    {
+        String[][] bibles = dwrBridge.getInstalledBooks("bookCategory=Bible"); //$NON-NLS-1$
+        assertTrue(bibles.length > 1);
+
+        String[][] dicts  = dwrBridge.getInstalledBooks("bookCategory=Dictionary"); //$NON-NLS-1$
+        assertTrue(dicts.length > 1);
+    }
+
+    public void testGetOsisString()
+    {
+        try
+        {
+            String verse = dwrBridge.getOSISString("KJV", "Gen 1:1", 100); //$NON-NLS-1$ //$NON-NLS-2$
+            assertEquals(verse, "<div><title type=\"x-gen\">Genesis 1:1</title><verse osisID=\"Gen.1.1\"><w lemma=\"strong:H07225\">In the beginning</w> <w lemma=\"strong:H0430\">God</w> <w lemma=\"strong:H0853 strong:H01254\" morph=\"strongMorph:TH8804\">created</w> <w lemma=\"strong:H08064\">the heaven</w> <w lemma=\"strong:H0853\">and</w> <w lemma=\"strong:H0776\">the earth</w>.</verse></div>"); //$NON-NLS-1$
+            String hdef = dwrBridge.getOSISString("StrongsHebrew", "H07225", 100); //$NON-NLS-1$ //$NON-NLS-2$
+            assertEquals(hdef, "H07225"); //$NON-NLS-1$
+        }
+        catch (BookException e)
+        {
+            fail(e.getDetailedMessage());
+        }
+        catch (NoSuchKeyException e)
+        {
+            fail();
+        }
+    }
+
+    public void testIndexed()
+    {
+        assertTrue(dwrBridge.isIndexed("KJV")); //$NON-NLS-1$
+        assertFalse(dwrBridge.isIndexed("not a bible")); //$NON-NLS-1$ 
+    }
+
+    public void testSearch()
+    {
+        try
+        {
+            String result = dwrBridge.search("KJV", "aaron AND moses AND egypt"); //$NON-NLS-1$ //$NON-NLS-2$
+            assertEquals(result, "Exo 5:4, 6:13, 26-27, 7:19, 8:5, 16, 12:1, 16:6, 32:1, Num 14:2, 26:59, 33:1, Jos 24:5, 1Sa 12:6, 8, Mic 6:4, Act 7:40"); //$NON-NLS-1$
+        }
+        catch (BookException e)
+        {
+            fail();
+        } 
+    }
+
+    public void testMatch()
+    {
+        String[] result = dwrBridge.match("StrongsGreek", "0001", 10); //$NON-NLS-1$ //$NON-NLS-2$
+        assertTrue(result.length == 10);
+    }
+}




More information about the jsword-svn mailing list