You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by dp...@apache.org on 2006/11/06 16:22:31 UTC

svn commit: r471760 [2/3] - in /jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core: ./ cluster/ config/ lock/ nodetype/virtual/ observation/ state/ version/

Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/FileRevision.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/FileRevision.java?view=auto&rev=471760
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/FileRevision.java (added)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/FileRevision.java Mon Nov  6 07:22:29 2006
@@ -0,0 +1,168 @@
+/*
+ * 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.cluster;
+
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.channels.FileLock;
+
+/**
+ * Maintains a file-based revision counter with locking, assuring uniqueness.
+ */
+class FileRevision {
+
+    /**
+     * Logger.
+     */
+    private static final Logger log = LoggerFactory.getLogger(FileRevision.class);
+
+    /**
+     * Underlying file.
+     */
+    private final File file;
+
+    /**
+     * Underlying random access file.
+     */
+    private RandomAccessFile raf;
+
+    /**
+     * File lock.
+     */
+    private FileLock lock;
+
+    /**
+     * Current lock count.
+     */
+    private int locks;
+
+    /**
+     * Creates a new file based revision counter.
+     *
+     * @param file holding global counter
+     */
+    public FileRevision(File file) {
+        this.file = file;
+
+        try {
+            if (!file.exists()) {
+                file.createNewFile();
+            }
+        } catch (IOException e) {
+            String msg = "I/O error while attempting to create new file '" + file + "': " + e.getMessage();
+            log.warn(msg);
+        }
+    }
+
+    /**
+     * Lock underlying file.
+     *
+     * @param shared whether to allow other readers or not
+     */
+    public void lock(boolean shared) throws JournalException {
+        if (lock == null) {
+            try {
+                raf = new RandomAccessFile(file, shared ? "r" : "rw");
+                lock = raf.getChannel().lock(0L, Long.MAX_VALUE, shared);
+            } catch (IOException e) {
+                String msg = "I/O error occurred: " + e.getMessage();
+                throw new JournalException(msg);
+            } finally {
+                if (lock == null && raf != null) {
+                    try {
+                        raf.close();
+                    } catch (IOException e) {
+                        String msg = "I/O error while closing file " + file.getPath() + ": " + e.getMessage();
+                        log.warn(msg);
+                    }
+                }
+            }
+        }
+        locks++;
+    }
+
+    /**
+     * Unlock underlying file.
+     */
+    public void unlock() {
+        if (lock != null && --locks == 0) {
+            try {
+                lock.release();
+            } catch (IOException e) {
+                String msg = "I/O error while releasing lock: " + e.getMessage();
+                log.warn(msg);
+            } finally {
+                lock = null;
+            }
+            try {
+                raf.close();
+            } catch (IOException e) {
+                String msg = "I/O error while closing file: " + e.getMessage();
+                log.warn(msg);
+            } finally {
+                raf = null;
+            }
+        }
+    }
+
+    /**
+     * Return current counter value.
+     *
+     * @return counter value
+     * @throws JournalException if some error occurs
+     */
+    public long get() throws JournalException {
+        try {
+            lock(true);
+
+            long value = 0;
+            if (raf.length() > 0) {
+                raf.seek(0L);
+                value = raf.readLong();
+            }
+            return value;
+
+        } catch (IOException e) {
+            throw new JournalException("I/O error occurred: ", e);
+        } finally {
+            unlock();
+        }
+    }
+
+    /**
+     * Set current counter value.
+     *
+     * @param value new counter value
+     * @throws JournalException if some error occurs
+     */
+    public void set(long value) throws JournalException {
+        try {
+            lock(false);
+
+            raf.seek(0L);
+            raf.writeLong(value);
+        } catch (IOException e) {
+            throw new JournalException("I/O error occurred.", e);
+        } finally {
+            unlock();
+        }
+    }
+}
\ No newline at end of file

Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/ItemOperation.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/ItemOperation.java?view=auto&rev=471760
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/ItemOperation.java (added)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/ItemOperation.java Mon Nov  6 07:22:29 2006
@@ -0,0 +1,68 @@
+/*
+ * 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.cluster;
+
+import org.apache.jackrabbit.core.state.ChangeLog;
+
+/**
+ * Item operation interface.
+ */
+public abstract class ItemOperation {
+
+    /**
+     * Operation type: added.
+     */
+    public static final int ADDED = 1;
+
+    /**
+     * Operation type: modified.
+     */
+    public static final int MODIFIED = 2;
+
+    /**
+     * Operation type: deleted.
+     */
+    public static final int DELETED = 3;
+
+    /**
+     * Operation type.
+     */
+    private final int operationType;
+
+    /**
+     * Creates a new instance of this class. Takes an operation type as parameter.
+     */
+    protected ItemOperation(int operationType) {
+        this.operationType = operationType;
+    }
+
+    /**
+     * Returns the operation type.
+     *
+     * @return operation type
+     */
+    public int getOperationType() {
+        return operationType;
+    }
+
+    /**
+     * Apply an operation to a change log. Subclass responsibility.
+     *
+     * @param changeLog change log
+     */
+    public abstract void apply(ChangeLog changeLog);
+}

Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/Journal.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/Journal.java?view=auto&rev=471760
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/Journal.java (added)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/Journal.java Mon Nov  6 07:22:29 2006
@@ -0,0 +1,102 @@
+/*
+ * 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.cluster;
+
+import org.apache.jackrabbit.core.state.ChangeLog;
+import org.apache.jackrabbit.core.observation.EventStateCollection;
+import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.name.NamespaceResolver;
+
+/**
+ * Journal interface. Defines operations on a journal that are used to synchronize clustered repository nodes.
+ */
+public interface Journal {
+
+    /**
+     * Initialize journal.
+     *
+     * @param id id this journal should use to write its own records
+     * @param resolver namespace resolver used to map prefixes to URIs and vice-versa.
+     * @param processor to invoke when new records are processed
+     * @throws JournalException if an error occurs
+     */
+    public void init(String id, RecordProcessor processor, NamespaceResolver resolver) throws JournalException;
+
+    /**
+     * Synchronize contents from journal.
+     *
+     * @throws JournalException if an error occurs
+     */
+    public void sync() throws JournalException;
+
+    /**
+     * Start an update operation on the journal.
+     * @param workspace workspace name, may be <code>null</code>
+     *
+     * @throws JournalException if an error occurs
+     */
+    public void begin(String workspace) throws JournalException;
+
+    /**
+     * Add item state operations to the journal.
+     *
+     * @param changes changes to transfer
+     * @throws JournalException if an error occurs
+     */
+    public void log(ChangeLog changes, EventStateCollection esc) throws JournalException;
+
+    /**
+     * Log a lock operation.
+     *
+     * @param nodeId node id
+     * @param isDeep flag indicating whether lock is deep
+     * @param owner lock owner
+     * @throws JournalException if an error occurs
+     */
+    public void log(NodeId nodeId, boolean isDeep, String owner) throws JournalException;
+
+    /**
+     * Log an unlock operation.
+     *
+     * @param nodeId node id
+     * @throws JournalException if an error occurs
+     */
+    public void log(NodeId nodeId) throws JournalException;
+
+    /**
+     * Prepare an update operation on the journal. This locks the journal exclusively for updates until this client
+     * either invokes {@link #cancel} or {@link #commit}. If a conflicting intermittent change is detected, this
+     * method should throw an exception, signaling that the whole update operation should be undone.
+     *
+     * @throws JournalException if an error occurs
+     */
+    public void prepare() throws JournalException;
+
+    /**
+     * End this update operation and definitely write changes to the journal.
+     *
+     * @throws JournalException if an error occurs
+     */
+    public void commit() throws JournalException;
+
+    /**
+     * End this update operation and discards changes made to the journal.
+     *
+     * @throws JournalException if an error occurs
+     */
+    public void cancel() throws JournalException;
+}

Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/JournalException.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/JournalException.java?view=auto&rev=471760
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/JournalException.java (added)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/JournalException.java Mon Nov  6 07:22:29 2006
@@ -0,0 +1,46 @@
+/*
+ * 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.cluster;
+
+/**
+ * The <code>JournalException</code> signals an error within a journal operation.
+ */
+public class JournalException extends ClusterException {
+
+    /**
+     * Constructs a new instance of this class with the specified detail
+     * message.
+     *
+     * @param message the detail message. The detail message is saved for
+     *                later retrieval by the {@link #getMessage()} method.
+     */
+    public JournalException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new instance of this class with the specified detail
+     * message and root cause.
+     *
+     * @param message   the detail message. The detail message is saved for
+     *                  later retrieval by the {@link #getMessage()} method.
+     * @param rootCause root failure cause
+     */
+    public JournalException(String message, Throwable rootCause) {
+        super(message, rootCause);
+    }
+}

Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/LockEventChannel.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/LockEventChannel.java?view=auto&rev=471760
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/LockEventChannel.java (added)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/LockEventChannel.java Mon Nov  6 07:22:29 2006
@@ -0,0 +1,48 @@
+/*
+ * 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.cluster;
+
+import org.apache.jackrabbit.core.NodeId;
+
+/**
+ * Event channel used to transmit lock events.
+ */
+public interface LockEventChannel {
+
+    /**
+     * Called when a node has been locked.
+     *
+     * @param nodeId node id
+     * @param deep flag indicating whether lock is deep
+     * @param owner lock owner
+     */
+    public void locked(NodeId nodeId, boolean deep, String owner);
+
+    /**
+     * Called when a node has been unlocked.
+     *
+     * @param nodeId node id
+     */
+    public void unlocked(NodeId nodeId);
+
+    /**
+     * Set listener that will receive information about incoming, external lock events.
+     *
+     * @param listener lock event listener
+     */
+    public void setListener(LockEventListener listener);
+}

Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/LockEventListener.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/LockEventListener.java?view=auto&rev=471760
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/LockEventListener.java (added)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/LockEventListener.java Mon Nov  6 07:22:29 2006
@@ -0,0 +1,46 @@
+/*
+ * 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.cluster;
+
+import org.apache.jackrabbit.core.NodeId;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * Interface used to receive information about incoming, external lock events.
+ */
+public interface LockEventListener {
+
+    /**
+     * Handle an external lock operation.
+     *
+     * @param nodeId node id
+     * @param isDeep <code>true</code> if the lock is deep;
+     *               <code>false</code> otherwise
+     * @param userId user id
+     * @throws RepositoryException if the lock cannot be processed
+     */
+    public void externalLock(NodeId nodeId, boolean isDeep, String userId) throws RepositoryException;
+
+    /**
+     * Handle an external unlock operation.
+     *
+     * @param nodeId node id
+     * @throws RepositoryException if the unlock cannot be processed
+     */
+    public void externalUnlock(NodeId nodeId) throws RepositoryException;
+}

Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/NodeAddedOperation.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/NodeAddedOperation.java?view=auto&rev=471760
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/NodeAddedOperation.java (added)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/NodeAddedOperation.java Mon Nov  6 07:22:29 2006
@@ -0,0 +1,55 @@
+/*
+ * 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.cluster;
+
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.state.ChangeLog;
+
+/**
+ * Describes a journal operation for a node addition.
+ */
+public class NodeAddedOperation extends NodeOperation {
+
+    /**
+     * Creates a new instance of this class.
+     */
+    NodeAddedOperation() {
+        super(ItemOperation.ADDED);
+    }
+
+    /**
+     * Create a node operation for an added node. All members must be remembered.
+     *
+     * @param state node state
+     * @return node operation
+     */
+    public static NodeOperation create(NodeState state) {
+        NodeOperation operation = new NodeAddedOperation();
+        operation.setId(state.getNodeId());
+        //todo set other members
+        return operation;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void apply(ChangeLog changeLog) {
+        NodeState state = new NodeState(getId(), null, null, NodeState.STATUS_NEW, false);
+        state.setStatus(NodeState.STATUS_EXISTING);
+        changeLog.added(state);
+    }
+}
\ No newline at end of file

Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/NodeDeletedOperation.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/NodeDeletedOperation.java?view=auto&rev=471760
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/NodeDeletedOperation.java (added)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/NodeDeletedOperation.java Mon Nov  6 07:22:29 2006
@@ -0,0 +1,54 @@
+/*
+ * 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.cluster;
+
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.state.ChangeLog;
+
+/**
+ * Describes a journal operation for a node deletion.
+ */
+public class NodeDeletedOperation extends NodeOperation {
+
+    /**
+     * Creates a new instance of this class.
+     */
+    NodeDeletedOperation() {
+        super(ItemOperation.DELETED);
+    }
+
+    /**
+     * Create a node operation for a deleted node. The only member that must be transmitted is the node id.
+     *
+     * @param state node state
+     * @return node operation
+     */
+    public static NodeOperation create(NodeState state) {
+        NodeOperation operation = new NodeDeletedOperation();
+        operation.setId(state.getNodeId());
+        return operation;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void apply(ChangeLog changeLog) {
+        NodeState state = new NodeState(getId(), null, null, NodeState.STATUS_NEW, false);
+        state.setStatus(NodeState.STATUS_EXISTING_REMOVED);
+        changeLog.deleted(state);
+    }
+}
\ No newline at end of file

Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/NodeModifiedOperation.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/NodeModifiedOperation.java?view=auto&rev=471760
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/NodeModifiedOperation.java (added)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/NodeModifiedOperation.java Mon Nov  6 07:22:29 2006
@@ -0,0 +1,55 @@
+/*
+ * 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.cluster;
+
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.state.ChangeLog;
+
+/**
+ * Describes a journal operation for a node modification.
+ */
+public class NodeModifiedOperation extends NodeOperation {
+
+    /**
+     * Creates a new instance of this class.
+     */
+    NodeModifiedOperation() {
+        super(ItemOperation.MODIFIED);
+    }
+
+    /**
+     * Create a node operation for a modified node. Only modified/modifiable members must be remembered.
+     *
+     * @param state node state
+     * @return node operation
+     */
+    public static NodeOperation create(NodeState state) {
+        NodeOperation operation = new NodeModifiedOperation();
+        operation.setId(state.getNodeId());
+        //todo set other members
+        return operation;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void apply(ChangeLog changeLog) {
+        NodeState state = new NodeState(getId(), null, null, NodeState.STATUS_NEW, false);
+        state.setStatus(NodeState.STATUS_EXISTING_MODIFIED);
+        changeLog.modified(state);
+    }
+}
\ No newline at end of file

Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/NodeOperation.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/NodeOperation.java?view=auto&rev=471760
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/NodeOperation.java (added)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/NodeOperation.java Mon Nov  6 07:22:29 2006
@@ -0,0 +1,123 @@
+/*
+ * 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.cluster;
+
+import org.apache.jackrabbit.core.nodetype.PropDefId;
+import org.apache.jackrabbit.core.nodetype.NodeDefId;
+import org.apache.jackrabbit.core.PropertyId;
+import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.value.InternalValue;
+
+/**
+ * Describes a journal record for a node change.
+ */
+abstract class NodeOperation extends ItemOperation {
+
+    /**
+     * Node id.
+     */
+    private NodeId id;
+
+    /**
+     * Node definition id.
+     */
+    private NodeDefId definitionId;
+
+    /**
+     * Creates a new instance of this class. Takes an operation type as paramter.
+     *
+     * @param operationType operation type
+     */
+    protected NodeOperation(int operationType) {
+        super(operationType);
+    }
+
+    /**
+     * Creates a new instance of a known subclass.
+     *
+     * @param operationType operation type
+     * @return instance of this class
+     */
+    public static NodeOperation create(int operationType) {
+        switch (operationType) {
+            case ADDED:
+                return new NodeAddedOperation();
+            case MODIFIED:
+                return new NodeModifiedOperation();
+            case DELETED:
+                return new NodeDeletedOperation();
+            default:
+                throw new IllegalArgumentException("Unknown operation type: " + operationType);
+        }
+    }
+
+    /**
+     * Return a flag indicating whether the node id is contained in this record.
+     *
+     * @return <code>true</code> if the node id is contained;
+     *         <code>false</code> otherwise.
+     */
+    public boolean hasId() {
+        return id != null;
+    }
+
+    /**
+     * Return the node id.
+     *
+     * @return node id
+     */
+    public NodeId getId() {
+        return id;
+    }
+
+    /**
+     * Set the node id.
+     *
+     * @param id node id
+     */
+    public void setId(NodeId id) {
+        this.id = id;
+    }
+
+    /**
+     * Return the definition id.
+     *
+     * @return definition id
+     */
+    public NodeDefId getDefintionId() {
+        return definitionId;
+    }
+
+    /**
+     * Return a flag indicating whether the definition id is contained in this record.
+     *
+     * @return <code>true</code> if the definition id is contained;
+     *         <code>false</code> otherwise.
+     */
+    public boolean hasDefinitionId() {
+        return definitionId != null;
+    }
+
+    /**
+     * Set the definition id.
+     *
+     * @param defintionId definition id
+     */
+    public void setDefintionId(NodeDefId defintionId) {
+        this.definitionId = defintionId;
+    }
+}

Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/PropertyAddedOperation.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/PropertyAddedOperation.java?view=auto&rev=471760
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/PropertyAddedOperation.java (added)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/PropertyAddedOperation.java Mon Nov  6 07:22:29 2006
@@ -0,0 +1,55 @@
+/*
+ * 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.cluster;
+
+import org.apache.jackrabbit.core.state.PropertyState;
+import org.apache.jackrabbit.core.state.ChangeLog;
+
+/**
+ * Describes a journal operation for a property addition.
+ */
+public class PropertyAddedOperation extends PropertyOperation {
+
+    /**
+     * Creates a new instance of this class.
+     */
+    PropertyAddedOperation() {
+        super(ItemOperation.ADDED);
+    }
+
+    /**
+     * Create a property record for an added property. All members must be remembered.
+     *
+     * @param state property state
+     * @return property operation
+     */
+    public static PropertyOperation create(PropertyState state) {
+        PropertyOperation operation = new PropertyAddedOperation();
+        operation.setId(state.getPropertyId());
+        //todo set other members
+        return operation;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void apply(ChangeLog changeLog) {
+        PropertyState state = new PropertyState(getId(), PropertyState.STATUS_NEW, false);
+        state.setStatus(PropertyState.STATUS_EXISTING);
+        changeLog.added(state);
+    }
+}
\ No newline at end of file

Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/PropertyDeletedOperation.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/PropertyDeletedOperation.java?view=auto&rev=471760
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/PropertyDeletedOperation.java (added)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/PropertyDeletedOperation.java Mon Nov  6 07:22:29 2006
@@ -0,0 +1,54 @@
+/*
+ * 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.cluster;
+
+import org.apache.jackrabbit.core.state.PropertyState;
+import org.apache.jackrabbit.core.state.ChangeLog;
+
+/**
+ * Describes a journal operation for a property deletion.
+ */
+public class PropertyDeletedOperation extends PropertyOperation {
+
+    /**
+     * Creates a new instance of this class.
+     */
+    PropertyDeletedOperation() {
+        super(ItemOperation.DELETED);
+    }
+
+    /**
+     * Create a property record for a deleted property. The only member that must be transmitted is the property id.
+     *
+     * @param state property state
+     * @return property operation
+     */
+    public static PropertyOperation create(PropertyState state) {
+        PropertyOperation operation = new PropertyDeletedOperation();
+        operation.setId(state.getPropertyId());
+        return operation;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void apply(ChangeLog changeLog) {
+        PropertyState state = new PropertyState(getId(), PropertyState.STATUS_NEW, false);
+        state.setStatus(PropertyState.STATUS_EXISTING_REMOVED);
+        changeLog.deleted(state);
+    }
+}
\ No newline at end of file

Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/PropertyModifiedOperation.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/PropertyModifiedOperation.java?view=auto&rev=471760
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/PropertyModifiedOperation.java (added)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/PropertyModifiedOperation.java Mon Nov  6 07:22:29 2006
@@ -0,0 +1,55 @@
+/*
+ * 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.cluster;
+
+import org.apache.jackrabbit.core.state.PropertyState;
+import org.apache.jackrabbit.core.state.ChangeLog;
+
+/**
+ * Describes a journal operation for a property modification.
+ */
+public class PropertyModifiedOperation extends PropertyOperation {
+
+    /**
+     * Creates a new instance of this class.
+     */
+    PropertyModifiedOperation() {
+        super(ItemOperation.MODIFIED);
+    }
+
+    /**
+     * Create a property record for a modified property. Only modified/modifiable members must be transmitted.
+     *
+     * @param state property state
+     * @return property operation
+     */
+    public static PropertyOperation create(PropertyState state) {
+        PropertyOperation operation = new PropertyModifiedOperation();
+        operation.setId(state.getPropertyId());
+        //todo set other members
+        return operation;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void apply(ChangeLog changeLog) {
+        PropertyState state = new PropertyState(getId(), PropertyState.STATUS_NEW, false);
+        state.setStatus(PropertyState.STATUS_EXISTING_MODIFIED);
+        changeLog.modified(state);
+    }
+}
\ No newline at end of file

Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/PropertyOperation.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/PropertyOperation.java?view=auto&rev=471760
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/PropertyOperation.java (added)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/PropertyOperation.java Mon Nov  6 07:22:29 2006
@@ -0,0 +1,204 @@
+/*
+ * 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.cluster;
+
+import org.apache.jackrabbit.core.nodetype.PropDefId;
+import org.apache.jackrabbit.core.PropertyId;
+import org.apache.jackrabbit.core.value.InternalValue;
+
+/**
+ * Describes a journal operation for a property change.
+ */
+abstract class PropertyOperation extends ItemOperation {
+
+    /**
+     * Definition id.
+     */
+    private PropDefId definitionId;
+
+    /**
+     * Property id.
+     */
+    private PropertyId id;
+
+    /**
+     * Multivalued flag.
+     */
+    private Boolean multiValued;
+
+    /**
+     * Type.
+     */
+    private Integer type;
+
+    /**
+     * Values.
+     */
+    private InternalValue[] values;
+
+    /**
+     * Creates a new instance of this class. Takes an operation type as paramter.
+     * @param operationType operation type
+     */
+    protected PropertyOperation(int operationType) {
+        super(operationType);
+    }
+
+    /**
+     * Creates a new instance of a known subclass.
+     *
+     * @param operationType operation type
+     * @return instance of this class
+     */
+    public static PropertyOperation create(int operationType) {
+        switch (operationType) {
+            case ADDED:
+                return new PropertyAddedOperation();
+            case MODIFIED:
+                return new PropertyModifiedOperation();
+            case DELETED:
+                return new PropertyDeletedOperation();
+            default:
+                throw new IllegalArgumentException("Unknown operation type: " + operationType);
+        }
+    }
+
+    /**
+     * Return a flag indicating whether the definiton id is contained in this record.
+     * @return <code>true</code> if the definition id is contained;
+     *         <code>false</code> otherwise.
+     */
+    public boolean hasDefinitionId() {
+        return definitionId != null;
+    }
+
+    /**
+     * Return the definition id.
+     * @return definition id
+     */
+    public PropDefId getDefinitionId() {
+        return definitionId;
+    }
+
+    /**
+     * Set the definition id.
+     * @param definitionId definition id
+     */
+    public void setDefinitionId(PropDefId definitionId) {
+        this.definitionId = definitionId;
+    }
+
+    /**
+     * Return a flag indicating whether the property id is contained in this record.
+     * @return <code>true</code> if the property id is contained;
+     *         <code>false</code> otherwise.
+     */
+    public boolean hasId() {
+        return id != null;
+    }
+
+    /**
+     * Return the property id.
+     * @return property id
+     */
+    public PropertyId getId() {
+        return id;
+    }
+
+    /**
+     * Set the property id.
+     * @param id property id
+     */
+    public void setId(PropertyId id) {
+        this.id = id;
+    }
+
+    /**
+     * Return a flag indicating whether the multivalued flag is contained in this record.
+     * @return <code>true</code> if the multivalued flag is contained;
+     *         <code>false</code> otherwise.
+     */
+    public boolean hasMultiValued() {
+        return multiValued != null;
+    }
+
+    /**
+     * Return the multivalued flag.
+     * @return multivalued flag
+     */
+    public boolean isMultiValued() {
+        return multiValued.booleanValue();
+    }
+
+    /**
+     * Set the multivalued flag.
+     * @param multiValued multivalued flag
+     */
+    public void setMultiValued(boolean multiValued) {
+        this.multiValued = new Boolean(multiValued);
+    }
+
+    /**
+     * Return a flag indicating whether the type is contained.
+     * @return <code>true</code> if the type is contained;
+     *         <code>false</code> otherwise.
+     */
+    public boolean hasType() {
+        return type != null;
+    }
+
+    /**
+     * Return the type.
+     * @return type
+     */
+    public int getType() {
+        return type.intValue();
+    }
+
+    /**
+     * Set the type.
+     * @param type type
+     */
+    public void setType(int type) {
+        this.type = new Integer(type);
+    }
+
+    /**
+     * Return a flag indicating whether the values contained in this record.
+     * @return <code>true</code> if the values contained contained;
+     *         <code>false</code> otherwise.
+     */
+    public boolean hasValues() {
+        return values != null;
+    }
+
+    /**
+     * Return the values.
+     * @return value
+     */
+    public InternalValue[] getValues() {
+        return values;
+    }
+
+    /**
+     * Set the values.
+     * @param values values
+     */
+    public void setValues(InternalValue[] values) {
+        this.values = values;
+    }
+}
\ No newline at end of file

Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/RecordProcessor.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/RecordProcessor.java?view=auto&rev=471760
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/RecordProcessor.java (added)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/RecordProcessor.java Mon Nov  6 07:22:29 2006
@@ -0,0 +1,78 @@
+/*
+ * 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.cluster;
+
+import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.name.Path;
+import org.apache.jackrabbit.name.QName;
+
+import java.util.Set;
+
+/**
+ * Listener interface on a journal that gets called back for records that should be processed.
+ */
+public interface RecordProcessor {
+
+    /**
+     * Invoked when a record starts.
+     *
+     * @param workspace workspace, may be <code>null</code>
+     */
+    public void start(String workspace);
+
+    /**
+     * Process an update operation.
+     *
+     * @param operation operation to process
+     */
+    public void process(ItemOperation operation);
+
+    /**
+     * Process an event.
+     *
+     * @param type event type
+     * @param parentId parent id
+     * @param parentPath parent path
+     * @param childId child id
+     * @param childRelPath child relative path
+     * @param ntName ndoe type name
+     * @param userId user id
+     */
+    public void process(int type, NodeId parentId, Path parentPath, NodeId childId,
+                        Path.PathElement childRelPath, QName ntName, Set mixins, String userId);
+
+    /**
+     * Process a lock operation.
+     *
+     * @param nodeId node id
+     * @param isDeep flag indicating whether lock is deep
+     * @param owner lock owner
+     */
+    public void process(NodeId nodeId, boolean isDeep, String owner);
+
+    /**
+     * Process an unlock operation.
+     *
+     * @param nodeId node id
+     */
+    public void process(NodeId nodeId);
+
+    /**
+     * Invoked when a record ends.
+     */
+    public void end();
+}

Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/UpdateEventChannel.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/UpdateEventChannel.java?view=auto&rev=471760
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/UpdateEventChannel.java (added)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/UpdateEventChannel.java Mon Nov  6 07:22:29 2006
@@ -0,0 +1,56 @@
+/*
+ * 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.cluster;
+
+import org.apache.jackrabbit.core.state.ChangeLog;
+import org.apache.jackrabbit.core.observation.EventStateCollection;
+
+/**
+ * Event channel used to transmit update operations.
+ */
+public interface UpdateEventChannel {
+
+    /**
+     * Called when an a update operation has been created.
+     *
+     * @param changes changes
+     * @param esc events as they will be delivered on success
+     */
+    public void updateCreated(ChangeLog changes, EventStateCollection esc);
+
+    /**
+     * Called when an a update operation has been prepared.
+     */
+    public void updatePrepared();
+
+    /**
+     * Called when an a update operation has been committed.
+     */
+    public void updateCommitted();
+
+    /**
+     * Called when an a update operation has been cancelled.
+     */
+    public void updateCancelled();
+
+    /**
+     * Set listener that will receive information about incoming, external update events.
+     *
+     * @param listener update event listener
+     */
+    public void setListener(UpdateEventListener listener);
+}

Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/UpdateEventListener.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/UpdateEventListener.java?view=auto&rev=471760
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/UpdateEventListener.java (added)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/cluster/UpdateEventListener.java Mon Nov  6 07:22:29 2006
@@ -0,0 +1,36 @@
+/*
+ * 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.cluster;
+
+import java.util.List;
+import org.apache.jackrabbit.core.state.ChangeLog;
+import javax.jcr.RepositoryException;
+
+/**
+ * Interface used to receive information about incoming, external update events.
+ */
+public interface UpdateEventListener {
+
+    /**
+     * Handle an external update.
+     *
+     * @param changes external changes containing only node and property ids.
+     * @param events events to deliver
+     * @throws RepositoryException if the update cannot be processed
+     */
+    public void externalUpdate(ChangeLog changes, List events) throws RepositoryException;
+}

Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/ClusterConfig.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/ClusterConfig.java?view=auto&rev=471760
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/ClusterConfig.java (added)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/ClusterConfig.java Mon Nov  6 07:22:29 2006
@@ -0,0 +1,78 @@
+/*
+ * 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.config;
+
+/**
+ * Cluster configuration. This encapsulates the security related sub
+ * configuration {@link JournalConfig}.
+ */
+public class ClusterConfig {
+
+    /**
+     * Identifier.
+     */
+    private final String id;
+
+    /**
+     * Sync delay.
+     */
+    private final int syncDelay;
+
+    /**
+     * Journal configuration.
+     */
+    private final JournalConfig jc;
+
+    /**
+     * Creates a new cluster configuration.
+     *
+     * @param id custom cluster node id
+     * @param jc journal configuration
+     */
+    public ClusterConfig(String id, int syncDelay, JournalConfig jc) {
+        this.id = id;
+        this.syncDelay = syncDelay;
+        this.jc = jc;
+    }
+
+    /**
+     * Return the id configuration attribute value.
+     *
+     * @return id attribute value
+     */
+    public String getId() {
+        return id;
+    }
+
+    /**
+     * Return the syncDelay configuration attribute value.
+     *
+     * @return syncDelay
+     */
+    public int getSyncDelay() {
+        return syncDelay;
+    }
+
+    /**
+     * Returns the journal configuration.
+     *
+     * @return journal configuration
+     */
+    public JournalConfig getJournalConfig() {
+        return jc;
+    }
+}

Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/JournalConfig.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/JournalConfig.java?view=auto&rev=471760
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/JournalConfig.java (added)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/JournalConfig.java Mon Nov  6 07:22:29 2006
@@ -0,0 +1,37 @@
+/*
+ * 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.config;
+
+/**
+ * Journal configuration. This bean configuration class
+ * is used to create configured journal.
+ * <p>
+ * This class is currently only used to assign a static type to
+ * more generic bean configuration information.
+ */
+public class JournalConfig extends BeanConfig {
+
+    /**
+     * Creates a journal configuration object from the given bean configuration.
+     *
+     * @param config bean configuration
+     */
+    public JournalConfig(BeanConfig config) {
+        super(config);
+    }
+
+}

Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java?view=diff&rev=471760&r1=471759&r2=471760
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java Mon Nov  6 07:22:29 2006
@@ -213,6 +213,11 @@
     private final SearchConfig sc;
 
     /**
+     * Optional cluster configuration.
+     */
+    private final ClusterConfig cc;
+
+    /**
      * Creates a repository configuration object.
      *
      * @param template workspace configuration template
@@ -225,13 +230,14 @@
      * @param defaultWorkspace name of the default workspace
      * @param vc versioning configuration
      * @param sc search configuration for system search manager.
+     * @param cc optional cluster configuration
      * @param parser configuration parser
      */
     public RepositoryConfig(String home, SecurityConfig sec, FileSystemConfig fsc,
             String workspaceDirectory, String workspaceConfigDirectory,
             String defaultWorkspace, int workspaceMaxIdleTime,
             Element template, VersioningConfig vc, SearchConfig sc,
-            RepositoryConfigurationParser parser) {
+            ClusterConfig cc, RepositoryConfigurationParser parser) {
         workspaces = new HashMap();
         this.home = home;
         this.sec = sec;
@@ -243,6 +249,7 @@
         this.template = template;
         this.vc = vc;
         this.sc = sc;
+        this.cc = cc;
         this.parser = parser;
     }
 
@@ -728,4 +735,11 @@
         return sc;
     }
 
+    /**
+     * Returns the cluster configuration. Returns <code>null</code> if clustering
+     * has not been configured.
+     */
+    public ClusterConfig getClusterConfig() {
+        return cc;
+    }
 }

Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java?view=diff&rev=471760&r1=471759&r2=471760
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java Mon Nov  6 07:22:29 2006
@@ -73,6 +73,12 @@
     /** Name of the file system configuration element. */
     public static final String FILE_SYSTEM_ELEMENT = "FileSystem";
 
+    /** Name of the cluster configuration element. */
+    public static final String CLUSTER_ELEMENT = "Cluster";
+
+    /** Name of the journal configuration element. */
+    public static final String JOURNAL_ELEMENT = "Journal";
+
     /** Name of the persistence manager configuration element. */
     public static final String PERSISTENCE_MANAGER_ELEMENT =
         "PersistenceManager";
@@ -96,6 +102,12 @@
     public static final String DEFAULT_WORKSPACE_ATTRIBUTE =
         "defaultWorkspace";
 
+    /** Name of the id configuration attribute. */
+    public static final String ID_ATTRIBUTE = "id";
+
+    /** Name of the syncDelay configuration attribute. */
+    public static final String SYNC_DELAY_ATTRIBUTE = "syncDelay";
+
     /** Name of the default search index implementation class. */
     public static final String DEFAULT_QUERY_HANDLER =
         "org.apache.jackrabbit.core.query.lucene.SearchIndex";
@@ -196,9 +208,12 @@
         // Optional search configuration
         SearchConfig sc = parseSearchConfig(root);
 
+        // Optional journal configuration
+        ClusterConfig cc = parseClusterConfig(root);
+
         return new RepositoryConfig(home, securityConfig, fsc,
                 workspaceDirectory, workspaceConfigDirectory, defaultWorkspace,
-                maxIdleTime, template, vc, sc, this);
+                maxIdleTime, template, vc, sc, cc, this);
     }
 
     /**
@@ -425,6 +440,68 @@
         PersistenceManagerConfig pmc = parsePersistenceManagerConfig(element);
 
         return new VersioningConfig(home, fsc, pmc);
+    }
+
+    /**
+     * Parses cluster configuration. Cluster configuration uses the following format:
+     * <pre>
+     *   &lt;Cluster&gt;
+     *     &lt;Journal ...&gt;
+     *   &lt;/Journal&gt;
+     * </pre>
+     * <p/>
+     * <code>Cluster</code> is a {@link #parseBeanConfig(Element,String) bean configuration}
+     * element.
+     * <p/>
+     * Clustering is an optional feature. If the cluster element is not found, then this
+     * method returns <code>null</code>.
+     *
+     * @param parent parent of the <code>Journal</code> element
+     * @return journal configuration, or <code>null</code>
+     * @throws ConfigurationException if the configuration is broken
+     */
+    protected ClusterConfig parseClusterConfig(Element parent)
+            throws ConfigurationException {
+
+        NodeList children = parent.getChildNodes();
+        for (int i = 0; i < children.getLength(); i++) {
+            Node child = children.item(i);
+            if (child.getNodeType() == Node.ELEMENT_NODE
+                    && CLUSTER_ELEMENT.equals(child.getNodeName())) {
+                Element element = (Element) child;
+
+                String id = getAttribute(element, ID_ATTRIBUTE, null);
+                int syncDelay = Integer.parseInt(
+                        getAttribute(element, SYNC_DELAY_ATTRIBUTE, "5"));
+
+                JournalConfig jc = parseJournalConfig(element);
+                return new ClusterConfig(id, syncDelay, jc);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Parses journal configuration. Journal configuration uses the following format:
+     * <pre>
+     *   &lt;Journal class="..."&gt;
+     *     &lt;param name="..." value="..."&gt;
+     *     ...
+     *   &lt;/Journal&gt;
+     * </pre>
+     * <p/>
+     * <code>Journal</code> is a {@link #parseBeanConfig(Element,String) bean configuration}
+     * element.
+     *
+     * @param cluster parent cluster element
+     * @return journal configuration, or <code>null</code>
+     * @throws ConfigurationException if the configuration is broken
+     */
+    protected JournalConfig parseJournalConfig(Element cluster)
+            throws ConfigurationException {
+
+        return new JournalConfig(
+                parseBeanConfig(cluster, JOURNAL_ELEMENT));
     }
 
     /**

Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/config.dtd
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/config.dtd?view=diff&rev=471760&r1=471759&r2=471760
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/config.dtd (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/config.dtd Mon Nov  6 07:22:29 2006
@@ -32,7 +32,7 @@
         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 
+        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
@@ -48,8 +48,11 @@
 
         a Versioning element that is used for configuring
         versioning-related settings
+
+        a Cluster element that is used for configuring an optional
+        clustering node that synchronizes changes made in a cluster
 -->
-<!ELEMENT Repository (FileSystem,Security,Workspaces,Workspace,Versioning)>
+<!ELEMENT Repository (FileSystem,Security,Workspaces,Workspace,Versioning,Cluster?)>
 
 <!--
     a virtual file system
@@ -154,3 +157,25 @@
 <!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 seconds 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>

Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/lock/LockManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/lock/LockManagerImpl.java?view=diff&rev=471760&r1=471759&r2=471760
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/lock/LockManagerImpl.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/lock/LockManagerImpl.java Mon Nov  6 07:22:29 2006
@@ -24,6 +24,8 @@
 import org.apache.jackrabbit.util.PathMap;
 import org.apache.jackrabbit.core.SessionImpl;
 import org.apache.jackrabbit.core.SessionListener;
+import org.apache.jackrabbit.core.cluster.LockEventChannel;
+import org.apache.jackrabbit.core.cluster.LockEventListener;
 import org.apache.jackrabbit.core.fs.FileSystem;
 import org.apache.jackrabbit.core.fs.FileSystemException;
 import org.apache.jackrabbit.core.fs.FileSystemResource;
@@ -54,11 +56,10 @@
 import java.util.ArrayList;
 import java.util.Iterator;
 
-
 /**
  * Provides the functionality needed for locking and unlocking nodes.
  */
-public class LockManagerImpl implements LockManager, SynchronousEventListener {
+public class LockManagerImpl implements LockManager, SynchronousEventListener, LockEventListener {
 
     /**
      * Logger
@@ -101,6 +102,11 @@
     private final NamespaceResolver nsResolver;
 
     /**
+     * Lock event channel.
+     */
+    private LockEventChannel eventChannel;
+
+    /**
      * Create a new instance of this class.
      *
      * @param session system session
@@ -280,6 +286,9 @@
             lockMap.put(path, info);
 
             if (!info.sessionScoped) {
+                if (eventChannel != null) {
+                    eventChannel.locked(node.getNodeId(), isDeep, session.getUserID());
+                }
                 save();
             }
             return info;
@@ -322,6 +331,9 @@
             info.setLive(false);
 
             if (!info.sessionScoped) {
+                if (eventChannel != null) {
+                    eventChannel.unlocked(node.getNodeId());
+                }
                 save();
             }
 
@@ -599,6 +611,7 @@
         release();
     }
 
+
     //----------------------------------------------< SynchronousEventListener >
 
     /**
@@ -909,6 +922,64 @@
          * {@inheritDoc}
          */
         public void loggedOut(SessionImpl session) {
+        }
+    }
+
+    //----------------------------------------------------< LockEventListener >
+
+    /**
+     * Set a lock event channel
+     *
+     * @param eventChannel lock event channel
+     */
+    public void setEventChannel(LockEventChannel eventChannel) {
+        this.eventChannel = eventChannel;
+        eventChannel.setListener(this);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void externalLock(NodeId nodeId, boolean isDeep, String userId) throws RepositoryException {
+        acquire();
+
+        try {
+            Path path = getPath(nodeId);
+
+            // create lock token
+            LockInfo info = new LockInfo(new LockToken(nodeId), false, isDeep, userId);
+            info.setLive(true);
+            lockMap.put(path, info);
+
+            save();
+        } finally {
+            release();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void externalUnlock(NodeId nodeId) throws RepositoryException {
+        acquire();
+
+        try {
+            Path path = getPath(nodeId);
+            PathMap.Element element = lockMap.map(path, true);
+            if (element == null) {
+                throw new LockException("Node not locked: " + path.toString());
+            }
+            AbstractLockInfo info = (AbstractLockInfo) element.get();
+            if (info == null) {
+                throw new LockException("Node not locked: " + path.toString());
+            }
+            element.set(null);
+            info.setLive(false);
+
+            save();
+
+        } finally {
+            release();
         }
     }
 }

Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/nodetype/virtual/VirtualNodeTypeStateManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/nodetype/virtual/VirtualNodeTypeStateManager.java?view=diff&rev=471760&r1=471759&r2=471760
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/nodetype/virtual/VirtualNodeTypeStateManager.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/nodetype/virtual/VirtualNodeTypeStateManager.java Mon Nov  6 07:22:29 2006
@@ -207,7 +207,7 @@
                 parent.getPrimaryPath(),
                 node.getNodeId(),
                 node.getPrimaryPath().getNameElement(),
-                (NodeTypeImpl) parent.getPrimaryNodeType(),
+                ((NodeTypeImpl) parent.getPrimaryNodeType()).getQName(),
                 parent.getMixinTypeNames(),
                 node.getSession()
         ));
@@ -219,7 +219,7 @@
                     (NodeId) node.getId(),
                     node.getPrimaryPath(),
                     prop.getPrimaryPath().getNameElement(),
-                    (NodeTypeImpl) node.getPrimaryNodeType(),
+                    ((NodeTypeImpl) node.getPrimaryNodeType()).getQName(),
                     node.getMixinTypeNames(),
                     node.getSession()
             ));
@@ -247,7 +247,7 @@
                 parent.getPrimaryPath(),
                 node.getNodeId(),
                 node.getPrimaryPath().getNameElement(),
-                (NodeTypeImpl) parent.getPrimaryNodeType(),
+                ((NodeTypeImpl) parent.getPrimaryNodeType()).getQName(),
                 parent.getMixinTypeNames(),
                 node.getSession()
         ));

Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/observation/EventState.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/observation/EventState.java?view=diff&rev=471760&r1=471759&r2=471760
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/observation/EventState.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/observation/EventState.java Mon Nov  6 07:22:29 2006
@@ -16,7 +16,6 @@
  */
 package org.apache.jackrabbit.core.observation;
 
-import org.apache.jackrabbit.core.nodetype.NodeTypeImpl;
 import org.apache.jackrabbit.core.nodetype.NodeTypeManagerImpl;
 import org.apache.jackrabbit.core.ItemId;
 import org.apache.jackrabbit.core.PropertyId;
@@ -74,9 +73,9 @@
     private final Path.PathElement childRelPath;
 
     /**
-     * The node type of the parent node.
+     * The node type name of the parent node.
      */
-    private final NodeTypeImpl nodeType;
+    private final QName nodeType;
 
     /**
      * Set of mixin QNames assigned to the parent node.
@@ -129,7 +128,7 @@
                        Path parentPath,
                        NodeId childId,
                        Path.PathElement childPath,
-                       NodeTypeImpl nodeType,
+                       QName nodeType,
                        Set mixins,
                        Session session) {
         int mask = (Event.PROPERTY_ADDED | Event.PROPERTY_CHANGED | Event.PROPERTY_REMOVED);
@@ -173,7 +172,7 @@
                                             Path parentPath,
                                             NodeId childId,
                                             Path.PathElement childPath,
-                                            NodeTypeImpl nodeType,
+                                            QName nodeType,
                                             Set mixins,
                                             Session session) {
         return new EventState(Event.NODE_ADDED,
@@ -205,7 +204,7 @@
                                               Path parentPath,
                                               NodeId childId,
                                               Path.PathElement childPath,
-                                              NodeTypeImpl nodeType,
+                                              QName nodeType,
                                               Set mixins,
                                               Session session) {
         return new EventState(Event.NODE_REMOVED,
@@ -235,7 +234,7 @@
     public static EventState propertyAdded(NodeId parentId,
                                            Path parentPath,
                                            Path.PathElement childPath,
-                                           NodeTypeImpl nodeType,
+                                           QName nodeType,
                                            Set mixins,
                                            Session session) {
         return new EventState(Event.PROPERTY_ADDED,
@@ -265,7 +264,7 @@
     public static EventState propertyRemoved(NodeId parentId,
                                              Path parentPath,
                                              Path.PathElement childPath,
-                                             NodeTypeImpl nodeType,
+                                             QName nodeType,
                                              Set mixins,
                                              Session session) {
         return new EventState(Event.PROPERTY_REMOVED,
@@ -295,7 +294,7 @@
     public static EventState propertyChanged(NodeId parentId,
                                              Path parentPath,
                                              Path.PathElement childPath,
-                                             NodeTypeImpl nodeType,
+                                             QName nodeType,
                                              Set mixins,
                                              Session session) {
         return new EventState(Event.PROPERTY_CHANGED,
@@ -359,7 +358,7 @@
      *
      * @return the node type of the parent associated with this event.
      */
-    public NodeTypeImpl getNodeType() {
+    public QName getNodeType() {
         return nodeType;
     }
 
@@ -384,7 +383,11 @@
     public Set getNodeTypes(NodeTypeManagerImpl ntMgr) {
         if (allTypes == null) {
             Set tmp = new HashSet();
-            tmp.add(nodeType);
+            try {
+                tmp.add(ntMgr.getNodeType(nodeType));
+            } catch (NoSuchNodeTypeException e) {
+                log.warn("Unknown node type: " + nodeType);
+            }
             for (Iterator it = mixins.iterator(); it.hasNext(); ) {
                 QName mixinName = (QName) it.next();
                 try {
@@ -502,7 +505,7 @@
         } else if (eventType == Event.PROPERTY_ADDED) {
             return "PropertyAdded";
         } else if (eventType == Event.PROPERTY_CHANGED) {
-            return "PropertyChanged";
+            return "PropertyOperation";
         } else if (eventType == Event.PROPERTY_REMOVED) {
             return "PropertyRemoved";
         } else {

Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/observation/EventStateCollection.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/observation/EventStateCollection.java?view=diff&rev=471760&r1=471759&r2=471760
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/observation/EventStateCollection.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/observation/EventStateCollection.java Mon Nov  6 07:22:29 2006
@@ -100,7 +100,7 @@
      * @param pathPrefix the path to prefix the event paths or <code>null</code>
      *                   if no prefix should be used.
      */
-    EventStateCollection(EventDispatcher dispatcher,
+    public EventStateCollection(EventDispatcher dispatcher,
                          SessionImpl session,
                          Path pathPrefix) {
         this.dispatcher = dispatcher;
@@ -185,7 +185,7 @@
                                     getParent(oldPath),
                                     n.getNodeId(),
                                     oldPath.getNameElement(),
-                                    oldParentNodeType,
+                                    oldParentNodeType.getQName(),
                                     mixins,
                                     session));
 
@@ -196,7 +196,7 @@
                                     getParent(newPath),
                                     n.getNodeId(),
                                     newPath.getNameElement(),
-                                    newParentNodeType,
+                                    newParentNodeType.getQName(),
                                     mixins,
                                     session));
                         } else {
@@ -249,14 +249,14 @@
                                         parentPath,
                                         n.getNodeId(),
                                         oldPath.getNameElement(),
-                                        nodeType,
+                                        nodeType.getQName(),
                                         mixins,
                                         session));
                                 events.add(EventState.childNodeAdded(parent.getNodeId(),
                                         parentPath,
                                         n.getNodeId(),
                                         newPath.getNameElement(),
-                                        nodeType,
+                                        nodeType.getQName(),
                                         mixins,
                                         session));
                             }
@@ -290,7 +290,7 @@
                                 parentPath,
                                 child.getId(),
                                 removedElem,
-                                nodeType,
+                                nodeType.getQName(),
                                 mixins,
                                 session));
 
@@ -298,7 +298,7 @@
                                 parentPath,
                                 child.getId(),
                                 addedElem,
-                                nodeType,
+                                nodeType.getQName(),
                                 mixins,
                                 session));
                     }
