Work on repo sync
authorMathieu Baudier <mbaudier@argeo.org>
Sun, 3 Feb 2013 17:37:14 +0000 (17:37 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Sun, 3 Feb 2013 17:37:14 +0000 (17:37 +0000)
git-svn-id: https://svn.argeo.org/slc/trunk@6068 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

demo/slc_demo_rcp.properties
lib/org.argeo.slc.lib.repo/META-INF/spring/main.xml [deleted file]
lib/org.argeo.slc.lib.repo/META-INF/spring/sync.xml [new file with mode: 0644]
runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/RepoSync.java

index 9ce3531661015cc8d4d7cbb0f59bce8017c6bd15..827ccca783c6395b8e1bf1b96b99b895878b2f59 100644 (file)
@@ -8,12 +8,7 @@ org.argeo.slc.agent.jcr,\
 org.argeo.slc.support.maven,\
 org.argeo.slc.server.repo,\
 
-argeo.osgi.start.5=org.argeo.server.catalina.start,\
-org.springframework.osgi.web.extender,\
-org.argeo.jackrabbit.webapp,\
-
-# Start internal web server
-#org.argeo.server.catalina.start,\
+#argeo.osgi.start.5=org.argeo.server.catalina.start,\
 #org.springframework.osgi.web.extender,\
 #org.argeo.jackrabbit.webapp,\
 
diff --git a/lib/org.argeo.slc.lib.repo/META-INF/spring/main.xml b/lib/org.argeo.slc.lib.repo/META-INF/spring/main.xml
deleted file mode 100644 (file)
index 25920c9..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>\r
-<beans xmlns:flow="http://www.argeo.org/schema/slc-flow" xmlns="http://www.springframework.org/schema/beans"\r
-       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"\r
-       xsi:schemaLocation="\r
-       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd\r
-       http://www.argeo.org/schema/slc-flow http://www.argeo.org/schema/slc-flow-1.2.xsd">\r
-\r
-       <!-- Hello world -->\r
-       <flow:flow name="sync">\r
-               <flow:spec>\r
-                       <flow:primitive name="sourceRepo"\r
-                               value="https://repo.argeo.org/org.argeo.jcr.webapp/remoting/java" />\r
-                       <flow:primitive name="sourceWksp" />\r
-                       <flow:primitive name="sourceUsername" value="${user.name}" />\r
-                       <flow:primitive name="sourcePassword" type="password"/>\r
-                       <flow:primitive name="targetRepo" value="vm:///java/" />\r
-               </flow:spec>\r
-               <bean class="org.argeo.slc.repo.RepoSync">\r
-                       <flow:variable proxy-target-class="false" />\r
-                       <property name="sourceRepo" value="@{sourceRepo}" />\r
-                       <property name="sourceWksp" value="@{sourceWksp}" />\r
-                       <property name="sourceUsername" value="@{sourceUsername}" />\r
-                       <property name="sourcePassword" value="@{sourcePassword}" />\r
-                       <property name="targetRepo" value="@{targetRepo}" />\r
-                       <property name="repositoryFactory" ref="repositoryFactory" />\r
-               </bean>\r
-       </flow:flow>\r
-\r
-</beans>
\ No newline at end of file
diff --git a/lib/org.argeo.slc.lib.repo/META-INF/spring/sync.xml b/lib/org.argeo.slc.lib.repo/META-INF/spring/sync.xml
new file mode 100644 (file)
index 0000000..34e0d47
--- /dev/null
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<beans xmlns:flow="http://www.argeo.org/schema/slc-flow" xmlns="http://www.springframework.org/schema/beans"\r
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"\r
+       xsi:schemaLocation="\r
+       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd\r
+       http://www.argeo.org/schema/slc-flow http://www.argeo.org/schema/slc-flow-1.2.xsd">\r
+\r
+       <!-- Hello world -->\r
+       <flow:flow name="sync">\r
+               <flow:spec>\r
+                       <flow:primitive name="sourceRepo"\r
+                               value="http://repo.argeo.org/data/pub/java" />\r
+                       <flow:primitive name="sourceWksp" value="" />\r
+                       <flow:primitive name="sourceUsername" value="${user.name}" />\r
+                       <flow:primitive name="sourcePassword" type="password"\r
+                               value="" />\r
+                       <flow:primitive name="targetRepo" value="vm:///java/" />\r
+               </flow:spec>\r
+               <bean class="org.argeo.slc.repo.RepoSync">\r
+                       <flow:variable proxy-target-class="false" />\r
+                       <property name="sourceRepo" value="@{sourceRepo}" />\r
+                       <property name="sourceWksp" value="@{sourceWksp}" />\r
+                       <property name="sourceUsername" value="@{sourceUsername}" />\r
+                       <property name="sourcePassword" value="@{sourcePassword}" />\r
+                       <property name="targetRepo" value="@{targetRepo}" />\r
+                       <property name="repositoryFactory" ref="repositoryFactory" />\r
+               </bean>\r
+       </flow:flow>\r
+\r
+</beans>
\ No newline at end of file
index 7de3e40c11c4bb2b02c108c050371d31ec6f7d94..4f8e924f4cb31a9fd70303b3cc1e823faf277695 100644 (file)
  */
 package org.argeo.slc.repo;
 
+import java.util.Calendar;
+
 import javax.jcr.Credentials;
+import javax.jcr.ImportUUIDBehavior;
+import javax.jcr.NoSuchWorkspaceException;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Property;
 import javax.jcr.Repository;
 import javax.jcr.RepositoryException;
 import javax.jcr.RepositoryFactory;
 import javax.jcr.Session;
 import javax.jcr.SimpleCredentials;
+import javax.jcr.nodetype.NodeType;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.argeo.jcr.ArgeoJcrUtils;
 import org.argeo.jcr.JcrUtils;
 import org.argeo.slc.SlcException;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
 
 /** Sync to from software repositories */
 public class RepoSync implements Runnable {
@@ -43,6 +53,8 @@ public class RepoSync implements Runnable {
        private RepositoryFactory repositoryFactory;
 
        public void run() {
+               Session sourceDefaultSession = null;
+               Session targetDefaultSession = null;
                try {
                        long begin = System.currentTimeMillis();
 
@@ -54,27 +66,146 @@ public class RepoSync implements Runnable {
                        if (sourceUsername != null)
                                sourceCredentials = new SimpleCredentials(sourceUsername,
                                                sourcePassword);
-                       Session sourceSession = sourceRepository.login(sourceCredentials,
-                                       sourceWksp);
-
                        Credentials targetCredentials = null;
-                       Session targetSession = targetRepository.login(targetCredentials,
-                                       sourceWksp);
-
-                       Long count = JcrUtils.copyFiles(sourceSession.getRootNode(),
-                                       targetSession.getRootNode(), true, null);
 
-                       long duration = (System.currentTimeMillis() - begin) / 1000;// in
-                       // s
-                       if (log.isDebugEnabled())
-                               log.debug("Copied " + count + " files in " + (duration / 60)
-                                               + "min " + (duration % 60) + "s");
+                       sourceDefaultSession = sourceRepository.login(sourceCredentials);
+                       targetDefaultSession = targetRepository.login(targetCredentials);
+                       for (String sourceWorkspaceName : sourceDefaultSession
+                                       .getWorkspace().getAccessibleWorkspaceNames()) {
+                               Session sourceSession = null;
+                               Session targetSession = null;
+                               try {
+                                       try {
+                                               targetSession = targetRepository.login(
+                                                               targetCredentials, sourceWorkspaceName);
+                                       } catch (NoSuchWorkspaceException e) {
+                                               targetDefaultSession.getWorkspace().createWorkspace(
+                                                               sourceWorkspaceName);
+                                               targetSession = targetRepository.login(
+                                                               targetCredentials, sourceWorkspaceName);
+                                       }
+                                       sourceSession = sourceRepository.login(sourceCredentials,
+                                                       sourceWorkspaceName);
+                                       syncWorkspace(sourceSession, targetSession);
+                               } finally {
+                                       JcrUtils.logoutQuietly(sourceSession);
+                                       JcrUtils.logoutQuietly(targetSession);
+                               }
+                       }
+                       // Session sourceSession = sourceRepository.login(sourceCredentials,
+                       // sourceWksp);
+                       //
+                       // Credentials targetCredentials = null;
+                       // Session targetSession = targetRepository.login(targetCredentials,
+                       // sourceWksp);
+                       //
+                       // Long count = JcrUtils.copyFiles(sourceSession.getRootNode(),
+                       // targetSession.getRootNode(), true, null);
+
+                       long duration = (System.currentTimeMillis() - begin) / 1000;// s
+                       log.info("Sync " + sourceRepo + " to " + targetRepo + " in "
+                                       + (duration / 60)
+
+                                       + "min " + (duration % 60) + "s");
                } catch (RepositoryException e) {
                        throw new SlcException("Cannot sync " + sourceRepo + " to "
                                        + targetRepo, e);
+               } finally {
+                       JcrUtils.logoutQuietly(sourceDefaultSession);
+                       JcrUtils.logoutQuietly(targetDefaultSession);
+               }
+       }
+
+       protected void syncWorkspace(Session sourceSession, Session targetSession) {
+               try {
+                       if (log.isDebugEnabled())
+                               log.debug("Syncing " + sourceSession.getWorkspace().getName()
+                                               + "...");
+                       for (NodeIterator it = sourceSession.getRootNode().getNodes(); it
+                                       .hasNext();) {
+                               Node node = it.nextNode();
+                               if (node.getName().equals("jcr:system"))
+                                       continue;
+                               // ContentHandler targetHandler = targetSession
+                               // .getWorkspace()
+                               // .getImportContentHandler(
+                               // "/",
+                               // ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING);
+                               // sourceSession.exportSystemView(node.getPath(), targetHandler,
+                               // true, false);
+                               // if (log.isDebugEnabled())
+                               // log.debug(" " + node.getPath());
+                               syncNode(node, targetSession.getRootNode());
+                       }
+                       if (log.isDebugEnabled())
+                               log.debug("Synced " + sourceSession.getWorkspace().getName());
+               } catch (Exception e) {
+                       throw new SlcException("Cannot sync "
+                                       + sourceSession.getWorkspace().getName() + " to "
+                                       + targetSession.getWorkspace().getName(), e);
                }
        }
 
+       protected void syncNode(Node sourceNode, Node targetParentNode)
+                       throws RepositoryException, SAXException {
+               Boolean noRecurse = noRecurse(sourceNode);
+               if (!targetParentNode.hasNode(sourceNode.getName())) {
+                       ContentHandler contentHandler = targetParentNode
+                                       .getSession()
+                                       .getWorkspace()
+                                       .getImportContentHandler(targetParentNode.getPath(),
+                                                       ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW);
+                       sourceNode.getSession().exportSystemView(sourceNode.getPath(),
+                                       contentHandler, false, noRecurse);
+                       if (log.isDebugEnabled())
+                               log.debug("Add " + sourceNode.getPath());
+               } else {
+                       Node targetNode = targetParentNode.getNode(sourceNode.getName());
+                       if (sourceNode.isNodeType(NodeType.MIX_LAST_MODIFIED)) {
+                               Calendar sourceLastModified = sourceNode.getProperty(
+                                               Property.JCR_LAST_MODIFIED).getDate();
+                               Calendar targetLastModified = null;
+                               if (targetNode.isNodeType(NodeType.MIX_LAST_MODIFIED)) {
+                                       targetLastModified = targetNode.getProperty(
+                                                       Property.JCR_LAST_MODIFIED).getDate();
+                               }
+
+                               if (targetLastModified == null
+                                               || targetLastModified.before(sourceLastModified)) {
+                                       ContentHandler contentHandler = targetParentNode
+                                                       .getSession()
+                                                       .getWorkspace()
+                                                       .getImportContentHandler(
+                                                                       targetParentNode.getPath(),
+                                                                       ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING);
+                                       sourceNode.getSession().exportSystemView(
+                                                       sourceNode.getPath(), contentHandler, false,
+                                                       noRecurse);
+                                       if (log.isDebugEnabled())
+                                               log.debug("Update " + targetNode.getPath());
+                               } else {
+                                       if (log.isDebugEnabled())
+                                               log.debug("Skip up to date " + targetNode.getPath());
+                               }
+                       }
+               }
+
+               if (noRecurse) {
+                       // recurse
+                       Node targetNode = targetParentNode.getNode(sourceNode.getName());
+                       for (NodeIterator it = sourceNode.getNodes(); it.hasNext();) {
+                               syncNode(it.nextNode(), targetNode);
+                       }
+               }
+
+       }
+
+       protected Boolean noRecurse(Node sourceNode) throws RepositoryException {
+               if (sourceNode.isNodeType(NodeType.NT_FILE))
+                       return false;
+               return true;
+       }
+
        public void setSourceRepo(String sourceRepo) {
                this.sourceRepo = sourceRepo;
        }
@@ -98,5 +229,4 @@ public class RepoSync implements Runnable {
        public void setSourcePassword(char[] sourcePassword) {
                this.sourcePassword = sourcePassword;
        }
-
 }