You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by th...@apache.org on 2009/02/16 17:23:44 UTC

svn commit: r744956 - in /jackrabbit/trunk/jackrabbit-core/src/main: java/org/apache/jackrabbit/core/ java/org/apache/jackrabbit/core/config/ java/org/apache/jackrabbit/core/util/ resources/org/apache/jackrabbit/core/config/

Author: thomasm
Date: Mon Feb 16 16:23:41 2009
New Revision: 744956

URL: http://svn.apache.org/viewvc?rev=744956&view=rev
Log:
JCR-1605 RepositoryLock does not work on NFS sometimes (configurable repository lock)

Added:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/CooperativeFileLock.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/RepositoryLockMechanism.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/RepositoryLockMechanismFactory.java
    jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/config/repository-1.6.dtd
Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/RepositoryLock.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java?rev=744956&r1=744955&r2=744956&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java Mon Feb 16 16:23:41 2009
@@ -62,7 +62,7 @@
 import org.apache.jackrabbit.core.state.ItemStateException;
 import org.apache.jackrabbit.core.state.ManagedMLRUItemStateCacheFactory;
 import org.apache.jackrabbit.core.state.SharedItemStateManager;
-import org.apache.jackrabbit.core.util.RepositoryLock;
+import org.apache.jackrabbit.core.util.RepositoryLockMechanism;
 import org.apache.jackrabbit.core.value.InternalValue;
 import org.apache.jackrabbit.core.version.VersionManager;
 import org.apache.jackrabbit.core.version.VersionManagerImpl;
@@ -206,9 +206,9 @@
     private boolean disposed = false;
 
     /**
-     * the lock that guards instantiation of multiple repositories.
+     * The repository lock mechanism ensures that a repository is only instantiated once.
      */
-    private RepositoryLock repLock;
+    private RepositoryLockMechanism repLock;
 
     /**
      * Clustered node used, <code>null</code> if clustering is not configured.
@@ -255,7 +255,8 @@
             this.repConfig = repConfig;
 
             // Acquire a lock on the repository home
-            repLock = new RepositoryLock(repConfig.getHomeDir());
+            repLock = repConfig.getRepositoryLockMechanism();
+            repLock.init(repConfig.getHomeDir());
             repLock.acquire();
 
             // setup file systems
@@ -1200,7 +1201,13 @@
         notifyAll();
 
         // finally release repository lock
-        repLock.release();
+        if (repLock != null) {
+            try {
+                repLock.release();
+            } catch (RepositoryException e) {
+                log.error("failed to release the repository lock", e);
+            }            
+        }
 
         log.info("Repository has been shutdown");
     }

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java?rev=744956&r1=744955&r2=744956&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java Mon Feb 16 16:23:41 2009
@@ -23,6 +23,8 @@
 import org.apache.jackrabbit.core.fs.FileSystemException;
 import org.apache.jackrabbit.core.fs.FileSystemFactory;
 import org.apache.jackrabbit.core.fs.FileSystemPathUtil;
+import org.apache.jackrabbit.core.util.RepositoryLockMechanism;
+import org.apache.jackrabbit.core.util.RepositoryLockMechanismFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.w3c.dom.Element;
@@ -224,10 +226,14 @@
     private final ClusterConfig cc;
 
     /**
-     * The optional data store factory, returns <code>null</code> if
-     * the data store is not configured.
+     * The data store factory.
      */
     private final DataStoreFactory dsf;