@@ -312,7 +312,7 @@
                 events.add(EventState.propertyChanged(state.getParentId(),
                         getParent(path),
                         path.getNameElement(),
-                        nodeType,
+                        nodeType.getQName(),
                         mixins,
                         session));
             }
@@ -333,7 +333,7 @@
                         getParent(path),
                         n.getNodeId(),
                         path.getNameElement(),
-                        nodeType,
+                        nodeType.getQName(),
                         mixins,
                         session));
             } else {
@@ -348,7 +348,7 @@
                     events.add(EventState.propertyRemoved(state.getParentId(),
                             getParent(path),
                             path.getNameElement(),
-                            nodeType,
+                            nodeType.getQName(),
                             mixins,
                             session));
                 } catch (NoSuchItemStateException e) {
@@ -379,7 +379,7 @@
                         getParent(path),
                         n.getNodeId(),
                         path.getNameElement(),
-                        nodeType,
+                        nodeType.getQName(),
                         mixins,
                         session));
             } else {
@@ -391,7 +391,7 @@
                 events.add(EventState.propertyAdded(state.getParentId(),
                         getParent(path),
                         path.getNameElement(),
-                        nodeType,
+                        nodeType.getQName(),
                         mixins,
                         session));
             }
@@ -454,7 +454,7 @@
      * Return the list of events.
      * @return list of events
      */
