]> git.argeo.org Git - gpl/argeo-slc.git/blobdiff - runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/RepoSync.java
Some more UI functionalities :
[gpl/argeo-slc.git] / runtime / org.argeo.slc.repo / src / main / java / org / argeo / slc / repo / RepoSync.java
index 3bcea12283a703bfc2a2d53f31ecf30d30e2f2b0..eaddaf690adcf5b80e799cb1da739eacb917c7f9 100644 (file)
  */
 package org.argeo.slc.repo;
 
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Calendar;
 import java.util.GregorianCalendar;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.TimeZone;
 
@@ -33,9 +36,12 @@ import javax.jcr.RepositoryFactory;
 import javax.jcr.Session;
 import javax.jcr.SimpleCredentials;
 import javax.jcr.nodetype.NodeType;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryResult;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.argeo.ArgeoMonitor;
 import org.argeo.jcr.ArgeoJcrUtils;
 import org.argeo.jcr.JcrUtils;
 import org.argeo.slc.SlcException;
@@ -46,56 +52,104 @@ import org.xml.sax.SAXException;
 public class RepoSync implements Runnable {
        private final static Log log = LogFactory.getLog(RepoSync.class);
 
-       private final Calendar zero;
+       // Centralizes definition of workspaces that must be ignored by the sync.
+       private final static List<String> IGNORED_WSKP_LIST = Arrays.asList(
+                       "security", "localrepo");
 
-       private String sourceRepo;
-       private String targetRepo;
+       private final Calendar zero;
+       private Session sourceDefaultSession = null;
+       private Session targetDefaultSession = null;
 
-       private String sourceWksp;
+       private Repository sourceRepository;
+       private Credentials sourceCredentials;
+       private Repository targetRepository;
+       private Credentials targetCredentials;
 
+       // if Repository and Credentials objects are not explicitly set
+       private String sourceRepoUri;
        private String sourceUsername;
        private char[] sourcePassword;
+       private String targetRepoUri;
        private String targetUsername;
        private char[] targetPassword;
 
        private RepositoryFactory repositoryFactory;
 
+       private ArgeoMonitor monitor;
+       private List<String> sourceWkspList;
+
        public RepoSync() {
                zero = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
                zero.setTimeInMillis(0);
        }
 
+       /**
+        * 
+        * Shortcut to instantiate a RepoSync with already known repositories and
+        * credentials.
+        * 
+        * @param sourceRepository
+        * @param sourceCredentials
+        * @param targetRepository
+        * @param targetCredentials
+        */
+       public RepoSync(Repository sourceRepository, Credentials sourceCredentials,
+                       Repository targetRepository, Credentials targetCredentials) {
+               this();
+               this.sourceRepository = sourceRepository;
+               this.sourceCredentials = sourceCredentials;
+               this.targetRepository = targetRepository;
+               this.targetCredentials = targetCredentials;
+       }
+
        public void run() {
-               Session sourceDefaultSession = null;
-               Session targetDefaultSession = null;
                try {
                        long begin = System.currentTimeMillis();
 
-                       Repository sourceRepository = ArgeoJcrUtils.getRepositoryByUri(
-                                       repositoryFactory, sourceRepo);
-                       Repository targetRepository = ArgeoJcrUtils.getRepositoryByUri(
-                                       repositoryFactory, targetRepo);
-                       Credentials sourceCredentials = null;
-                       if (sourceUsername != null)
+                       // Setup
+                       if (sourceRepository == null)
+                               sourceRepository = ArgeoJcrUtils.getRepositoryByUri(
+                                               repositoryFactory, sourceRepoUri);
+                       if (sourceCredentials == null && sourceUsername != null)
                                sourceCredentials = new SimpleCredentials(sourceUsername,
                                                sourcePassword);
-                       Credentials targetCredentials = null;
-                       if (targetUsername != null)
+                       sourceDefaultSession = sourceRepository.login(sourceCredentials);
+
+                       if (targetRepository == null)
+                               targetRepository = ArgeoJcrUtils.getRepositoryByUri(
+                                               repositoryFactory, targetRepoUri);
+                       if (targetCredentials == null && targetUsername != null)
                                targetCredentials = new SimpleCredentials(targetUsername,
                                                targetPassword);
+                       targetDefaultSession = targetRepository.login(targetCredentials);
+
+                       // Compute job size
+                       if (monitor != null) {
+                               Long totalAmount = 0l;
+                               if (sourceWkspList != null) {
+                                       for (String wkspName : sourceWkspList) {
+                                               totalAmount += getNodesNumber(wkspName);
+                                       }
+                               } else
+                                       for (String sourceWorkspaceName : sourceDefaultSession
+                                                       .getWorkspace().getAccessibleWorkspaceNames()) {
+                                               totalAmount += getNodesNumber(sourceWorkspaceName);
+                                       }
+                               monitor.beginTask("Fetch", totalAmount.intValue());
+                               if (log.isDebugEnabled())
+                                       log.debug("Nb of nodes to sync: " + totalAmount.intValue());
+                       }
 
                        Map<String, Exception> errors = new HashMap<String, Exception>();
-                       sourceDefaultSession = sourceRepository.login(sourceCredentials);
-                       targetDefaultSession = targetRepository.login(targetCredentials);
                        for (String sourceWorkspaceName : sourceDefaultSession
                                        .getWorkspace().getAccessibleWorkspaceNames()) {
-                               if (sourceWksp != null && !sourceWksp.trim().equals("")
-                                               && !sourceWorkspaceName.equals(sourceWksp))
-                                       continue;
-                               if (sourceWorkspaceName.equals("security"))
+
+                               if (sourceWkspList != null
+                                               && !sourceWkspList.contains(sourceWorkspaceName))
                                        continue;
-                               if (sourceWorkspaceName.equals("localrepo"))
+                               if (IGNORED_WSKP_LIST.contains(sourceWorkspaceName))
                                        continue;
+
                                Session sourceSession = null;
                                Session targetSession = null;
                                try {
@@ -114,23 +168,19 @@ public class RepoSync implements Runnable {
                                } catch (Exception e) {
                                        errors.put("Could not sync workspace "
                                                        + sourceWorkspaceName, e);
+                                       if (log.isDebugEnabled())
+                                               e.printStackTrace();
                                } 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);
+
+                       if (monitor != null && monitor.isCanceled())
+                               log.info("Sync has been canceled by user");
 
                        long duration = (System.currentTimeMillis() - begin) / 1000;// s
-                       log.info("Sync " + sourceRepo + " to " + targetRepo + " in "
+                       log.info("Sync " + sourceRepoUri + " to " + targetRepoUri + " in "
                                        + (duration / 60)
 
                                        + "min " + (duration % 60) + "s");
@@ -139,33 +189,49 @@ public class RepoSync implements Runnable {
                                throw new SlcException("Sync failed " + errors);
                        }
                } catch (RepositoryException e) {
-                       throw new SlcException("Cannot sync " + sourceRepo + " to "
-                                       + targetRepo, e);
+                       throw new SlcException("Cannot sync " + sourceRepoUri + " to "
+                                       + targetRepoUri, e);
                } finally {
                        JcrUtils.logoutQuietly(sourceDefaultSession);
                        JcrUtils.logoutQuietly(targetDefaultSession);
                }
        }
 
+       private long getNodesNumber(String wkspName) {
+               if (IGNORED_WSKP_LIST.contains(wkspName))
+                       return 0l;
+               Session sourceSession = null;
+               try {
+                       sourceSession = sourceRepository.login(sourceCredentials, wkspName);
+                       Query countQuery = sourceDefaultSession
+                                       .getWorkspace()
+                                       .getQueryManager()
+                                       .createQuery("select file from [nt:base] as file",
+                                                       Query.JCR_SQL2);
+                       QueryResult result = countQuery.execute();
+                       Long expectedCount = result.getNodes().getSize();
+                       return expectedCount;
+               } catch (RepositoryException e) {
+                       throw new SlcException("Unexpected error while computing "
+                                       + "the size of the fetch for workspace " + wkspName, e);
+               } finally {
+                       JcrUtils.logoutQuietly(sourceSession);
+               }
+       }
+
        protected void syncWorkspace(Session sourceSession, Session targetSession) {
                try {
+                       String msg = "Synchronizing workspace: "
+                                       + sourceSession.getWorkspace().getName();
+                       if (monitor != null)
+                               monitor.setTaskName(msg);
                        if (log.isDebugEnabled())
-                               log.debug("Syncing " + sourceSession.getWorkspace().getName()
-                                               + "...");
+                               log.debug(msg);
                        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())
@@ -177,8 +243,25 @@ public class RepoSync implements Runnable {
                }
        }
 
+       /** factorizes monitor management */
+       private void updateMonitor(String msg) {
+               if (monitor != null) {
+                       monitor.worked(1);
+                       monitor.subTask(msg);
+               }
+       }
+
        protected void syncNode(Node sourceNode, Node targetParentNode)
                        throws RepositoryException, SAXException {
+
+               // enable cancelation of the current fetch process
+               // FIXME insure the repository stays in a stable state
+               if (monitor != null && monitor.isCanceled()) {
+                       updateMonitor("Fetched has been canceled, "
+                                       + "process is terminating");
+                       return;
+               }
+
                Boolean noRecurse = noRecurse(sourceNode);
                Calendar sourceLastModified = null;
                if (sourceNode.isNodeType(NodeType.MIX_LAST_MODIFIED)) {
@@ -187,6 +270,10 @@ public class RepoSync implements Runnable {
                }
 
                if (!targetParentNode.hasNode(sourceNode.getName())) {
+                       String msg = "Adding " + sourceNode.getPath();
+                       updateMonitor(msg);
+                       if (log.isDebugEnabled())
+                               log.debug(msg);
                        ContentHandler contentHandler = targetParentNode
                                        .getSession()
                                        .getWorkspace()
@@ -194,8 +281,6 @@ public class RepoSync implements Runnable {
                                                        ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW);
                        sourceNode.getSession().exportSystemView(sourceNode.getPath(),
                                        contentHandler, false, noRecurse);
-                       if (log.isDebugEnabled())
-                               log.debug("Added " + sourceNode.getPath());
                } else {
                        Node targetNode = targetParentNode.getNode(sourceNode.getName());
                        if (sourceLastModified != null) {
@@ -207,6 +292,10 @@ public class RepoSync implements Runnable {
 
                                if (targetLastModified == null
                                                || targetLastModified.before(sourceLastModified)) {
+                                       String msg = "Updating " + targetNode.getPath();
+                                       updateMonitor(msg);
+                                       if (log.isDebugEnabled())
+                                               log.debug(msg);
                                        ContentHandler contentHandler = targetParentNode
                                                        .getSession()
                                                        .getWorkspace()
@@ -216,12 +305,11 @@ public class RepoSync implements Runnable {
                                        sourceNode.getSession().exportSystemView(
                                                        sourceNode.getPath(), contentHandler, false,
                                                        noRecurse);
-                                       if (log.isDebugEnabled())
-                                               log.debug("Updated " + targetNode.getPath());
                                } else {
+                                       String msg = "Skipped up to date " + targetNode.getPath();
+                                       updateMonitor(msg);
                                        if (log.isDebugEnabled())
-                                               log.debug("Skipped up to date " + targetNode.getPath());
-                                       // if (!noRecurse)
+                                               log.debug(msg);
                                        return;
                                }
                        }
@@ -247,7 +335,6 @@ public class RepoSync implements Runnable {
                                targetNode.getSession().save();
                        }
                }
-
        }
 
        protected Boolean noRecurse(Node sourceNode) throws RepositoryException {
@@ -256,22 +343,43 @@ public class RepoSync implements Runnable {
                return true;
        }
 
-       public void setSourceRepo(String sourceRepo) {
-               this.sourceRepo = sourceRepo;
+       /** synchronise only one workspace retrieved by name */
+       public void setSourceWksp(String sourceWksp) {
+               if (sourceWksp != null && !sourceWksp.trim().equals("")) {
+                       List<String> list = new ArrayList<String>();
+                       list.add(sourceWksp);
+                       setSourceWkspList(list);
+               }
        }
 
-       public void setTargetRepo(String targetRepo) {
-               this.targetRepo = targetRepo;
+       /** synchronise a list workspace that will be retrieved by name */
+       public void setSourceWkspList(List<String> sourceWkspList) {
+               // clean the list to ease later use
+               this.sourceWkspList = null;
+               if (sourceWkspList != null) {
+                       for (String wkspName : sourceWkspList) {
+                               if (!wkspName.trim().equals("")) {
+                                       // only instantiate if needed
+                                       if (this.sourceWkspList == null)
+                                               this.sourceWkspList = new ArrayList<String>();
+                                       this.sourceWkspList.add(wkspName);
+                               }
+                       }
+               }
        }
 
-       public void setSourceWksp(String sourceWksp) {
-               this.sourceWksp = sourceWksp;
+       public void setMonitor(ArgeoMonitor monitor) {
+               this.monitor = monitor;
        }
 
        public void setRepositoryFactory(RepositoryFactory repositoryFactory) {
                this.repositoryFactory = repositoryFactory;
        }
 
+       public void setSourceRepoUri(String sourceRepoUri) {
+               this.sourceRepoUri = sourceRepoUri;
+       }
+
        public void setSourceUsername(String sourceUsername) {
                this.sourceUsername = sourceUsername;
        }
@@ -280,6 +388,10 @@ public class RepoSync implements Runnable {
                this.sourcePassword = sourcePassword;
        }
 
+       public void setTargetRepoUri(String targetRepoUri) {
+               this.targetRepoUri = targetRepoUri;
+       }
+
        public void setTargetUsername(String targetUsername) {
                this.targetUsername = targetUsername;
        }
@@ -288,4 +400,19 @@ public class RepoSync implements Runnable {
                this.targetPassword = targetPassword;
        }
 
-}
+       public void setSourceRepository(Repository sourceRepository) {
+               this.sourceRepository = sourceRepository;
+       }
+
+       public void setSourceCredentials(Credentials sourceCredentials) {
+               this.sourceCredentials = sourceCredentials;
+       }
+
+       public void setTargetRepository(Repository targetRepository) {
+               this.targetRepository = targetRepository;
+       }
+
+       public void setTargetCredentials(Credentials targetCredentials) {
+               this.targetCredentials = targetCredentials;
+       }
+}
\ No newline at end of file