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/18 08:50:20 UTC

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

Author: jukka
Date: Mon May 18 06:50:16 2009
New Revision: 775833

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

Initial version of a repository copy mechanism that can also be used to migrate an entire repository (with namespaces, node types, and version histories) to a new configuration.

Be gentle, work in progress...

Added:
    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/RepositoryImpl.java

Added: 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=775833&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryCopier.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryCopier.java Mon May 18 06:50:16 2009
@@ -0,0 +1,166 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.jackrabbit.core;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+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;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.jackrabbit.core.config.RepositoryConfig;
+import org.apache.jackrabbit.core.nodetype.InvalidNodeTypeDefException;
+import org.apache.jackrabbit.core.nodetype.NodeTypeDef;
+import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
+import org.apache.jackrabbit.core.persistence.PersistenceCopier;
+import org.apache.jackrabbit.core.state.ItemStateException;
+import org.apache.jackrabbit.core.version.VersionManagerImpl;
+import org.apache.jackrabbit.spi.Name;
+
+public class RepositoryCopier {
+
+    private final RepositoryImpl source;
+
+    private final RepositoryImpl target;
+
+    public RepositoryCopier(File source, File target)
+            throws RepositoryException, IOException {
+        if (!source.isDirectory()) {
+            throw new RepositoryException("Not a directory: " + source);
+        }
+
+        File sx = new File(source, "repository.xml");
+        if (!sx.isFile()) {
+            throw new RepositoryException(
+                    "Not a repository directory: " + source);
+        }
+
+        if (target.exists()) {
+            throw new RepositoryException("Target directory exists: " + target);
+        }
+        target.mkdirs();
+
+        File tx = new File(target, "repository.xml");
+        OutputStream output = new FileOutputStream(tx);
+        try {
+            InputStream input =
+                RepositoryImpl.class.getResourceAsStream("repository.xml");
+            try {
+                IOUtils.copy(input, output);
+            } finally {
+                input.close();
+            }
+        } finally {
+            output.close();
+        }
+
+        this.source = RepositoryImpl.create(
+                RepositoryConfig.create(sx.getPath(), source.getPath()));
+        this.target = RepositoryImpl.create(
+                RepositoryConfig.create(tx.getPath(), target.getPath()));
+    }
+
+    public RepositoryCopier(RepositoryConfig source, RepositoryConfig target)
+            throws RepositoryException {
+        this.source = RepositoryImpl.create(source);
+        this.target = RepositoryImpl.create(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()) {
+            if (!existing.contains(uri)) {
+                // TODO: what if the prefix is already taken?
+                targetRegistry.registerNamespace(
+                        sourceRegistry.getPrefix(uri), uri);
+            }
+        }
+    }
+
+    private void copyNodeTypes()
+            throws RepositoryException, InvalidNodeTypeDefException {
+        NodeTypeRegistry sourceRegistry = source.getNodeTypeRegistry();
+        NodeTypeRegistry targetRegistry = target.getNodeTypeRegistry();
+        Set<Name> existing = new HashSet<Name>(Arrays.asList(
+                targetRegistry.getRegisteredNodeTypes()));
+        Collection<NodeTypeDef> register = new ArrayList<NodeTypeDef>();
+        for (Name name : sourceRegistry.getRegisteredNodeTypes()) {
+            // TODO: what about modified node types?
+            if (!existing.contains(name)) {
+                register.add(sourceRegistry.getNodeTypeDef(name));
+            }
+        }
+        targetRegistry.registerNodeTypes(register);
+    }
+
+    private void copyVersionStore()
+            throws RepositoryException, ItemStateException {
+        System.out.println("  Copying version histories...");
+        VersionManagerImpl sourceManager = source.getVersionManagerImpl();
+        VersionManagerImpl targetManager = target.getVersionManagerImpl();
+        PersistenceCopier copier = new PersistenceCopier(
+                sourceManager.getPersistenceManager(),
+                targetManager.getPersistenceManager());
+        copier.copy(RepositoryImpl.VERSION_STORAGE_NODE_ID);
+    }
+
+    private void copyWorkspaces()
+            throws RepositoryException, ItemStateException {
+        Set<String> existing = new HashSet<String>(Arrays.asList(
+                target.getWorkspaceNames()));
+        for (String name : source.getWorkspaceNames()) {
+            System.out.println("  Copying workspace " + name + "...");
+
+            if (!existing.contains(name)) {
+                target.createWorkspace(name);
+            }
+
+            PersistenceCopier copier = new PersistenceCopier(
+                    source.getWorkspaceInfo(name).getPersistenceManager(),
+                    target.getWorkspaceInfo(name).getPersistenceManager());
+            copier.excludeNode(RepositoryImpl.SYSTEM_ROOT_NODE_ID);
+            copier.copy(RepositoryImpl.ROOT_NODE_ID);
+        }
+    }
+
+}

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java?rev=775833&r1=775832&r2=775833&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java Mon May 18 06:50:16 2009
@@ -2321,4 +2321,9 @@
             return RepositoryImpl.this.getDataStore();
         }
     }
