X-Git-Url: http://git.argeo.org/?a=blobdiff_plain;f=org.argeo.slc.support%2Fsrc%2Forg%2Fargeo%2Fslc%2Flib%2Fjcr%2FJcrRepositoryBackup.java;fp=org.argeo.slc.support%2Fsrc%2Forg%2Fargeo%2Fslc%2Flib%2Fjcr%2FJcrRepositoryBackup.java;h=d2bb56b2e28d63ce28e8104d759a4419a719b0f8;hb=b9505fef5ba8186433e903e9de3c73c17bdf6562;hp=0000000000000000000000000000000000000000;hpb=04ef2e4533e909122a560a5cb6499fa62bac82ec;p=gpl%2Fargeo-slc.git diff --git a/org.argeo.slc.support/src/org/argeo/slc/lib/jcr/JcrRepositoryBackup.java b/org.argeo.slc.support/src/org/argeo/slc/lib/jcr/JcrRepositoryBackup.java new file mode 100644 index 000000000..d2bb56b2e --- /dev/null +++ b/org.argeo.slc.support/src/org/argeo/slc/lib/jcr/JcrRepositoryBackup.java @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.lib.jcr; + +import java.util.UUID; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; + +import javax.jcr.Credentials; +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.Repository; +import javax.jcr.RepositoryFactory; +import javax.jcr.Session; +import javax.jcr.SimpleCredentials; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.vfs2.FileObject; +import org.apache.commons.vfs2.FileSelectInfo; +import org.apache.commons.vfs2.FileSelector; +import org.apache.commons.vfs2.FileSystemException; +import org.apache.commons.vfs2.FileSystemManager; +import org.argeo.jcr.ArgeoJcrUtils; +import org.argeo.jcr.JcrUtils; +import org.argeo.slc.SlcException; + +/** Backups a JCR repository */ +public class JcrRepositoryBackup implements Runnable { + private final static Log log = LogFactory.getLog(JcrRepositoryBackup.class); + + private String sourceRepo; + private String sourceDatastore; + private String targetFile; + + private String sourceWksp; + + private String sourceUsername; + private char[] sourcePassword; + + private RepositoryFactory repositoryFactory; + private FileSystemManager fileSystemManager; + + public void run() { + Session sourceDefaultSession = null; + try { + long begin = System.currentTimeMillis(); + + FileObject archiveRoot = fileSystemManager.resolveFile(targetFile); + archiveRoot.createFolder(); + + String datastoreFolderName = "datastore"; + if (hasDatastore()) + backupDataStore(archiveRoot.resolveFile(datastoreFolderName)); + + Repository sourceRepository = ArgeoJcrUtils.getRepositoryByUri( + repositoryFactory, sourceRepo); + Credentials sourceCredentials = null; + if (sourceUsername != null) + sourceCredentials = new SimpleCredentials(sourceUsername, + sourcePassword); + + sourceDefaultSession = sourceRepository.login(sourceCredentials); + for (String sourceWorkspaceName : sourceDefaultSession + .getWorkspace().getAccessibleWorkspaceNames()) { + if (Thread.interrupted()) { + log.error("Workspace backup interrupted"); + Thread.currentThread().interrupt(); + return; + } + + if (sourceWksp != null && !sourceWksp.trim().equals("") + && !sourceWorkspaceName.equals(sourceWksp)) + continue; + Session sourceSession = null; + JarOutputStream out = null; + FileObject workspaceBackup = null; + try { + Manifest manifest = new Manifest(); + manifest.getMainAttributes().put( + Attributes.Name.MANIFEST_VERSION, "1.0"); + manifest.getMainAttributes().putValue("Backup-UUID", + UUID.randomUUID().toString()); + manifest.getMainAttributes().putValue("Backup-Timestamp", + Long.toString(System.currentTimeMillis())); + manifest.getMainAttributes().putValue( + "Backup-JCR-Workspace", sourceWorkspaceName); + workspaceBackup = fileSystemManager.resolveFile(targetFile + + "/" + sourceWorkspaceName + ".jar"); + + out = new JarOutputStream(workspaceBackup.getContent() + .getOutputStream(), manifest); + sourceSession = sourceRepository.login(sourceCredentials, + sourceWorkspaceName); + backupWorkspace(sourceSession, out); + } finally { + JcrUtils.logoutQuietly(sourceSession); + IOUtils.closeQuietly(out); + if (workspaceBackup != null) + workspaceBackup.close(); + } + } + + // in case some binaries have been added during the backup + if (hasDatastore()) + backupDataStore(archiveRoot.resolveFile(datastoreFolderName)); + + long duration = (System.currentTimeMillis() - begin) / 1000;// s + log.info("Backed-up " + sourceRepo + " in " + (duration / 60) + + "min " + (duration % 60) + "s"); + } catch (Exception e) { + throw new SlcException("Cannot backup " + sourceRepo, e); + } finally { + JcrUtils.logoutQuietly(sourceDefaultSession); + } + } + + protected Boolean hasDatastore() { + return sourceDatastore != null && !sourceDatastore.trim().equals(""); + } + + protected void backupWorkspace(Session sourceSession, JarOutputStream out) { + try { + if (log.isTraceEnabled()) + log.trace("Backup " + sourceSession.getWorkspace().getName() + + "..."); + Boolean skipBinaries = hasDatastore(); + for (NodeIterator it = sourceSession.getRootNode().getNodes(); it + .hasNext();) { + if (Thread.interrupted()) { + log.error("Node backup interrupted"); + Thread.currentThread().interrupt(); + return; + } + Node node = it.nextNode(); + JarEntry entry = new JarEntry(node.getPath()); + out.putNextEntry(entry); + sourceSession.exportSystemView(node.getPath(), out, + skipBinaries, false); + out.flush(); + out.closeEntry(); + } + if (log.isDebugEnabled()) + log.debug("Backed up " + sourceSession.getWorkspace().getName()); + } catch (Exception e) { + throw new SlcException("Cannot backup " + + sourceSession.getWorkspace().getName(), e); + } + } + + protected void backupDataStore(final FileObject targetDatastore) { + try { + targetDatastore.createFolder(); + final FileObject sourceDataStore = fileSystemManager + .resolveFile(sourceDatastore); + if (log.isDebugEnabled()) + log.debug("Backup " + sourceDatastore); + targetDatastore.copyFrom(sourceDataStore, new FileSelector() { + public boolean traverseDescendents(FileSelectInfo fileInfo) + throws Exception { + return true; + } + + public boolean includeFile(FileSelectInfo fileInfo) + throws Exception { + String relativeName = fileInfo + .getFile() + .getName() + .getPath() + .substring( + sourceDataStore.getName().getPath() + .length()); + FileObject target = targetDatastore + .resolveFile(relativeName); + if (target.exists()) { + return false; + } else { + return true; + } + } + }); + if (log.isDebugEnabled()) + log.debug("Backed-up " + sourceDatastore); + } catch (FileSystemException e) { + throw new SlcException("Cannot backup datastore", e); + } + } + + public void setSourceRepo(String sourceRepo) { + this.sourceRepo = sourceRepo; + } + + public void setSourceWksp(String sourceWksp) { + this.sourceWksp = sourceWksp; + } + + public void setRepositoryFactory(RepositoryFactory repositoryFactory) { + this.repositoryFactory = repositoryFactory; + } + + public void setSourceUsername(String sourceUsername) { + this.sourceUsername = sourceUsername; + } + + public void setSourcePassword(char[] sourcePassword) { + this.sourcePassword = sourcePassword; + } + + public void setFileSystemManager(FileSystemManager fileSystemManager) { + this.fileSystemManager = fileSystemManager; + } + + public void setTargetFile(String targetFile) { + this.targetFile = targetFile; + } + + public void setSourceDatastore(String sourceDatastore) { + this.sourceDatastore = sourceDatastore; + } + +}