How do we upgrade existing domains with new changes to structural template ?How do we upgrade existing domains with new changes to the structural template?

This is an interesting question because a lot of people actually have those needs. Whether it is while using a content template or while using an importer, you need to be able to update existing documents. See this other question, for instance.

So for the Content Template, the factory creates the template items when a document from a specific type is created. It means nothing will happen for existing documents if you deploy a new template. The next tempting thing to do is to reapply the template to all existing documents. But then there’s a bunch of questions you need to ask yourself. Do you overwrite the content of an existing template item? What if you’ve renamed or moved a document created by the previous template? Do you create it again anyway? Do you remove existing children that are not part of the template? And should you merge the new metadata or ACL from the template?

Currently, we don’t have anything that works out of the box, and as you can see it’s a complex issue to address. They are many choices to make that we can’t impose. So, what we recommend is to write code that does exactly what you want, and run it for instance with a postContentCreationHandlers. It’s actually a shortcut to the RepositoryInitializationHandler. From the JavaDoc:

The handler is called each time a repository is opened in a JVM session. This can be used to create a default structure for the repository.

Here’s how you can add your postContentCreationHandler:

  <extension point="postContentCreationHandlers" target="org.nuxeo.ecm.platform.content.template.service.ContentTemplateService">
    <postContentCreationHandler class="org.nuxeo.ecm.platform.content.template.tests.CustomContentCreationHandler" name="customContentCreationHandler"/>
  </extension>

I just wrote a really simple handler that creates a Workspaces document named anotherworkspaceroot with title ‘Another Workspace root’ and description ‘The Description’ inside every existing Domain. It starts by a basic query returning all Domain documents. Then if there’s a child document named anotherworkspaceroot, we update its title and description. If it does not exist, we create it.

package org.nuxeo.ecm.platform.content.template.tests;

import org.nuxeo.ecm.core.api.ClientException;
import org.nuxeo.ecm.core.api.ClientRuntimeException;
import org.nuxeo.ecm.core.api.CoreSession;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.api.DocumentModelList;
import org.nuxeo.ecm.platform.content.template.service.PostContentCreationHandler;

/**
 * This ContentCreationHandler adds a child document to all domains.
 *
 * @author ldoguin
 *
 */
public class CustomContentCreationHandler implements PostContentCreationHandler {
    public static final String DC_TITLE_PROPERTY_NAME = "dc:title";
    public static final String DC_DESCRIPTION_PROPERTY_NAME = "dc:description";
    public static final String GET_ALL_DOMAINS = "Select * From Domain";
    private static final String NEW_DOCUMENT_TYPE = "Workspaces";
    private static final String CHILD_DOC_NAME = "anotherworkspaceroot";
    public static final String DC_TITLE = "Another Workspace root";
    public static final String DC_DESCRIPTION = "The Description";

    @Override
    public void execute(CoreSession session) {
        try {
            DocumentModelList domains = session.query(GET_ALL_DOMAINS);
            for (DocumentModel domain : domains) {
                DocumentModel childDocToCreate = session.getChild(
                        domain.getRef(), CHILD_DOC_NAME);
                if (childDocToCreate != null) {
                    // The document exist, maybe we have properties or right to
                    // update
                    childDocToCreate.setPropertyValue(DC_TITLE_PROPERTY_NAME,
                            DC_TITLE);
                    childDocToCreate.setPropertyValue(
                            DC_DESCRIPTION_PROPERTY_NAME, DC_DESCRIPTION);
                    session.saveDocument(childDocToCreate);
                } else {
                    // the doc has not been created yet, let's do this
                    childDocToCreate = session.createDocumentModel(
                            domain.getPathAsString(), CHILD_DOC_NAME,
                            NEW_DOCUMENT_TYPE);
                    childDocToCreate.setPropertyValue(DC_TITLE_PROPERTY_NAME,
                            DC_TITLE);
                    childDocToCreate.setPropertyValue(
                            DC_DESCRIPTION_PROPERTY_NAME, DC_DESCRIPTION);
                    session.createDocument(childDocToCreate);
                }
            }
        } catch (ClientException e) {
            throw new ClientRuntimeException(e);
        }
    }
}

This code should answer all the questions you have when automatically modifying an existing document structure.

That’s it for today. If you have other questions, just ask them on answers.nuxeo.com. Cheers!