[JENA-1927] Link to TDB FAQs in error message

Where relevant include a link to the TDB FAQs in error messages
diff --git a/jena-tdb/src/main/java/org/apache/jena/tdb/TDB.java b/jena-tdb/src/main/java/org/apache/jena/tdb/TDB.java
index df34856..8006091 100644
--- a/jena-tdb/src/main/java/org/apache/jena/tdb/TDB.java
+++ b/jena-tdb/src/main/java/org/apache/jena/tdb/TDB.java
@@ -111,6 +111,8 @@
      * "mapped" = Memory mapped temporary file <br>
      */
     public static final Symbol  transactionJournalWriteBlockMode = SystemTDB.allocSymbol("transactionJournalWriteBlockMode") ;
+    
+    public static final String  tdbFaqsLink                      = "See https://jena.apache.org/documentation/tdb/faqs.html for more information.";
 
     public static Context getContext() {
         return ARQ.getContext() ;
diff --git a/jena-tdb/src/main/java/org/apache/jena/tdb/base/file/LocationLock.java b/jena-tdb/src/main/java/org/apache/jena/tdb/base/file/LocationLock.java
index c03ed27..60b3b00 100644
--- a/jena-tdb/src/main/java/org/apache/jena/tdb/base/file/LocationLock.java
+++ b/jena-tdb/src/main/java/org/apache/jena/tdb/base/file/LocationLock.java
@@ -24,6 +24,7 @@
 import java.io.IOException;
 
 import org.apache.jena.atlas.io.IO;
+import org.apache.jena.tdb.TDB;
 import org.apache.jena.tdb.TDBException;
 import org.apache.jena.tdb.sys.ProcessUtils;
 import org.apache.jena.tdb.sys.SystemTDB;
@@ -105,15 +106,17 @@
                 String rawLockInfo = IO.readWholeFileAsUTF8(lockFile.getAbsolutePath());
                 if (rawLockInfo.endsWith("\n")) {
                     // This is most likely down to trying to open a TDB2 database with TDB1
-                    throw new FileException("Unable to check TDB lock owner, the lock file contents appear to be for a TDB2 database.  Please try loading this location as a TDB2 database.");
+                    throw new FileException("Unable to check TDB lock owner, the lock file contents appear to be for a TDB2 database.  " + 
+                            "Please try loading this location as a TDB2 database. " + 
+                            TDB.tdbFaqsLink);
                 }
                 
                 int owner = Integer.parseInt(rawLockInfo);
                 return owner;
             } catch (IOException e) {
-                throw new FileException("Unable to check TDB lock owner due to an IO error reading the lock file", e);
+                throw new FileException("Unable to check TDB lock owner due to an IO error reading the lock file. " + TDB.tdbFaqsLink, e);
             } catch (NumberFormatException e) {
-                throw new FileException("Unable to check TDB lock owner as the lock file contains invalid data", e);
+                throw new FileException("Unable to check TDB lock owner as the lock file contains invalid data. " + TDB.tdbFaqsLink, e);
             }
         } else {
             // No lock file so nobody owns the lock currently
@@ -169,7 +172,8 @@
                 // In the case where we cannot obtain our PID then we cannot obtain a lock
                 SystemTDB.errlog.warn("Location " + location.getDirectoryPath()
                         + " cannot be locked as unable to obtain PID of current process."
-                        + " If another JVM accessed this location while this process is accessing it then data corruption may occur");
+                        + " If another JVM accessed this location while this process is accessing it then data corruption may occur. "
+                        + TDB.tdbFaqsLink);
                 return;
             }
 
@@ -182,7 +186,8 @@
             if (ProcessUtils.isAlive(owner)) {
                 throw new TDBException("Location " + location.getDirectoryPath() + " is currently locked by PID "
                         + owner + "(this process is PID "+pid+")"
-                        + ".  TDB databases do not permit concurrent usage across JVMs so in order to prevent possible data corruption you cannot open this location from the JVM that does not own the lock for the dataset");
+                        + ".  TDB databases do not permit concurrent usage across JVMs so in order to prevent possible data corruption you cannot open this location from the JVM that does not own the lock for the dataset. "
+                        + TDB.tdbFaqsLink);
             }
 
             // Otherwise the previous owner is dead so we can take the lock
@@ -198,7 +203,8 @@
             writer.write(Integer.toString(pid));
             writer.close();
         } catch (IOException e) {
-            throw new TDBException("Failed to obtain a lock on the location " + location.getDirectoryPath(), e);
+            throw new TDBException("Failed to obtain a lock on the location " + location.getDirectoryPath()
+                                   + TDB.tdbFaqsLink, e);
         }
 
         // Mark lock for deletion on JVM exit
