This page provides an overview of all ways to define custom JCR node types and create new workspaces with Magnolia.

Even though it has always been possible to define node types and create workspaces within Magnolia Maven modules, the Content Types module brings this functionality also to the light modules. Both approaches are valid. 

Whichever approach you choose, we recommend not to develop and refine these definitions in a productive environment.

Editing node type and workspace definitions can lead to new node type definitions and workspaces which are registered again, whereas the system keeps the "old" ones which become obsolete.

With content types

By utilizing the magnolia-content-types module you can define custom JCR content types and workspaces within light modules.

Defining content types within light modules can be accomplished on a running Magnolia system without redeploying the WAR file of your Magnolia instances and without restarting the instance or a module. This makes it a perfect approach if you have a Magnolia Cloud subscription package.

A content type definition in one file

You can define all of the following in just one file:

  1. JCR workspace
  2. JCR nodetype
    This node type inherits from the Magnolia node type mgnl:content. To define more sophisticated node types, you can create a node type definition file in a light module
  3. JCR namespace

Example

datasource:
  workspace: tourguides
  namespaces:
    mt: https://www.magnolia-travel.com/jcr/1.0/mt
  autoCreate: true
  
model:
  nodeType: mt:tourGuide
  properties:
    - name: birthday
      type: Date
    - name: gender
    - name: shortBio

Best practice

If a node type inheriting from mgnl:content complies with your requirements, we recommend defining all of the items – namespace, node type and workspace in the content type definition, all in one file.

Defining and using a node type definition

You can define JCR namespaces and nodetypes in a CND file. 

The Compact Namespace and Node Type Definition (CND) notation provides a compact standardized syntax for defining node types and making namespace declarations. The notation is intended both for documentation and for programmatically registering node types. See http://jackrabbit.apache.org/jcr/node-type-notation.html for more details.

While XML-based node type definitions are still supported, we recommend using CND.

Since this definition must be readable as a Magnolia Resource, it can be a file in a light module or in a JAR file or in the resources JCR workspace.

The CND node type definition resource is loaded only if the CND resource is referenced in the Content type Data source definition of a Content type definition.

Once the resource is loaded, the system registers the defined JCR node types and namespaces. If required and Jackrabbit allows it, the system may update the definitions.

Example:

  1. Create a CND file in your light module and define a namespace and node types:

    /content-type-examples/jcr-node-type-files/travellers-node-types.cnd
    <mt = 'http://www.magnolia.info/jcr/mt'>
    
    [mt:traveller] > mgnl:content
     orderable
    
    [mt:tourGuide] > mt:traveller
     orderable
    
    [mt:happyCustomer] > mt:traveller
     orderable

  2. Reference the node type definition from a content type definition:

    /content-type-examples/contentTypes/happyCustomer.yaml
    datasource:
      workspace: happycustomers
      autoCreate: true
      nodeTypeDefinition: /content-type-examples/jcr-node-type-files/travellers-node-types.cnd
     
    model:
      nodeType: mt:happyCustomer
      properties:
        - name: country
        - name: age
          type: Double
    Line 4: References the node type definition resource via nodeTypeDefinition.

With a Magnolia Maven module descriptor

With Magnolia Maven modules you can register new JCR workspaces and node types. The registration involves the XML-based module descriptor.

Magnolia registers workspaces and node types during a module's start-up phase in case they have not yet been registered.


 Example of a module descriptor:

