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>
+ * <RepositoryLockMechanism class="..." >
+ * <param name="..." value="...">
+ * ...
+ * </RepositoryLockMechanism>
+ * </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>