Author: jukka
Date: Fri Oct 25 19:07:21 2013
New Revision: 1535820
URL: http://svn.apache.org/r1535820
Log:
OAK-806: Content migration from Jackrabbit to Oak
Use the NodeState abtraction for content migration
Added:
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/JackrabbitNodeState.java
- copied, changed from r1535777,
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/PersistenceCopier.java
Removed:
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/PersistenceCopier.java
Modified:
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java
Copied:
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/JackrabbitNodeState.java
(from r1535777,
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/PersistenceCopier.java)
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/JackrabbitNodeState.java?p2=jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/JackrabbitNodeState.java&p1=jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/PersistenceCopier.java&r1=1535777&r2=1535820&rev=1535820&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/PersistenceCopier.java
(original)
+++
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/JackrabbitNodeState.java
Fri Oct 25 19:07:21 2013
@@ -16,16 +16,15 @@
*/
package org.apache.jackrabbit.oak.upgrade;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Lists.newArrayListWithCapacity;
-import static org.apache.jackrabbit.JcrConstants.JCR_MIXINTYPES;
-import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
-import static org.apache.jackrabbit.oak.api.Type.NAME;
import java.io.IOException;
+import java.io.InputStream;
import java.math.BigDecimal;
-import java.util.HashSet;
import java.util.List;
-import java.util.Set;
import javax.jcr.NamespaceRegistry;
import javax.jcr.PropertyType;
@@ -41,18 +40,17 @@ import org.apache.jackrabbit.core.state.
import org.apache.jackrabbit.core.value.InternalValue;
import org.apache.jackrabbit.oak.api.Blob;
import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.plugins.memory.AbstractBlob;
+import org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState;
+import org.apache.jackrabbit.oak.plugins.memory.MemoryChildNodeEntry;
+import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeBuilder;
import org.apache.jackrabbit.oak.plugins.memory.PropertyStates;
+import org.apache.jackrabbit.oak.spi.state.AbstractNodeState;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
-import org.apache.jackrabbit.oak.spi.state.NodeStore;
import org.apache.jackrabbit.spi.Name;
import org.apache.jackrabbit.spi.Path;
-/**
- * Tool for copying item states from a Jackrabbit persistence manager to
- * an Oak node builder. Used for migrating repository content from Jackrabbit
- * to Oak.
- */
-class PersistenceCopier {
+class JackrabbitNodeState extends AbstractNodeState {
/**
* Source persistence manager.
@@ -64,149 +62,149 @@ class PersistenceCopier {
*/
private final NamespaceRegistry registry;
- /**
- * Target node store.
- */
- private final NodeStore store;
+ private final NodeId id;
- /**
- * 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>();
+ private NodeState state = null;
- public PersistenceCopier(
+ JackrabbitNodeState(
PersistenceManager source, NamespaceRegistry registry,
- NodeStore store) {
+ NodeId id) {
this.source = source;
this.registry = registry;
- this.store = store;
+ this.id = id;
}
- private String getOakName(Name name) throws RepositoryException {
- String uri = name.getNamespaceURI();
- String local = name.getLocalName();
- if (uri == null || uri.isEmpty()) {
- return local;
- } else {
- return registry.getPrefix(uri) + ":" + local;
+ private NodeState getState() {
+ if (state == null) {
+ try {
+ state = source.load(id);
+ } catch (ItemStateException e) {
+ throw new IllegalStateException(e);
+ }
}
+ return state;
}
- private String getOakPath(Path path) throws RepositoryException {
- StringBuilder builder = new StringBuilder();
- for (Path.Element element : path.getElements()) {
- if (builder.length() > 1
- || (builder.length() == 1 &&
!"/".equals(builder.toString()))) {
- builder.append('/');
- }
- if (element.denotesRoot()) {
- builder.append('/');
- } else if (element.denotesIdentifier()) {
-
builder.append('[').append(element.getIdentifier()).append(']');
- } else if (element.denotesName()) {
- builder.append(getOakName(element.getName()));
- if (element.getIndex() >= Path.INDEX_DEFAULT) {
- builder.append('[').append(element.getIndex()).append(']');
+ //---------------------------------------------------------< NodeState >--
+
+ @Override
+ public boolean exists() {
+ return true;
+ }
+
+ @Override
+ public Iterable<org.apache.jackrabbit.oak.api.PropertyState>
getProperties() {
+ List<org.apache.jackrabbit.oak.api.PropertyState> properties =
newArrayList();
+ for (Name name : getState().getPropertyNames()) {
+ try {
+ PropertyState property = source.load(new PropertyId(id, name));
+ int type = property.getType();
+ if (property.isMultiValued()) {
+ properties.add(createProperty(
+ createName(name), type, property.getValues()));
+ } else {
+ properties.add(createProperty(
+ createName(name), type, property.getValues()[0]));
}
- } else if (element.denotesParent()) {
- builder.append("..");
- } else if (element.denotesCurrent()) {
- builder.append('.');
- } else {
- throw new RepositoryException(
- "Unknown path element: " + element);
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
}
}
- return builder.toString();
+ return properties;
}
- /**
- * 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);
+ @Override
+ public org.apache.jackrabbit.oak.spi.state.NodeState getChildNode(String
name) {
+ for (MemoryChildNodeEntry entry : getChildNodeEntries()) {
+ if (name.equals(entry.getName())) {
+ return entry.getNodeState();
+ }
+ }
+ return EmptyNodeState.MISSING_NODE;
}
- /**
- * 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 RepositoryException if the copy operation fails
- */
- public void copy(NodeId id, NodeBuilder builder)
- throws RepositoryException, IOException {
- try {
- NodeState node = source.load(id);
- copy(node, builder);
-
- for (ChildNodeEntry entry : node.getChildNodeEntries()) {
- NodeId childId = entry.getId();
- if (!exclude.contains(childId)) {
- exclude.add(childId);
- String name = getOakName(entry.getName());
- copy(childId, builder.child(name));
- exclude.remove(childId);
+ @Override
+ public Iterable<MemoryChildNodeEntry> getChildNodeEntries() {
+ List<MemoryChildNodeEntry> entries = newArrayList();
+ for (ChildNodeEntry entry : getState().getChildNodeEntries()) {
+ try {
+ String name = createName(entry.getName());
+ int index = entry.getIndex();
+ if (index > 1) {
+ name = name + '[' + index + ']';
}
+
+ JackrabbitNodeState state = new JackrabbitNodeState(
+ source, registry, entry.getId());
+
+ entries.add(new MemoryChildNodeEntry(name, state));
+ } catch (RepositoryException e) {
+ throw new IllegalStateException(e);
}
- } catch (ItemStateException e) {
- throw new RepositoryException("Unable to copy " + id, e);
}
+ return entries;
}
- /**
- * Copies the given node state and all associated property states
- * to the node builder.
- *
- * @param sourceNode source node state
- * @throws RepositoryException if the copy operation fails
- */
- private void copy(NodeState sourceNode, NodeBuilder builder)
- throws RepositoryException, IOException, ItemStateException {
- // Copy the node state
- String primary = getOakName(sourceNode.getNodeTypeName());
- builder.setProperty(JCR_PRIMARYTYPE, primary, NAME);
-
- Set<Name> mixinNames = sourceNode.getMixinTypeNames();
- if (!mixinNames.isEmpty()) {
- List<String> mixins = newArrayListWithCapacity(mixinNames.size());
- for (Name name : mixinNames) {
- mixins.add(getOakName(name));
- }
- builder.setProperty(JCR_MIXINTYPES, mixins, Type.NAMES);
- }
+ @Override
+ public NodeBuilder builder() {
+ return new MemoryNodeBuilder(this);
+ }
- // Copy all associated property states
- for (Name name : sourceNode.getPropertyNames()) {
- PropertyId id = new PropertyId(sourceNode.getNodeId(), name);
- PropertyState sourceState = source.load(id);
-
- InternalValue[] values = sourceState.getValues();
- int type = sourceState.getType();
- String oakName = getOakName(name);
- if (sourceState.isMultiValued() || values.length != 1) {
- builder.setProperty(getProperty(oakName, values, type));
- } else {
- builder.setProperty(getProperty(oakName, values[0], type));
- }
+ //-----------------------------------------------------------< private >--
+
+ private org.apache.jackrabbit.oak.api.PropertyState createProperty(
+ String name, int type, InternalValue value)
+ throws RepositoryException, IOException {
+ switch (type) {
+ case PropertyType.BINARY:
+ return PropertyStates.createProperty(
+ name, createBlob(value), Type.BINARY);
+ case PropertyType.BOOLEAN:
+ return PropertyStates.createProperty(
+ name, value.getBoolean(), Type.BOOLEAN);
+ case PropertyType.DATE:
+ return PropertyStates.createProperty(
+ name, value.getString(), Type.DATE);
+ case PropertyType.DECIMAL:
+ return PropertyStates.createProperty(
+ name, value.getDecimal(), Type.DECIMAL);
+ case PropertyType.DOUBLE:
+ return PropertyStates.createProperty(
+ name, value.getDouble(), Type.DOUBLE);
+ case PropertyType.LONG:
+ return PropertyStates.createProperty(
+ name, value.getLong(), Type.LONG);
+ case PropertyType.NAME:
+ return PropertyStates.createProperty(
+ name, createName(value.getName()), Type.NAME);
+ case PropertyType.PATH:
+ return PropertyStates.createProperty(
+ name, createPath(value.getPath()), Type.PATH);
+ case PropertyType.REFERENCE:
+ return PropertyStates.createProperty(
+ name, value.getNodeId().toString(), Type.REFERENCE);
+ case PropertyType.STRING:
+ return PropertyStates.createProperty(
+ name, value.getString(), Type.STRING);
+ case PropertyType.URI:
+ return PropertyStates.createProperty(
+ name, value.getURI().toString(), Type.URI);
+ case PropertyType.WEAKREFERENCE:
+ return PropertyStates.createProperty(
+ name, value.getNodeId().toString(), Type.WEAKREFERENCE);
+ default:
+ throw new RepositoryException("Unknown value type: " + type);
}
}
- private org.apache.jackrabbit.oak.api.PropertyState getProperty(
- String name, InternalValue[] values, int type)
+ private org.apache.jackrabbit.oak.api.PropertyState createProperty(
+ String name, int type, InternalValue[] values)
throws RepositoryException, IOException {
switch (type) {
case PropertyType.BINARY:
List<Blob> binaries = newArrayListWithCapacity(values.length);
for (InternalValue value : values) {
- binaries.add(store.createBlob(value.getStream()));
+ binaries.add(createBlob(value));
}
return PropertyStates.createProperty(name, binaries,
Type.BINARIES);
case PropertyType.BOOLEAN:
@@ -242,13 +240,13 @@ class PersistenceCopier {
case PropertyType.NAME:
List<String> names = newArrayListWithCapacity(values.length);
for (InternalValue value : values) {
- names.add(getOakName(value.getName()));
+ names.add(createName(value.getName()));
}
return PropertyStates.createProperty(name, names, Type.NAMES);
case PropertyType.PATH:
List<String> paths = newArrayListWithCapacity(values.length);
for (InternalValue value : values) {
- paths.add(getOakPath(value.getPath()));
+ paths.add(createPath(value.getPath()));
}
return PropertyStates.createProperty(name, paths, Type.PATHS);
case PropertyType.REFERENCE:
@@ -280,49 +278,64 @@ class PersistenceCopier {
}
}
- private org.apache.jackrabbit.oak.api.PropertyState getProperty(
- String name, InternalValue value, int type)
- throws RepositoryException, IOException {
- switch (type) {
- case PropertyType.BINARY:
- return PropertyStates.createProperty(
- name, store.createBlob(value.getStream()), Type.BINARY);
- case PropertyType.BOOLEAN:
- return PropertyStates.createProperty(
- name, value.getBoolean(), Type.BOOLEAN);
- case PropertyType.DATE:
- return PropertyStates.createProperty(
- name, value.getString(), Type.DATE);
- case PropertyType.DECIMAL:
- return PropertyStates.createProperty(
- name, value.getDecimal(), Type.DECIMAL);
- case PropertyType.DOUBLE:
- return PropertyStates.createProperty(
- name, value.getDouble(), Type.DOUBLE);
- case PropertyType.LONG:
- return PropertyStates.createProperty(
- name, value.getLong(), Type.LONG);
- case PropertyType.NAME:
- return PropertyStates.createProperty(
- name, getOakName(value.getName()), Type.NAME);
- case PropertyType.PATH:
- return PropertyStates.createProperty(
- name, getOakPath(value.getPath()), Type.PATH);
- case PropertyType.REFERENCE:
- return PropertyStates.createProperty(
- name, value.getNodeId().toString(), Type.REFERENCE);
- case PropertyType.STRING:
- return PropertyStates.createProperty(
- name, value.getString(), Type.STRING);
- case PropertyType.URI:
- return PropertyStates.createProperty(
- name, value.getURI().toString(), Type.URI);
- case PropertyType.WEAKREFERENCE:
- return PropertyStates.createProperty(
- name, value.getNodeId().toString(), Type.WEAKREFERENCE);
- default:
- throw new RepositoryException("Unknown value type: " + type);
+ private Blob createBlob(final InternalValue value) {
+ checkArgument(checkNotNull(value).getType() == PropertyType.BINARY);
+ return new AbstractBlob() {
+ @Override
+ public long length() {
+ try {
+ return value.getLength();
+ } catch (RepositoryException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ @Override
+ public InputStream getNewStream() {
+ try {
+ return value.getStream();
+ } catch (RepositoryException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ };
+ }
+
+ private String createName(Name name) throws RepositoryException {
+ String uri = name.getNamespaceURI();
+ String local = name.getLocalName();
+ if (uri == null || uri.isEmpty()) {
+ return local;
+ } else {
+ return registry.getPrefix(uri) + ":" + local;
}
}
+ private String createPath(Path path) throws RepositoryException {
+ StringBuilder builder = new StringBuilder();
+ for (Path.Element element : path.getElements()) {
+ if (builder.length() > 1
+ || (builder.length() == 1 &&
!"/".equals(builder.toString()))) {
+ builder.append('/');
+ }
+ if (element.denotesRoot()) {
+ builder.append('/');
+ } else if (element.denotesIdentifier()) {
+
builder.append('[').append(element.getIdentifier()).append(']');
+ } else if (element.denotesName()) {
+ builder.append(createName(element.getName()));
+ if (element.getIndex() >= Path.INDEX_DEFAULT) {
+ builder.append('[').append(element.getIndex()).append(']');
+ }
+ } else if (element.denotesParent()) {
+ builder.append("..");
+ } else if (element.denotesCurrent()) {
+ builder.append('.');
+ } else {
+ throw new RepositoryException(
+ "Unknown path element: " + element);
+ }
+ }
+ return builder.toString();
+ }
+
}
Modified:
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java?rev=1535820&r1=1535819&r2=1535820&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java
(original)
+++
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java
Fri Oct 25 19:07:21 2013
@@ -44,6 +44,9 @@ import static org.apache.jackrabbit.JcrC
import static org.apache.jackrabbit.JcrConstants.NT_CHILDNODEDEFINITION;
import static org.apache.jackrabbit.JcrConstants.NT_NODETYPE;
import static org.apache.jackrabbit.JcrConstants.NT_PROPERTYDEFINITION;
+import static org.apache.jackrabbit.core.RepositoryImpl.ACTIVITIES_NODE_ID;
+import static org.apache.jackrabbit.core.RepositoryImpl.ROOT_NODE_ID;
+import static
org.apache.jackrabbit.core.RepositoryImpl.VERSION_STORAGE_NODE_ID;
import static org.apache.jackrabbit.oak.api.Type.NAME;
import static org.apache.jackrabbit.oak.api.Type.NAMES;
import static org.apache.jackrabbit.oak.api.Type.STRINGS;
@@ -63,21 +66,26 @@ import java.util.Map;
import java.util.Properties;
import javax.jcr.NamespaceException;
+import javax.jcr.NamespaceRegistry;
import javax.jcr.RepositoryException;
import javax.jcr.version.OnParentVersionAction;
+import org.apache.jackrabbit.core.NamespaceRegistryImpl;
import org.apache.jackrabbit.core.RepositoryContext;
-import org.apache.jackrabbit.core.RepositoryImpl;
import org.apache.jackrabbit.core.config.RepositoryConfig;
import org.apache.jackrabbit.core.fs.FileSystem;
import org.apache.jackrabbit.core.fs.FileSystemException;
import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
+import org.apache.jackrabbit.core.persistence.PersistenceManager;
+import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.plugins.name.Namespaces;
import org.apache.jackrabbit.oak.plugins.nodetype.RegistrationEditorProvider;
import org.apache.jackrabbit.oak.spi.commit.CommitHook;
import org.apache.jackrabbit.oak.spi.commit.EditorHook;
+import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.apache.jackrabbit.oak.spi.state.NodeStore;
import org.apache.jackrabbit.spi.Name;
import org.apache.jackrabbit.spi.QItemDefinition;
@@ -416,15 +424,18 @@ public class RepositoryUpgrade {
NodeBuilder root, Map<Integer, String> idxToPrefix)
throws RepositoryException, IOException {
logger.info("Copying version histories");
- NodeBuilder system = root.child(JCR_SYSTEM);
- NodeBuilder versionStorage = system.child(JCR_VERSIONSTORAGE);
- NodeBuilder activities = system.child("jcr:activities");
- PersistenceCopier copier = new PersistenceCopier(
- source.getInternalVersionManager().getPersistenceManager(),
- source.getNamespaceRegistry(), target);
- copier.copy(RepositoryImpl.VERSION_STORAGE_NODE_ID, versionStorage);
- copier.copy(RepositoryImpl.ACTIVITIES_NODE_ID, activities);
+ PersistenceManager pm =
+ source.getInternalVersionManager().getPersistenceManager();
+ NamespaceRegistry nr =source.getNamespaceRegistry();
+
+ NodeBuilder system = root.child(JCR_SYSTEM);
+ system.setChildNode(
+ JCR_VERSIONSTORAGE,
+ new JackrabbitNodeState(pm, nr, VERSION_STORAGE_NODE_ID));
+ system.setChildNode(
+ "jcr:activities",
+ new JackrabbitNodeState(pm, nr, ACTIVITIES_NODE_ID));
}
private void copyWorkspaces(
@@ -435,11 +446,21 @@ public class RepositoryUpgrade {
// Copy all the default workspace content
RepositoryConfig config = source.getRepositoryConfig();
String name = config.getDefaultWorkspaceName();
- PersistenceCopier copier = new PersistenceCopier(
- source.getWorkspaceInfo(name).getPersistenceManager(),
- source.getNamespaceRegistry(), target);
- copier.excludeNode(RepositoryImpl.SYSTEM_ROOT_NODE_ID);
- copier.copy(RepositoryImpl.ROOT_NODE_ID, root);
+
+ PersistenceManager pm =
+ source.getWorkspaceInfo(name).getPersistenceManager();
+ NamespaceRegistryImpl nr = source.getNamespaceRegistry();
+
+ NodeState state = new JackrabbitNodeState(pm, nr, ROOT_NODE_ID);
+ for (PropertyState property : state.getProperties()) {
+ root.setProperty(property);
+ }
+ for (ChildNodeEntry child : state.getChildNodeEntries()) {
+ String childName = child.getName();
+ if (!JCR_SYSTEM.equals(childName)) {
+ root.setChildNode(childName, child.getNodeState());
+ }
+ }
// TODO: Copy all the active open-scoped locks
}