From 5a33c7e7fbfffaeb6c57cd488505ccbf613826d8 Mon Sep 17 00:00:00 2001
From: Jukka Zitting <jukka@apache.org>
Date: Thu, 6 Oct 2011 16:58:18 +0200
Subject: [PATCH] JCR-2968: Add an option to read the Clustering Journal from
 a different source than the rest of the clustering info

Allow a journal to be configured as read-only and add an optional separate data source for accessing the local revision table.
---
 .../jackrabbit/core/journal/AbstractJournal.java   |   32 +++++++++
 .../jackrabbit/core/journal/DatabaseJournal.java   |   67 ++++++++++++++++++--
 2 files changed, 94 insertions(+), 5 deletions(-)

diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/AbstractJournal.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/AbstractJournal.java
index 00d4a96..7315fbf 100644
--- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/AbstractJournal.java
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/AbstractJournal.java
@@ -48,6 +48,14 @@ public abstract class AbstractJournal implements Journal {
     private String id;
 
     /**
+     * Flag of whether this is supposed to be a read-only cluster node.
+     *
+     * @since Apache Jackrabbit 2.3.1
+     */
+    private boolean readOnly = false;
+
+
+    /**
      * Namespace resolver.
      */
     private NamespaceResolver resolver;
@@ -93,6 +101,26 @@ public abstract class AbstractJournal implements Journal {
     private InternalVersionManagerImpl internalVersionManager;
 
     /**
+     * Checks whether this cluster node is read-only.
+     *
+     * @since Apache Jackrabbit 2.3.1
+     * @return <code>true</code> for a read-only cluster node
+     */
+    public boolean isReadOnly() {
+        return readOnly;
+    }
+
+    /**
+     * Sets whether this cluster node is read-only.
+     *
+     * @since Apache Jackrabbit 2.3.1
+     * @param readOnly <code>true</code> for a read-only cluster node
+     */
+    public void setReadOnly(boolean readOnly) {
+        this.readOnly = readOnly;
+    }
+
+    /**
      * {@inheritDoc}
      */
     public void init(String id, NamespaceResolver resolver) throws JournalException {
@@ -258,6 +286,10 @@ public abstract class AbstractJournal implements Journal {
      * @throws JournalException if an error occurs
      */
     public void lockAndSync() throws JournalException {
+        if (isReadOnly()) {
+            throw new JournalException("This is a read-only cluster node");
+        }
+
         if (internalVersionManager != null) {
             VersioningLock.ReadLock lock =
                 internalVersionManager.acquireReadLock();
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/DatabaseJournal.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/DatabaseJournal.java
index 7ba58ab..e9c1ffd 100644
--- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/DatabaseJournal.java
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/DatabaseJournal.java
@@ -126,9 +126,22 @@ public class DatabaseJournal extends AbstractJournal implements DatabaseAware {
     private String dataSourceName;
 
     /**
+     * Logical name of the data source for the local revisions table,
+     * or <code>null</code> (the default) for using the normal data source.
+     */
+    private String localRevisionDataSourceName = null;
+
+    /**
      * The connection helper
      */
-    ConnectionHelper conHelper;
+    private ConnectionHelper conHelper;
+
+    /**
+     * Connection helper for accessing the local revision table.
+     * This is the equal to the {@link #conHelper} object unless the
+     * {@link #localRevisionDataSourceName} option has been specified.
+     */
+    private ConnectionHelper localRevisionConHelper;
 
     /**
      * Auto commit level.
@@ -257,6 +270,13 @@ public class DatabaseJournal extends AbstractJournal implements DatabaseAware {
 
         try {
             conHelper = createConnectionHelper(getDataSource());
+            String dsn = getLocalRevisionDataSourceName();
+            if (dsn != null) {
+                DataSource ds = connectionFactory.getDataSource(dsn);
+                localRevisionConHelper = createConnectionHelper(ds);
+            } else {
+                localRevisionConHelper = conHelper;
+            }
 
             // make sure schemaObjectPrefix consists of legal name characters only
             schemaObjectPrefix = conHelper.prepareDbIdentifier(schemaObjectPrefix);
@@ -743,6 +763,39 @@ public class DatabaseJournal extends AbstractJournal implements DatabaseAware {
     }
 
     /**
+     * Returns the name of the local revision data source, if configured.
+     *
+     * @since Apache Jackrabbit 2.3.1
+     * @return local revision data source name, or <code>null</code>
+     */
+    public String getLocalRevisionDataSourceName() {
+        return localRevisionDataSourceName;
+    }
+
+    /**
+     * Sets the name of the local revision data source.
+     *
+     * @since Apache Jackrabbit 2.3.1
+     * @return local revision data source name
+     */
+    public void setLocalRevisionDataSourceName(String name) {
+        if (name != null && name.length() > 0) {
+            this.localRevisionDataSourceName = name;
+        } else {
+            this.localRevisionDataSourceName = null;
+        }
+    }
+
+    /**
+     * This journal is read-only either if explicitly so configured or
+     * if a separate local revision data source has been specified.
+     */
+    @Override
+    public boolean isReadOnly() {
+        return super.isReadOnly() || getLocalRevisionDataSourceName() != null;
+    }
+
+    /**
      * @return whether the schema check is enabled
      */
     public final boolean isSchemaCheckEnabled() {
@@ -785,7 +838,9 @@ public class DatabaseJournal extends AbstractJournal implements DatabaseAware {
             ResultSet rs = null;
             try {
                 // Check whether there is an entry in the database.
-                rs = conHelper.exec(getLocalRevisionStmtSQL, new Object[]{getId()}, false, 0);
+                rs = localRevisionConHelper.exec(
+                        getLocalRevisionStmtSQL, new Object[]{getId()},
+                        false, 0);
                 boolean exists = rs.next();
                 if (exists) {
                     revision = rs.getLong(1);
@@ -793,7 +848,8 @@ public class DatabaseJournal extends AbstractJournal implements DatabaseAware {
 
                 // Insert the given revision in the database
                 if (!exists) {
-                    conHelper.exec(insertLocalRevisionStmtSQL, revision, getId());
+                    localRevisionConHelper.exec(
+                            insertLocalRevisionStmtSQL, revision, getId());
                 }
 
                 // Set the cached local revision and return
@@ -824,7 +880,8 @@ public class DatabaseJournal extends AbstractJournal implements DatabaseAware {
 
             // Update the cached value and the table with local revisions.
             try {
-                conHelper.exec(updateLocalRevisionStmtSQL, localRevision, getId());
+                localRevisionConHelper.exec(
+                        updateLocalRevisionStmtSQL, localRevision, getId());
                 this.localRevision = localRevision;
             } catch (SQLException e) {
                 log.warn("Failed to update local revision.", e);
@@ -878,7 +935,7 @@ public class DatabaseJournal extends AbstractJournal implements DatabaseAware {
                 }
 
                 // Clean up if necessary:
-                if (cleanUp) {
+                if (cleanUp && !isReadOnly()) {
                     conHelper.exec(cleanRevisionStmtSQL, minRevision);
                     log.info("Cleaned old revisions up to revision " + minRevision + ".");
                 }
-- 
1.7.4.4

