Migration

The migration feature allows Gentics CMS Administrators to migrate tags of pages, templates and object type definitions. The migration feature is divided into two parts. The Tagtype Migration and the Template Migration. This document will explain both types.

This feature is available with Gentics CMS Version 5.13.0 and later.

This feature is a purchasable addon that needs to be activated for your Gentics CMS license key by Gentics Support.

1 Tagtype Migration

The Tagtype Migration (TTM) feature allows Gentics CMS Administrators to map existing tags from one construct to another. A Tagtype Migration modifies the tags so that they match the structure of the selected tag type (construct) they will be mapped to during the migration process.

1.1 Access

The TTM is accessible using the action drop-down menu within page lists and template lists. Additionally it is also possible to access the TTM using the right click context menu within page and template lists. Furthermore the TTM can be accessed through the object property definition top menu. It is possible to invoke the tag type migration for a set of pages. In this case the pages have to be selected and the tag type migration action has to be invoked using the actions dropdown menu witin the page list. In this case all tagtype that are being used within the pages will be collected in order to fill the tagtype dropdown box (Add mapping) within the tag type migration view.

Additionally to the methods described above, it is possible to start a “global” migration from the top menu of the tag types list. The global migration will migrate all objects, that have tags using the tag types that are selected to be migrated. However it is possible to restrict by type (pages, templates, object properties) or by node.

The feature tag typemigration must be enabled and the user must have the permission to create new tag types in order to access the TTM.

1.2 Phases of a page migration

* Determination of the objects that should be migrated
* Validation of the given mapping on the previously determined objects
* Creation of a backup using the export functionality
  * Migration of each page
    * Iterate over all contenttags of the page
      * Apply pre processors on each tag
        * pre processors may modify the tag
        * pre processors may request the tag to be skipped
        * pre processors may request the page to be skipped
      * Apply mapping on the contenttags of the page
    * Invocation of the selected post processors
    * Save the page and handle the original page status. Published pages will be marked for publishing. Offline pages will be taken offline. Please note that pages that were added to the publish queue will published according to the permissions of the user that invoked the migration process.
* Commit of the transaction once the migration completed successfully

1.3 Logging

The migration logfiles are located in /Node/node/log/migration. Please note that javascript errors will only be logged inside your browser window.

1.4 Options

1.4.1 Enable Pre processors

It is possible to enable a set of pre processors. See Pre Processors for more information.

1.4.2 Enable Post processors

It is possible to enable a set of post processors. See Post Processors for more information.

1.4.3 Handle pages by template

When the user starts a Tag Type Migrations on a single page an additional option checkbox will be shown. The Apply this migration to all pages using this page’s template. option allows the user to apply the mapping to all pages of this node that use the template of this page.

This option is useful if you want to migrate a single contenttag in all pages that use a specific template.

1.4.4 Handle all nodes

When the option Apply this migration to all pages using this page’s template. is selected, an additional checkbox will be shown to Apply this migration to all nodes. By default, only pages in the same node as the originally selected page would be migrated. When this option is selected, all pages having the same template in all nodes will be migrated.

1.4.5 Prevent trigger events

When enabled no trigger events will be invoked. This will effectively speed up the final phase of the migration process.

It is mandatory to manually republish all objects when this option was enabled. When enabled the dirting and dependency calculation will not be directly invoked.

1.4.6 Node restriction (for global TTM)

When starting a global Tag Type Migration, it is possible to restrict the migration to specific nodes or channels. By default, the migration will affect objects of all nodes.

The node restriction will affect the migration in the following way:

  • If pages are migrated, they will only be affected if they are contained in one of the selected nodes. Localized copies or channel local pages will only be affected, if their channel is selected.
  • If templates are migrated, they will only be affected if they are assigned to at least one folder in one of the selected nodes. Localized copies or channel local templates will only be affected, if their channel is selected.
  • If object property definitions are migrated, they will only be affected, if they are either not restricted to nodes, or are restricted to at least one of the selected nodes. Because object property definitions cannot be assigned to channels, selecting channels for the node restriction will not affect object property definitions.

If a template is migrated, all pages effectively using that template will have the tags changed, that are defined in the template as being “editable in page”, even if the page is contained in a node, which is not chosen to be migrated.

