]> git.argeo.org Git - gpl/argeo-slc.git/blob - runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/RepoSync.java
Sync repos
[gpl/argeo-slc.git] / runtime / org.argeo.slc.repo / src / main / java / org / argeo / slc / repo / RepoSync.java
1 /*
2 * Copyright (C) 2007-2012 Argeo GmbH
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.argeo.slc.repo;
17
18 import java.util.Calendar;
19 import java.util.GregorianCalendar;
20 import java.util.HashMap;
21 import java.util.Map;
22 import java.util.TimeZone;
23
24 import javax.jcr.Credentials;
25 import javax.jcr.ImportUUIDBehavior;
26 import javax.jcr.NoSuchWorkspaceException;
27 import javax.jcr.Node;
28 import javax.jcr.NodeIterator;
29 import javax.jcr.Property;
30 import javax.jcr.Repository;
31 import javax.jcr.RepositoryException;
32 import javax.jcr.RepositoryFactory;
33 import javax.jcr.Session;
34 import javax.jcr.SimpleCredentials;
35 import javax.jcr.nodetype.NodeType;
36
37 import org.apache.commons.logging.Log;
38 import org.apache.commons.logging.LogFactory;
39 import org.argeo.jcr.ArgeoJcrUtils;
40 import org.argeo.jcr.JcrUtils;
41 import org.argeo.slc.SlcException;
42 import org.xml.sax.ContentHandler;
43 import org.xml.sax.SAXException;
44
45 /** Sync to from software repositories */
46 public class RepoSync implements Runnable {
47 private final static Log log = LogFactory.getLog(RepoSync.class);
48
49 private final Calendar zero;
50
51 private String sourceRepo;
52 private String targetRepo;
53
54 private String sourceWksp;
55
56 private String sourceUsername;
57 private char[] sourcePassword;
58 private String targetUsername;
59 private char[] targetPassword;
60
61 private RepositoryFactory repositoryFactory;
62
63 public RepoSync() {
64 zero = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
65 zero.setTimeInMillis(0);
66 }
67
68 public void run() {
69 Session sourceDefaultSession = null;
70 Session targetDefaultSession = null;
71 try {
72 long begin = System.currentTimeMillis();
73
74 Repository sourceRepository = ArgeoJcrUtils.getRepositoryByUri(
75 repositoryFactory, sourceRepo);
76 Repository targetRepository = ArgeoJcrUtils.getRepositoryByUri(
77 repositoryFactory, targetRepo);
78 Credentials sourceCredentials = null;
79 if (sourceUsername != null)
80 sourceCredentials = new SimpleCredentials(sourceUsername,
81 sourcePassword);
82 Credentials targetCredentials = null;
83 if (targetUsername != null)
84 targetCredentials = new SimpleCredentials(targetUsername,
85 targetPassword);
86
87 Map<String, Exception> errors = new HashMap<String, Exception>();
88 sourceDefaultSession = sourceRepository.login(sourceCredentials);
89 targetDefaultSession = targetRepository.login(targetCredentials);
90 for (String sourceWorkspaceName : sourceDefaultSession
91 .getWorkspace().getAccessibleWorkspaceNames()) {
92 if (sourceWksp != null && !sourceWksp.trim().equals("")
93 && !sourceWorkspaceName.equals(sourceWksp))
94 continue;
95 if (sourceWorkspaceName.equals("security"))
96 continue;
97 if (sourceWorkspaceName.equals("localrepo"))
98 continue;
99 Session sourceSession = null;
100 Session targetSession = null;
101 try {
102 try {
103 targetSession = targetRepository.login(
104 targetCredentials, sourceWorkspaceName);
105 } catch (NoSuchWorkspaceException e) {
106 targetDefaultSession.getWorkspace().createWorkspace(
107 sourceWorkspaceName);
108 targetSession = targetRepository.login(
109 targetCredentials, sourceWorkspaceName);
110 }
111 sourceSession = sourceRepository.login(sourceCredentials,
112 sourceWorkspaceName);
113 syncWorkspace(sourceSession, targetSession);
114 } catch (Exception e) {
115 errors.put("Could not sync workspace "
116 + sourceWorkspaceName, e);
117 } finally {
118 JcrUtils.logoutQuietly(sourceSession);
119 JcrUtils.logoutQuietly(targetSession);
120 }
121 }
122 // Session sourceSession = sourceRepository.login(sourceCredentials,
123 // sourceWksp);
124 //
125 // Credentials targetCredentials = null;
126 // Session targetSession = targetRepository.login(targetCredentials,
127 // sourceWksp);
128 //
129 // Long count = JcrUtils.copyFiles(sourceSession.getRootNode(),
130 // targetSession.getRootNode(), true, null);
131
132 long duration = (System.currentTimeMillis() - begin) / 1000;// s
133 log.info("Sync " + sourceRepo + " to " + targetRepo + " in "
134 + (duration / 60)
135
136 + "min " + (duration % 60) + "s");
137
138 if (errors.size() > 0) {
139 throw new SlcException("Sync failed " + errors);
140 }
141 } catch (RepositoryException e) {
142 throw new SlcException("Cannot sync " + sourceRepo + " to "
143 + targetRepo, e);
144 } finally {
145 JcrUtils.logoutQuietly(sourceDefaultSession);
146 JcrUtils.logoutQuietly(targetDefaultSession);
147 }
148 }
149
150 protected void syncWorkspace(Session sourceSession, Session targetSession) {
151 try {
152 if (log.isDebugEnabled())
153 log.debug("Syncing " + sourceSession.getWorkspace().getName()
154 + "...");
155 for (NodeIterator it = sourceSession.getRootNode().getNodes(); it
156 .hasNext();) {
157 Node node = it.nextNode();
158 if (node.getName().equals("jcr:system"))
159 continue;
160 // ContentHandler targetHandler = targetSession
161 // .getWorkspace()
162 // .getImportContentHandler(
163 // "/",
164 // ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING);
165 // sourceSession.exportSystemView(node.getPath(), targetHandler,
166 // true, false);
167 // if (log.isDebugEnabled())
168 // log.debug(" " + node.getPath());
169 syncNode(node, targetSession.getRootNode());
170 }
171 if (log.isDebugEnabled())
172 log.debug("Synced " + sourceSession.getWorkspace().getName());
173 } catch (Exception e) {
174 throw new SlcException("Cannot sync "
175 + sourceSession.getWorkspace().getName() + " to "
176 + targetSession.getWorkspace().getName(), e);
177 }
178 }
179
180 protected void syncNode(Node sourceNode, Node targetParentNode)
181 throws RepositoryException, SAXException {
182 Boolean noRecurse = noRecurse(sourceNode);
183 Calendar sourceLastModified = null;
184 if (sourceNode.isNodeType(NodeType.MIX_LAST_MODIFIED)) {
185 sourceLastModified = sourceNode.getProperty(
186 Property.JCR_LAST_MODIFIED).getDate();
187 }
188
189 if (!targetParentNode.hasNode(sourceNode.getName())) {
190 ContentHandler contentHandler = targetParentNode
191 .getSession()
192 .getWorkspace()
193 .getImportContentHandler(targetParentNode.getPath(),
194 ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW);
195 sourceNode.getSession().exportSystemView(sourceNode.getPath(),
196 contentHandler, false, noRecurse);
197 if (log.isDebugEnabled())
198 log.debug("Added " + sourceNode.getPath());
199 } else {
200 Node targetNode = targetParentNode.getNode(sourceNode.getName());
201 if (sourceLastModified != null) {
202 Calendar targetLastModified = null;
203 if (targetNode.isNodeType(NodeType.MIX_LAST_MODIFIED)) {
204 targetLastModified = targetNode.getProperty(
205 Property.JCR_LAST_MODIFIED).getDate();
206 }
207
208 if (targetLastModified == null
209 || targetLastModified.before(sourceLastModified)) {
210 ContentHandler contentHandler = targetParentNode
211 .getSession()
212 .getWorkspace()
213 .getImportContentHandler(
214 targetParentNode.getPath(),
215 ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING);
216 sourceNode.getSession().exportSystemView(
217 sourceNode.getPath(), contentHandler, false,
218 noRecurse);
219 if (log.isDebugEnabled())
220 log.debug("Updated " + targetNode.getPath());
221 } else {
222 if (log.isDebugEnabled())
223 log.debug("Skipped up to date " + targetNode.getPath());
224 // if (!noRecurse)
225 return;
226 }
227 }
228 }
229
230 if (noRecurse) {
231 // recurse
232 Node targetNode = targetParentNode.getNode(sourceNode.getName());
233 if (sourceLastModified != null) {
234 Calendar zero = new GregorianCalendar();
235 zero.setTimeInMillis(0);
236 targetNode.setProperty(Property.JCR_LAST_MODIFIED, zero);
237 targetNode.getSession().save();
238 }
239
240 for (NodeIterator it = sourceNode.getNodes(); it.hasNext();) {
241 syncNode(it.nextNode(), targetNode);
242 }
243
244 if (sourceLastModified != null) {
245 targetNode.setProperty(Property.JCR_LAST_MODIFIED,
246 sourceLastModified);
247 targetNode.getSession().save();
248 }
249 }
250
251 }
252
253 protected Boolean noRecurse(Node sourceNode) throws RepositoryException {
254 if (sourceNode.isNodeType(NodeType.NT_FILE))
255 return false;
256 return true;
257 }
258
259 public void setSourceRepo(String sourceRepo) {
260 this.sourceRepo = sourceRepo;
261 }
262
263 public void setTargetRepo(String targetRepo) {
264 this.targetRepo = targetRepo;
265 }
266
267 public void setSourceWksp(String sourceWksp) {
268 this.sourceWksp = sourceWksp;
269 }
270
271 public void setRepositoryFactory(RepositoryFactory repositoryFactory) {
272 this.repositoryFactory = repositoryFactory;
273 }
274
275 public void setSourceUsername(String sourceUsername) {
276 this.sourceUsername = sourceUsername;
277 }
278
279 public void setSourcePassword(char[] sourcePassword) {
280 this.sourcePassword = sourcePassword;
281 }
282 }