jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From thom...@apache.org
Subject svn commit: r935321 [1/2] - in /jackrabbit/sandbox/jackrabbit-j3/src: main/java/org/apache/jackrabbit/j3/ main/java/org/apache/jackrabbit/j3/mc/ main/java/org/apache/jackrabbit/j3/mc/jdbc/ main/java/org/apache/jackrabbit/j3/mc/mem/ main/java/org/apache...
Date Sun, 18 Apr 2010 09:52:28 GMT
Author: thomasm
Date: Sun Apr 18 09:52:27 2010
New Revision: 935321

URL: http://svn.apache.org/viewvc?rev=935321&view=rev
Log:
Unlimited transient space / transaction size

Added:
    jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/ChangeSet.java
    jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventFilter.java
    jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventJournalImpl.java
    jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestEventJournal.java
    jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/slow/
    jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/slow/TestLargeTransaction.java
Removed:
    jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventList.java
Modified:
    jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/NodeImpl.java
    jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/NodeState.java
    jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/RangeIteratorImpl.java
    jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/RepositoryImpl.java
    jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/SessionImpl.java
    jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/Bundle.java
    jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/NodeData.java
    jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/StorageSession.java
    jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/jdbc/JdbcStorage.java
    jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/jdbc/JdbcStorageSession.java
    jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/mem/MemStorageSession.java
    jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/nodetype/NodeTypeImpl.java
    jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/nodetype/NodeTypeIteratorImpl.java
    jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddLock.java
    jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddMixin.java
    jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddNode.java
    jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddProperty.java
    jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventConsumer.java
    jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventImpl.java
    jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventModifyProperty.java
    jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventRemoveNode.java
    jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/ObservationManagerImpl.java
    jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/query/RowIteratorImpl.java
    jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/security/AccessControlManagerImpl.java
    jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/util/Constants.java
    jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/version/VersionIteratorImpl.java
    jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestAll.java
    jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestBundle.java
    jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestConcurrentWrite.java
    jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestLock.java
    jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestObservation.java
    jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestSimple.java