With the node restriction, it is possible to migrate master templates or pages, but not their localized copies (or vice versa).

1.4.7 Migrated objects (for global TTM)

For a global Tag Type Migration, it is necessary to choose, which objects shall be migrated (at least one type needs to be selected):

  • Pages will migrate all pages containing tags that use the tag types that shall be migrated.
  • Templates will migrate all templates containing tags that use the tag types that shall be migrated.
  • Object properties will migrate all object property definitions using the migrated tag types.

1.5 Configuration


  // Enables the migration feature
  $FEATURE["tagtypemigration"] = true;
  $TAGTYPEMIGRATION_POSTPROCESSORS = array();
  // Adds the processor to the list of post processors
  $TAGTYPEMIGRATION_POSTPROCESSORS[0] = 'com.gentics.contentnode.TestProcessor';
  // Enables or disables the creation of a backup before each migration run. Default is false.
  // This is useful when you plan to do a large migration with a database backup
  $TAGTYPEMIGRATION_SKIPBACKUP = false;
  // Set the poll interval for getting the status in the migration dialog in seconds (Default is 1)
  $TAGTYPEMIGRATION_POLLINTERVAL = 10;

1.6 Use Cases

The page ‘demopage.html’ contains the following legacy content tags:

Tag Keyword Tagtype
externallink1 Link [pagelink]
externallink2 Link [pagelink]
subnav Legacy Overview [legacyoverview]
content Text/HTML (long) [textlang]
teaserimage Legacy Image [legacyimage]

The goal is to migrate the content tags so that they no longer reference legacy tag types (constructs):

Tag Keyword Tagtype
externallink1 Aloha Link [gtxalohapagelink]
externallink2 Aloha Link [gtxalohapagelink]
subnav Overview [overview]
content WrappedContent [wrappedcontent]
teaserimage Bild [image]

This can be achieved using the Tagtype Migration. The user needs to input a mapping that defines which part values of the source tag should be mapped to the new tag type parts.

Example:

The source tag externallink1 tag type contains the following parts:

Part Keyword Part Type Description
vtl Velocity Basic velocity part with no value
template Text/HTML Basic velocity template with the velocity code
linkurl URL (page) Basic url page part for storing the url
class Text (short) Contains the css class
data Text (short) Legacy data attribute field value
behaviour Text (short) Legacy field for the link target

The target tag type contains the following part:

Part Keyword Part Type Description
vtl Velocity Basic velocity part with no value
template Text/HTML Basic velocity template with the velocity code
url URL (page) Basic url page part for storing the url
class Text (short) Contains the css class
title Text (short) Contains the link title
target Text (short) The link target

We can now use the Tagtype Migration to map the parts:


  linkurl -> url
  class -> class
  behaviour -> target

The vtl part cannot be mapped since it does not contain a value. The template part will not be mapped since we want to keep the template of the target tag type (construct). The data part type value will be omitted. The data from that part type will be deleted.

The migration job will migrate the tag externallink1 and externallink2. All other content tags will not be affected since no mapping has been specified for the corresponding tags.

1.7 References

Certain references to parts that are migrated using TTM are automatically updated during the migration process. The scope of these automatically updated references is limited to the tag type being migrated. This means that part references from other parts within the same tag will be updated automatically. References that are beyond the scope of the automatic reference update process, such as references to a part from another tag, must also be updated manually after the migration process has completed.

References to parts that are deleted during Tagtype Migration are not automatically updated and must be removed manually after migration.

1.8 Limitations

When tags in a template are migrated, that are editable in pages, the tags in the pages will also be changed to use the new construct, but not migrated with the mapping. If the pages also should be migrated with a mapping, this must either be done in a separate step before the template is migrated, or by doing a global tagtype migration on pages and templates.

  • Part types of type Select (multiple) and Select (single) can only be mapped to another Select (single) / Select (multiple) part type when the target and source part types utilize the same datasource.
  • The Post Processors can’t be used to change the status of a given page.

1.9 Allowed PartType Mapping Table

