Index: oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/SlingDiff.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/SlingDiff.java (revision ) +++ oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/SlingDiff.java (revision ) @@ -0,0 +1,159 @@ +/* + * 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.oak.kernel; + +import static org.apache.jackrabbit.oak.commons.PathUtils.concat; + +import java.util.Map; +import java.util.Set; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import org.apache.jackrabbit.oak.api.PropertyState; +import org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState; +import org.apache.jackrabbit.oak.spi.commit.Observer; +import org.apache.jackrabbit.oak.spi.state.NodeState; +import org.apache.jackrabbit.oak.spi.state.NodeStateDiff; + +public class SlingDiff implements NodeStateDiff, Observer { + private final String path; + private final Map properties = Maps.newHashMap(); + private final Set added = Sets.newHashSet(); + private final Set changed = Sets.newHashSet(); + private final Set deleted = Sets.newHashSet(); + + public SlingDiff() { + this("/"); + } + + public SlingDiff(String path) { + this.path = path; + } + + @Override + public void contentChanged(NodeState before, NodeState after) { + after.compareAgainstBaseState(before, this); + addIfNotNull(after, "jcr:primaryType"); + addIfNotNull(after, "sling:resourceType"); + addIfNotNull(after, "sling:resourceSuperType"); + + if (before == EmptyNodeState.EMPTY_NODE) { + nodeAdded(path, properties, added); + } else if (after == EmptyNodeState.EMPTY_NODE) { + nodeDeleted(path, properties, deleted); + } else if (!added.isEmpty() || !changed.isEmpty() || !deleted.isEmpty()) { + nodeChanged(path, properties, added, changed, deleted); + } + } + + private void addIfNotNull(NodeState nodeState, String name) { + PropertyState property = nodeState.getProperty(name); + if (property != null) { + properties.put(name, property); + } + } + + protected void nodeAdded(String path, Map typeProperties, + Set added) { + System.out.println("Added node at " + path); + printProperties(typeProperties.values()); + if (!added.isEmpty()) { + System.out.println("Added properties"); + printProperties(added); + } + System.out.println(); + } + + protected void nodeDeleted(String path, Map typeProperties, + Set deleted) { + System.out.println("Deleted node at " + path); + printProperties(typeProperties.values()); + if (!deleted.isEmpty()) { + System.out.println("Deleted properties"); + printProperties(deleted); + } + System.out.println(); + } + + protected void nodeChanged(String path, Map typeProperties, + Set added, Set changed, Set deleted) { + System.out.println("Changed node at " + path); + printProperties(typeProperties.values()); + if (!added.isEmpty()) { + System.out.println("Added properties"); + printProperties(added); + } + if (!deleted.isEmpty()) { + System.out.println("Deleted properties"); + printProperties(deleted); + } + if (!changed.isEmpty()) { + System.out.println("Changed properties"); + printProperties(changed); + } + System.out.println(); + } + + private static void printProperties(Iterable properties) { + for (PropertyState property : properties) { + System.out.println(property); + } + } + + @Override + public boolean propertyAdded(PropertyState after) { + added.add(after); + return true; + } + + @Override + public boolean propertyChanged(PropertyState before, PropertyState after) { + changed.add(after); + return true; + } + + @Override + public boolean propertyDeleted(PropertyState before) { + deleted.add(before); + return true; + } + + @Override + public boolean childNodeAdded(String name, NodeState after) { + new SlingDiff(concat(path, name)) + .contentChanged(EmptyNodeState.EMPTY_NODE, after); + return true; + } + + @Override + public boolean childNodeChanged(String name, NodeState before, NodeState after) { + new SlingDiff(concat(path, name)) + .contentChanged(before, after); + return true; + } + + @Override + public boolean childNodeDeleted(String name, NodeState before) { + new SlingDiff(concat(path, name)) + .contentChanged(before, EmptyNodeState.EMPTY_NODE); + return true; + } + +} Index: oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/NodeStoreTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/NodeStoreTest.java (revision 181aaca44320997d57ab3115033440f3fb897d46) +++ oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/NodeStoreTest.java (revision ) @@ -173,6 +173,22 @@ } @Test + public void slingCommitHook() throws CommitFailedException { + // this test only works with a KernelNodeStore + assumeTrue(store instanceof KernelNodeStore); + ((KernelNodeStore) store).setObserver(new SlingDiff()); + + NodeBuilder root= store.getRoot().builder(); + NodeBuilder test = root.getChildNode("test"); + NodeBuilder newNode = test.child("newNode").setProperty("n", 42); + test.getChildNode("x").remove(); + test.removeProperty("a"); + + store.merge(root, EmptyHook.INSTANCE, null); + NodeState newRoot = store.getRoot(); // triggers the observer + } + + @Test public void beforeCommitHook() throws CommitFailedException { NodeState root = store.getRoot(); NodeBuilder rootBuilder = root.builder();