2 * Copyright (C) 2007-2012 Argeo GmbH
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package org
.argeo
.slc
.repo
;
18 import java
.util
.Calendar
;
19 import java
.util
.GregorianCalendar
;
20 import java
.util
.HashMap
;
22 import java
.util
.TimeZone
;
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
;
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
;
45 /** Sync to from software repositories */
46 public class RepoSync
implements Runnable
{
47 private final static Log log
= LogFactory
.getLog(RepoSync
.class);
49 private final Calendar zero
;
51 private String sourceRepo
;
52 private String targetRepo
;
54 private String sourceWksp
;
56 private String sourceUsername
;
57 private char[] sourcePassword
;
58 private String targetUsername
;
59 private char[] targetPassword
;
61 private RepositoryFactory repositoryFactory
;
64 zero
= new GregorianCalendar(TimeZone
.getTimeZone("UTC"));
65 zero
.setTimeInMillis(0);
69 Session sourceDefaultSession
= null;
70 Session targetDefaultSession
= null;
72 long begin
= System
.currentTimeMillis();
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
,
82 Credentials targetCredentials
= null;
83 if (targetUsername
!= null)
84 targetCredentials
= new SimpleCredentials(targetUsername
,
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
))
95 if (sourceWorkspaceName
.equals("security"))
97 if (sourceWorkspaceName
.equals("localrepo"))
99 Session sourceSession
= null;
100 Session targetSession
= null;
103 targetSession
= targetRepository
.login(
104 targetCredentials
, sourceWorkspaceName
);
105 } catch (NoSuchWorkspaceException e
) {
106 targetDefaultSession
.getWorkspace().createWorkspace(
107 sourceWorkspaceName
);
108 targetSession
= targetRepository
.login(
109 targetCredentials
, sourceWorkspaceName
);
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
);
118 JcrUtils
.logoutQuietly(sourceSession
);
119 JcrUtils
.logoutQuietly(targetSession
);
122 // Session sourceSession = sourceRepository.login(sourceCredentials,
125 // Credentials targetCredentials = null;
126 // Session targetSession = targetRepository.login(targetCredentials,
129 // Long count = JcrUtils.copyFiles(sourceSession.getRootNode(),
130 // targetSession.getRootNode(), true, null);
132 long duration
= (System
.currentTimeMillis() - begin
) / 1000;// s
133 log
.info("Sync " + sourceRepo
+ " to " + targetRepo
+ " in "
136 + "min " + (duration
% 60) + "s");
138 if (errors
.size() > 0) {
139 throw new SlcException("Sync failed " + errors
);
141 } catch (RepositoryException e
) {
142 throw new SlcException("Cannot sync " + sourceRepo
+ " to "
145 JcrUtils
.logoutQuietly(sourceDefaultSession
);
146 JcrUtils
.logoutQuietly(targetDefaultSession
);
150 protected void syncWorkspace(Session sourceSession
, Session targetSession
) {
152 if (log
.isDebugEnabled())
153 log
.debug("Syncing " + sourceSession
.getWorkspace().getName()
155 for (NodeIterator it
= sourceSession
.getRootNode().getNodes(); it
157 Node node
= it
.nextNode();
158 if (node
.getName().equals("jcr:system"))
160 // ContentHandler targetHandler = targetSession
162 // .getImportContentHandler(
164 // ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING);
165 // sourceSession.exportSystemView(node.getPath(), targetHandler,
167 // if (log.isDebugEnabled())
168 // log.debug(" " + node.getPath());
169 syncNode(node
, targetSession
.getRootNode());
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
);
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();
189 if (!targetParentNode
.hasNode(sourceNode
.getName())) {
190 ContentHandler contentHandler
= targetParentNode
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());
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();
208 if (targetLastModified
== null
209 || targetLastModified
.before(sourceLastModified
)) {
210 ContentHandler contentHandler
= targetParentNode
213 .getImportContentHandler(
214 targetParentNode
.getPath(),
215 ImportUUIDBehavior
.IMPORT_UUID_COLLISION_REMOVE_EXISTING
);
216 sourceNode
.getSession().exportSystemView(
217 sourceNode
.getPath(), contentHandler
, false,
219 if (log
.isDebugEnabled())
220 log
.debug("Updated " + targetNode
.getPath());
222 if (log
.isDebugEnabled())
223 log
.debug("Skipped up to date " + targetNode
.getPath());
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();
240 for (NodeIterator it
= sourceNode
.getNodes(); it
.hasNext();) {
241 syncNode(it
.nextNode(), targetNode
);
244 if (sourceLastModified
!= null) {
245 targetNode
.setProperty(Property
.JCR_LAST_MODIFIED
,
247 targetNode
.getSession().save();
253 protected Boolean
noRecurse(Node sourceNode
) throws RepositoryException
{
254 if (sourceNode
.isNodeType(NodeType
.NT_FILE
))
259 public void setSourceRepo(String sourceRepo
) {
260 this.sourceRepo
= sourceRepo
;
263 public void setTargetRepo(String targetRepo
) {
264 this.targetRepo
= targetRepo
;
267 public void setSourceWksp(String sourceWksp
) {
268 this.sourceWksp
= sourceWksp
;
271 public void setRepositoryFactory(RepositoryFactory repositoryFactory
) {
272 this.repositoryFactory
= repositoryFactory
;
275 public void setSourceUsername(String sourceUsername
) {
276 this.sourceUsername
= sourceUsername
;
279 public void setSourcePassword(char[] sourcePassword
) {
280 this.sourcePassword
= sourcePassword
;