Added: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/ChangeSet.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/ChangeSet.java?rev=935321&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/ChangeSet.java (added)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/ChangeSet.java Sun Apr 18 09:52:27 2010
@@ -0,0 +1,384 @@
+/*
+ * 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.j3;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import javax.jcr.RepositoryException;
+import org.apache.jackrabbit.j3.mc.Bundle;
+import org.apache.jackrabbit.j3.mc.NodeData;
+import org.apache.jackrabbit.j3.mc.StorageSession;
+import org.apache.jackrabbit.j3.mc.Val;
+import org.apache.jackrabbit.j3.observation.EventImpl;
+import org.apache.jackrabbit.j3.util.Constants;
+import org.apache.jackrabbit.j3.util.ExceptionFactory;
+import org.apache.jackrabbit.j3.util.Log;
+
+/**
+ * This objects keeps changed nodes and events for a session. Once there are too
+ * many entries, the data is stored in a backend storage.
+ */
+public class ChangeSet {
+
+    private final LinkedHashMap<Val, NodeState> nodes = new LinkedHashMap<Val, NodeState>();
+    private final LinkedList<EventImpl> events = new LinkedList<EventImpl>();
+    private final int maxMemorySize;
+    private final SessionImpl session;
+    private final StorageSession storageSession;
+    private final Log log;
+    private final boolean unlimited;
+    private String userId;
+    private int tempBlocks;
+    private long persistedDate;
+    private String userData;
+    private int nodeMemoryUsed;
+    private int nodesCountTotal;
+    private boolean persistEvents = true;
+
+    /**
+     * A bloom filter to quickly check if an entry might be in the backend storage.
+     */
+    private final BitSet backendFilter = new BitSet();
+    private final int backendFilterMask;
+
+    public ChangeSet(SessionImpl session, StorageSession storageSession, int maxMemorySize) {
+        this.session = session;
+        this.storageSession = storageSession;
+        this.maxMemorySize = maxMemorySize;
+        this.log = session.getLog();
+        this.userId = session.getUserId();
+        if (maxMemorySize == Integer.MAX_VALUE) {
+            unlimited = true;
+            backendFilterMask = 0;
+        } else {
+            unlimited = false;
+            // the bloom filter uses about 10% of the cache size
+            int maxFilterBytes = maxMemorySize / 10;
+            int maxFilterBits = maxFilterBytes * 8;
+            int p = 4;
+            while (p < maxFilterBits) {
+                p <<= 1;
+            }
+            backendFilterMask = (p >> 1) - 1;
+        }
+    }
+
+    public Iterator<NodeState> valueIterator() {
+        if (tempBlocks == 0) {
+            return nodes.values().iterator();
+        }
+        return new TransientNodeIterator(nodes.values().iterator(), tempBlocks);
+    }
+
+    public NodeState get(Val key) {
+        NodeState node = nodes.get(key);
+        if (node != null || unlimited) {
+            return node;
+        }
+        if (!backendFilter.get(key.hashCode() & backendFilterMask)) {
+            return null;
+        }
+        NodeData data = storageSession.getNode(key);
+        if (data == null) {
+            return null;
+        }
+        node = new NodeState(session, data, 0);
+        put(key, node);
+        return node;
+    }
+
+    public void put(Val key, NodeState value) {
+        NodeState old = nodes.put(key, value);
+        if (old == value) {
+            return;
+        }
+        if (unlimited) {
+            nodesCountTotal = nodes.size();
+            return;
+        }
+        if (old != null) {
+            nodeMemoryUsed -= old.getNodeData().getMemoryUsed();
+        } else {
+            nodesCountTotal++;
+        }
+        nodeMemoryUsed += value.getNodeData().getMemoryUsed();
+        if (nodeMemoryUsed + events.size() * Constants.MEM_EVENT > maxMemorySize) {
+            store(true, nodes.size() / 2);
+        }
+    }
+
+    boolean hasPendingChanges() {
+        return nodesCountTotal > 0;
+    }
+
+    void clearAll() {
+        clearNodes();
+        clearEvents();
+        tempBlocks = 0;
+    }
+
+    void clearEvents() {
+        events.clear();
+        if (tempBlocks > 0) {
+            storageSession.clearTemp(false, true);
+        }
+    }
+
+    void clearNodes() {
+        nodesCountTotal = 0;
+        nodes.clear();
+        if (tempBlocks > 0) {
+            backendFilter.clear();
+            storageSession.clearTemp(true, false);
+        }
+        nodeMemoryUsed = 0;
+    }
+
+    public void storeAll() {
+        store(false, 0);
+    }
+
+    private void store(boolean temporary, int skip) {
+        Iterator<NodeState> it = nodes.values().iterator();
+        NodeData[] nodeArray = new NodeData[nodes.size() - skip];
+        // re-calculate the memory because it might have changed
+        nodeMemoryUsed = 0;
+        for (int i = 0; it.hasNext() && i < skip; i++) {
+            NodeData n = it.next().getNodeData();
+            nodeMemoryUsed += n.getMemoryUsed();
+        }
+        for (int i = 0; it.hasNext(); i++) {
+            NodeData n = it.next().getNodeData();
+            if (temporary) {
+                backendFilter.set(n.getId().hashCode() & backendFilterMask);
+                it.remove();
+            }
+            nodeArray[i] = n;
+        }
+        Bundle[] bundles;
+        if (persistEvents || temporary) {
+            bundles = getEventBundles();
+        } else {
+            bundles = null;
+        }
+        if (temporary) {
+            storageSession.storeTemp(tempBlocks++, nodeArray, bundles);
+            events.clear();
+        } else {
+            long now = System.currentTimeMillis();
+            storageSession.store(now, nodeArray, bundles);
+        }
+    }
+
+    public SessionImpl getSession() {
+        return session;
+    }
+
+    public Log getLog() {
+        return log;
+    }
+
+    public void dispatchEvents() {
+        persistedDate = System.currentTimeMillis();
+        userData = session.getObservationUserData();
+        session.getRepository().dispatchEvents(this);
+    }
+
+    public long getPersistedDate() {
+        return persistedDate;
+    }
+
+    public void applyEvents() throws RepositoryException {
+        Iterator<EventImpl> it = getEvents();
+        while (it.hasNext()) {
+            it.next().apply();
+        }
+    }
+
+    public Iterator<EventImpl> getEvents() {
+        if (tempBlocks == 0) {
+            return events.iterator();
+        }
+        return new EventIterator(events.iterator(), tempBlocks);
+    }
+
+    public void addEvent(EventImpl event) {
+        events.add(event);
+    }
+
+    private Bundle[] getEventBundles() {
+        ArrayList<Bundle> bundles = new ArrayList<Bundle>();
+        Bundle b = null;
+        for (EventImpl e : events) {
+            if (b == null) {
+                b = new Bundle(new byte[events.size()]);
+                writeHeader(b);
+            }
+            e.writeTo(b);
+            if (b.getPos() > Constants.SIZE_EVENT_BUNDLE) {
+                bundles.add(b);
+                b = null;
+            }
+        }
+        if (b != null && b.getPos() > 0) {
+            bundles.add(b);
+        }
+        return bundles.toArray(new Bundle[bundles.size()]);
+    }
+
+    private void writeHeader(Bundle b) {
+        if (userId != null) {
+            b.writeVarInt(EventImpl.TOKEN_USER_ID);
+            b.writeVal(Val.get(userId));
+        }
+        if (userData != null) {
+            b.writeVarInt(EventImpl.TOKEN_USER_DATA);
+            b.writeVal(Val.get(userData));
+        }
+    }
+
+    public String getUserData() {
+        return userData;
+    }
+
+    public String getUserID() {
+        return userId;
+    }
+
+    public String toString() {
+        return "nodes: " + nodesCountTotal + " events: " + events.size() + " temp blocks: " + tempBlocks;
+    }
+
+    /**
+     * An iterator over all events.
+     */
+    class EventIterator implements Iterator<EventImpl> {
+
+        private final int maxBlock;
+        private Iterator<EventImpl> iterator;
+        private Iterator<EventImpl> lastIterator;
+        private EventImpl current;
+        private int currentBlock;
+
+        EventIterator(Iterator<EventImpl> lastIterator, int maxBlock) {
+            this.lastIterator = lastIterator;
+            this.maxBlock = maxBlock;
+            go();
+        }
+
+        private void go() {
+            while (true) {
+                if (iterator == null) {
+                    if (currentBlock == maxBlock) {
+                        iterator = lastIterator;
+                    } else {
+                        Bundle[] bundles = storageSession.getTempEvents(currentBlock++);
+                        iterator = EventImpl.readFrom(ChangeSet.this, bundles);
+                    }
+                }
+                if (iterator.hasNext()) {
+                    current = iterator.next();
+                    break;
+                }
+                if (iterator == lastIterator) {
+                    current = null;
+                    break;
+                }
+                iterator = null;
+            }
+        }
+
+        public boolean hasNext() {
+            return current != null;
+        }
+
+        public EventImpl next() {
+            EventImpl e = current;
+            go();
+            return e;
+        }
+
+        public void remove() {
+            throw ExceptionFactory.unsupportedOperation();
+        }
+
+    }
+
+    /**
+     * An iterator over all nodes.
+     */
+    class TransientNodeIterator implements Iterator<NodeState> {
+
+        private final int maxBlock;
+        private Iterator<NodeState> iterator;
+        private NodeState current;
+        private int currentBlock;
+
+        TransientNodeIterator(Iterator<NodeState> iterator, int maxBlock) {
+            this.iterator = iterator;
+            this.maxBlock = maxBlock;
+            go();
+        }
+
+        public boolean hasNext() {
+            return current != null;
+        }
+
+        public NodeState next() {
+            NodeState n = current;
+            go();
+            return n;
+        }
+
+        private void go() {
+            while (true) {
+                if (iterator.hasNext()) {
+                    current = iterator.next();
+                    break;
+                }
+                if (currentBlock == maxBlock) {
+                    current = null;
+                    break;
+                }
+                NodeData[] data = storageSession.getTempNodes(currentBlock++);
+                NodeState[] nodes = new NodeState[data.length];
+                for (int i = 0; i < nodes.length; i++) {
+                    nodes[i] = new NodeState(session, data[i], 0);
+                }
+                iterator = Arrays.asList(nodes).iterator();
+            }
+        }
+
+        public void remove() {
+            throw ExceptionFactory.unsupportedOperation();
+        }
+
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    public void setUserData(String userData) {
+        this.userData = userData;
+    }
+
+}

Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/NodeImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/NodeImpl.java?rev=935321&r1=935320&r2=935321&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/NodeImpl.java (original)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/NodeImpl.java Sun Apr 18 09:52:27 2010
@@ -19,6 +19,7 @@ package org.apache.jackrabbit.j3;
 import java.io.InputStream;
 import java.math.BigDecimal;
 import java.util.Calendar;
+import java.util.HashSet;
 import javax.jcr.AccessDeniedException;
 import javax.jcr.Binary;
 import javax.jcr.InvalidItemStateException;
@@ -52,6 +53,7 @@ import javax.jcr.version.VersionHistory;
 import org.apache.jackrabbit.j3.lock.LockImpl;
 import org.apache.jackrabbit.j3.mc.Val;
 import org.apache.jackrabbit.j3.nodetype.NodeTypeImpl;
+import org.apache.jackrabbit.j3.nodetype.NodeTypeManagerImpl;
 import org.apache.jackrabbit.j3.nodetype.PropertyDefinitionImpl;
 import org.apache.jackrabbit.j3.observation.EventAddLock;
 import org.apache.jackrabbit.j3.observation.EventAddMixin;
@@ -96,8 +98,10 @@ public class NodeImpl implements Node, L
     private NodeImpl addNode(String relPath, NodeTypeImpl nt) throws RepositoryException {
         SessionImpl s = state.getSession();
         synchronized (s) {
-            NodeImpl node = s.createNode(this, state.getId());
-            EventAddNode event = new EventAddNode(s, Val.get(relPath), node);
+            Val nodeId = s.getStorageSession().newNodeId(state.getId());
+            EventAddNode event = new EventAddNode(s.getTransientChanges(), this, Val.get(relPath), nodeId);
+            event.applyAndAdd();
+            NodeImpl node = event.getNode();
             Val primaryNodeType;
             if (nt == null) {
                 // TODO primaryNodeTypeName may be incorrect
@@ -105,9 +109,8 @@ public class NodeImpl implements Node, L
             } else {
                 primaryNodeType = nt.getNameVal();
             }
-            EventAddProperty eventSetPrimaryType = new EventAddProperty(s, node, NodeState.PROPERTY_PRIMARY_TYPE,  primaryNodeType);
+            EventAddProperty eventSetPrimaryType = new EventAddProperty(s.getTransientChanges(), node, NodeState.PROPERTY_PRIMARY_TYPE,  primaryNodeType);
             eventSetPrimaryType.applyAndAdd();
-            event.applyAndAdd();
             if (nt != null) {
                 nt.visit(node);
             }
@@ -120,7 +123,7 @@ public class NodeImpl implements Node, L
         if (p.isAutoCreated()) {
             Val propertyName = p.getNameVal();
             Val value = p.getDefaultVal();
-            EventModifyProperty event = new EventModifyProperty(s, this, propertyName, value);
+            EventModifyProperty event = new EventModifyProperty(s.getTransientChanges(), this, propertyName, value);
             event.applyAndAdd();
         }
     }
@@ -158,10 +161,18 @@ public class NodeImpl implements Node, L
     private PropertyImpl setProperty(String name, Val value) throws RepositoryException {
         SessionImpl s = state.getSession();
         Val propertyName = Val.get(name);
-        EventModifyProperty event = new EventModifyProperty(s, this, propertyName, value);
-        synchronized (s) {
-            event.applyAndAdd();
-            return new PropertyImpl(this, propertyName);
+        if (state.getPropertyInternal(propertyName) != null) {
+            EventModifyProperty event = new EventModifyProperty(s.getTransientChanges(), this, propertyName, value);
+            synchronized (s) {
+                event.applyAndAdd();
+                return new PropertyImpl(this, propertyName);
+            }
+        } else {
+            EventAddProperty event = new EventAddProperty(s.getTransientChanges(), this, propertyName, value);
+            synchronized (s) {
+                event.applyAndAdd();
+                return new PropertyImpl(this, propertyName);
+            }
         }
     }
 
@@ -184,7 +195,7 @@ public class NodeImpl implements Node, L
         return getValueFactory().wrap(state.getPropertyInternal(name));
     }
 
-    public NodeImpl getParent() throws ItemNotFoundException, AccessDeniedException, RepositoryException {
+    public NodeImpl getParent() {
         log.codeAssign(parent, this, "getParent");
         return parent;
     }
@@ -258,7 +269,7 @@ public class NodeImpl implements Node, L
             throw ExceptionFactory.repository("Can not remove the root node");
         }
         synchronized (s) {
-            EventRemoveNode event = new EventRemoveNode(s, this);
+            EventRemoveNode event = new EventRemoveNode(s.getTransientChanges(), this);
             event.applyAndAdd();
         }
     }
@@ -306,7 +317,7 @@ public class NodeImpl implements Node, L
             ConstraintViolationException, LockException, RepositoryException {
         log.code(this, "addMixin", mixinName);
         SessionImpl s = state.getSession();
-        EventAddMixin event = new EventAddMixin(s, this, Val.get(mixinName));
+        EventAddMixin event = new EventAddMixin(s.getTransientChanges(), this, Val.get(mixinName));
         synchronized (s) {
             event.applyAndAdd();
         }
@@ -333,7 +344,7 @@ public class NodeImpl implements Node, L
         // TODO the lock token currently is the node id; this is not secure
         Val lockToken = state.getId();
         LockImpl lock = new LockImpl(this, lockToken, isDeep, isSessionScoped);
-        EventAddLock event = new EventAddLock(s, lock);
+        EventAddLock event = new EventAddLock(s.getTransientChanges(), lock);
         synchronized (s) {
             event.applyAndAdd();
         }
@@ -458,6 +469,48 @@ public class NodeImpl implements Node, L
         return log;
     }
 
+    public boolean matchesNodeTypeSet(HashSet<NodeType> nodeTypeSet) throws RepositoryException {
+        for (NodeType nt : nodeTypeSet) {
+            if (isNodeType(nt)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean isNodeType(NodeType nt) throws RepositoryException {
+        if (getPrimaryNodeType().isNodeType(nt)) {
+            return true;
+        }
+        for (NodeTypeImpl mixin : getMixinNodeTypes()) {
+            if (mixin.isNodeType(nt)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public NodeTypeImpl[] getMixinNodeTypes() throws RepositoryException {
+        log.code(this, "getMixinNodeTypes");
+        Val m = state.getPropertyInternal(NodeState.PROPERTY_MIXIN_TYPES);
+        if (m == null) {
+            return NodeTypeImpl.EMPTY_ARRAY;
+        }
+        Val[] array = m.getArray();
+        NodeTypeImpl[] mixins = new NodeTypeImpl[array.length];
+        NodeTypeManagerImpl ntMan = state.getSession().getNodeTypeManager();
+        for (int i = 0; i < array.length; i++) {
+            mixins[i] = ntMan.getNodeType(array[i]);
+        }
+        return mixins;
+    }
+
+    public boolean isNodeType(String nodeTypeName) throws RepositoryException {
+        log.code(this, "isNodeType", nodeTypeName);
+        NodeType nt = getSession().getNodeTypeManager().getNodeType(nodeTypeName);
+        return isNodeType(nt);
+    }
+
     public Item getPrimaryItem() throws ItemNotFoundException, RepositoryException {
         log.code(this, "getPrimaryItem");
         // TODO
@@ -544,12 +597,6 @@ public class NodeImpl implements Node, L
         return null;
     }
 
-    public NodeType[] getMixinNodeTypes() throws RepositoryException {
-        log.code(this, "getMixinNodeTypes");
-        // TODO
-        return null;
-    }
-
     public NodeIterator getNodes(String namePattern) throws RepositoryException {
         log.code(this, "getNodes", namePattern);
         // TODO
@@ -652,12 +699,6 @@ public class NodeImpl implements Node, L
         return false;
     }
 
-    public boolean isNodeType(String nodeTypeName) throws RepositoryException {
-        log.code(this, "isNodeType", nodeTypeName);
-        // TODO
-        return false;
-    }
-
     public NodeIterator merge(String srcWorkspace, boolean bestEffort) throws NoSuchWorkspaceException,
             AccessDeniedException, MergeException, LockException, InvalidItemStateException, RepositoryException {
         log.code(this, "merge", srcWorkspace, bestEffort);

Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/NodeState.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/NodeState.java?rev=935321&r1=935320&r2=935321&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/NodeState.java (original)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/NodeState.java Sun Apr 18 09:52:27 2010
@@ -48,13 +48,16 @@ public class NodeState {
         this.modCount = modCount;
     }
 
-    void modify() {
+    void modifyBegin() {
         if (modCount++ == 0) {
             data = data.createCopy();
-            session.modify(this);
         }
     }
 
+    void modifyEnd() {
+        session.modify(this);
+    }
+
     void reset(NodeData data) {
         modCount = 0;
         this.data = data;
@@ -70,7 +73,7 @@ public class NodeState {
      * @param value the value
      */
     void setPropertyInternal(Val name, Val value) {
-        modify();
+        modifyBegin();
         if (name.equals(NodeState.PROPERTY_PRIMARY_TYPE)) {
             if (value.equals(DEFAULT_PRIMARY_TYPE)) {
                 data.setPrimaryType(null);
@@ -80,6 +83,7 @@ public class NodeState {
         } else {
             data.setPropertyValue(name, value);
         }
+        modifyEnd();
     }
 
     /**
@@ -124,7 +128,7 @@ public class NodeState {
         return v;
     }
 
-    Val getId() {
+    public Val getId() {
         return data.getId();
     }
 
@@ -133,18 +137,21 @@ public class NodeState {
     }
 
     void addChild(Val childName, Val id) {
-        modify();
+        modifyBegin();
         data.addChild(childName, id);
+        modifyEnd();
     }
 
     void removeChild(Val childName) {
-        modify();
+        modifyBegin();
         data.removeChild(childName);
+        modifyEnd();
     }
 
     void setLockToken(Val lockToken) {
-        modify();
+        modifyBegin();
         data.setLockToken(lockToken);
+        modifyEnd();
     }
 
     Val getName(NodeState parent) {
@@ -197,4 +204,8 @@ public class NodeState {
         return data.getNextChildId(last == null ? null : last.data);
     }
 
+    boolean isModified() {
+        return modCount != 0;
+    }
+
 }

Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/RangeIteratorImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/RangeIteratorImpl.java?rev=935321&r1=935320&r2=935321&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/RangeIteratorImpl.java (original)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/RangeIteratorImpl.java Sun Apr 18 09:52:27 2010
@@ -40,14 +40,14 @@ public abstract class RangeIteratorImpl<
         this.iterator = iterator;
         this.size = size;
         this.log = log;
-        go();
+        fetchNext();
     }
 
     public boolean skip(T x) throws RepositoryException {
         return false;
     }
 
-    void go() {
+    void fetchNext() {
         try {
             while (true) {
                 if (!iterator.hasNext()) {
@@ -66,16 +66,16 @@ public abstract class RangeIteratorImpl<
     }
 
     public Object next() {
-        return goNext();
+        return getNext();
     }
 
-    public T goNext() {
+    public T getNext() {
         pos++;
         T result = next;
         if (result == null) {
             throw ExceptionFactory.noSuchElement();
         }
-        go();
+        fetchNext();
         return result;
     }
 
@@ -92,7 +92,7 @@ public abstract class RangeIteratorImpl<
     public void skip(long skipNum) {
         log.code(this, "skip", skipNum);
         for (int i = 0; i < skipNum; i++) {
-            go();
+            getNext();
         }
     }
 

Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/RepositoryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/RepositoryImpl.java?rev=935321&r1=935320&r2=935321&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/RepositoryImpl.java (original)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/RepositoryImpl.java Sun Apr 18 09:52:27 2010
@@ -36,7 +36,6 @@ import org.apache.jackrabbit.j3.mc.Val;
 import org.apache.jackrabbit.j3.mc.jdbc.JdbcStorage;
 import org.apache.jackrabbit.j3.mc.mem.MemStorage;
 import org.apache.jackrabbit.j3.nodetype.NodeTypeRegistry;
-import org.apache.jackrabbit.j3.observation.EventList;
 import org.apache.jackrabbit.j3.query.qom.QueryObjectModelFactoryImpl;
 import org.apache.jackrabbit.j3.util.Cache;
 import org.apache.jackrabbit.j3.util.Constants;
@@ -289,9 +288,9 @@ public class RepositoryImpl implements R
         return lockSystem;
     }
 
-    public synchronized void dispatchEvents(EventList events) {
+    public synchronized void dispatchEvents(ChangeSet changes) {
         for (SessionImpl session : sessions) {
-            session.dispatchEvents(events);
+            session.dispatchEvents(changes);
         }
     }
 
@@ -307,4 +306,53 @@ public class RepositoryImpl implements R
         return qomFactory;
     }
 
+    static int getWorkspaceId(long nodeId) {
+        if ((nodeId & 1) == 0) {
+            return 0;
+        } else if ((nodeId & 3) == 1) {
+            return (int) ((nodeId >> 2) & ((1 << 4) - 1));
+        } else if ((nodeId & 7) == 3) {
+            return (int) ((nodeId >> 3) & ((1 << 11) - 1));
+        } else if ((nodeId & 15) == 7) {
+            return (int) ((nodeId >> 4) & ((1 << 28) - 1));
+        } else {
+            throw ExceptionFactory.illegalArgument("Node {0}", nodeId);
+        }
+    }
+
+    static long getBaseNodeId(long nodeId) {
+        if ((nodeId & 1) == 0) {
+            return nodeId >> 1;
+        } else if ((nodeId & 3) == 1) {
+            return nodeId >> 6;
+        } else if ((nodeId & 7) == 3) {
+            return nodeId >> 14;
+        } else if ((nodeId & 15) == 7) {
+            return nodeId >> 32;
+        } else {
+            throw ExceptionFactory.illegalArgument("Node {0}", nodeId);
+        }
+    }
+
+    static long getNodeId(int workspaceId, long baseNodeId) {
+        if (workspaceId == 0) {
+            // ... nnnnnnnn nnnnnnn0
+            return baseNodeId << 1;
+        } else if ((workspaceId & ~((1 << 4) - 1)) == 0) {
+            // up to workspace #15
+            // ... nnnnnnnn nnwwww01
+            return (baseNodeId << 6) + (workspaceId << 2) + 1;
+        } else if ((workspaceId & ~((1 << 11) - 1)) == 0) {
+            // up to workspace #2047
+            // ... nnwwwwww wwwww011
+            return (baseNodeId << 14) + (workspaceId << 3) + 3;
+        } else if ((workspaceId & ~((1 << 28) - 1)) == 0) {
+            // up to workspace #268'435'455
+            // ... nnnnnnnn wwwwww ... wwww0111
+            return (baseNodeId << 32) + ((long) workspaceId << 4) + 7;
+        } else {
+            throw ExceptionFactory.illegalArgument("Workspace {0}", workspaceId);
+        }
+    }
+
 }

Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/SessionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/SessionImpl.java?rev=935321&r1=935320&r2=935321&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/SessionImpl.java (original)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/SessionImpl.java Sun Apr 18 09:52:27 2010
@@ -21,9 +21,9 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.lang.ref.WeakReference;
 import java.security.AccessControlException;
-import java.util.HashMap;
 import java.util.Iterator;
 import java.util.WeakHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
 import javax.jcr.AccessDeniedException;
 import javax.jcr.Credentials;
 import javax.jcr.InvalidItemStateException;
@@ -51,11 +51,11 @@ import org.apache.jackrabbit.j3.mc.NodeD
 import org.apache.jackrabbit.j3.mc.StorageSession;
 import org.apache.jackrabbit.j3.mc.Val;
 import org.apache.jackrabbit.j3.nodetype.NodeTypeManagerImpl;
-import org.apache.jackrabbit.j3.observation.EventList;
 import org.apache.jackrabbit.j3.observation.ObservationManagerImpl;
 import org.apache.jackrabbit.j3.query.QueryManagerImpl;
 import org.apache.jackrabbit.j3.retention.RetentionManagerImpl;
 import org.apache.jackrabbit.j3.security.AccessControlManagerImpl;
+import org.apache.jackrabbit.j3.util.Constants;
 import org.apache.jackrabbit.j3.util.ExceptionFactory;
 import org.apache.jackrabbit.j3.util.Log;
 import org.apache.jackrabbit.j3.util.LogObject;
@@ -68,18 +68,19 @@ import org.xml.sax.SAXException;
  */
 public class SessionImpl implements Session, LogObject {
 
-    private static final int MAX_RETRY = 3;
+    private static final AtomicInteger SESSION_ID = new AtomicInteger(0);
+
     private final RepositoryImpl rep;
+    private final int id;
     private final StorageSession storageSession;
     private final WeakHashMap<Val, WeakReference<NodeState>> weakMap = new WeakHashMap<Val, WeakReference<NodeState>>();
-    private final HashMap<Val, NodeState> modified = new HashMap<Val, NodeState>();
+    private final ChangeSet changes;
     private final NamespaceRegistryImpl namespaceRegistry;
     private final WorkspaceImpl workspace;
     private final SimpleCredentials credentials;
     private final String userId;
     private final Log log;
     private boolean isAdmin;
-    private EventList eventList;
     private LockManagerImpl lockManager;
     private ObservationManagerImpl observationManager;
     private NodeTypeManagerImpl nodeTypeManager;
@@ -92,13 +93,15 @@ public class SessionImpl implements Sess
 
     public SessionImpl(RepositoryImpl rep, SimpleCredentials credentials, StorageSession storageSession, String workspaceName, Log log) {
         this.rep = rep;
+        this.id = SESSION_ID.getAndIncrement();
         this.log = log;
-        this.eventList = new EventList(this);
         this.credentials = credentials;
         this.userId = credentials.getUserID();
         this.storageSession = storageSession;
         this.workspace = new WorkspaceImpl(this, workspaceName, log);
         this.namespaceRegistry = NamespaceRegistryImpl.createLocalInstance(log);
+        int maxMemory = storageSession.supportsTemp() ? Constants.MEM_CACHE_PER_SESSION : Integer.MAX_VALUE;
+        this.changes = new ChangeSet(this, storageSession, maxMemory);
     }
 
     public synchronized void logout() {
@@ -107,8 +110,8 @@ public class SessionImpl implements Sess
         rep.close(this);
     }
 
-    NodeImpl getNode(NodeImpl parent, Val nodeId) throws RepositoryException {
-        NodeState state = modified.get(nodeId);
+    public NodeImpl getNode(NodeImpl parent, Val nodeId) throws RepositoryException {
+        NodeState state = changes.get(nodeId);
         if (state == null) {
             WeakReference<NodeState> ref = weakMap.get(nodeId);
             state = ref == null ? null : ref.get();
@@ -148,9 +151,8 @@ public class SessionImpl implements Sess
         return n;
     }
 
-    synchronized NodeImpl createNode(NodeImpl parent, Val parentId) {
-        Val nodeId = storageSession.newNodeId(parentId);
-        NodeData newData = new NodeData(nodeId, parentId, 0);
+    public synchronized NodeImpl createNode(NodeImpl parent, Val parentId, Val newNodeId) {
+        NodeData newData = new NodeData(newNodeId, parentId, 0);
         NodeState state = new NodeState(this, newData, 1);
         modify(state);
         cacheNodeState(state);
@@ -164,14 +166,14 @@ public class SessionImpl implements Sess
     }
 
     synchronized void modify(NodeState state) {
-        modified.put(state.getId(), state);
+        changes.put(state.getId(), state);
     }
 
     public synchronized void save() throws AccessDeniedException, ItemExistsException, ReferentialIntegrityException,
             ConstraintViolationException, InvalidItemStateException, VersionException, LockException,
             NoSuchNodeTypeException, RepositoryException {
         log.code(this, "save");
-        for (int i = 0; i < MAX_RETRY; i++) {
+        for (int i = 0; i < Constants.MAX_STORE_RETRY; i++) {
             try {
                 trySave();
                return;
@@ -184,24 +186,15 @@ public class SessionImpl implements Sess
     }
 
     private void trySave() {
-        NodeData[] changed = new NodeData[modified.size()];
-        Iterator<NodeState> it = modified.values().iterator();
-        for (int i = 0; i < modified.size(); i++) {
+        changes.storeAll();
+        for (Iterator<NodeState> it = changes.valueIterator(); it.hasNext();) {
             NodeState s = it.next();
-            changed[i] = s.getNodeData();
-        }
-        storageSession.save(changed);
-        for (NodeData n : changed) {
+            NodeData n = s.getNodeData();
             rep.cacheNodeData(n);
+            s.reset(n);
         }
-        it = modified.values().iterator();
-        for (int i = 0; i < modified.size(); i++) {
-            NodeState s = it.next();
-            s.reset(s.getNodeData());
-        }
-        modified.clear();
-        eventList.persisted();
-        eventList = new EventList(this);
+        changes.dispatchEvents();
+        changes.clearAll();
     }
 
     public synchronized NodeImpl getNodeByIdentifier(String id) throws ItemNotFoundException, RepositoryException {
@@ -217,16 +210,11 @@ public class SessionImpl implements Sess
 
     public synchronized void refresh(boolean keepChanges) throws RepositoryException {
         log.code(this, "refresh", keepChanges);
-        Iterator<NodeState> it = modified.values().iterator();
-        for (int i = 0; i < modified.size(); i++) {
-            NodeState s = it.next();
-            NodeData data = getPersistedNodeData(s.getId());
-            s.reset(data);
-        }
         if (keepChanges) {
-            eventList.apply();
+            changes.clearNodes();
+            changes.applyEvents();
         } else {
-            eventList = new EventList(this);
+            changes.clearAll();
         }
     }
 
@@ -269,7 +257,7 @@ public class SessionImpl implements Sess
 
     public synchronized boolean hasPendingChanges() throws RepositoryException {
         log.code(this, "hasPendingChanges");
-        return modified.size() > 0;
+        return changes.hasPendingChanges();
     }
 
     public synchronized ObservationManagerImpl getObservationManager() {
@@ -287,11 +275,11 @@ public class SessionImpl implements Sess
         return nodeTypeManager;
     }
 
-    public void dispatchEvents(EventList events) {
+    public void dispatchEvents(ChangeSet changes) {
         if (observationManager == null) {
             return;
         }
-        observationManager.dispatchEvents(events);
+        observationManager.dispatchEvents(changes);
     }
 
     public NamespaceRegistryImpl getNamespaceRegistry() {
@@ -300,16 +288,13 @@ public class SessionImpl implements Sess
 
     public void setObservationUserData(String userData) {
         this.observationUserData = userData;
+        changes.setUserData(userData);
     }
 
     public String getObservationUserData() {
         return observationUserData;
     }
 
-    public EventList getEventList() {
-        return eventList;
-    }
-
     public String getNamespacePrefix(String uri) throws NamespaceException, RepositoryException {
         log.code(this, "getNamespacePrefix", uri);
         return namespaceRegistry.getPrefix(uri);
@@ -407,6 +392,10 @@ public class SessionImpl implements Sess
         return log;
     }
 
+    public ChangeSet getTransientChanges() {
+        return changes;
+    }
+
     public boolean isLive() {
         log.code(this, "isLive");
         // TODO Auto-generated method stub
@@ -549,7 +538,7 @@ public class SessionImpl implements Sess
     }
 
     public String toString() {
-        return rep + " events: " + eventList + " modified nodes: " + modified.size() + " weak map: " + weakMap.size();
+        return "session #" + id + " " + rep + " changes: " + changes + " weak map: " + weakMap.size();
     }
 
 }

Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/Bundle.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/Bundle.java?rev=935321&r1=935320&r2=935321&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/Bundle.java (original)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/Bundle.java Sun Apr 18 09:52:27 2010
@@ -17,6 +17,7 @@
 package org.apache.jackrabbit.j3.mc;
 
 import javax.jcr.PropertyType;
+import org.apache.jackrabbit.j3.util.Constants;
 import org.apache.jackrabbit.j3.util.ExceptionFactory;
 
 /**
@@ -51,7 +52,7 @@ public class Bundle {
      */
     private int pos;
 
-    private Bundle(byte[] data) {
+    public Bundle(byte[] data) {
         this.data = data;
     }
 
@@ -161,13 +162,12 @@ public class Bundle {
     }
 
     /**
-     * Get the current write position of this buffer, which is the current
-     * length.
+     * The total length of the buffer.
      *
      * @return the length
      */
     public int length() {
-        return pos;
+        return data.length;
     }
 
     /**
@@ -223,6 +223,10 @@ public class Bundle {
         data[pos++] = x;
     }
 
+    private byte readByte() {
+        return data[pos++];
+    }
+
     /**
      * Append a value.
      *
@@ -305,7 +309,7 @@ public class Bundle {
             throw ExceptionFactory.illegalArgument("type: {0}", v.getType());
         }
         int len = pos - start;
-        if (len > 8) {
+        if (len >= Constants.BUNDLE_MIN_COMPRESS) {
             int hash = data[start] ^ data[start + 1] ^ data[start + 2];
             hash = hash & (last.length - 1);
             int test = last[hash];
@@ -320,10 +324,13 @@ public class Bundle {
                     }
                 }
                 if (i == len) {
-                    // write back pointer instead of the data
-                    pos = start;
-                    writeByte((byte) BACK_POINTER);
-                    writeVarInt(start - test);
+                    // write back pointer instead of the data,
+                    // but only if that's smaller
+                    if (len > 3 || getVarIntLen(start - test) < 2) {
+                        pos = start;
+                        writeByte((byte) BACK_POINTER);
+                        writeVarInt(start - test);
+                    }
                 }
             }
         }
@@ -602,4 +609,21 @@ public class Bundle {
         data = d;
     }
 
+    public void writeBoolean(boolean value) {
+        writeByte((byte) (value ? 1 : 0));
+    }
+
+    public boolean readBoolean() {
+        return readByte() == 1;
+    }
+
+    /**
+     * Get the current write/read position of this buffer.
+     *
+     * @return the position
+     */
+    public int getPos() {
+        return pos;
+    }
+
 }

Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/NodeData.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/NodeData.java?rev=935321&r1=935320&r2=935321&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/NodeData.java (original)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/NodeData.java Sun Apr 18 09:52:27 2010
@@ -30,6 +30,7 @@ public class NodeData implements CacheEl
     private static final int BIT_PROPERTIES = 4;
     private static final int BIT_PRIMARY_TYPE = 8;
     private static final int BIT_LOCKED = 16;
+    private static final int BIT_EMBEDDED_CHILD_NODES = 32;
 
     private final Val id;
     private final Val primaryParentId;
@@ -85,7 +86,7 @@ public class NodeData implements CacheEl
 
     public void addChild(Val childName, Val childId) {
         if (getChildId(childName) != null) {
-            throw ExceptionFactory.mcException("Duplicate node");
+            throw ExceptionFactory.mcException("Duplicate node {0}", childName);
         }
         childNameIdPairs = updatePair(childNameIdPairs, childName, childId);
     }
@@ -333,6 +334,9 @@ public class NodeData implements CacheEl
             int count = bundle.readVarInt();
             data.propertyValuePairs = readArray(bundle, count * 2);
         }
+        if ((flags & BIT_EMBEDDED_CHILD_NODES) != 0) {
+            throw ExceptionFactory.unsupportedOperation();
+        }
         return data;
     }
 

Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/StorageSession.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/StorageSession.java?rev=935321&r1=935320&r2=935321&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/StorageSession.java (original)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/StorageSession.java Sun Apr 18 09:52:27 2010
@@ -21,18 +21,32 @@ package org.apache.jackrabbit.j3.mc;
  */
 public interface StorageSession {
 
-    void close();
-
     Val getRootNodeId();
 
     NodeData getNode(Val nodeId);
 
     Val newNodeId(Val parentId);
 
-    void save(NodeData[] changed);
+    void store(long date, NodeData[] nodes, Bundle[] events);
+
+    Bundle[] getEvents(long date, int size);
 
     Val convertIdentifierToNodeId(String id);
 
     String convertNodeIdToIdentifier(Val nodeId);
 
+    void close();
+
+    boolean supportsEventJournal();
+
+    boolean supportsTemp();
+
+    void storeTemp(int block, NodeData[] nodes, Bundle[] events);
+
+    NodeData[] getTempNodes(int block);
+
+    Bundle[] getTempEvents(int block);
+
+    void clearTemp(boolean nodes, boolean events);
+
 }

Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/jdbc/JdbcStorage.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/jdbc/JdbcStorage.java?rev=935321&r1=935320&r2=935321&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/jdbc/JdbcStorage.java (original)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/jdbc/JdbcStorage.java Sun Apr 18 09:52:27 2010
@@ -36,6 +36,7 @@ public class JdbcStorage implements Stor
     private boolean initDone;
     private static final Val rootNodeId = Val.get(0);
     private AtomicLong nextNodeId;
+    private AtomicLong nextSessionId = new AtomicLong(1);
 
     public JdbcStorage(String url) {
         this.url = url;
@@ -44,7 +45,7 @@ public class JdbcStorage implements Stor
     public StorageSession openSession(String user, char[] password) {
         try {
             Connection conn = JdbcUtils.getConnection(null, url, user, new String(password));
-            JdbcStorageSession session = new JdbcStorageSession(this, conn);
+            JdbcStorageSession session = new JdbcStorageSession(this, conn, nextSessionId.getAndIncrement());
             init(conn, session);
             return session;
         } catch (SQLException e) {
@@ -59,12 +60,18 @@ public class JdbcStorage implements Stor
         try {
             Statement stat = conn.createStatement();
             stat.execute("create table if not exists bundles(id bigint primary key, version bigint, data binary)");
+            stat.execute("create table if not exists bundles_temp(id bigint, sessionId bigint, block int, version int, data binary, primary key(id, sessionId))");
+            stat.execute("create table if not exists events(id identity, persistedDate bigint, data binary)");
+            stat.execute("create table if not exists events_temp(id identity, sessionId bigint, block int, data binary)");
+            stat.execute("create index if not exists events_persisted on events(persistedDate, id)");
+            stat.execute("create index if not exists bundles_temp_block on bundles_temp(sessionId, block, id)");
+            stat.execute("create index if not exists events_temp_block on events_temp(sessionId, block)");
             ResultSet rs = stat.executeQuery("select max(id) from bundles");
             rs.next();
             nextNodeId = new AtomicLong(rs.getLong(1) + 1);
             if (rs.wasNull()) {
                 NodeData root = new NodeData(rootNodeId, null, 0);
-                session.save(new NodeData[] { root });
+                session.store(0, new NodeData[] { root }, null);
             }
         } catch (SQLException e) {
             throw ExceptionFactory.mcException(e);

Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/jdbc/JdbcStorageSession.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/jdbc/JdbcStorageSession.java?rev=935321&r1=935320&r2=935321&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/jdbc/JdbcStorageSession.java (original)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/jdbc/JdbcStorageSession.java Sun Apr 18 09:52:27 2010
@@ -20,6 +20,7 @@ import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
+import java.util.ArrayList;
 import java.util.HashMap;
 import org.apache.jackrabbit.j3.mc.Bundle;
 import org.apache.jackrabbit.j3.mc.NodeData;
@@ -36,10 +37,15 @@ public class JdbcStorageSession implemen
     private final Connection conn;
     private final HashMap<String, PreparedStatement> prepared = new HashMap<String, PreparedStatement>();
     private final Bundle bundle = Bundle.create(512);
+    private final long sessionId;
+    private int tempNodeBlocks;
+    private int tempEventBlocks;
+    private long nextEventId;
 
-    JdbcStorageSession(JdbcStorage storage, Connection conn) {
+    JdbcStorageSession(JdbcStorage storage, Connection conn, long sessionId) {
         this.storage = storage;
         this.conn = conn;
+        this.sessionId = sessionId;
     }
 
     private PreparedStatement prepare(String sql) throws SQLException {
@@ -51,23 +57,28 @@ public class JdbcStorageSession implemen
         return p;
     }
 
-    public void close() {
-        try {
-            conn.close();
-        } catch (SQLException e) {
-            throw ExceptionFactory.mcException(e);
-        }
-    }
-
     public Val getRootNodeId() {
         return storage.getRootNodeId();
     }
 
     public NodeData getNode(Val nodeId) {
         try {
-            PreparedStatement p = prepare("select data from bundles where id = ?");
-            p.setLong(1, nodeId.getLong());
-            ResultSet rs = p.executeQuery();
+            ResultSet rs;
+            if (tempNodeBlocks > 0) {
+                PreparedStatement p = prepare("select data from bundles_temp where id = ? and sessionId = ?");
+                p.setLong(1, nodeId.getLong());
+                p.setLong(2, sessionId);
+                rs = p.executeQuery();
+                if (!rs.next()) {
+                    p = prepare("select data from bundles where id = ?");
+                    p.setLong(1, nodeId.getLong());
+                    rs = p.executeQuery();
+                }
+            } else {
+                PreparedStatement p = prepare("select data from bundles where id = ?");
+                p.setLong(1, nodeId.getLong());
+                rs = p.executeQuery();
+            }
             if (!rs.next()) {
                 rs.close();
                 return null;
@@ -86,34 +97,111 @@ public class JdbcStorageSession implemen
         return storage.newNodeId();
     }
 
-    public void save(NodeData[] changed) {
+    public void store(long date, NodeData[] nodes, Bundle[] events) {
         try {
-            PreparedStatement insert = prepare("insert into bundles(id, version, data) values(?, ?, ?)");
-            PreparedStatement update = prepare("update bundles set version = ?, data = ? where id = ?");
-            for (NodeData n : changed) {
-                try {
-                    if (n.getVersion() == 0) {
-                        n.incrementVersion();
-                        insert.setLong(1, n.getId().getLong());
-                        insert.setLong(2, n.getVersion());
-                        bundle.reset();
-                        n.writeTo(bundle);
-                        insert.setBytes(3, bundle.getBytes());
-                        insert.executeUpdate();
+            if (tempNodeBlocks > 0 || tempEventBlocks > 0) {
+                int max = Math.max(tempNodeBlocks, tempEventBlocks);
+                tempNodeBlocks = 0;
+                for (int i = 0; i <= max; i++) {
+                    NodeData[] tempNodes = getTempNodes(i);
+                    Bundle[] tempEvents;
+                    if (events == null) {
+                        tempEvents = null;
                     } else {
-                        n.incrementVersion();
-                        update.setLong(3, n.getId().getLong());
-                        update.setLong(1, n.getVersion());
-                        bundle.reset();
-                        n.writeTo(bundle);
-                        update.setBytes(2, bundle.getBytes());
-                        int updateCount = update.executeUpdate();
-                        if (updateCount != 1) {
-                            throw ExceptionFactory.mcException("Update failed, update count is {0}", updateCount);
-                        }
+                        tempEvents = getTempEvents(i);
                     }
-                } catch (SQLException e) {
-                    throw ExceptionFactory.mcException(e);
+                    store(date, tempNodes, tempEvents);
+                }
+            }
+            PreparedStatement insert = prepare("insert into bundles(id, version, data) values(?, ?, ?)");
+            PreparedStatement update = prepare("update bundles set version = ?, data = ? where id = ?");
+            for (NodeData n : nodes) {
+                n.incrementVersion();
+                bundle.reset();
+                n.writeTo(bundle);
+                update.setLong(3, n.getId().getLong());
+                update.setLong(1, n.getVersion());
+                update.setBytes(2, bundle.getBytes());
+                int updateCount = update.executeUpdate();
+                if (updateCount == 0) {
+                    insert.setLong(1, n.getId().getLong());
+                    insert.setLong(2, n.getVersion());
+                    insert.setBytes(3, bundle.getBytes());
+                    insert.executeUpdate();
+                }
+            }
+            if (events != null) {
+                PreparedStatement eventsInsert = prepare("insert into events(persistedDate, data) values(?, ?)");
+                for (Bundle e : events) {
+                    eventsInsert.setLong(1, date);
+                    eventsInsert.setBytes(2, e.getBytes());
+                    eventsInsert.execute();
+                }
+            }
+        } catch (SQLException e) {
+            throw ExceptionFactory.mcException(e);
+        }
+    }
+
+    public Bundle[] getEvents(long date, int size) {
+        try {
+            if (date != -1) {
+                PreparedStatement get = prepare("select min(id) from events where persistedDate >= ?");
+                get.setLong(1, date);
+                ResultSet rs = get.executeQuery();
+                rs.next();
+                nextEventId = rs.getLong(1);
+            }
+            PreparedStatement get = prepare("select id, data from events where id >= ? limit ?");
+            get.setLong(1, nextEventId);
+            get.setInt(2, size);
+            ResultSet rs = get.executeQuery();
+            ArrayList<Bundle> bundles = new ArrayList<Bundle>();
+            while (rs.next()) {
+                nextEventId = rs.getLong(1) + 1;
+                byte[] data = rs.getBytes(2);
+                Bundle b = new Bundle(data);
+                bundles.add(b);
+            }
+            if (bundles.size() == 0) {
+                return null;
+            }
+            return bundles.toArray(new Bundle[bundles.size()]);
+        } catch (SQLException e) {
+            throw ExceptionFactory.mcException(e);
+        }
+    }
+
+    public void storeTemp(int block, NodeData[] nodes, Bundle[] events) {
+        tempNodeBlocks = Math.max(tempNodeBlocks, block + 1);
+        try {
+            PreparedStatement insert = prepare("insert into bundles_temp(id, sessionId, block, version, data) values(?, ?, ?, ?, ?)");
+            PreparedStatement update = prepare("update bundles_temp set block = ?, version = ?, data = ? where id = ? and sessionId = ?");
+            for (NodeData n : nodes) {
+                bundle.reset();
+                n.writeTo(bundle);
+                update.setLong(4, n.getId().getLong());
+                update.setLong(5, sessionId);
+                update.setLong(1, block);
+                update.setLong(2, n.getVersion());
+                update.setBytes(3, bundle.getBytes());
+                int updateCount = update.executeUpdate();
+                if (updateCount == 0) {
+                    insert.setLong(1, n.getId().getLong());
+                    insert.setLong(2, sessionId);
+                    insert.setLong(3, block);
+                    insert.setLong(4, n.getVersion());
+                    insert.setBytes(5, bundle.getBytes());
+                    insert.executeUpdate();
+                }
+            }
+            if (events != null) {
+                PreparedStatement eventsInsert = prepare("insert into events_temp(sessionId, block, data) values(?, ?, ?)");
+                for (Bundle e : events) {
+                    eventsInsert.setLong(1, sessionId);
+                    eventsInsert.setLong(2, block);
+                    eventsInsert.setBytes(3, e.getBytes());
+                    eventsInsert.execute();
                 }
             }
         } catch (SQLException e) {
@@ -129,5 +217,77 @@ public class JdbcStorageSession implemen
         return nodeId.getString();
     }
 
+    public void close() {
+        try {
+            clearTemp(true, true);
+            conn.close();
+        } catch (SQLException e) {
+            throw ExceptionFactory.mcException(e);
+        }
+    }
+
+    public void clearTemp(boolean nodes, boolean events) {
+        try {
+            PreparedStatement prep;
+            if (nodes) {
+                prep = prepare("delete from bundles_temp where sessionId = ?");
+                prep.setLong(1, sessionId);
+                prep.execute();
+                tempNodeBlocks = 0;
+            }
+            if (events) {
+                prep = prepare("delete from events_temp where sessionId = ?");
+                prep.setLong(1, sessionId);
+                prep.execute();
+                tempEventBlocks = 0;
+            }
+        } catch (SQLException e) {
+            throw ExceptionFactory.mcException(e);
+        }
+    }
+
+    public boolean supportsEventJournal() {
+        return true;
+    }
+
+    public boolean supportsTemp() {
+        return true;
+    }
+
+    public NodeData[] getTempNodes(int block) {
+        ArrayList<NodeData> list = new ArrayList<NodeData>();
+        try {
+            PreparedStatement get = prepare("select data from bundles_temp where sessionId = ? and block = ? order by id");
+            get.setLong(1, sessionId);
+            get.setInt(2, block);
+            ResultSet rs = get.executeQuery();
+            while (rs.next()) {
+                byte[] data = rs.getBytes(1);
+                Bundle bundle = Bundle.create(data);
+                list.add(NodeData.readFrom(bundle));
+            }
+            return list.toArray(new NodeData[list.size()]);
+        } catch (SQLException e) {
+            throw ExceptionFactory.mcException(e);
+        }
+    }
+
+    public Bundle[] getTempEvents(int block) {
+        ArrayList<Bundle> list = new ArrayList<Bundle>();
+        try {
+            PreparedStatement get = prepare("select data from events_temp where sessionId = ? and block = ? order by id");
+            get.setLong(1, sessionId);
+            get.setInt(2, block);
+            ResultSet rs = get.executeQuery();
+            while (rs.next()) {
+                byte[] data = rs.getBytes(1);
+                Bundle bundle = Bundle.create(data);
+                list.add(bundle);
+            }
+            return list.toArray(new Bundle[list.size()]);
+        } catch (SQLException e) {
+            throw ExceptionFactory.mcException(e);
+        }
+    }
 
 }

Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/mem/MemStorageSession.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/mem/MemStorageSession.java?rev=935321&r1=935320&r2=935321&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/mem/MemStorageSession.java (original)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/mem/MemStorageSession.java Sun Apr 18 09:52:27 2010
@@ -17,9 +17,11 @@
 package org.apache.jackrabbit.j3.mc.mem;
 
 import java.util.HashMap;
+import org.apache.jackrabbit.j3.mc.Bundle;
 import org.apache.jackrabbit.j3.mc.NodeData;
 import org.apache.jackrabbit.j3.mc.StorageSession;
 import org.apache.jackrabbit.j3.mc.Val;
+import org.apache.jackrabbit.j3.util.ExceptionFactory;
 
 /**
  * A session for the memory storage.
@@ -49,9 +51,9 @@ public class MemStorageSession implement
         return storage.newNodeId();
     }
 
-    public void save(NodeData[] changed) {
+    public void store(long date, NodeData[] nodes, Bundle[] events) {
         synchronized (storage) {
-            for (NodeData n : changed) {
+            for (NodeData n : nodes) {
                 content.put(n.getId(), n);
                 n.incrementVersion();
             }
@@ -66,4 +68,32 @@ public class MemStorageSession implement
         return nodeId.getString();
     }
 
+    public boolean supportsTemp() {
+        return false;
+    }
+
+    public boolean supportsEventJournal() {
+        return false;
+    }
+
+    public Bundle[] getEvents(long date, int size) {
+        throw ExceptionFactory.unsupportedOperation();
+    }
+
+    public void storeTemp(int block, NodeData[] nodes, Bundle[] events) {
+        throw ExceptionFactory.unsupportedOperation();
+    }
+
+    public NodeData[] getTempNodes(int block) {
+        throw ExceptionFactory.unsupportedOperation();
+    }
+
+    public Bundle[] getTempEvents(int block) {
+        throw ExceptionFactory.unsupportedOperation();
+    }
+
+    public void clearTemp(boolean nodes, boolean events) {
+        throw ExceptionFactory.unsupportedOperation();
+    }
+
 }

Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/nodetype/NodeTypeImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/nodetype/NodeTypeImpl.java?rev=935321&r1=935320&r2=935321&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/nodetype/NodeTypeImpl.java (original)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/nodetype/NodeTypeImpl.java Sun Apr 18 09:52:27 2010
@@ -32,6 +32,7 @@ import org.apache.jackrabbit.j3.mc.Val;
  */
 public class NodeTypeImpl extends NodeTypeDefinitionImpl implements NodeType {
 
+    public static final NodeTypeImpl[] EMPTY_ARRAY = new NodeTypeImpl[0];
     private final NodeTypeImpl[] declaredSupertypes;
 
     NodeTypeImpl(NodeTypeManagerImpl manager, NodeTypeDefinitionImpl ntd) {
@@ -235,6 +236,18 @@ public class NodeTypeImpl extends NodeTy
         return isNodeType(manager.parseName(nodeTypeName));
     }
 
+    public boolean isNodeType(NodeType nt) {
+        if (this == nt) {
+            return true;
+        }
+        for (NodeTypeImpl s : declaredSupertypes) {
+            if (s.isNodeType(nt)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     private boolean isNodeType(Val n) {
         if (n.equals(name)) {
             return true;

Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/nodetype/NodeTypeIteratorImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/nodetype/NodeTypeIteratorImpl.java?rev=935321&r1=935320&r2=935321&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/nodetype/NodeTypeIteratorImpl.java (original)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/nodetype/NodeTypeIteratorImpl.java Sun Apr 18 09:52:27 2010
@@ -33,7 +33,7 @@ class NodeTypeIteratorImpl extends Range
 
     public NodeType nextNodeType() {
         log.code(this, "nextNodeType");
-        return goNext();
+        return getNext();
     }
 
 }
\ No newline at end of file

Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddLock.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddLock.java?rev=935321&r1=935320&r2=935321&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddLock.java (original)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddLock.java Sun Apr 18 09:52:27 2010
@@ -18,8 +18,11 @@ package org.apache.jackrabbit.j3.observa
 
 import javax.jcr.RepositoryException;
 import javax.jcr.observation.Event;
-import org.apache.jackrabbit.j3.SessionImpl;
+import org.apache.jackrabbit.j3.NodeImpl;
+import org.apache.jackrabbit.j3.ChangeSet;
 import org.apache.jackrabbit.j3.lock.LockImpl;
+import org.apache.jackrabbit.j3.mc.Bundle;
+import org.apache.jackrabbit.j3.mc.Val;
 
 
 /**
@@ -28,17 +31,42 @@ import org.apache.jackrabbit.j3.lock.Loc
 public class EventAddLock extends EventImpl {
     private final LockImpl lock;
 
-    public EventAddLock(SessionImpl session, LockImpl lock) {
-        super(session);
+    public EventAddLock(ChangeSet changes, LockImpl lock) {
+        super(changes);
         this.lock = lock;
     }
 
+    public int getType() {
+        return Event.PROPERTY_ADDED;
+    }
+
+    @Override
     public void apply() throws RepositoryException {
         lock.getNode().doAddLock(lock);
     }
 
-    public int getType() {
-        return Event.PROPERTY_ADDED;
+    @Override
+    public void writeTo(Bundle bundle) {
+        bundle.writeVarInt(TOKEN_ADD_LOCK);
+        bundle.writeVal(lock.getNode().getNodeState().getId());
+        bundle.writeVal(lock.getInternalLockToken());
+        bundle.writeBoolean(lock.isDeep());
+        bundle.writeBoolean(lock.isSessionScoped());
+    }
+
+    public static EventAddLock readFrom(ChangeSet changes, Bundle bundle) throws RepositoryException {
+        Val id = bundle.readVal();
+        NodeImpl node = changes.getSession().getNode(null, id);
+        Val lockToken = bundle.readVal();
+        boolean isDeep = bundle.readBoolean();
+        boolean isSessionScoped = bundle.readBoolean();
+        LockImpl lock = new LockImpl(node, lockToken, isDeep, isSessionScoped);
+        return new EventAddLock(changes, lock);
+    }
+
+    @Override
+    public NodeImpl getParentNode() {
+        return lock.getNode();
     }
 
 }

Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddMixin.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddMixin.java?rev=935321&r1=935320&r2=935321&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddMixin.java (original)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddMixin.java Sun Apr 18 09:52:27 2010
@@ -16,10 +16,12 @@
  */
 package org.apache.jackrabbit.j3.observation;
 
+import javax.jcr.RepositoryException;
 import javax.jcr.lock.LockException;
 import javax.jcr.observation.Event;
 import org.apache.jackrabbit.j3.NodeImpl;
-import org.apache.jackrabbit.j3.SessionImpl;
+import org.apache.jackrabbit.j3.ChangeSet;
+import org.apache.jackrabbit.j3.mc.Bundle;
 import org.apache.jackrabbit.j3.mc.Val;
 
 /**
@@ -29,18 +31,38 @@ public class EventAddMixin extends Event
     private final NodeImpl node;
     private final Val mixin;
 
-    public EventAddMixin(SessionImpl session, NodeImpl node, Val mixin) {
-        super(session);
+    public EventAddMixin(ChangeSet changes, NodeImpl node, Val mixin) {
+        super(changes);
         this.node = node;
         this.mixin = mixin;
     }
 
+    public int getType() {
+        return Event.PROPERTY_CHANGED;
+    }
+
+    @Override
     public void apply() throws LockException {
         node.doAddMixin(mixin);
     }
 
-    public int getType() {
-        return Event.PROPERTY_CHANGED;
+    @Override
+    public void writeTo(Bundle bundle) {
+        bundle.writeVarInt(TOKEN_ADD_MIXIN);
+        bundle.writeVal(node.getNodeState().getId());
+        bundle.writeVal(mixin);
+    }
+
+    public static EventAddMixin readFrom(ChangeSet changes, Bundle bundle) throws RepositoryException {
+        Val id = bundle.readVal();
+        NodeImpl node = changes.getSession().getNode(null, id);
+        Val mixin = bundle.readVal();
+        return new EventAddMixin(changes, node, mixin);
+    }
+
+    @Override
+    public NodeImpl getParentNode() {
+        return node;
     }
 
 }

Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddNode.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddNode.java?rev=935321&r1=935320&r2=935321&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddNode.java (original)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddNode.java Sun Apr 18 09:52:27 2010
@@ -20,31 +20,44 @@ import javax.jcr.RepositoryException;
 import javax.jcr.lock.LockException;
 import javax.jcr.observation.Event;
 import org.apache.jackrabbit.j3.NodeImpl;
-import org.apache.jackrabbit.j3.SessionImpl;
+import org.apache.jackrabbit.j3.ChangeSet;
+import org.apache.jackrabbit.j3.mc.Bundle;
 import org.apache.jackrabbit.j3.mc.Val;
 
 /**
  * Add a node.
  */
 public class EventAddNode extends EventImpl {
-    private final NodeImpl newNode;
+    private final NodeImpl parent;
+    private final Val parentId;
     private final Val childName;
+    private final Val newNodeId;
+    private NodeImpl newNode;
     private String path;
 
-    public EventAddNode(SessionImpl session, Val childName, NodeImpl newNode) {
-        super(session);
+    public EventAddNode(ChangeSet changes, NodeImpl parent, Val childName, Val newNodeId) {
+        super(changes);
+        this.parent = parent;
+        this.parentId = parent.getNodeState().getId();
         this.childName = childName;
-        this.newNode = newNode;
+        this.newNodeId = newNodeId;
     }
 
-    public void apply() throws LockException {
-        newNode.getParentNode().doAddNode(childName, newNode);
+    public NodeImpl getNode() {
+        return newNode;
     }
 
     public int getType() {
         return Event.NODE_ADDED;
     }
 
+    @Override
+    public void apply() throws LockException {
+        newNode = getSession().createNode(parent, parentId, newNodeId);
+        newNode.getParentNode().doAddNode(childName, newNode);
+    }
+
+    @Override
     public String getPath() throws RepositoryException {
         if (path == null) {
             path = newNode.getPath();
@@ -52,4 +65,28 @@ public class EventAddNode extends EventI
         return path;
     }
 
+    @Override
+    public void writeTo(Bundle bundle) {
+        bundle.writeVarInt(TOKEN_ADD_NODE);
+        bundle.writeVal(parentId);
+        bundle.writeVal(childName);
+        bundle.writeVal(newNodeId);
+    }
+
+    public static EventAddNode readFrom(ChangeSet changes, Bundle bundle) throws RepositoryException {
+        Val parentId = bundle.readVal();
+        NodeImpl parent = changes.getSession().getNode(null, parentId);
+        Val childName = bundle.readVal();
+        Val newNodeId = bundle.readVal();
+        EventAddNode e = new EventAddNode(changes, parent, childName, newNodeId);
+        e.newNode = e.getSession().getNode(parent, newNodeId);
+        return e;
+    }
+
+    @Override
+    public NodeImpl getParentNode() {
+        // TODO return the parent, or the node?
+        return parent;
+    }
+
 }
\ No newline at end of file

Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddProperty.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddProperty.java?rev=935321&r1=935320&r2=935321&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddProperty.java (original)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddProperty.java Sun Apr 18 09:52:27 2010
@@ -20,7 +20,8 @@ import javax.jcr.RepositoryException;
 import javax.jcr.lock.LockException;
 import javax.jcr.observation.Event;
 import org.apache.jackrabbit.j3.NodeImpl;
-import org.apache.jackrabbit.j3.SessionImpl;
+import org.apache.jackrabbit.j3.ChangeSet;
+import org.apache.jackrabbit.j3.mc.Bundle;
 import org.apache.jackrabbit.j3.mc.Val;
 
 /**
@@ -32,26 +33,48 @@ public class EventAddProperty extends Ev
     private final Val value;
     private String path;
 
-    public EventAddProperty(SessionImpl session, NodeImpl node, Val propertyName, Val value) {
-        super(session);
+    public EventAddProperty(ChangeSet changes, NodeImpl node, Val propertyName, Val value) {
+        super(changes);
         this.node = node;
         this.propertyName = propertyName;
         this.value = value;
     }
 
-    public void apply() throws LockException {
-        node.doSetProperty(propertyName, value);
-    }
-
     public int getType() {
         return Event.PROPERTY_ADDED;
     }
 
     public String getPath() throws RepositoryException {
         if (path == null) {
-            path = node.getPath() + "/" + eventList.getSession().nameToString(propertyName);
+            path = node.getPath() + "/" + getSession().nameToString(propertyName);
         }
         return path;
     }
 
+    @Override
+    public void apply() throws LockException {
+        node.doSetProperty(propertyName, value);
+    }
+
+    @Override
+    public void writeTo(Bundle bundle) {
+        bundle.writeVarInt(TOKEN_ADD_PROPERTY);
+        bundle.writeVal(node.getNodeState().getId());
+        bundle.writeVal(propertyName);
+        bundle.writeVal(value);
+    }
+
+    public static EventAddProperty readFrom(ChangeSet changes, Bundle bundle) throws RepositoryException {
+        Val id = bundle.readVal();
+        NodeImpl node = changes.getSession().getNode(null, id);
+        Val propertyName = bundle.readVal();
+        Val value = bundle.readVal();
+        return new EventAddProperty(changes, node, propertyName, value);
+    }
+
+    @Override
+    public NodeImpl getParentNode() {
+        return node;
+    }
+
 }
\ No newline at end of file

Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventConsumer.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventConsumer.java?rev=935321&r1=935320&r2=935321&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventConsumer.java (original)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventConsumer.java Sun Apr 18 09:52:27 2010
@@ -16,13 +16,13 @@
  */
 package org.apache.jackrabbit.j3.observation;
 
-import java.util.HashSet;
 import javax.jcr.RepositoryException;
 import javax.jcr.observation.Event;
 import javax.jcr.observation.EventIterator;
 import javax.jcr.observation.EventListener;
 import org.apache.jackrabbit.j3.RangeIteratorImpl;
 import org.apache.jackrabbit.j3.SessionImpl;
+import org.apache.jackrabbit.j3.ChangeSet;
 import org.apache.jackrabbit.j3.util.Log;
 
 /**
@@ -30,67 +30,25 @@ import org.apache.jackrabbit.j3.util.Log
  */
 public class EventConsumer {
 
-    private final SessionImpl session;
     private final EventListener listener;
-    private final int eventTypes;
-    private final String absPath;
-    private final boolean isDeep;
-    private final HashSet<String> identifierSet;
-    private final HashSet<String> nodeTypeNameSet;
-    private final boolean noLocal;
+    private final SessionImpl session;
+    private final EventFilter filter;
 
-    EventConsumer(SessionImpl session, EventListener listener, int eventTypes, String absPath, boolean isDeep, String[] identifiers, String[] nodeTypeName, boolean noLocal) {
+    EventConsumer(SessionImpl session, EventListener listener, EventFilter filter) {
         this.session = session;
         this.listener = listener;
-        this.eventTypes = eventTypes;
-        this.absPath = absPath;
-        this.isDeep = isDeep;
-        if (identifiers == null) {
-            identifierSet = null;
-        } else {
-            identifierSet = new HashSet<String>();
-            for (String id : identifiers) {
-                identifierSet.add(id);
-            }
-        }
-        if (nodeTypeName == null) {
-            nodeTypeNameSet = null;
-        } else {
-            nodeTypeNameSet = new HashSet<String>();
-            for (String name : nodeTypeName) {
-                nodeTypeNameSet.add(name);
-            }
-        }
-        this.noLocal = noLocal;
+        this.filter = filter;
     }
 
     public EventListener getListener() {
         return listener;
     }
 
-    boolean matchesType(int type) {
-        return (type & eventTypes) != 0;
-    }
-
-    boolean matchesIdentifier(String identifier) {
-        if (identifier == null || identifierSet == null) {
-            return true;
-        }
-        return identifierSet.contains(identifier);
-    }
-
-    boolean matchesNodeTypeName(String nodeTypeName) {
-        if (nodeTypeName == null || nodeTypeNameSet == null) {
-            return true;
-        }
-        return nodeTypeNameSet.contains(nodeTypeName);
-    }
-
-    void dispatch(EventList events) {
-        if (noLocal && events.getSession() == session) {
+    void dispatch(ChangeSet changes) {
+        if (filter.getNoLocal() && changes.getSession() == session) {
             return;
         }
-        listener.onEvent(new FilteredEventIterator(events, session.getLog()));
+        listener.onEvent(new FilteredEventIterator(changes, session.getLog()));
     }
 
     /**
@@ -98,22 +56,16 @@ public class EventConsumer {
      */
     class FilteredEventIterator extends RangeIteratorImpl<EventImpl> implements EventIterator {
 
-        FilteredEventIterator(EventList events, Log log) {
-            super(events.getChangeList().iterator(), -1, log);
+        FilteredEventIterator(ChangeSet changes, Log log) {
+            super(changes.getEvents(), -1, log);
         }
 
         public boolean skip(EventImpl x) throws RepositoryException {
-            if (!matchesType(x.getType())) {
-                return true;
-            }
-            if (!matchesIdentifier(x.getIdentifier())) {
-                return true;
-            }
-            return false;
+            return !filter.matches(x);
         }
 
         public Event nextEvent() {
-            EventImpl e = goNext();
+            EventImpl e = getNext();
             log.codeAssign(e, this, "nextEvent");
             return e;
         }

Added: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventFilter.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventFilter.java?rev=935321&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventFilter.java (added)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventFilter.java Sun Apr 18 09:52:27 2010
@@ -0,0 +1,109 @@
+/*
+ * 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.j3.observation;
+
+import java.util.HashSet;
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+import javax.jcr.nodetype.NodeType;
+import org.apache.jackrabbit.j3.SessionImpl;
+import org.apache.jackrabbit.j3.util.ExceptionFactory;
+
+/**
+ * A filter for event iterators.
+ */
+public class EventFilter {
+    private final SessionImpl session;
+    private final int eventTypes;
+    private final String absPath;
+    private final boolean isDeep;
+    private final HashSet<String> identifierSet;
+    private final HashSet<NodeType> nodeTypeSet;
+    private final boolean noLocal;
+
+    EventFilter(SessionImpl session, int eventTypes, String absPath, boolean isDeep, String[] identifiers, String[] nodeTypeName, boolean noLocal) throws NoSuchNodeTypeException, RepositoryException {
+        this.session = session;
+        this.eventTypes = eventTypes;
+        this.absPath = absPath;
+        this.isDeep = isDeep;
+        if (identifiers == null) {
+            identifierSet = null;
+        } else {
+            identifierSet = new HashSet<String>();
+            for (String id : identifiers) {
+                identifierSet.add(id);
+            }
+        }
+        if (nodeTypeName == null) {
+            nodeTypeSet = null;
+        } else {
+            nodeTypeSet = new HashSet<NodeType>();
+            for (String name : nodeTypeName) {
+                NodeType nt = session.getNodeTypeManager().getNodeType(name);
+                nodeTypeSet.add(nt);
+            }
+        }
+        this.noLocal = noLocal;
+    }
+
+    public boolean matches(EventImpl event) {
+        if ((event.getType() & eventTypes) == 0) {
+            return false;
+        }
+        if (identifierSet != null) {
+            String id = event.getIdentifier();
+            if (id != null && !identifierSet.contains(id)) {
+                return false;
+            }
+        }
+        if (absPath != null) {
+            // TODO need to match path according to this sessions namespace mapping
+            String path;
+            try {
+                path = event.getPath();
+                if (path != null) {
+                    if (isDeep) {
+                        if (!path.startsWith(absPath)) {
+                            return false;
+                        }
+                    } else {
+                        if (!path.equals(absPath)) {
+                            return false;
+                        }
+                    }
+                }
+            } catch (RepositoryException e) {
+                throw ExceptionFactory.runtime(e);
+            }
+        }
+        if (nodeTypeSet != null) {
+            try {
+                if (!event.matchesNodeTypeSet(nodeTypeSet)) {
+                    return false;
+                }
+            } catch (RepositoryException e) {
+                throw ExceptionFactory.runtime(e);
+            }
+        }
+        return true;
+    }
+
+    public boolean getNoLocal() {
+        return noLocal;
+    }
+
+}



Mime
View raw message