[jsword-svn] r1693 - in trunk: bibledesktop/src/main/java/org/crosswire/bibledesktop/book common common/src/main/java/org/crosswire/common/util common/src/test/java/org/crosswire/common/icu jsword/src/main/java/org/crosswire/jsword/book/install/sword jsword/src/main/java/org/crosswire/jsword/book/sword jsword/src/main/java/org/crosswire/jsword/index/lucene jsword/src/main/java/org/crosswire/jsword/util jsword-limbo/src/main/java/org/crosswire/jsword/book/search/ser

dmsmith at www.crosswire.org dmsmith at www.crosswire.org
Sun Aug 26 18:00:37 MST 2007


Author: dmsmith
Date: 2007-08-26 18:00:36 -0700 (Sun, 26 Aug 2007)
New Revision: 1693

Modified:
   trunk/bibledesktop/src/main/java/org/crosswire/bibledesktop/book/BibleViewPane.java
   trunk/common/JSwordDictionary.txt
   trunk/common/src/main/java/org/crosswire/common/util/CWClassLoader.java
   trunk/common/src/main/java/org/crosswire/common/util/NetUtil.java
   trunk/common/src/test/java/org/crosswire/common/icu/AllTests.java
   trunk/jsword-limbo/src/main/java/org/crosswire/jsword/book/search/ser/SerIndexManager.java
   trunk/jsword/src/main/java/org/crosswire/jsword/book/install/sword/AbstractSwordInstaller.java
   trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/SwordBookPath.java
   trunk/jsword/src/main/java/org/crosswire/jsword/index/lucene/LuceneIndexManager.java
   trunk/jsword/src/main/java/org/crosswire/jsword/util/Project.java
Log:
Made CD installations use a read-only jsword.home

Modified: trunk/bibledesktop/src/main/java/org/crosswire/bibledesktop/book/BibleViewPane.java
===================================================================
--- trunk/bibledesktop/src/main/java/org/crosswire/bibledesktop/book/BibleViewPane.java	2007-08-26 22:56:26 UTC (rev 1692)
+++ trunk/bibledesktop/src/main/java/org/crosswire/bibledesktop/book/BibleViewPane.java	2007-08-27 01:00:36 UTC (rev 1693)
@@ -89,11 +89,11 @@
     {
         try
         {
-            chooser = new JFileChooser(Project.instance().getUserSubProjectDir(BOOKMARK_DIR, true).getPath());
+            chooser = new JFileChooser(Project.instance().getWriteableProjectSubdir(BOOKMARK_DIR, true).getPath());
         }
         catch (IOException ex)
         {
-            chooser = new JFileChooser(Project.instance().getUserProjectDir().getPath());
+            chooser = new JFileChooser(Project.instance().getWritableProjectDir().getPath());
         }
 
         chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);

Modified: trunk/common/JSwordDictionary.txt
===================================================================
--- trunk/common/JSwordDictionary.txt	2007-08-26 22:56:26 UTC (rev 1692)
+++ trunk/common/JSwordDictionary.txt	2007-08-27 01:00:36 UTC (rev 1693)
@@ -24,3 +24,5 @@
 eireneh
 subdirectory
 deprecated
+primordial
+filesystem

Modified: trunk/common/src/main/java/org/crosswire/common/util/CWClassLoader.java
===================================================================
--- trunk/common/src/main/java/org/crosswire/common/util/CWClassLoader.java	2007-08-26 22:56:26 UTC (rev 1692)
+++ trunk/common/src/main/java/org/crosswire/common/util/CWClassLoader.java	2007-08-27 01:00:36 UTC (rev 1693)
@@ -21,7 +21,6 @@
  */
 package org.crosswire.common.util;
 
-import java.io.File;
 import java.net.URI;
 import java.net.URL;
 import java.security.AccessController;
@@ -31,6 +30,8 @@
  * CWClassLoader extends the regular class loader by using looking
  * in more places. This is needed so that ResourceBundle can find
  * resources that are not held in the same package as the class.