my-maven-module/src/main/resources/META-INF/magnolia/my-module.xml
<!DOCTYPE module SYSTEM "module.dtd" >
<module>
  <name>my-module</name>
  <displayName>${project.name}</displayName>
  <description>${project.description}</description>
  <class>com.example.magnolia.myModule.MyModuleDefinition</class>
  <versionHandler>com.example.magnolia.myModule.setup.MyModuleVersionHandler</versionHandler>
  <version>${project.version}</version>

  <dependencies>
    <dependency>
      <name>core</name>
      <version>6.0/*</version>
    </dependency>
  </dependencies>

  <repositories>
    <repository>
      <name>magnolia</name>
      <workspaces>
        <workspace>products</workspace>
      </workspaces>
      <nodeTypeFile>/mgnl-nodetypes/products-nodetypes.cnd</nodeTypeFile>
    </repository>
  </repositories>

</module>

Workspaces

In the XML-based module descriptor you can add a <workspace /> section in /repositories/repository/workspaces.

<workspaces>
  <workspace>products</workspace>
</workspaces>

Node types

To define and register new node types requires two things:

  1. Creating a node type definition file (CND or XML) where you define the required node types and name spaces. Create the file in the my-maven-module/src/main/resources/mgnl-nodetypes/ folder.
    Example:

    my-maven-module/src/main/resources/mgnl-nodetypes/my-node-types.cnd
    <'mgnl' = 'http://www.magnolia.info/jcr/mgnl'>
    
    [mt:product] > mgnl:content
     orderable

  2. Referencing the node type file in the XML-based module descriptor:
    Example:

    my-maven-module/src/main/resources/META-INF/magnolia/my-module.xml (fragment)
    <nodeTypeFile>/mgnl-nodetypes/my-node-types.cnd</nodeTypeFile>

#trackbackRdf ($trackbackUtils.getContentIdentifier($page) $page.title $trackbackUtils.getPingUrl($page))
  • No labels

2 Comments

  1. It seems like at least defining node types through a Module Descriptor and custom node types file only works for the magnolia  repository, e.g. a clustered repo. As soon as you define a second repository, the "mgnl:*" node types like mgnl:content  are missing. You will get a RepositoryException  when the custom node type is registered:

    ...
    Caused by: org.apache.jackrabbit.core.nodetype.InvalidNodeTypeDefException: [{}testNodeType] invalid supertype: {http://www.magnolia.info/jcr/mgnl}content

    This occurs on Magnolia 6.1, but I'm quite certain it does work in Magnolia 5.7.

    Any instructions on this page how to add custom node types in repositories other than magnolia  would be greatly appreciated!

    1. So, after much try&error I found out that Magnolia will  actually register the default node types if the repo is setup correctly. Back "in the old days" we always setup the repositories by modifying WEB-INF/config/default/repositories.xml . Here, we added a new repo definition, workspaces, and workspace mappings. This could end up looking like this:

      Repositories Definition
      <!DOCTYPE JCR [
              <!ELEMENT Map (#PCDATA)>
              <!ATTLIST Map
                      name CDATA #REQUIRED
                      repositoryName CDATA #REQUIRED
                      workspaceName CDATA #REQUIRED>
              <!ELEMENT JCR (RepositoryMapping|Repository)*>
              <!ELEMENT param (#PCDATA)>
              <!ATTLIST param
                      name CDATA #REQUIRED
                      value CDATA #REQUIRED>
              <!ELEMENT Repository (param|workspace)*>
              <!ATTLIST Repository
                      loadOnStartup CDATA #REQUIRED
                      name CDATA #REQUIRED
                      provider CDATA #REQUIRED>
              <!ELEMENT workspace (#PCDATA)>
              <!ATTLIST workspace
                      name CDATA #REQUIRED>
              <!ELEMENT RepositoryMapping (Map)*>
              ]><JCR>
          <RepositoryMapping>
              <Map name="website" repositoryName="magnolia" workspaceName="website" />
              <Map name="config" repositoryName="magnolia" workspaceName="config" />
              <Map name="users" repositoryName="magnolia" workspaceName="users" />
              <Map name="userroles" repositoryName="magnolia" workspaceName="userroles" />
              <Map name="usergroups" repositoryName="magnolia" workspaceName="usergroups" />
              <Map name="foo" repositoryName="magnoliaClustered" workspaceName="foo" />
          </RepositoryMapping>
      
          <!-- magnolia default repository -->
          <Repository name="magnolia" provider="info.magnolia.jackrabbit.ProviderImpl" loadOnStartup="true">
              <param name="configFile" value="${magnolia.repositories.jackrabbit.config}" />
              <param name="repositoryHome" value="${magnolia.repositories.home}/magnolia" />
              <!-- the default node types are loaded automatically
      			<param name="customNodeTypes" value="WEB-INF/config/repo-conf/nodetypes/magnolia_nodetypes.xml" />
      		-->
              <param name="contextFactoryClass" value="org.apache.jackrabbit.core.jndi.provider.DummyInitialContextFactory" />
              <param name="providerURL" value="localhost" />
              <param name="bindName" value="${magnolia.webapp}" />
              <workspace name="website" />
              <workspace name="config" />
              <workspace name="users" />
              <workspace name="userroles" />
              <workspace name="usergroups" />
          </Repository>
      
          <!-- custom repository -->
          <Repository name="magnoliaClustered" provider="info.magnolia.jackrabbit.ProviderImpl" loadOnStartup="true">
              <param name="configFile" value="${magnolia.repositories.jackrabbit.clustered.config}"/>
              <param name="repositoryHome" value="${magnolia.repositories.home}/magnoliaClustered"/>
      <!--
              <param name="customNodeTypes" value="WEB-INF/config/nodetypes/additional_nodetypes.xml" />
      -->
              <param name="contextFactoryClass" value="org.apache.jackrabbit.core.jndi.provider.DummyInitialContextFactory"/>
              <param name="providerURL" value="localhost"/>
              <param name="bindName" value="${magnolia.webapp}Clustered"/>
      		<workspace name="foo" />
          </Repository>
      </JCR>
      
      

      (For this to work, you'll also need to create a corresponding jackrabbit configuration file, add a property magnolia.repositories.jackrabbit.clustered.config to your properties file and set its value to the path of that config file.)

      Then, life got simply with the possibility to define workspaces and reference node type files in the module descriptor as described on this page. Slowly but surely I forgot about the old way of doing things, because as long as you are working with the default magnolia  repository, the module descriptor is all you'll ever need to touch (or a content types definition).

      However, if you need your workspaces to live a separate repository, all the comfort is gone again. The module descriptor might give you the impression that it can create a repository (after all you can also create a workspace there), but this is not really the case. You'll need to configure it the old way. But don't try to define your node types there, because at that time, the default magnolia node types are not registered yet and you'll end up with the unknown node type error message.

      So what worked for me now:

      1. Define the repository in the repositories.xml  config file. Do not define any workspaces or mappings there (so remove line 28 and 58 in the sample above). Magnolia will initialise the repository and register all default magnolia node types. However node types of modules like dam or categorisation are not registered!
      2. Define the workspaces in the module descriptor in the corresponding <repository>  element.
      3. Add the reference to your  custom node types file here in the module descriptor. At the time when Magnolia handles the module descriptors, the repositories are already set up and the default magnolia node types are added. So your node types can extend mgnl:content  or alike.

      Your definition in the module descriptor could look like this:

      Section from Module Descriptor
          <repositories>
              <repository>
                  <name>magnolia</name>
                  <workspaces>
                      <workspace>foo</workspace>
                  </workspaces>
                  <nodeTypeFile>/mgnl-nodetypes/additional-nodetypes.xml</nodeTypeFile>
              </repository>
              <repository>
                  <name>magnoliaClustered</name>
                  <workspaces>
                      <workspace>bar</workspace>
                  </workspaces>
                  <nodeTypeFile>/mgnl-nodetypes/additional-nodetypes.xml</nodeTypeFile>
              </repository>
          </repositories>