-    List getEvents() {
+    public List getEvents() {
         return Collections.unmodifiableList(events);
     }
 

Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java?view=diff&rev=471760&r1=471759&r2=471760
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java Mon Nov  6 07:22:29 2006
@@ -22,6 +22,7 @@
 import org.apache.jackrabbit.core.NodeId;
 import org.apache.jackrabbit.core.PropertyId;
 import org.apache.jackrabbit.core.RepositoryImpl;
+import org.apache.jackrabbit.core.cluster.UpdateEventChannel;
 import org.apache.jackrabbit.core.persistence.PersistenceManager;
 import org.apache.jackrabbit.core.version.XAVersionManager;
 import org.apache.jackrabbit.core.nodetype.EffectiveNodeType;
@@ -181,6 +182,11 @@
             };
 
     /**
+     * Update event channel.
+     */
+    private UpdateEventChannel eventChannel;
+
+    /**
      * Creates a new <code>SharedItemStateManager</code> instance.
      *
      * @param persistMgr
@@ -213,6 +219,15 @@
         this.noLockHack = noLockHack;
     }
 
+    /**
+     * Set an update event channel
+     *
+     * @param eventChannel update event channel
+     */
+    public void setEventChannel(UpdateEventChannel eventChannel) {
+        this.eventChannel = eventChannel;
+    }
+
     //-----------------------------------------------------< ItemStateManager >
     /**
      * {@inheritDoc}
@@ -619,8 +634,14 @@
                 }
 
                 /* create event states */