+ * This is expressed as a list of locations, called homes, that
+ * the program will look in.
  *
  * @see gnu.lgpl.License for license details.<br>
  *      The copyright to this program is held by it's authors.
@@ -125,7 +126,7 @@
             }
         }
 
-        // See if it can be found in the home directory
+        // See if it can be found in a home directory
         if (resource == null)
         {
             URI homeResource = CWClassLoader.findHomeResource(search);
@@ -261,50 +262,58 @@
     }
 
     /**
-     * If the application has set the home, it will return
-     * the application's home directory, otherwise it returns null.
+     * If the application has set the homes, it will return
+     * the application's requested home directory, otherwise it returns null.
      * @return Returns the home.
      */
-    public static synchronized URI getHome()
+    public static synchronized URI getHome(int i)
     {
-        return home;
+        if (i > 0 && i < homes.length)
+        {
+            return homes[i];
+        }
+        return null;
     }
 
     /**
      * Establish the applications home directory from where
      * additional resources can be found. URL is expected to
      * end with the directory name, not '/'.
-     * @param newhome The home to set.
+     * @param newHomes The home to set.
      */
-    public static synchronized void setHome(URI newhome)
+    public static synchronized void setHome(URI[] newHomes)
     {
-        home = newhome;
+        homes = new URI[newHomes.length];
+        System.arraycopy(newHomes, 0, homes, 0, newHomes.length);
     }
 
     /**
-     * Look for the resource in the home directory
+     * Look for the resource in the home directories, returning the first
+     * readable file.
+     * 
      * @param search must be non-null, non-empty
      */
     public static URI findHomeResource(String search)
     {
-        URI reply = null;
+        if (homes == null)
+        {
+            return null;
+        }
 
-        URI homeURI = getHome();
+        for (int i = 0; i < homes.length; i++)
+        {
+            URI homeURI = homes[i];
 
-        // Look at the application's home first to allow overrides
-        if (homeURI != null)
-        {
             URI override = NetUtil.lengthenURI(homeURI, search);
 
             // Make sure the file exists and can be read
-            File file = new File(override.getPath());
-            if (file.canRead())
+            if (NetUtil.canRead(override))
             {
-                reply = override;
+                return override;
             }
         }
 
-        return reply;
+        return null;
     }
 
     /**
@@ -355,5 +364,5 @@
     /**
      * Notion of a project's home from where additional resources can be found.
      */
-    private static URI home;
+    private static URI[] homes;
 }

Modified: trunk/common/src/main/java/org/crosswire/common/util/NetUtil.java
===================================================================
--- trunk/common/src/main/java/org/crosswire/common/util/NetUtil.java	2007-08-26 22:56:26 UTC (rev 1692)
+++ trunk/common/src/main/java/org/crosswire/common/util/NetUtil.java	2007-08-27 01:00:36 UTC (rev 1693)
@@ -227,7 +227,7 @@
      * If there is a writable directory or file at the other end of this URI return true.
      * Note non file: type URIs will always return false
      * @param orig The URI to check