+    
+    /**
+     * The repository lock mechanism factory.
+     */
+    private final RepositoryLockMechanismFactory rlf;
 
     /**
      * Creates a repository configuration object.
@@ -252,6 +258,7 @@
             String defaultWorkspace, int workspaceMaxIdleTime,
             Element template, VersioningConfig vc, SearchConfig sc,
             ClusterConfig cc, DataStoreFactory dsf,
+            RepositoryLockMechanismFactory rlf,
             RepositoryConfigurationParser parser) {
         workspaces = new HashMap();
         this.home = home;
@@ -266,6 +273,7 @@
         this.sc = sc;
         this.cc = cc;
         this.dsf = dsf;
+        this.rlf = rlf;
         this.parser = parser;
     }
 
@@ -543,13 +551,10 @@
                 Transformer transformer = factory.newTransformer();
                 transformer.setOutputProperty(OutputKeys.INDENT, "yes");
 
-                if (configContent == null)
-                {
+                if (configContent == null) {
                     transformer.transform(
                             new DOMSource(template), new StreamResult(configWriter));
-                }
-                else
-                {
+                } else {
                     StringWriter writer = new StringWriter();
                     transformer.transform(
                             new DOMSource(template), new StreamResult(writer));
@@ -792,5 +797,17 @@
         return dsf.getDataStore();
     }
 
+    /**
+     * Creates and returns the configured repository lock mechanism. This method
+     * returns the default repository lock mechanism if no other mechanism is
+     * configured.
+     * 
+     * @return the repository lock mechanism (never <code>null</code>)
+     * @throws RepositoryException if the repository lock mechanism can not be created
+     */
+    public RepositoryLockMechanism getRepositoryLockMechanism() throws RepositoryException {
+        return rlf.getRepositoryLockMechanism();
+    }
+
 }
 

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java?rev=744956&r1=744955&r2=744956&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java Mon Feb 16 16:23:41 2009
@@ -24,6 +24,9 @@
 import org.apache.jackrabbit.core.state.DefaultISMLocking;
 import org.apache.jackrabbit.core.state.ISMLocking;
 import org.apache.jackrabbit.core.state.ISMLockingFactory;
+import org.apache.jackrabbit.core.util.RepositoryLock;
+import org.apache.jackrabbit.core.util.RepositoryLockMechanism;
+import org.apache.jackrabbit.core.util.RepositoryLockMechanismFactory;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
@@ -101,6 +104,10 @@
     /** Name of the data store configuration element. */
     public static final String DATA_STORE_ELEMENT = "DataStore";
 
+    /** Name of the repository lock mechanism configuration element. */
+    public static final String REPOSITORY_LOCK_MECHANISM_ELEMENT = 
+        "RepositoryLockMechanism";
+
     /** Name of the persistence manager configuration element. */
     public static final String PERSISTENCE_MANAGER_ELEMENT =
         "PersistenceManager";
@@ -256,10 +263,12 @@
 
         // Optional data store factory
         DataStoreFactory dsf = getDataStoreFactory(root, home);
