You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by th...@apache.org on 2012/02/13 10:58:26 UTC
svn commit: r1243459 - in /jackrabbit/sandbox/microkernel/src:
main/java/org/apache/jackrabbit/mk/util/Sync.java
test/java/org/apache/jackrabbit/mk/util/SyncTest.java
Author: thomasm
Date: Mon Feb 13 09:58:25 2012
New Revision: 1243459
URL: http://svn.apache.org/viewvc?rev=1243459&view=rev
Log:
Sync utility.
Added:
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/Sync.java
jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/util/SyncTest.java
Added: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/Sync.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/Sync.java?rev=1243459&view=auto
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/Sync.java (added)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/Sync.java Mon Feb 13 09:58:25 2012
@@ -0,0 +1,160 @@
+/*
+ * 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.mk.util;
+
+import org.apache.jackrabbit.mk.api.MicroKernel;
+import org.apache.jackrabbit.mk.mem.NodeImpl;
+
+/**
+ * Traverse the nodes in two repositories / revisions / nodes in order to
+ * synchronize them or list the differences.
+ * <p>
+ * If the target is not set, the tool can be used to list or backup the content,
+ * for (data store) garbage collection, or similar.
+ */
+public class Sync {
+
+ private MicroKernel sourceMk, targetMk;
+ private String sourceRev, targetRev;
+ private String sourcePath, targetPath = "/";
+
+ private Handler handler;
+
+ /**
+ * Set the source (required).
+ *
+ * @param mk the source
+ * @param rev the revision
+ * @param path the path
+ */
+ public void setSource(MicroKernel mk, String rev, String path) {
+ sourceMk = mk;
+ sourceRev = rev;
+ sourcePath = path;
+ }
+
+ /**
+ * Set the target (optional). If not set, the tool assumes no nodes exist on
+ * the target.
+ *
+ * @param mk the target
+ * @param rev the revision
+ * @param path the path
+ */
+
+ public void setTarget(MicroKernel mk, String rev, String path) {
+ targetMk = mk;
+ targetRev = rev;
+ targetPath = path;
+ }
+
+ public void run(Handler handler) {
+ this.handler = handler;
+ visit("");
+ }
+
+ public void visit(String relPath) {
+ String source = PathUtils.concat(sourcePath, relPath);
+ String target = PathUtils.concat(targetPath, relPath);
+ NodeImpl s = null, t = null;
+ // TODO support large child node lists
+ if (sourceMk.nodeExists(source, sourceRev)) {
+ s = NodeImpl.parse(sourceMk.getNodes(source, sourceRev, 0, 0, Integer.MAX_VALUE));
+ }
+ if (targetMk != null && targetMk.nodeExists(target, targetRev)) {
+ t = NodeImpl.parse(targetMk.getNodes(target, targetRev, 0, 0, Integer.MAX_VALUE));
+ }
+ if (s == null || t == null) {
+ if (s == t) {
+ // both don't exist - ok
+ return;
+ } else if (s == null) {
+ handler.removeNode(target);
+ return;
+ } else {
+ if (!PathUtils.denotesRoot(target)) {
+ handler.addNode(target);
+ }
+ }
+ }
+ // properties
+ for (int i = 0; i < s.getPropertyCount(); i++) {
+ String name = s.getProperty(i);
+ String sourceValue = s.getPropertyValue(i);
+ String targetValue = t != null && t.hasProperty(name) ? t.getProperty(name) : null;
+ if (!sourceValue.equals(targetValue)) {
+ handler.setProperty(target, name, sourceValue);
+ }
+ }
+ for (int i = 0; t != null && i < t.getPropertyCount(); i++) {
+ String name = t.getProperty(i);
+ // if it exists in the source, it's already updated
+ if (!s.hasProperty(name)) {
+ handler.setProperty(target, name, null);
+ }
+ }
+ // child nodes
+ for (int i = 0;; i++) {
+ String name = s.getChildNodeName(i);
+ if (name == null) {
+ break;
+ }
+ visit(PathUtils.concat(relPath, name));
+ }
+ for (int i = 0; t != null; i++) {
+ String name = t.getChildNodeName(i);
+ if (name == null) {
+ break;
+ }
+ // if it exists in the source, it's already updated
+ if (!s.exists(name)) {
+ visit(PathUtils.concat(relPath, name));
+ }
+ }
+ }
+
+ /**
+ * The sync handler.
+ */
+ public interface Handler {
+
+ /**
+ * The given node needs to be added to the target.
+ *
+ * @param path the path
+ */
+ void addNode(String path);
+
+ /**
+ * The given node needs to be removed from the target.
+ *
+ * @param path the path
+ */
+ void removeNode(String target);
+
+ /**
+ * The given property needs to be set on the target.
+ *
+ * @param path the path
+ * @param property the property name
+ * @param value the new value, or null to remove it
+ */
+ void setProperty(String target, String property, String value);
+
+ }
+
+}
Added: jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/util/SyncTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/util/SyncTest.java?rev=1243459&view=auto
==============================================================================
--- jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/util/SyncTest.java (added)
+++ jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/util/SyncTest.java Mon Feb 13 09:58:25 2012
@@ -0,0 +1,103 @@
+/*
+ * 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.mk.util;
+
+import static org.junit.Assert.assertEquals;
+import org.apache.jackrabbit.mk.MultiMkTestBase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+/**
+ * Test the sync util.
+ */
+@RunWith(Parameterized.class)
+public class SyncTest extends MultiMkTestBase {
+
+ public SyncTest(String url) {
+ super(url);
+ }
+
+ @Test
+ public void test() {
+ mk.commit("/", "+ \"source\": { \"id\": 1, \"plus\": 0, \"a\": { \"x\": 10, \"y\": 20 }, \"b\": {\"z\": 100}, \"d\":{} }", mk.getHeadRevision(), "");
+ Sync sync = new Sync();
+ String head = mk.getHeadRevision();
+ sync.setSource(mk, head, "/");
+ String diff = syncToString(sync);
+ assertEquals(
+ "add /source\n" +
+ "setProperty /source id=1\n" +
+ "setProperty /source plus=0\n" +
+ "add /source/a\n" +
+ "setProperty /source/a x=10\n" +
+ "setProperty /source/a y=20\n" +
+ "add /source/b\n" +
+ "setProperty /source/b z=100\n" +
+ "add /source/d\n",
+ diff);
+
+ mk.commit("/", "+ \"target\": { \"id\": 2, \"minus\": 0, \"a\": { \"x\": 10 }, \"c\": {} }", mk.getHeadRevision(), "");
+ head = mk.getHeadRevision();
+ sync.setSource(mk, head, "/source");
+ sync.setTarget(mk, head, "/target");
+ diff = syncToString(sync);
+ assertEquals(
+ "setProperty /target id=1\n" +
+ "setProperty /target plus=0\n" +
+ "setProperty /target minus=null\n" +
+ "setProperty /target/a y=20\n" +
+ "add /target/b\n" +
+ "setProperty /target/b z=100\n" +
+ "add /target/d\n" +
+ "remove /target/c\n", diff);
+
+ sync.setSource(mk, head, "/notExist");
+ sync.setTarget(mk, head, "/target");
+ diff = syncToString(sync);
+ assertEquals(
+ "remove /target\n", diff);
+
+ sync.setSource(mk, head, "/notExist");
+ sync.setTarget(mk, head, "/notExist2");
+ diff = syncToString(sync);
+ assertEquals("", diff);
+
+ }
+
+ private static String syncToString(Sync sync) {
+ final StringBuilder buff = new StringBuilder();
+ sync.run(new Sync.Handler() {
+
+ @Override
+ public void addNode(String targetPath) {
+ buff.append("add ").append(targetPath).append('\n');
+ }
+
+ @Override
+ public void removeNode(String targetPath) {
+ buff.append("remove ").append(targetPath).append('\n');
+ }
+
+ @Override
+ public void setProperty(String targetPath, String property, String value) {
+ buff.append("setProperty ").append(targetPath).append(' ').
+ append(property).append('=').append(value).append('\n');
+ }
+ });
+ return buff.toString();
+
+ }
+
+}