-                events.createEventStates(rootNodeId, local,
-                        SharedItemStateManager.this);
+                events.createEventStates(rootNodeId, local, SharedItemStateManager.this);
+
+                /* let listener know about change */
+                if (eventChannel != null) {
+                    eventChannel.updateCreated(local, events);
+                }
+
+                //todo check whether local states are now stale...
 
                 /* Push all changes from the local items to the shared items */
                 local.push();
@@ -645,6 +666,11 @@
             boolean succeeded = false;
 
             try {
+                /* let listener know about preparation */
+                if (eventChannel != null) {
+                    eventChannel.updatePrepared();
+                }
+
                 /* Store items in the underlying persistence manager */
                 long t0 = System.currentTimeMillis();
                 persistMgr.store(shared);
@@ -682,6 +708,11 @@
                 /* dispatch the events */
                 events.dispatch();
 
+                /* let listener know about finished operation */
+                if (eventChannel != null) {
+                    eventChannel.updateCommitted();
+                }
+
             } finally {
                 if (holdingWriteLock) {
                     // exception occured before downgrading lock
@@ -699,6 +730,11 @@
          */
         public void cancel() {
             try {
+                /* let listener know about cancelled operation */
+                if (eventChannel != null) {
+                    eventChannel.updateCancelled();
+                }
+
                 local.disconnect();
 
                 for (Iterator iter = shared.modifiedStates(); iter.hasNext();) {
@@ -771,6 +807,71 @@
                    ItemStateException {
 
         beginUpdate(local, factory, null).end();
+    }
+
+    /**
+     * Handle an external update.
+     *
+     * @param external external change containing only node and property ids.
+     * @param events events to deliver
+     */
+    public void externalUpdate(ChangeLog external, EventStateCollection events) {
+        boolean holdingWriteLock = false;
+
+        ChangeLog shared = new ChangeLog();
+
+        try {
+            acquireWriteLock();
+            holdingWriteLock = true;
+
+            Iterator modifiedStates = external.modifiedStates();
+            while (modifiedStates.hasNext()) {
+                ItemState state = (ItemState) modifiedStates.next();
+                state = cache.retrieve(state.getId());
+                if (state != null) {
+                    try {
+                        state.copy(loadItemState(state.getId()));
+                        shared.modified(state);
+                    } catch (ItemStateException e) {
+                        String msg = "Unable to retrieve state: " + state.getId();
+                        log.warn(msg, e);
+                        state.discard();
+                    }
+                }
+            }
+            Iterator deletedStates = external.deletedStates();
+            while (deletedStates.hasNext()) {
+                ItemState state = (ItemState) deletedStates.next();
+                state = cache.retrieve(state.getId());
+                if (state != null) {
+                    shared.deleted(state);
+                }
+            }
+            shared.persisted();
+
+        } catch (ItemStateException e) {
+            String msg = "Unable to acquire write lock.";
+            log.error(msg);
+        }
+
+        try {
+            acquireReadLock();
+            rwLock.writeLock().release();
+            holdingWriteLock = false;
+
+            events.dispatch();
+        } catch (ItemStateException e) {
+            String msg = "Unable to downgrade to read lock.";
+            log.error(msg);
+        } finally {
+            if (holdingWriteLock) {
+                rwLock.writeLock().release();
+                holdingWriteLock = false;
+            } else {
+                rwLock.readLock().release();
+            }
+        }
+
     }
 
     /**