-     * @return true if the URI points at a file: directory
+     * @return true if the URI points at a writable file or directory
      */
     public static boolean canWrite(URI orig)
     {
@@ -240,6 +240,22 @@
     }
 
     /**
+     * If there is a readable directory or file at the other end of this URI return true.
+     * Note non file: type URIs will always return false
+     * @param orig The URI to check
+     * @return true if the URI points at a readable file or directory
+     */
+    public static boolean canRead(URI orig)
+    {
+        if (!orig.getScheme().equals(PROTOCOL_FILE))
+        {
+            return false;
+        }
+
+        return new File(orig.getPath()).canRead();
+    }
+
+    /**
      * Move a URI from one place to another. Currently this only works for
      * file: URIs, however the interface should not need to change to
      * handle more complex URIs

Modified: trunk/common/src/test/java/org/crosswire/common/icu/AllTests.java
===================================================================
--- trunk/common/src/test/java/org/crosswire/common/icu/AllTests.java	2007-08-26 22:56:26 UTC (rev 1692)
+++ trunk/common/src/test/java/org/crosswire/common/icu/AllTests.java	2007-08-27 01:00:36 UTC (rev 1693)
@@ -37,7 +37,7 @@
     {
         TestSuite suite = new TestSuite("Test for org.crosswire.common.icu"); //$NON-NLS-1$
         //$JUnit-BEGIN$
-        suite.addTest(new TestSuite(NumberShaper.class));
+        suite.addTest(new TestSuite(NumberShaperTest.class));
         //$JUnit-END$
         return suite;
     }

Modified: trunk/jsword/src/main/java/org/crosswire/jsword/book/install/sword/AbstractSwordInstaller.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/book/install/sword/AbstractSwordInstaller.java	2007-08-26 22:56:26 UTC (rev 1692)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/book/install/sword/AbstractSwordInstaller.java	2007-08-27 01:00:36 UTC (rev 1693)
@@ -489,7 +489,7 @@
     {
         try
         {
-            URI scratchdir = Project.instance().getUserSubProjectDir(getTempFileExtension(host, catalogDirectory), true);
+            URI scratchdir = Project.instance().getWriteableProjectSubdir(getTempFileExtension(host, catalogDirectory), true);
             return NetUtil.lengthenURI(scratchdir, FILE_LIST_GZ);
         }
         catch (IOException ex)

Modified: trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/SwordBookPath.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/SwordBookPath.java	2007-08-26 22:56:26 UTC (rev 1692)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/SwordBookPath.java	2007-08-27 01:00:36 UTC (rev 1693)
@@ -32,6 +32,7 @@
 import java.util.Properties;
 
 import org.crosswire.common.util.Logger;
+import org.crosswire.common.util.OSType;
 import org.crosswire.common.util.StringUtil;
 import org.crosswire.jsword.book.BookException;
 import org.crosswire.jsword.book.Books;
@@ -181,13 +182,13 @@
             readSwordConf(bookDirs, sysconfigPaths[i]);
         }
 
-        URI userDataArea = Project.instance().getUserProjectDir(DIR_SWORD_CONF, DIR_SWORD_CONF_ALT);
+        URI userDataArea = OSType.getOSType().getUserAreaFolder(DIR_SWORD_CONF, DIR_SWORD_CONF_ALT);
 
         // Check look for mods.d in the sword user data area
         testDefaultPath(bookDirs, new File(userDataArea.getPath()));
 
         // If the migration did not work then use the old area
-        testDefaultPath(bookDirs, new File(Project.instance().getUserProjectDir().getPath()));
+        testDefaultPath(bookDirs, new File(Project.instance().getWritableProjectDir().getPath()));
 
         return (File[]) bookDirs.toArray(new File[bookDirs.size()]);
     }
@@ -291,7 +292,7 @@
         // If it is not found on the path then it doesn't exist yet and needs to be established
         if (path == null)
         {
-            URI userDataArea = Project.instance().getUserProjectDir(DIR_SWORD_CONF, DIR_SWORD_CONF_ALT);
+            URI userDataArea = OSType.getOSType().getUserAreaFolder(DIR_SWORD_CONF, DIR_SWORD_CONF_ALT);
             path = new File(userDataArea.getPath());
         }
 
@@ -301,13 +302,13 @@
     private static void migrateBookDir()
     {
         // Books should be on this path
-        URI userDataArea = Project.instance().getUserProjectDir(DIR_SWORD_CONF, DIR_SWORD_CONF_ALT);
+        URI userDataArea = OSType.getOSType().getUserAreaFolder(DIR_SWORD_CONF, DIR_SWORD_CONF_ALT);
 
         File swordBookPath = new File(userDataArea.getPath());
 
         // The "old" Book location might be in one of two locations
         // It might be ~/.jsword or the new project dir
-        File oldPath = new File(Project.instance().getDeprecatedUserProjectDir().getPath());
+        File oldPath = new File(Project.instance().getDeprecatedWritableProjectDir().getPath());
 
         if (oldPath.isDirectory())
         {
@@ -315,7 +316,7 @@
             return;
         }
 
-        oldPath = new File(Project.instance().getUserProjectDir().getPath());
+        oldPath = new File(Project.instance().getWritableProjectDir().getPath());
 
         if (oldPath.isDirectory())
         {

Modified: trunk/jsword/src/main/java/org/crosswire/jsword/index/lucene/LuceneIndexManager.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/index/lucene/LuceneIndexManager.java	2007-08-26 22:56:26 UTC (rev 1692)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/index/lucene/LuceneIndexManager.java	2007-08-27 01:00:36 UTC (rev 1693)
@@ -190,7 +190,7 @@
         assert driverName != null;
         assert bookName != null;
 
-        URI base = Project.instance().getUserSubProjectDir(DIR_LUCENE, false);
+        URI base = Project.instance().getWriteableProjectSubdir(DIR_LUCENE, false);
         URI driver = NetUtil.lengthenURI(base, driverName);
 
         return NetUtil.lengthenURI(driver, bookName);

Modified: trunk/jsword/src/main/java/org/crosswire/jsword/util/Project.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/util/Project.java	2007-08-26 22:56:26 UTC (rev 1692)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/util/Project.java	2007-08-27 01:00:36 UTC (rev 1693)
@@ -93,11 +93,11 @@
      */
     private Project()
     {
-        CWClassLoader.setHome(getUserProjectDir());
+        CWClassLoader.setHome(getProjectResourceDirs());
 
         try
         {
-            URI uricache = getUserSubProjectDir(DIR_NETCACHE, true);
+            URI uricache = getWriteableProjectSubdir(DIR_NETCACHE, true);
             File filecache = new File(uricache.getPath());
             NetUtil.setURICacheDir(filecache);
         }
@@ -110,48 +110,33 @@
     }
 
     /**
-     * Establishes the user's project directory.
+     * Get the writable user project directory.
+     * 
+     * @return the writable user project directory.
      */
