Return-Path: X-Original-To: apmail-jackrabbit-commits-archive@www.apache.org Delivered-To: apmail-jackrabbit-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 0362E9A1F for ; Mon, 13 Feb 2012 09:59:00 +0000 (UTC) Received: (qmail 89061 invoked by uid 500); 13 Feb 2012 09:58:59 -0000 Delivered-To: apmail-jackrabbit-commits-archive@jackrabbit.apache.org Received: (qmail 88997 invoked by uid 500); 13 Feb 2012 09:58:54 -0000 Mailing-List: contact commits-help@jackrabbit.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@jackrabbit.apache.org Delivered-To: mailing list commits@jackrabbit.apache.org Received: (qmail 88982 invoked by uid 99); 13 Feb 2012 09:58:51 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 13 Feb 2012 09:58:51 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 13 Feb 2012 09:58:47 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 478E223888E4; Mon, 13 Feb 2012 09:58:26 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: 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 Date: Mon, 13 Feb 2012 09:58:26 -0000 To: commits@jackrabbit.apache.org From: thomasm@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20120213095826.478E223888E4@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org 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. + *

+ * 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(); + + } + +}