@@ -225,7 +231,8 @@
         // Some other process owns the lock so we can't release it
         if (owner != ProcessUtils.getPid(NO_OWNER))
             throw new TDBException("Cannot release the lock on location " + location.getDirectoryPath()
-                    + " since this process does not own the lock");
+                    + " since this process does not own the lock." 
+                    + TDB.tdbFaqsLink);
 
         File lockFile = getLockFile();
 
@@ -236,7 +243,8 @@
         // Try and delete the lock file thereby releasing the lock
         if (!lockFile.delete())
             throw new TDBException("Failed to release the lock on location " + location.getDirectoryPath()
-                    + ", it may be necessary to manually remove the lock file");
+                    + ", it may be necessary to manually remove the lock file. "
+                    + TDB.tdbFaqsLink);
 
     }
 
@@ -265,7 +273,8 @@
             // Unable to read lock owner because it isn't a file or we don't
             // have read permission
             throw new FileException(
-                    "Unable to check TDB lock owner for this location since the expected lock file is not a file/not readable");
+                    "Unable to check TDB lock owner for this location since the expected lock file is not a file/not readable. " 
+                    + TDB.tdbFaqsLink);
         }
     }
 
@@ -285,7 +294,8 @@
             // Unable to read lock owner because it isn't a file or we don't
             // have read permission
             throw new FileException(
-                    "Unable to check TDB lock owner for this location since the expected lock file is not a file/not writable");
+                    "Unable to check TDB lock owner for this location since the expected lock file is not a file/not writable. " 
+                    + TDB.tdbFaqsLink);
         }
     }
 }
diff --git a/jena-tdb/src/main/java/org/apache/jena/tdb/base/objectfile/ObjectFileStorage.java b/jena-tdb/src/main/java/org/apache/jena/tdb/base/objectfile/ObjectFileStorage.java
index 9b40243..1c5974b 100644
--- a/jena-tdb/src/main/java/org/apache/jena/tdb/base/objectfile/ObjectFileStorage.java
+++ b/jena-tdb/src/main/java/org/apache/jena/tdb/base/objectfile/ObjectFileStorage.java
@@ -171,7 +171,8 @@
             log("R(0x%X)", loc);
 
         if ( loc < 0 )
-            throw new IllegalArgumentException("ObjectFile.read[" + file.getLabel() + "]: Bad read: " + loc);
+            throw new IllegalArgumentException("ObjectFile.read[" + file.getLabel() + "]: Bad read: " + loc
+                                               + "\n" + TDB.tdbFaqsLink);
 
         // Maybe it's in the in the write buffer.
         if ( loc >= filesize ) {
@@ -179,7 +180,8 @@
             synchronized (lockWriteBuffer) {
                 if ( loc >= filesize + writeBuffer.position() )
                     throw new IllegalArgumentException("ObjectFileStorage.read[" + file.getLabel() + "]: Bad read: location=" + loc
-                                                       + " >= max=" + (filesize + writeBuffer.position()));
+                                                       + " >= max=" + (filesize + writeBuffer.position())
+                                                       + "\n" + TDB.tdbFaqsLink);
                 int offset = (int)(loc - filesize);
                 int len = writeBuffer.getInt(offset);
                 int posn = offset + SizeOfInt;
@@ -197,7 +199,8 @@
         int x = file.read(lengthBuffer, loc);
         if ( x != 4 ) {
             String msg = "ObjectFileStorage.read[" + file.getLabel() + "](" + loc + ")[filesize=" + filesize + "]"
-                         + "[file.size()=" + file.size() + "]: Failed to read the length : got " + x + " bytes";
+                         + "[file.size()=" + file.size() + "]: Failed to read the length : got " + x + " bytes"
+                         + "\n" + TDB.tdbFaqsLink;
             lengthBuffer.clear();
             int x1 = file.read(lengthBuffer, loc);
             throw new FileException(msg);
@@ -207,7 +210,8 @@
         if ( len > filesize - (loc + SizeOfInt) ) {
             String msg = "ObjectFileStorage.read[" + file.getLabel() + "](" + loc + ")[filesize=" + filesize + "][file.size()="
                          + file.size() + "]: Impossibly large object : " + len + " bytes > filesize-(loc+SizeOfInt)="
-                         + (filesize - (loc + SizeOfInt));
+                         + (filesize - (loc + SizeOfInt) 
+                         + "\n" + TDB.tdbFaqsLink);
             throw new FileException(msg);
         }
 
@@ -218,7 +222,8 @@
         x = file.read(bb, loc + SizeOfInt);
         bb.flip();
         if ( x != len )
-            throw new FileException("ObjectFileStorage.read: Failed to read the object (" + len + " bytes) : got " + x + " bytes");
+            throw new FileException("ObjectFileStorage.read: Failed to read the object (" + len + " bytes) : got " + x + " bytes"
+                                    + "\n" + TDB.tdbFaqsLink);
         return bb;
     }