X-Git-Url: http://git.argeo.org/?a=blobdiff_plain;f=runtime%2Forg.argeo.slc.repo%2Fsrc%2Fmain%2Fjava%2Forg%2Fargeo%2Fslc%2Frepo%2FRepoSync.java;h=eaddaf690adcf5b80e799cb1da739eacb917c7f9;hb=5187ffaff5610275cf3dbc5fb913f59126576da8;hp=bdde722dea68934c2b8cbe28b1cb1842f03ff0e9;hpb=c00ca34d7115c3ff3288648af88c2395a26df228;p=gpl%2Fargeo-slc.git diff --git a/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/RepoSync.java b/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/RepoSync.java index bdde722de..eaddaf690 100644 --- a/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/RepoSync.java +++ b/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/RepoSync.java @@ -15,9 +15,12 @@ */ 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 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 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 errors = new HashMap(); - 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 list = new ArrayList(); + 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 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(); + 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; } @@ -279,4 +387,32 @@ public class RepoSync implements Runnable { public void setSourcePassword(char[] sourcePassword) { this.sourcePassword = sourcePassword; } -} + + public void setTargetRepoUri(String targetRepoUri) { + this.targetRepoUri = targetRepoUri; + } + + public void setTargetUsername(String targetUsername) { + this.targetUsername = targetUsername; + } + + public void setTargetPassword(char[] targetPassword) { + 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