Part Type Value Classification Mappable To
Breadcrumb No value Not mappable
Navigation No value Not mappable
Table ext No value Not mappable
Velocity No value Not mappable
Checkbox Boolean value Boolean value
Datasource Datasource Datasource
Select (image-height) Legacy Type Not mappable
Select (image-width) Legacy Type Not mappable
DHTML Editor String value String value
HTML (custom form) String value String value
HTML (long) String value String value
Java Editor String value String value
Text String value String value
Text (custom form) String value String value
Text (short) String value String value
Text/HTML String value String value
Text/HTML (long) String value String value
HTML String value String value
List String value String value
List (ordered) String value String value
List (unordered) String value String value
Folder (Upload) FolderId FolderId
URL (Folder) FolderId FolderId
Overview Overview Overview
Select (multiple) Select multiple Select multiple
Select (single) Select single Select single
Tag (page) PageTag Ref PageTag Ref
Tag (template) TempateTag Ref TempateTag Ref
URL (file) FileId FileId
File (Upload) FileId FileId
URL (image) ImageId ImageId
URL (page) PageId, String value String value, PageId

2 Template Migration

The template migration allows the user to migrate pages by defining a mapping in between two templates. The user has to select the source template and after that the target template. After that step a mapping between the template tags of that template can be specified.

2.1 Use Case

Source Template:

Tag Description
css Text/HTML (long), Contains inline CSS
javascript Text/HTML (long), Contains a reference to the carouseljavascript tag
carouseljavascript Text/HTML (long), Contains inline javascript which updates a jquery carousel
content Text/HTML (long), In page editable tag that contains the main content
header Text/HTML (long), In page editable tag that contains the header content

Target Template:

Tag Description
inlinecss Text/HTML (long), Contains inline CSS
inlinejs Text/HTML (long), Contains inline JS
inlinejs2 Text/HTML (long), Contains inline JS
inlinejs3 Text/HTML (long), Contains inline JS
body Text/HTML (long), In page editable tag that contains the main content
headertext Text/HTML (long), In page editable tag that contains the header content

Mapping:

  • carouseljavascript → inlinejs3
  • css → inlinecss
  • javascript → inlinejs
  • content → body
  • header → headertext

This migration will modify all pages that use the source template. The tags in that page that were inherited by the non editable template tag will be renamed to the target template tag name. In our case the carouseljavascript tag will be renamed to inlinejs3. This will also affect the references to the carouseljavascript tag. All those references will be changed to inlinejs3. The construct id for the tags in the page will be changed according to the defined mapping. The migration will select the target construct / tagtype for the migration by examining the target template tag construct type.

2.2 Limitations

The Template Migration will only be applied for the parent Node of the template you selected first.

3 Post Processors

Following the migration process, custom post processors may be applied to migrated objects. To achieve this, an implementation of the interface com.gentics.api.contentnode.ttm.ITagMigrationPostprocessor must to be specified in the configuration.

The implemented class must be able to be loaded by the Servlet ClassLoader. The compiled jar file/s can be placed in the /Node/tomcat/shared/lib/custom directory. A restart of the tomcat server is required in order to load the TagMigrationPostprocessor classes.

The ITagMigrationPostprocessor interface provides method definitions for pages, templates, folders, files and images, all of which can be modified following the migration. The TtmMigrationRequest object is provided as well and can be used to retrieve the migration mapping parameters. A logger class is also available and logging calls made in the post processor will appear in the log file for the corresponding migration job.

Post processors can be specified by adding the following configuration to the node.conf file.


	$TAGTYPEMIGRATION_POSTPROCESSORS = array();
	$TAGTYPEMIGRATION_POSTPROCESSORS[0] = 'tdl.yourcompany.contentnode.TTMTestProcessor';
	$TAGTYPEMIGRATION_POSTPROCESSORS[1] = 'tdl.yourcompany.contentnode.TTMTestProcessor2';
	$TAGTYPEMIGRATION_POSTPROCESSORS[2] = 'tdl.yourcompany.contentnode.TTMTestProcessor3';

Each post processor has a unique id, which is defined as the array index of the $TAGTYPEMIGRATION_POSTPROCESSTORS array. The id also determines the order in which the post processors will be invoked.

During the migration process, the post processor(s) that should be applied following the migration can be selected in the user interface by activating the corresponding checkboxes.