-    public URI getUserProjectDir(String hiddenFolderName, String visibleFolderName)
+    public URI getWritableProjectDir()
     {
-        return OSType.getOSType().getUserAreaFolder(hiddenFolderName, visibleFolderName);
+        establishProjectHome();
+        return writeHome;
     }
 
     /**
-     * Establishes the user's project directory.
+     * Get the locations where project resources can be found.
+     * 
+     * @return an array of URIs which can be used to look up resources.
      */
-    public URI getUserProjectDir()
+    public URI[] getProjectResourceDirs()
     {
-        if (home == null)
-        {
-            // if there is a property set for the jsword home directory
-            String jswordhome = System.getProperty(PROPERTY_JSWORD_HOME);
-            if (jswordhome != null)
-            {
-                home = NetUtil.getURI(new File(jswordhome));
-                if (!NetUtil.canWrite(home))
-                {
-                    home = null;
-                }
-            }
-        }
-
-        if (home == null)
-        {
-            URI path = getUserProjectDir(DIR_PROJECT, DIR_PROJECT_ALT);
-            URI oldPath = getDeprecatedUserProjectDir();
-            home = migrateUserProjectDir(oldPath, path);
-        }
-
-        return home;
+        establishProjectHome();
+        return homes;
     }
 
     /**
-     * Get the location where the project dir used to be.
+     * Get the location where the project directory used to be.
      *
      * @return ~/.jsword
      */
-    public URI getDeprecatedUserProjectDir()
+    public URI getDeprecatedWritableProjectDir()
     {
         return OSType.DEFAULT.getUserAreaFolder(DIR_PROJECT, DIR_PROJECT_ALT);
     }
@@ -199,18 +184,18 @@
      */
     public URI getWritablePropertiesURI(String subject)
     {
-        return NetUtil.lengthenURI(getUserProjectDir(), subject + FileUtil.EXTENSION_PROPERTIES);
+        return NetUtil.lengthenURI(getWritableProjectDir(), subject + FileUtil.EXTENSION_PROPERTIES);
     }
 
     /**
-     * A directory within the project dir.
+     * A directory within the project directory.
      * 
      * @param subject A name for the subdirectory of the Project directory.
      * @return A file: URI pointing at a local writable directory.
      */