+
+    VersionManagerImpl getVersionManagerImpl() {
+        return vMgr;
+    }
+
 }

Added: 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=775833&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/PersistenceCopier.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/PersistenceCopier.java Mon May 18 06:50:16 2009
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.jackrabbit.core.persistence;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.PropertyId;
+import org.apache.jackrabbit.core.state.ChangeLog;
+import org.apache.jackrabbit.core.state.ChildNodeEntry;
+import org.apache.jackrabbit.core.state.ItemStateException;
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.state.PropertyState;
+import org.apache.jackrabbit.spi.Name;
+
+/**
+ * 
+ */
+public class PersistenceCopier {
+
+    private final PersistenceManager source;
+
+    private final PersistenceManager target;
+
+    private final Set<NodeId> exclude = new HashSet<NodeId>();
+
+    public PersistenceCopier(
+            PersistenceManager source, PersistenceManager target) {
+        this.source = source;
+        this.target = target;
+    }
+
+    public void excludeNode(NodeId id) {
+        exclude.add(id);
+    }
+
+    public void copy(NodeId id) throws ItemStateException {
+        if (!exclude.contains(id)) {
+            NodeState node = source.load(id);
+
+            for (ChildNodeEntry entry : node.getChildNodeEntries()) {
+                copy(entry.getId());
+            }
+
+            copy(node);
+        }
+    }
+
+    private void copy(NodeState sourceNode) throws ItemStateException {
+        ChangeLog changes = new ChangeLog();
+
+        NodeState targetNode = target.createNew(sourceNode.getNodeId());
+        targetNode.setParentId(sourceNode.getParentId());
+        targetNode.setDefinitionId(sourceNode.getDefinitionId());
+        targetNode.setNodeTypeName(sourceNode.getNodeTypeName());
+        targetNode.setMixinTypeNames(sourceNode.getMixinTypeNames());
+        targetNode.setPropertyNames(sourceNode.getPropertyNames());
+        targetNode.setChildNodeEntries(sourceNode.getChildNodeEntries());
+        if (target.exists(targetNode.getNodeId())) {
+            changes.modified(targetNode);
+        } else {
+            changes.added(targetNode);
+        }
+
+        for (Name name : sourceNode.getPropertyNames()) {
+            PropertyId id = new PropertyId(sourceNode.getNodeId(), name);
+            PropertyState sourceState = source.load(id);
+            PropertyState targetState = target.createNew(id);
+            targetState.setDefinitionId(sourceState.getDefinitionId());
+            targetState.setType(sourceState.getType());
+            targetState.setMultiValued(sourceState.isMultiValued());
+            // TODO: Copy binaries?
+            targetState.setValues(sourceState.getValues());
+            if (target.exists(targetState.getPropertyId())) {
+                changes.modified(targetState);
+            } else {
+                changes.added(targetState);
+            }
+        }
+
+        target.store(changes);
+    }
+
+}