3.1 Limitations

  • Currenly it is not possible to change the page status within a post processor.

3.2 Example Implementation

A custom postprocessor can be used to migrate certain parts in a tag from one value to another that is not supported by the direct mapping.

In this example we want to migrate all the tags of a certain page. The tagtype that was choosen for the migration contains three parts. Two checkboxes parts are used to select two options. The third part is a selectbox part which was added for this migration.

Part Keyword Type
selectbox Select (single)
checkbox1 Checkbox
checkbox2 Checkbox

The goal of the migration is to read the checkbox values and set the selectbox value that matches the checkbox value. The mapping of the checkbox values to the selectbox option will be handled within the post processor.

DummyPostProcessor.java

package com.gentics.contentnode.migration.postprocessor;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import com.gentics.api.contentnode.migration.IMigrationPostprocessor;
import com.gentics.api.contentnode.migration.MigrationException;
import com.gentics.contentnode.rest.model.File;
import com.gentics.contentnode.rest.model.Folder;
import com.gentics.contentnode.rest.model.Image;
import com.gentics.contentnode.rest.model.Page;
import com.gentics.contentnode.rest.model.Property;
import com.gentics.contentnode.rest.model.SelectOption;
import com.gentics.contentnode.rest.model.Tag;
import com.gentics.contentnode.rest.model.Template;
import com.gentics.contentnode.rest.model.request.migration.TagTypeMigrationRequest;
import com.gentics.contentnode.rest.model.request.migration.TemplateMigrationRequest;

/**
 * 
 * An example dummy post processor for the tagtype migration which will migrate
 * tags of a single tag. The processor
 * 
 */
public class DummyPostProcessor implements IMigrationPostprocessor {

	/**
	 * ID of the construct that should be used for the migration.
	 */
	final private static int TARGET_CONSTRUCT_ID = 67;

	/*
	 * (non-Javadoc)
	 * 
	 * @see IMigrationPostprocessor#applyPostMigrationProcessing(Template,
	 * TagTypeMigrationRequest, Logger)
	 */
	public void applyPostMigrationProcessing(Template template, TagTypeMigrationRequest request, Logger logger) throws MigrationException {

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see IMigrationPostprocessor#applyPostMigrationProcessing(Page,
	 * TagTypeMigrationRequest, Logger)
	 */
	public void applyPostMigrationProcessing(Page page, TagTypeMigrationRequest request, Logger logger) throws MigrationException {

		// Iterate over all tags and try to find our target tags
		for (Tag tag : page.getTags().values()) {
			// Only update tags that were created using the target construct id
			if (tag.getType() == Tag.Type.CONTENTTAG && tag.getConstructId() == TARGET_CONSTRUCT_ID) {
				// First update the tag and set the selectbox value to 1 if the
				// checkbox1 value is true
				updateTag(tag, "checkbox1", "1");
				// Second update the tag and set the selectbox value to 0 if the
				// checkbox2 value is true, this will overwrite any previously
				// set values
				updateTag(tag, "checkbox2", "0");
			}
		}
	}