-    public URI getUserSubProjectDir(String subject, boolean create) throws IOException
+    public URI getWriteableProjectSubdir(String subject, boolean create) throws IOException
     {
-        URI temp = NetUtil.lengthenURI(getUserProjectDir(), subject);
+        URI temp = NetUtil.lengthenURI(getWritableProjectDir(), subject);
 
         if (create && !NetUtil.isDirectory(temp))
         {
@@ -219,18 +204,84 @@
 
         return temp;
     }
+    /**
+     * Establishes the user's project directory.
+     * In a CD installation, the home directory on the CD will be read-only.
+     * This is not sufficient. We also need a writable home directory. And
+     * in looking up resources, the ones in the writable directory trump
+     * those in the readable directory, allowing the read-only resources
+     * to be overridden.
+     * <p>Here is the lookup order:
+     * <ol>
+     * <li>Check first to see if the jsword.home property is set.</li>
+     * <li>Check for the existence of a platform specific project area and for the existence of a deprecated project area (~/.jsword on Windows and Mac)
+     * and if it exists and it is possible "upgrade" to the platform specific project area. Of these "two" only one is the folder to check.</li>
+     * </ol>
+     * In checking these areas, if the one is read-only, add it to the list and keep going.
+     * However, if it is also writable, then use it alone.
+     */
+    private void establishProjectHome()
+    {
+        if (writeHome == null && readHome == null)
+        {
+            // if there is a property set for the jsword home directory
+            String jswordhome = System.getProperty(PROPERTY_JSWORD_HOME);
+            if (jswordhome != null)
+            {
+                URI home = NetUtil.getURI(new File(jswordhome));
+                if (NetUtil.canWrite(home))
+                {
+                    writeHome = home;
+                }
+                else if (NetUtil.canRead(home))
+                {
+                    readHome = home;
+                }
+                // otherwise jsword.home is not usable.
+            }
+        }
 
+        if (writeHome == null)
+        {
+            URI path = OSType.getOSType().getUserAreaFolder(DIR_PROJECT, DIR_PROJECT_ALT);
+            URI oldPath = getDeprecatedWritableProjectDir();
+            writeHome = migrateUserProjectDir(oldPath, path);
+        }
+
+        if (homes == null)
+        {
+            if (readHome == null)
+            {
+                homes = new URI[] { writeHome };
+            }
+            else
+            {
+                homes = new URI[] { writeHome, readHome };
+            }
+        }
+    }
+
     /**
      * System property for jsword home directory
      */
     private static final String PROPERTY_JSWORD_HOME = "jsword.home"; //$NON-NLS-1$
 
     /**
-     * The home for this application
+     * The homes for this application: first is writable, second (if present) is read-only and specified by the system property jsword.home.
      */
-    private URI home;
+    private URI[] homes;
 
     /**
+     * The writable home for this application.
+     */
+    private URI writeHome;
+
+    /**
+     * The readable home for this application, specified by the system property jsword.home. Null, if jsword.home is also writable.
+     */
+    private URI readHome;
+
+    /**
      * The log stream
      */
     private static final Logger log = Logger.getLogger(Project.class);

Modified: trunk/jsword-limbo/src/main/java/org/crosswire/jsword/book/search/ser/SerIndexManager.java
===================================================================
--- trunk/jsword-limbo/src/main/java/org/crosswire/jsword/book/search/ser/SerIndexManager.java	2007-08-26 22:56:26 UTC (rev 1692)
+++ trunk/jsword-limbo/src/main/java/org/crosswire/jsword/book/search/ser/SerIndexManager.java	2007-08-27 01:00:36 UTC (rev 1693)
@@ -161,7 +161,7 @@
         assert driverName != null;
         assert bookName != null;
 
-        URI base = Project.instance().getUserSubProjectDir(DIR_SER, false);
+        URI base = Project.instance().getWriteableProjectSubdir(DIR_SER, false);
         URI driver = NetUtil.lengthenURI(base, driverName);
 
         return NetUtil.lengthenURI(driver, bookName);




More information about the jsword-svn mailing list