+        
+        RepositoryLockMechanismFactory rlf = getRepositoryLockMechanismFactory(root);
 
         return new RepositoryConfig(home, securityConfig, fsf,
                 workspaceDirectory, workspaceConfigDirectory, defaultWorkspace,
-                maxIdleTime, template, vc, sc, cc, dsf, this);
+                maxIdleTime, template, vc, sc, cc, dsf, rlf, this);
     }
 
     /**
@@ -526,7 +535,7 @@
         Element element = getElement(parent, WSP_SECURITY_ELEMENT, false);
         if (element != null) {
             Element provFact = getElement(element, AC_PROVIDER_ELEMENT, false);
-            if (provFact !=null ) {
+            if (provFact != null) {
                 factConf = parseBeanConfig(element, AC_PROVIDER_ELEMENT);
                 factConf.setValidate(false); // JCR-1920
             }
@@ -696,8 +705,9 @@
      * <code>DataStore</code> is a {@link #parseBeanConfig(Element,String) bean configuration}
      * element.
      *
-     * @param parent cluster element
-     * @return journal configuration, or <code>null</code>
+     * @param parent configuration element
+     * @param directory the repository directory
+     * @return data store factory
      * @throws ConfigurationException if the configuration is broken
      */
     protected DataStoreFactory getDataStoreFactory(
@@ -723,6 +733,46 @@
     }
 
     /**
+     * Parses repository lock mechanism configuration. Repository lock mechanism
+     * configuration uses the following format:
+     * <pre>
+     *   &lt;RepositoryLockMechanism class=&quot;...&quot; &gt;
+     *     &lt;param name=&quot;...&quot; value=&quot;...&quot;&gt;
+     *     ...
+     *   &lt;/RepositoryLockMechanism&gt;
+     * </pre>
+     * <p/>
+     * <code>RepositoryLockMechanism</code> is a
+     * {@link #parseBeanConfig(Element,String) bean configuration} element.
+     * 
+     * @param root the root configuration element
+     * @return repository lock mechanism factory
+     * @throws ConfigurationException if the configuration is broken
+     */    
+    protected RepositoryLockMechanismFactory getRepositoryLockMechanismFactory(final Element root) {
+        return new RepositoryLockMechanismFactory() {
+            public RepositoryLockMechanism getRepositoryLockMechanism() throws RepositoryException {
+                RepositoryLockMechanism lock = null;
+                NodeList children = root.getChildNodes();
+                for (int i = 0; i < children.getLength(); i++) {
+                    Node child = children.item(i);
+                    if (child.getNodeType() == Node.ELEMENT_NODE
+                            && REPOSITORY_LOCK_MECHANISM_ELEMENT.equals(child.getNodeName())) {
+                        BeanConfig bc =
+                            parseBeanConfig(root, REPOSITORY_LOCK_MECHANISM_ELEMENT);
+                        lock = (RepositoryLockMechanism) bc.newInstance();
+                        break;
+                    }
+                }
+                if (lock == null) {
+                    lock = new RepositoryLock();
+                }
+                return lock;
+            }
+        };
+    }
+
+    /**
      * Parses the PersistenceManager config.
      *
      * @param parent parent of the <code>PersistenceManager</code> element

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/CooperativeFileLock.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/CooperativeFileLock.java?rev=744956&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/CooperativeFileLock.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/CooperativeFileLock.java Mon Feb 16 16:23:41 2009
@@ -0,0 +1,304 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.util;
+
+import org.apache.jackrabbit.uuid.UUID;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Properties;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * The file lock is used to ensure a resource is only open once at any time. 
+ * It uses a cooperative locking protocol. 
+ */
+public class CooperativeFileLock implements RepositoryLockMechanism {
+    
+    /**
+     * Logger instance.
+     */
+    private static final Logger LOG =
+        LoggerFactory.getLogger(CooperativeFileLock.class);
+
+    private static final String MAGIC = "CooperativeFileLock";
+    private static final String FILE_NAME = "lock.properties";
+    private static final int MAX_FILE_RETRY = 16;
+    private static final int SLEEP_GAP = 25;
+    private static final int TIME_GRANULARITY = 2000;
+    private static final int LOCK_SLEEP = 1000;
+
+    private String fileName;
+    private long lastWrite;
+    private Properties properties;
+    private boolean locked;
+    private volatile boolean stop;
+
+    /**
+     * Create a new file locking object using the given file name.
+     * 
+     * @param fileName the name of the properties file
+     */
+    public void init(String path) {
+        this.fileName = path + File.separatorChar + FILE_NAME;
+    }
+
+    /**
+     * Lock the directory if possible.
+     * This method will also start a background watchdog thread.
+     * A file may only be locked once.
+     * 
+     * @throws RepositoryException if locking was not successful
+     */
+    public synchronized void acquire() throws RepositoryException {
+        if (locked) {
+            throw new RepositoryException("Already locked " + fileName);
+        }
+        stop = false;
+        lockFile();
+        locked = true;
+    }
+
+    /**
+     * Unlock the directory.
+     * The watchdog thread is stopped.
+     * This method does nothing if the file is already unlocked.
+     */
+    public synchronized void release() {
+        if (!locked) {
+            return;
+        }
+        try {
+            if (fileName != null) {
+                if (load().equals(properties)) {
+                    delete(fileName);
+                }
+            }
+        } catch (Exception e) {
+            LOG.warn("Error unlocking " + fileName, e);
+        }
+        stop = true;
+        locked = false;
+    }
+
+    /**
+     * This finalizer unlocks the file if necessary.
+     */
+    protected void finalize() {
+        if (locked) {
+            release();
+        }
+    }
+
+    /**
+     * Save the properties file.
+     */
+    private void save() throws RepositoryException {
+        try {
+            OutputStream out = new FileOutputStream(fileName);
+            try {
+                properties.store(out, MAGIC);
+            } finally {
+                out.close();
+            }
+            lastWrite = new File(fileName).lastModified();
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("Save " + properties);
+            }
+        } catch (IOException e) {
+            throw getException(e);
+        }
+    }
+
+    /**
+     * Load the properties file.
+     * 
+     * @return the properties object
+     */
+    private Properties load() throws RepositoryException {
+        try {
+            Properties p2 = new Properties();
+            InputStream in = new FileInputStream(fileName);
+            try {
+                p2.load(in);
+            } finally {
+                in.close();
+            }
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("Load " + p2);
+            }
+            return p2;
+        } catch (IOException e) {
+            throw getException(e);
+        }
+    }
+
+    /**
+     * Wait until the file is old (not modified for a certain time).
+     */
+    private void waitUntilOld() throws RepositoryException {
+        for (int i = 0; i < TIME_GRANULARITY / SLEEP_GAP; i++) {
+            File f = new File(fileName);
+            long last = f.lastModified();
+            long dist = System.currentTimeMillis() - last;
+            if (dist < -TIME_GRANULARITY) {
+                throw error("Lock file modified in the future: dist=" + dist);
+            } else if (dist > TIME_GRANULARITY) {
+                return;
+            }
+            try {
+                Thread.sleep(SLEEP_GAP);
+            } catch (Exception e) {
+                    LOG.debug("Sleep", e);
+            }
+        }
+        throw error("Lock file recently modified");
+    }
+
+    /**
+     * Lock the file.
+     */
+    private void lockFile() throws RepositoryException {
+        properties = new Properties();
+        UUID uuid = UUID.randomUUID();
+        properties.setProperty("id", uuid.toString());
+        if (!createNewFile(fileName)) {
+            waitUntilOld();
+            save();
+            sleep(2 * LOCK_SLEEP);
+            if (!load().equals(properties)) {
+                throw error("Locked by another process");
+            }
+            delete(fileName);
+            if (!createNewFile(fileName)) {
+                throw error("Another process was faster");
+            }
+        }
+        save();
+        sleep(SLEEP_GAP);
+        if (!load().equals(properties)) {
+            stop = true;
+            throw error("Concurrent update");
+        }
+        Thread watchdog = new Thread(new Runnable() {
+            public void run() {
+                try {
+                    while (!stop) {
+                        // debug("Watchdog check");
+                        try {
+                            File f = new File(fileName);
+                            if (!f.exists() || f.lastModified() != lastWrite) {
+                                save();
+                            }
+                            Thread.sleep(LOCK_SLEEP);
+                        } catch (Exception e) {
+                            LOG.debug("Watchdog", e);
+                        }
+                    }
+                } catch (Exception e) {
+                    LOG.debug("Watchdog", e);
+                }
+                LOG.debug("Watchdog end");
+            }
+        });
+        watchdog.setName(MAGIC + " Watchdog " + fileName);
+        watchdog.setDaemon(true);
+        watchdog.setPriority(Thread.MAX_PRIORITY - 1);
+        watchdog.start();
+    }
+
+    private RepositoryException getException(Throwable t) {
+        return new RepositoryException("Internal error in file lock " + fileName, t);
+    }
+
+    private RepositoryException error(String reason) {
+        return new RepositoryException("Error locking " + fileName + ", reason: " + reason);
+    }
+
+    private void sleep(int time) throws RepositoryException {
+        try {
+            Thread.sleep(time);
+        } catch (InterruptedException e) {
+            throw getException(e);
+        }
+    }
+    
+    /**
+     * Create a new file, and retry if this doesn't work.
+     * If it still doesn't work after some time, this method returns false.
+     * 
+     * @param fileName the name of the file to create
+     * @return if the file was created
+     */
+    private static boolean createNewFile(String fileName) {
+        File file = new File(fileName);
+        for (int i = 0; i < MAX_FILE_RETRY; i++) {
+            try {
+                return file.createNewFile();
+            } catch (IOException e) {
+                // 'access denied' is really a concurrent access problem
+                wait(i);
+            }
+        }
+        return false;
+    }
+    
+    /**
+     * Delete a file, and retry if this doesn't work.
+     * If it still doesn't work after some time, an exception is thrown.
+     * 
+     * @param fileName the name of the file to delete
+     * @throws RepositoryException if the file could not be deleted
+     */
+    private static void delete(String fileName) throws RepositoryException {
+        File file = new File(fileName);
+        if (file.exists()) {
+            for (int i = 0; i < MAX_FILE_RETRY; i++) {
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug("Deleting " + fileName);
+                }
+                boolean ok = file.delete();
+                if (ok) {
+                    return;
+                }
+                wait(i);
+            }
+            throw new RepositoryException("Could not delete file " + fileName);
+        }
+    }    
+    
+    private static void wait(int i) {
+        if (i > 8) {
+            System.gc();
+        }
+        try {
+            // sleep at most 256 ms
+            long sleep = Math.min(256, i * i);
+            Thread.sleep(sleep);
+        } catch (InterruptedException e) {
+            // ignore
+        }
+    }
+
+}

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/RepositoryLock.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/RepositoryLock.java?rev=744956&r1=744955&r2=744956&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/RepositoryLock.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/RepositoryLock.java Mon Feb 16 16:23:41 2009
@@ -41,7 +41,7 @@
  * @see https://issues.apache.org/jira/browse/JCR-912
  * @see https://issues.apache.org/jira/browse/JCR-933
  */
