You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by ju...@apache.org on 2009/05/19 12:02:52 UTC

svn commit: r776256 - in /jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core: RepositoryCopier.java persistence/PersistenceCopier.java

Author: jukka
Date: Tue May 19 10:02:51 2009
New Revision: 776256

URL: http://svn.apache.org/viewvc?rev=776256&view=rev
Log:
JCR-422: Implement a backup tool

Document and clean up the initial backup code. Add better logging and some TODO markers.

Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryCopier.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/PersistenceCopier.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryCopier.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryCopier.java?rev=776256&r1=776255&r2=776256&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryCopier.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryCopier.java Tue May 19 10:02:51 2009
@@ -24,8 +24,6 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
 
 import javax.jcr.NamespaceRegistry;
 import javax.jcr.RepositoryException;
@@ -39,13 +37,46 @@
 import org.apache.jackrabbit.core.state.ItemStateException;
 import org.apache.jackrabbit.core.version.VersionManagerImpl;
 import org.apache.jackrabbit.spi.Name;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
+/**
+ * Tool for backing up or migrating the entire contents (workspaces,
+ * version histories, namespaces, node types, etc.) of a repository to
+ * a new repository. The target repository (if it exists) is overwritten.
+ *
+ * @since Apache Jackrabbit 1.6
+ */
 public class RepositoryCopier {
 
-    private final RepositoryImpl source;
-
-    private final RepositoryImpl target;
-
+    /**
+     * Logger instance
+     */
+    private static final Logger logger =
+        LoggerFactory.getLogger(RepositoryCopier.class);
+
+    /**
+     * Source repository configuration
+     */
+    private final RepositoryConfig sourceConfig;
+
+    /**
+     * Target repository configuration
+     */
+    private final RepositoryConfig targetConfig;
+
+    /**
+     * Creates a tool for copying the full contents of the source repository.
+     * The given source repository directory is expected to contain the
+     * repository configuration as a <code>repository.xml</code> file.
+     * The target repository directory must not already exist. It will be
+     * automatically created with default repository configuration.
+     *
+     * @param source source repository directory
+     * @param target target repository directory
+     * @throws RepositoryException if the repositories can not be accessed
+     * @throws IOException if the target directory can not be initialized
+     */
     public RepositoryCopier(File source, File target)
             throws RepositoryException, IOException {
         if (!source.isDirectory()) {
@@ -77,79 +108,110 @@
             output.close();
         }
 
-        this.source = RepositoryImpl.create(
-                RepositoryConfig.create(sx.getPath(), source.getPath()));
-        this.target = RepositoryImpl.create(
-                RepositoryConfig.create(tx.getPath(), target.getPath()));
+        sourceConfig = RepositoryConfig.create(sx.getPath(), source.getPath());
+        targetConfig = RepositoryConfig.create(tx.getPath(), target.getPath());
     }
 
+    /**
+     * Creates a tool for copying the full contents of the source repository
+     * to the given target repository. Any existing content in the target
+     * repository will be overwritten.
+     *
+     * @param source source repository configuration
+     * @param target target repository configuration
+     * @throws RepositoryException if the repositories can not be accessed
+     */
     public RepositoryCopier(RepositoryConfig source, RepositoryConfig target)
             throws RepositoryException {
-        this.source = RepositoryImpl.create(source);
-        this.target = RepositoryImpl.create(target);
+        sourceConfig = source;
+        targetConfig = target;
     }
 
-    public void copy() throws Exception {
-        System.out.println(
-                "Copying repository " + source.getConfig().getHomeDir());
-        copyNamespaces();
-        copyNodeTypes();
-        copyVersionStore();
-        copyWorkspaces();
-
-        target.shutdown();
-        source.shutdown();
-
-        System.out.println("  Done.");
-    }
-
-    private void copyNamespaces() throws RepositoryException {
-        NamespaceRegistry sourceRegistry = source.getNamespaceRegistry();
-        NamespaceRegistry targetRegistry = target.getNamespaceRegistry();
-        Set<String> existing = new HashSet<String>(Arrays.asList(
-                targetRegistry.getURIs()));
-        for (String uri : sourceRegistry.getURIs()) {
+    /**
+     * Copies the full content from the source to the target repository.
+     * Note that both the source and the target repository must be closed
+     * during the copy operation as this method requires exclusive access
+     * to the repositories.
+     *
+     * @throws RepositoryException if the copy operation fails
+     */
+    public void copy() throws RepositoryException {
+        logger.info(
+                "Copying repository content from {} to {}",
+                sourceConfig.getHomeDir(), targetConfig.getHomeDir());
+
+        RepositoryImpl source = RepositoryImpl.create(sourceConfig);
+        try {
+            RepositoryImpl target = RepositoryImpl.create(targetConfig);
+            try {
+                copyNamespaces(
+                        source.getNamespaceRegistry(),
+                        target.getNamespaceRegistry());
+                copyNodeTypes(
+                        source.getNodeTypeRegistry(),
+                        target.getNodeTypeRegistry());
+                copyVersionStore(
+                        source.getVersionManagerImpl(),
+                        target.getVersionManagerImpl());
+                copyWorkspaces(source, target);
+            } catch (InvalidNodeTypeDefException e) {
+                throw new RepositoryException("Failed to copy node types", e);
+            } catch (ItemStateException e) {
+                throw new RepositoryException("Failed to copy item states", e);
+            } finally {
+                target.shutdown();
+            }
+        } finally {
+            source.shutdown();
+        }
+    }
+
+    private void copyNamespaces(
+            NamespaceRegistry source, NamespaceRegistry target)
+            throws RepositoryException {
+        logger.info("Copying registered namespaces");
+
+        Collection<String> existing = Arrays.asList(target.getURIs());
+        for (String uri : source.getURIs()) {
             if (!existing.contains(uri)) {
                 // TODO: what if the prefix is already taken?
-                targetRegistry.registerNamespace(
-                        sourceRegistry.getPrefix(uri), uri);
+                target.registerNamespace(source.getPrefix(uri), uri);
             }
         }
     }
 
-    private void copyNodeTypes()
+    private void copyNodeTypes(NodeTypeRegistry source, NodeTypeRegistry target)
             throws RepositoryException, InvalidNodeTypeDefException {
-        NodeTypeRegistry sourceRegistry = source.getNodeTypeRegistry();
-        NodeTypeRegistry targetRegistry = target.getNodeTypeRegistry();
-        Set<Name> existing = new HashSet<Name>(Arrays.asList(
-                targetRegistry.getRegisteredNodeTypes()));
+        logger.info("Copying registered node types");
+
+        Collection<Name> existing =
+            Arrays.asList(target.getRegisteredNodeTypes());
         Collection<NodeTypeDef> register = new ArrayList<NodeTypeDef>();
-        for (Name name : sourceRegistry.getRegisteredNodeTypes()) {
+        for (Name name : source.getRegisteredNodeTypes()) {
             // TODO: what about modified node types?
             if (!existing.contains(name)) {
-                register.add(sourceRegistry.getNodeTypeDef(name));
+                register.add(source.getNodeTypeDef(name));
             }
         }
-        targetRegistry.registerNodeTypes(register);
+        target.registerNodeTypes(register);
     }
 
-    private void copyVersionStore()
+    private void copyVersionStore(
+            VersionManagerImpl source, VersionManagerImpl target)
             throws RepositoryException, ItemStateException {
-        System.out.println("  Copying version histories...");
-        VersionManagerImpl sourceManager = source.getVersionManagerImpl();
-        VersionManagerImpl targetManager = target.getVersionManagerImpl();
+        logger.info("Copying version histories");
+
         PersistenceCopier copier = new PersistenceCopier(
-                sourceManager.getPersistenceManager(),
-                targetManager.getPersistenceManager());
+                source.getPersistenceManager(),
+                target.getPersistenceManager());
         copier.copy(RepositoryImpl.VERSION_STORAGE_NODE_ID);
     }
 
-    private void copyWorkspaces()
+    private void copyWorkspaces(RepositoryImpl source, RepositoryImpl target)
             throws RepositoryException, ItemStateException {
-        Set<String> existing = new HashSet<String>(Arrays.asList(
-                target.getWorkspaceNames()));
+        Collection<String> existing = Arrays.asList(target.getWorkspaceNames());
         for (String name : source.getWorkspaceNames()) {
-            System.out.println("  Copying workspace " + name + "...");
+            logger.info("Copying workspace {}" , name);
 
             if (!existing.contains(name)) {
                 target.createWorkspace(name);

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/PersistenceCopier.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/PersistenceCopier.java?rev=776256&r1=776255&r2=776256&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/PersistenceCopier.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/PersistenceCopier.java Tue May 19 10:02:51 2009
@@ -29,26 +29,62 @@
 import org.apache.jackrabbit.spi.Name;
 
 /**
- * 
+ * Tool for copying item states from one persistence manager to another.
+ * Used for backing up or migrating repository content.
+ *
+ * @since Apache Jackrabbit 1.6
  */
 public class PersistenceCopier {
 
+    /**
+     * Source persistence manager.
+     */
     private final PersistenceManager source;
 
+    /**
+     * Target persistence manager.
+     */
     private final PersistenceManager target;
 
+    /**
+     * Identifiers of the nodes that have already been copied or that
+     * should explicitly not be copied. Used to avoid duplicate copies
+     * of shareable nodes and to avoid trying to copy "missing" nodes
+     * like the virtual "/jcr:system" node.
+     */
     private final Set<NodeId> exclude = new HashSet<NodeId>();
 
+    /**
+     * Creates a tool for copying content from one persistence manager
+     * to another.
+     *
+     * @param source source persistence manager
+     * @param target target persistence manager
+     */
     public PersistenceCopier(
             PersistenceManager source, PersistenceManager target) {
         this.source = source;
         this.target = target;
     }
 
+    /**
+     * Explicitly exclude the identified node from being copied. Used for
+     * excluding virtual nodes like "/jcr:system" from the copy process.
+     *
+     * @param id identifier of the node to be excluded
+     */
     public void excludeNode(NodeId id) {
         exclude.add(id);
     }
 
+    /**
+     * Recursively copies the identified node and all its descendants.
+     * Explicitly excluded nodes and nodes that have already been copied
+     * are automatically skipped.
+     *
+     * @param id identifier of the node to be copied
+     * @throws ItemStateException if the copy operation fails
+     */
     public void copy(NodeId id) throws ItemStateException {
         if (!exclude.contains(id)) {
             NodeState node = source.load(id);
@@ -58,12 +94,21 @@
             }
 
             copy(node);
+            exclude.add(id);
         }
     }
 
+    /**
+     * Copies the given node state and all associated property states
+     * to the target persistence manager.
+     *
+     * @param sourceNode source node state
+     * @throws ItemStateException if the copy operation fails
+     */
     private void copy(NodeState sourceNode) throws ItemStateException {
         ChangeLog changes = new ChangeLog();
 
+        // Copy the node state
         NodeState targetNode = target.createNew(sourceNode.getNodeId());
         targetNode.setParentId(sourceNode.getParentId());
         targetNode.setDefinitionId(sourceNode.getDefinitionId());
@@ -77,6 +122,7 @@
             changes.added(targetNode);
         }
 
+        // Copy all associated property states
         for (Name name : sourceNode.getPropertyNames()) {
             PropertyId id = new PropertyId(sourceNode.getNodeId(), name);
             PropertyState sourceState = source.load(id);
@@ -93,6 +139,9 @@
             }
         }
 
+        // TODO: Copy node references?
+
+        // Persist the copied states
         target.store(changes);
     }