Namespace Migration

Overview

This page describes how to make backward-incompatible changes to a namespace's node type definitions in Bloomreach Content. The process involves migrating content to a new namespace to avoid issues with existing nodes.

When to Use Namespace Migration

You need to migrate a namespace when you want to make changes to node type definitions that are not backward-compatible. Changes fall into two categories:

  • Backward-compatible changes: These do not affect existing nodes. For example, adding a non-mandatory property to a node type does not invalidate current content.
  • Backward-incompatible changes: These may cause existing nodes to violate constraints. For example, removing a property from a node type may result in nodes that cannot be loaded because they still contain the removed property.

Jackrabbit restricts changes to existing namespaces to backward-compatible modifications. To apply backward-incompatible changes, you must migrate to a new namespace.

Migration Procedure

To perform a namespace migration, follow these steps:

  1. Remap the namespace URI of the existing namespace to a new prefix.
  2. Register a new namespace URI using the original prefix.
  3. Import the node type definitions into the new namespace and apply the required changes.
  4. Update all nodes in the repository that reference the old namespace to use the new namespace.

Example

Suppose you have the following node type definitions in the namespace http://example.com/1.0:

<nt='http://www.jcp.org/jcr/nt/1.0'> <example='http://example.com/1.0'> [example:foo] > nt:base - example:bar (string)

The namespace URI http://example.com/1.0 is mapped to the prefix example. Start by remapping this namespace to a different prefix, such as example_1. The JCR namespace registry is repository-wide. All content, including node types, is stored with the namespace URI, not the prefix. After remapping, the node type previously called example:foo becomes example_1:foo, and the property example:bar becomes example_1:bar. Name-type properties are also updated accordingly.

Next, register a new namespace with the original prefix, typically using a new versioned URI such as http://example.com/2.0.

Import the node types and make the necessary changes:

<nt='http://www.jcp.org/jcr/nt/1.0'> <example='http://example.com/2.0'> [example:foo] > nt:base

Finally, update all nodes in the old namespace (http://example.com/1.0). In this example, remove the property example_1:bar from all nodes of type example_1:foo and change their primary node type to example:foo.

Migrator Tool

Bloomreach provides a standalone tool for migrating namespaces. This tool follows the procedure described above. Unlike the checker tool, the migrator requires a custom updater to rewrite affected nodes. You must build a custom migrator JAR that includes your updater implementation.

Implementing a Custom Updater

To rewrite nodes affected by the namespace change, implement the Updater interface. Add the migrator tool as a Maven dependency to access the Updater interface:

<dependencies> <dependency> <groupId>org.onehippo.cms7</groupId> <artifactId>hippo-migrator</artifactId> <version>1.01.01</version> </dependency> </dependencies>

Refer to the Maven repository for the latest version.

A default implementation, BasicUpdater, is available and can be extended for custom logic. BasicUpdater handles:

  • Updating the primary type if it is in the old namespace.
  • Renaming mixin types in the old namespace.
  • Renaming nodes and properties with the old namespace prefix.
  • Updating Name and URI type properties that reference the old namespace.

Add custom logic for changes specific to your node type definitions. For example, to remove a property and update the node type:

package com.example.update; import javax.jcr.Node; import javax.jcr.RepositoryException; import org.onehippo.cms7.repository.migration.BasicUpdater; public class ExampleUpdater extends BasicUpdater { @Override public void update(final Node node) throws RepositoryException { final String primaryNodeTypeName = node.getPrimaryNodeType().getName(); if (primaryNodeTypeName.equals(getOldNamespacePrefix() + ":foo")) { node.addMixin("hipposys:unstructured"); node.setPrimaryType(getNewNamespacePrefix() + ":foo"); node.getProperty(getOldNamespacePrefix() + ":bar").remove(); node.removeMixin("hipposys:unstructured"); } super.update(node); } }

Key points:

  • Use BasicUpdater's getters for old and new namespace URIs and prefixes.
  • The old namespace prefix may be generated automatically by the migrator.
  • Temporarily add the hipposys:unstructured mixin to relax node type constraints during migration. Remove the mixin after updating the node.

Building the Executable JAR

After implementing the custom updater, use the Maven Shade plugin to create the executable migrator JAR:

<plugin> <artifactId>maven-shade-plugin</artifactId> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> </execution> </executions> </plugin>

Run the following command to build the JAR:

mvn package

Running the Migrator

Warning: Do not run the migrator tool in a live cluster. Ensure all repository nodes are offline and the migrator is the only process accessing the database.

Run the migrator with:

java -jar migrator.jar <command>

Initial Setup

Start by running the help command to review available options.

Create a migration.properties file:

java -jar migrator.jar props > migration.properties

Edit migration.properties to specify:

  • The path to your repository.xml
  • The CND file for your new node type definitions
  • The fully qualified class name of your updater
# point to your custom repository.xml
rep.config=example-repository.xml

# your new cnd
migration.cnd=example.cnd

# your Updater to migrate the nodes
migration.updater=com.example.ExampleUpdater

Generate a template repository configuration file:

java -jar migrator.jar config > example-repository.xml

The template uses example settings for a MySQL database. Update it to match your environment.

The new CND file must define node types in the new namespace. The migrator reads both the prefix and the new namespace URI, determines the current mapping, and generates a new prefix for the old namespace. The migrator will not run if the namespace URI in the CND is already mapped.

Running the Migration

Execute the migration:

java -jar migrator.jar migrate

Error Recovery

Test the migration thoroughly before running it on a production database. Always create a backup before proceeding.

If an error occurs in your updater, you can resume the migration without starting over. Use the --continue flag:

java -jar migrator.jar migrate --continue

This skips the namespace remapping phase and proceeds directly to content migration.

Reindexing Cluster Nodes

After completing a namespace migration, reindex all cluster nodes. The index stores names using the namespace URI. Remove the Lucene indices from each cluster node to trigger reindexing on startup.

Limitations

If you migrate a namespace used for document types, previous versions of those documents (created before migration) become inaccessible. You cannot restore document versions that use the old namespace after migration.

Share Feedback
Page: /about/upgrade-guides/namespace-migration
Section: About
Category *
Namespace Migration | Bloomreach Content Documentation