]> git.argeo.org Git - gpl/argeo-slc.git/blob - org.argeo.slc.support/src/org/argeo/slc/lib/jcr/JcrRepositoryBackup.java
Merge branch 'master' of https://github.com/argeo/argeo-slc.git
[gpl/argeo-slc.git] / org.argeo.slc.support / src / org / argeo / slc / lib / jcr / JcrRepositoryBackup.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.lib.jcr;
17
18 import java.util.UUID;
19 import java.util.jar.Attributes;
20 import java.util.jar.JarEntry;
21 import java.util.jar.JarOutputStream;
22 import java.util.jar.Manifest;
23
24 import javax.jcr.Credentials;
25 import javax.jcr.Node;
26 import javax.jcr.NodeIterator;
27 import javax.jcr.Repository;
28 import javax.jcr.RepositoryFactory;
29 import javax.jcr.Session;
30 import javax.jcr.SimpleCredentials;
31
32 import org.apache.commons.io.IOUtils;
33 import org.apache.commons.logging.Log;
34 import org.apache.commons.logging.LogFactory;
35 import org.apache.commons.vfs2.FileObject;
36 import org.apache.commons.vfs2.FileSelectInfo;
37 import org.apache.commons.vfs2.FileSelector;
38 import org.apache.commons.vfs2.FileSystemException;
39 import org.apache.commons.vfs2.FileSystemManager;
40 import org.argeo.jcr.JcrUtils;
41 import org.argeo.node.NodeUtils;
42 import org.argeo.slc.SlcException;
43
44 /** Backups a JCR repository */
45 public class JcrRepositoryBackup implements Runnable {
46 private final static Log log = LogFactory.getLog(JcrRepositoryBackup.class);
47
48 private String sourceRepo;
49 private String sourceDatastore;
50 private String targetFile;
51
52 private String sourceWksp;
53
54 private String sourceUsername;
55 private char[] sourcePassword;
56
57 private RepositoryFactory repositoryFactory;
58 private FileSystemManager fileSystemManager;
59
60 public void run() {
61 Session sourceDefaultSession = null;
62 try {
63 long begin = System.currentTimeMillis();
64
65 FileObject archiveRoot = fileSystemManager.resolveFile(targetFile);
66 archiveRoot.createFolder();
67
68 String datastoreFolderName = "datastore";
69 if (hasDatastore())
70 backupDataStore(archiveRoot.resolveFile(datastoreFolderName));
71
72 Repository sourceRepository = NodeUtils.getRepositoryByUri(
73 repositoryFactory, sourceRepo);
74 Credentials sourceCredentials = null;
75 if (sourceUsername != null)
76 sourceCredentials = new SimpleCredentials(sourceUsername,
77 sourcePassword);
78
79 sourceDefaultSession = sourceRepository.login(sourceCredentials);
80 for (String sourceWorkspaceName : sourceDefaultSession
81 .getWorkspace().getAccessibleWorkspaceNames()) {
82 if (Thread.interrupted()) {
83 log.error("Workspace backup interrupted");
84 Thread.currentThread().interrupt();
85 return;
86 }
87
88 if (sourceWksp != null && !sourceWksp.trim().equals("")
89 && !sourceWorkspaceName.equals(sourceWksp))
90 continue;
91 Session sourceSession = null;
92 JarOutputStream out = null;
93 FileObject workspaceBackup = null;
94 try {
95 Manifest manifest = new Manifest();
96 manifest.getMainAttributes().put(
97 Attributes.Name.MANIFEST_VERSION, "1.0");
98 manifest.getMainAttributes().putValue("Backup-UUID",
99 UUID.randomUUID().toString());
100 manifest.getMainAttributes().putValue("Backup-Timestamp",
101 Long.toString(System.currentTimeMillis()));
102 manifest.getMainAttributes().putValue(
103 "Backup-JCR-Workspace", sourceWorkspaceName);
104 workspaceBackup = fileSystemManager.resolveFile(targetFile
105 + "/" + sourceWorkspaceName + ".jar");
106
107 out = new JarOutputStream(workspaceBackup.getContent()
108 .getOutputStream(), manifest);
109 sourceSession = sourceRepository.login(sourceCredentials,
110 sourceWorkspaceName);
111 backupWorkspace(sourceSession, out);
112 } finally {
113 JcrUtils.logoutQuietly(sourceSession);
114 IOUtils.closeQuietly(out);
115 if (workspaceBackup != null)
116 workspaceBackup.close();
117 }
118 }
119
120 // in case some binaries have been added during the backup
121 if (hasDatastore())
122 backupDataStore(archiveRoot.resolveFile(datastoreFolderName));
123
124 long duration = (System.currentTimeMillis() - begin) / 1000;// s
125 log.info("Backed-up " + sourceRepo + " in " + (duration / 60)
126 + "min " + (duration % 60) + "s");
127 } catch (Exception e) {
128 throw new SlcException("Cannot backup " + sourceRepo, e);
129 } finally {
130 JcrUtils.logoutQuietly(sourceDefaultSession);
131 }
132 }
133
134 protected Boolean hasDatastore() {
135 return sourceDatastore != null && !sourceDatastore.trim().equals("");
136 }
137
138 protected void backupWorkspace(Session sourceSession, JarOutputStream out) {
139 try {
140 if (log.isTraceEnabled())
141 log.trace("Backup " + sourceSession.getWorkspace().getName()
142 + "...");
143 Boolean skipBinaries = hasDatastore();
144 for (NodeIterator it = sourceSession.getRootNode().getNodes(); it
145 .hasNext();) {
146 if (Thread.interrupted()) {
147 log.error("Node backup interrupted");
148 Thread.currentThread().interrupt();
149 return;
150 }
151 Node node = it.nextNode();
152 JarEntry entry = new JarEntry(node.getPath());
153 out.putNextEntry(entry);
154 sourceSession.exportSystemView(node.getPath(), out,
155 skipBinaries, false);
156 out.flush();
157 out.closeEntry();
158 }
159 if (log.isDebugEnabled())
160 log.debug("Backed up " + sourceSession.getWorkspace().getName());
161 } catch (Exception e) {
162 throw new SlcException("Cannot backup "
163 + sourceSession.getWorkspace().getName(), e);
164 }
165 }
166
167 protected void backupDataStore(final FileObject targetDatastore) {
168 try {
169 targetDatastore.createFolder();
170 final FileObject sourceDataStore = fileSystemManager
171 .resolveFile(sourceDatastore);
172 if (log.isDebugEnabled())
173 log.debug("Backup " + sourceDatastore);
174 targetDatastore.copyFrom(sourceDataStore, new FileSelector() {
175 public boolean traverseDescendents(FileSelectInfo fileInfo)
176 throws Exception {
177 return true;
178 }
179
180 public boolean includeFile(FileSelectInfo fileInfo)
181 throws Exception {
182 String relativeName = fileInfo
183 .getFile()
184 .getName()
185 .getPath()
186 .substring(
187 sourceDataStore.getName().getPath()
188 .length());
189 FileObject target = targetDatastore
190 .resolveFile(relativeName);
191 if (target.exists()) {
192 return false;
193 } else {
194 return true;
195 }
196 }
197 });
198 if (log.isDebugEnabled())
199 log.debug("Backed-up " + sourceDatastore);
200 } catch (FileSystemException e) {
201 throw new SlcException("Cannot backup datastore", e);
202 }
203 }
204
205 public void setSourceRepo(String sourceRepo) {
206 this.sourceRepo = sourceRepo;
207 }
208
209 public void setSourceWksp(String sourceWksp) {
210 this.sourceWksp = sourceWksp;
211 }
212
213 public void setRepositoryFactory(RepositoryFactory repositoryFactory) {
214 this.repositoryFactory = repositoryFactory;
215 }
216
217 public void setSourceUsername(String sourceUsername) {
218 this.sourceUsername = sourceUsername;
219 }
220
221 public void setSourcePassword(char[] sourcePassword) {
222 this.sourcePassword = sourcePassword;
223 }
224
225 public void setFileSystemManager(FileSystemManager fileSystemManager) {
226 this.fileSystemManager = fileSystemManager;
227 }
228
229 public void setTargetFile(String targetFile) {
230 this.targetFile = targetFile;
231 }
232
233 public void setSourceDatastore(String sourceDatastore) {
234 this.sourceDatastore = sourceDatastore;
235 }
236
237 }