	/**
	 * Updates the given tag. The keyword and value strings are used to identify
	 * the correct parts and set the desired value.
	 * 
	 * @param tag
	 *            Tag that should be updated
	 * @param checkboxPartKeyword
	 *            Keyword of the checkbox part that should be inspected
	 * @param selectboxUpdateValue
	 *            Value for the selectbox option that should be set when the
	 *            given checkbox part value is true.
	 */
	private void updateTag(Tag tag, String checkboxPartKeyword, String selectboxUpdateValue) {
		final String SELECTBOX_PART_KEYWORD = "selectbox";
		// Load the parts (properties) of that tag and try to load the
		// checkbox value
		Map<String, Property> parts = tag.getProperties();
		Property checkboxPartValue = parts.get(checkboxPartKeyword);
		// Only update the selectbox part when the checkbox is checked
		if (checkboxPartValue != null && checkboxPartValue.getBooleanValue()) {
			// Iterate over all options
			Property selectPartProperty = parts.get(SELECTBOX_PART_KEYWORD);
			if (selectPartProperty.getType() == Property.Type.SELECT) {
				List<SelectOption> options = selectPartProperty.getOptions();
				for (SelectOption option : options) {
					// Set the option value1 for the selectbox part. discard
					// all previously set values
					if (selectboxUpdateValue.equalsIgnoreCase(option.getValue())) {
						List<SelectOption> newOption = new ArrayList<SelectOption>();
						newOption.add(option);
						selectPartProperty.setSelectedOptions(newOption);
					}
				}
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see IMigrationPostprocessor#applyPostMigrationProcessing(Folder,
	 * TagTypeMigrationRequest, Logger)
	 */
	public void applyPostMigrationProcessing(Folder folder, TagTypeMigrationRequest request, Logger logger) throws MigrationException {

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see IMigrationPostprocessor#applyPostMigrationProcessing(Image,
	 * TagTypeMigrationRequest, Logger)
	 */
	public void applyPostMigrationProcessing(Image image, TagTypeMigrationRequest request, Logger logger) throws MigrationException {

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see IMigrationPostprocessor#applyPostMigrationProcessing(File,
	 * TagTypeMigrationRequest, Logger)
	 */
	public void applyPostMigrationProcessing(File file, TagTypeMigrationRequest request, Logger logger) throws MigrationException {

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see IMigrationPostprocessor#applyPostMigrationProcessing(Page,
	 * TagTypeMigrationRequest, Logger)
	 */
	public void applyPostMigrationProcessing(Page page, TemplateMigrationRequest request, Logger logger) throws MigrationException {
		// Iterate over all tags and try to find our target tags
		for (Tag tag : page.getTags().values()) {
			if (tag.getType() == Tag.Type.CONTENTTAG && tag.getConstructId() == TARGET_CONSTRUCT_ID) {
				updateTag(tag, "checkbox1", "value1");
				updateTag(tag, "checkbox2", "value2");
			}
		}
	}

}

You may use this maven snippet to add the needed dependencies to your maven project.


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>your.company</groupId>
	<artifactId>your-project-artifact-name</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<dependencies>
		<dependency>
			<groupId>com.gentics</groupId>
			<artifactId>contentnode-api</artifactId>
			<version>5.17.0</version>
		</dependency>
	</dependencies>
	<repositories>
		<repository>
			<id>maven.gentics.com</id>
			<name>Gentics Maven Repository</name>
			<url>https://maven.gentics.com/maven2/</url>
			<releases>
				<enabled>true</enabled>
			</releases>
			<snapshots>
				<enabled>false</enabled>
			</snapshots>
		</repository>
	</repositories>
</project>

Enable the post processor within your conf.d/node.ttm.conf file. You may create the file if it does not exist.


  $TAGTYPEMIGRATION_POSTPROCESSORS = array();
  $TAGTYPEMIGRATION_POSTPROCESSORS[0] = 'com.gentics.contentnode.migration.postprocessor.DummyPostProcessor';

Once you have build your post processor and added the resulting jar file to the sharedclass loader path of Gentics CMS you are ready to start your migration.

  • Copy your jar file to /Node/tomcat/shared/lib/custom/
  • Select the objects you want to migrate and choose the DummyPostProcessor.
  • Select the source Tagtype and select the same tagtype for the target mapping.
  • Invoke your migration.

4 Pre Processors

Analogously to post processors, it is also possible to define pre processors (which must implement the interface com.gentics.api.contentnode.ttm.ITagMigrationPreprocessor).

Pre processors must be defined with


	$TAGTYPEMIGRATION_PREPROCESSORS = array();
	$TAGTYPEMIGRATION_PREPROCESSORS[0] = 'tdl.yourcompany.contentnode.TTMTestProcessor';
	$TAGTYPEMIGRATION_PREPROCESSORS[1] = 'tdl.yourcompany.contentnode.TTMTestProcessor2';
	$TAGTYPEMIGRATION_PREPROCESSORS[2] = 'tdl.yourcompany.contentnode.TTMTestProcessor3';

Before an object is migrated, all of its tags that will be touched during the migration are passed through all enabled pre processors. Every pre processor can

  • Modify the tag
  • Let the migration skip the tag (all modifications done by previous pre processors will be thrown away)
  • Let the migration skip the whole object (all modifications done to any of the tags will be thrown away)