-public class RepositoryLock {
+public class RepositoryLock implements RepositoryLockMechanism {
 
     /**
      * Name of the lock file within a directory.
@@ -57,12 +57,12 @@
     /**
      * The locked directory.
      */
-    private final File directory;
+    private File directory;
 
     /**
      * The lock file within the given directory.
      */
-    private final File file;
+    private File file;
 
     /**
      * The random access file.
@@ -75,25 +75,42 @@
      *
      * @see https://issues.apache.org/jira/browse/JCR-933
      */
-    private final String identifier;
+    private String identifier;
 
     /**
-     * The file lock. Used to ensure exlusive lockin across process boundaries.
+     * The file lock. Used to ensure exclusive locking across process boundaries.
      *
      * @see https://issues.apache.org/jira/browse/JCR-233
      */
     private FileLock lock;
 
+    public RepositoryLock() {
+        // used by the factory
+    }
+    
     /**
-     * Creates a lock instance for the given directory path. An instantiated
-     * lock still needs to be explicitly acquired using the {@link #acquire()}
-     * method.
-     *
+     * Create a new RepositoryLock object and initialize it.
+     * @deprecated 
+     * This constructor is deprecated; use the default constructor
+     * and {@link #init(String)} instead.
+     * 
      * @param path directory path
      * @throws RepositoryException if the canonical path of the directory
      *                             can not be determined
      */
     public RepositoryLock(String path) throws RepositoryException {
+        init(path);
+    }
+    
+    /**
+     * Initialize the instance for the given directory path. The lock still needs to be 
+     * explicitly acquired using the {@link #acquire()} method.
+     *
+     * @param path directory path
+     * @throws RepositoryException if the canonical path of the directory
+     *                             can not be determined
+     */
+    public void init(String path) throws RepositoryException {
         try {
             directory = new File(path).getCanonicalFile();
             file = new File(directory, LOCK);

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/RepositoryLockMechanism.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/RepositoryLockMechanism.java?rev=744956&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/RepositoryLockMechanism.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/RepositoryLockMechanism.java Mon Feb 16 16:23:41 2009
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.util;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * Exclusive lock on a repository home directory. This class encapsulates
+ * collective experience on how to acquire an exclusive lock on a given
+ * directory. The lock is expected to be exclusive both across process
+ * boundaries and within a single JVM.
+ */
+public interface RepositoryLockMechanism {
+
+    /**
+     * Initialize the instance for the given directory path. The lock still needs to be 
+     * explicitly acquired using the {@link #acquire()} method.
+     *
+     * @param path directory path
+     * @throws RepositoryException if the canonical path of the directory
+     *                             can not be determined
+     */
+    void init(String homeDir) throws RepositoryException;
+    
+    /**
+     * Lock the repository home.
+     *
+     * @throws RepositoryException if the repository lock can not be acquired
+     */
+    void acquire() throws RepositoryException;
+    
+    /**
+     * Releases repository lock.
+     * 
+     * @throws RepositoryException if the repository lock can not be released
+     */
+    void release() throws RepositoryException;
+}

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/RepositoryLockMechanismFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/RepositoryLockMechanismFactory.java?rev=744956&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/RepositoryLockMechanismFactory.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/RepositoryLockMechanismFactory.java Mon Feb 16 16:23:41 2009
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.util;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * Factory interface for creating {@link RepositoryLockMechanism} instances. Used
+ * to decouple the repository internals from the repository configuration
+ * mechanism.
+ *
+ * @since Jackrabbit 1.5
+ * @see <a href="https://issues.apache.org/jira/browse/JCR-1438">JCR-1438</a>
+ */
+public interface RepositoryLockMechanismFactory {
+
+    /**
+     * Creates, configures, and returns a {@link RepositoryLockMechanism} instance
+     * for use by the repository. Note that no information is passed from
+     * the client, so all required configuration information must be
+     * encapsulated in the factory.
+     *
+     * @return the configures repository lock mechanism
+     * @throws RepositoryException if the repository lock mechanism can not be created
+     */
+    RepositoryLockMechanism getRepositoryLockMechanism() throws RepositoryException;
+}

Added: jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/config/repository-1.6.dtd
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/config/repository-1.6.dtd?rev=744956&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/config/repository-1.6.dtd (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/config/repository-1.6.dtd Mon Feb 16 16:23:41 2009
@@ -0,0 +1,229 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at 
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!--
+    the Repository element configures a repository instance; individual 
+    workspaces of the repository are configured through separate configuration 
+    files called workspace.xml which are located in a subfolder of the 
+    workspaces root directory (see Workspaces element).
+
+    it consists of
+
+      - an optional Cluster element that is used for configuring a
+        clustering node that synchronizes changes made in a cluster
+       
+      - a FileSystem element (the virtual file system
+        used by the repository to persist global state such as
+        registered namespaces, custom node types, etc.
+        
+      - an optional DataStore element to configure the component
+        to use for storing large binary objects
+
+      - a Security element that specifies the name of the app-entry
+        in the JAAS config and the access manager
+
+      - a Workspaces element that specifies the location of the 
+        workspaces root directory, the name of the default workspace,
+        the maximum idle time before a workspace is automatically
+        shutdown (optional) and the workspace configuration root directory
+        within the virtual repository file system (optional)
+
+      - a Workspace element that is used as a workspace configuration
+        template; it is used to create the initial workspace if there's
+        no workspace yet and for creating additional workspaces through
+        the API
+
+      - a Versioning element that is used for configuring
+        versioning-related settings
+
+      - an optional SearchIndex element that is used for configuring Indexing-related
+        settings on the /jcr:system tree.
+
+-->
+<!ELEMENT Repository (Cluster|FileSystem|DataStore|Security|Workspaces|Workspace|Versioning|SearchIndex)*> 
+
+<!--
+    a virtual file system
+-->
+<!ELEMENT FileSystem (param*)>
+<!ATTLIST FileSystem class CDATA #REQUIRED>
+
+<!--
+    the Security element specifies the name (appName attribute)
+    of the JAAS configuration app-entry for this repository. 
+
+    it also specifies various security related managers to be used.
+-->
+<!ELEMENT Security (SecurityManager?, AccessManager?, LoginModule?)>
+<!ATTLIST Security appName CDATA #REQUIRED>
+
+<!--
+    the SecurityManager element configures the general security manager to be
+    used by this repository instance; the class attribute specifies the FQN of the
+    class implementing the JackrabbitSecurityManager interface
+-->
+<!ELEMENT SecurityManager (WorkspaceAccessManager?, param*)>
+<!ATTLIST SecurityManager class CDATA #REQUIRED
+                          workspaceName CDATA #IMPLIED>
+
+<!--
+    the AccessManager element configures the access manager to be used by
+    this repository instance; the class attribute specifies the FQN of the
+    class implementing the AccessManager interface
+-->
+<!ELEMENT AccessManager (param*)>
+<!ATTLIST AccessManager class CDATA #REQUIRED>
+
+<!--
+    generic parameter (name/value pair)
+-->
+<!ELEMENT param EMPTY>
+<!ATTLIST param name  CDATA #REQUIRED
+                value CDATA #REQUIRED>
+
+<!--
+    the LoginModule element optionally specifies a JAAS login module to
+    authenticate users. This feature allows the use of Jackrabbit in a
+    non-JAAS environment.
+-->
+<!ELEMENT LoginModule (param*)>
+<!ATTLIST LoginModule class CDATA #REQUIRED>
+
+<!--
+    the WorkspaceAccessManager element optionally configures the manager
+    to be used by this repository instance to determine if access to a specific
+    workspace is granted for a specific subject;
+    the class attribute specifies the FQN of the class implementing the
+    WorkspaceAccessManager interface
+-->
+<!ELEMENT WorkspaceAccessManager EMPTY>
+<!ATTLIST WorkspaceAccessManager class CDATA #REQUIRED>
+
+<!--
+    the Workspaces element specifies the physical workspaces root directory
+    (rootPath attribute), the name of the default workspace (defaultWorkspace 
+    attribute), the (optional) maximum amount of time in seconds before an idle 
+    workspace is automatically shutdown (maxIdleTime attribute) and the 
+    (optional) workspace configuration root directory within the virtual 
+    repository file system (configRootPath attribute).
+
+    individual workspaces are configured through individual workspace.xml files 
+    located in a subfolder each of either
+
+    a) the physical workspaces root directory
+
+    or, if configRootPath had been specified,
+
+    b) the configuration root directory within the virtual repository file 
+    system.
+-->
+<!ELEMENT Workspaces EMPTY>
+<!ATTLIST Workspaces rootPath         CDATA #REQUIRED
+                     defaultWorkspace CDATA #REQUIRED
+                     configRootPath   CDATA #IMPLIED
+                     maxIdleTime      CDATA #IMPLIED>
+
+<!--
+    the Workspace element serves as a workspace configuration template;
+    it is used to create the initial workspace if there's no workspace yet
+    and for creating additional workspaces through the api
+-->
+<!ELEMENT Workspace (FileSystem,PersistenceManager,SearchIndex?,ISMLocking?,WorkspaceSecurity?)>
+<!ATTLIST Workspace name CDATA #REQUIRED>
+
+<!--
+    the PersistenceManager element configures the persistence manager
+    to be used for the workspace; the class attribute specifies the
+    FQN of the class implementing the PersistenceManager interface
+-->
+<!ELEMENT PersistenceManager (param*)>
+<!ATTLIST PersistenceManager class CDATA #REQUIRED>
+
+<!--
+    the SearchIndex element specifies the locaction of the search index
+    (used by the QueryHandler); the class attribute specifies the
+    FQN of the class implementing the QueryHandler interface.
+-->
+<!ELEMENT SearchIndex (param*,FileSystem?)>
+<!ATTLIST SearchIndex class CDATA #REQUIRED>
+
+
+<!--
+    the WorkspaceSecurity element specifies the workspace specific security
+    configuration.
+-->
+<!ELEMENT WorkspaceSecurity (AccessControlProvider?)>
+
+<!--
+    the AccessControlProvider element defines a class attribute specifying the
+    FQN of the class implementing the AccessControlProvider interface.
+    The param(s) define implementation specific parameters.
+-->
+<!ELEMENT AccessControlProvider (param*)>
+<!ATTLIST AccessControlProvider class CDATA #REQUIRED>
+
+<!--
+    the Versioning element configures the persistence manager
+    to be used for persisting version state
+-->
+<!ELEMENT Versioning (FileSystem, PersistenceManager, ISMLocking?)>
+<!ATTLIST Versioning rootPath CDATA #REQUIRED>
+
+<!--
+    the Cluster element configures the optional participation of this
+    repository in a clustered environment. a literal id may be
+    specified that uniquely identifies this node in a cluster, as well
+    as the delay in milliseconds before changes to the journal are
+    automatically detected.
+-->
+<!ELEMENT Cluster (Journal)>
+<!ATTLIST Cluster id        CDATA #IMPLIED
+                  syncDelay CDATA #IMPLIED>
+
+<!--
+    the Journal element configures the journal used in clustering; the
+    class attribute specifies the FQN of the class implementing the
+    Journal interface.
+-->
+<!ELEMENT Journal (param*)>
+<!ATTLIST Journal class CDATA #REQUIRED>
+
+<!--
+    the ISMLocking element configures the locking implementation
+    to be used for the workspace and version storage; the class
+    attribute specifies the FQN of the class implementing the
+    ISMLocking interface.
+-->
+<!ELEMENT ISMLocking (param*)>
+<!ATTLIST ISMLocking class CDATA #REQUIRED>
+
+<!--
+    the RepsitoryLockMechanism element configures the mechanism
+    that is used to ensure only one process writes to the 
+    backend (file system or database) at any time; the class
+    attribute specifies the FQN of the class implementing the
+    RepsitoryLockMechanism interface.
+-->
+<!ELEMENT RepsitoryLockMechanism (param*)>
+<!ATTLIST RepsitoryLockMechanism class CDATA #REQUIRED>
+
+<!--
+    the DataStore element configures the data store
+    to be used for the workspace; the class attribute specifies the
+    FQN of the class implementing the DataStore interface
+-->
+<!ELEMENT DataStore (param*)>
+<!ATTLIST DataStore class CDATA #REQUIRED>