Jackrabbit Content Repository
  1. Jackrabbit Content Repository
  2. JCR-324

Create a mechanism allowing Jackrabbit to automatically install custom nodes when it creates a repository

    Details

    • Type: Improvement Improvement
    • Status: Closed
    • Priority: Minor Minor
    • Resolution: Won't Fix
    • Affects Version/s: None
    • Fix Version/s: None
    • Component/s: config
    • Labels:
      None

      Description

      The current process for adding new nodes requires clients to open a new session, get a session, then a workspace, then the Jackrabbit implementation of a NodeTypeManager where the Jackrabbit NodeTypeDef objects can be added. However, custom node types need only be added once, preferably when the repository is created/initialized, as this is the most appropriate time for such actions. The alternatives for clients wishing to install custom node types include:

      • configuring an object to run when their app is deployed or started; this method may be dependent on the environment and may not be portable
      • checking to see if custom node types exist whenever they go to access the repository; this degrades performance

      A better alternative would be to allow Jackrabbit to add the custom node types when it creates a repository. This could be accomplished by either adding an element to the repository configuration XML file. In one scenario, the element specifies the location of the custom node file and the class of the node type reader used to process the file. In another scenario, the element specifies the name of a class and a method to call on that class that will initialize the repository. In my mind, the first scenario seems like a better solution. While it is no more portable than a custom initialization object invoked by the environment, it has the benefit of not being non-portable code.

      I would be happy to code up the first scenario (location of custom node file and a reader class) if it is an appropriate improvement to the system.

        Activity

        Mark Slater created issue -
        Hide
        Mark Slater added a comment -

        I've attached a patch that allows adds a CustomNodeTypeDefinitions element to the repository configuration. This element is optional. If it is present, the file specified in the param sub-element is processed to extract custom node types. The client specifies the class used to process the file in the readerClass attribute of the CustomNodeTypeDefinitions element.

        === New Files ===

        src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeReader.java
        > an interface that must be implemented by classes in order to process custom node type files when the repository is created.

        src/main/java/org/apache/jackrabbit/core/nodetype/xml/XmlNodeTypeReader.java
        > This is the new version of org.apache.jackrabbit.core.nodetype.xml.NodeTypeReader. The class name was changed to avoid confusion. It now implements the NodeTypeReader interface.

        src/main/java/org/apache/jackrabbit/core/nodetype/xml/XmlNodeTypeWriter.java
        > This is the new version of org.apache.jackrabbit.core.nodetype.xml.NodeTypeWriter. The class name was changed to avoid confusion. There is no new functionality here.

        src/main/java/org/apache/jackrabbit/core/config/CustomNodeTypeConfig.java
        > This is the class that manages the custom node type configuration. When it processes the configuration file, it adds any new namespaces to the NamespaceRegistryImpl.

        src/test/java/org/apache/jackrabbit/core/config/testCustomNodeTypes.xml
        > This file contains one very simple custom node type. The unit test repository.xml refers to it.

        === Altered files ===

        src/test/java/org/apache/jackrabbit/core/config/repository.xml
        > Added a reference to the org/apache/jackrabbit/core/config/testCustomNodeTypes.xml file so it is processed during the the unit tests (as in the CustomNodeTypeConfig object is generated; I wasn't able to find a good way of testing the process of extracting the custom types from within the unit tests. See below for more information on testing.)

        src/test/java/org/apache/jackrabbit/core/nodetype/xml/TestAll.java
        > Now refers to XmlNodeTypeReader and XmlNodeTypeWriter. All tests pass.

        src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java
        > Checks the configuration for custom node type definition info. If no custom node types have been defined in the repository, it gets the NodeTypeDefs out of the file and adds them to the NodeTypeRegistry. If any errors occur while processing the file, they are logged and startup continues without the custom node type definitions.

        src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeManagerImpl.java
        > Now refers to XmlNodeTypeReader.

        src/main/java/org/apache/jackrabbit/core/nodetype/xml/NodeTypeReader.java
        > Added a @deprecated Javadoc Tag so as to not break existing clients.

        src/main/java/org/apache/jackrabbit/core/nodetype/xml/NodeTypeWriter.java
        > Added a @deprecated Javadoc Tag so as to not break existing clients.

        src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java
        > Added a function hasCustomNodeTypesDefined() that returns true if the custom node types resource file already exists.

        src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeDefStore.java
        > Now refers to XmlNodeTypeReader.

        src/main/java/org/apache/jackrabbit/core/config/config.dtd
        > Added the CustomNodeTypeDefinitions ELEMENT definition.

        src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java
        > Added a CustomNodeTypeConfig parameter to the constructor and an accessor for the member variable. Also added a call to the init() function. If the init fails, it throws a ConfigurationException; failure occurs when the NodeTypeReader specified by the user can't be instantiated.

        src/main/java/org/apache/jackrabbit/core/config/ConfigurationParser.java
        > Added code to parse the new CustomNodeTypeDefinitions ELEMENT and create the CustomNodeTypeConfig object. If the CustomNodeTypeDefinitions is not present, the null is passed for that parameter to RepositoryConfig.

        === Tests performed ===

        I tested these changes with my own client's configuration and unit tests. If there are any problems in the specified node type file, the RepositoryImpl logs the exception to the output and continues as it had before. The file is not processed when the repository starts and the repository/nodetypes/custom_nodetypes.xml file already exists. I can try to come up with test cases for Jackrabbit, but I may need some help blending them into the existing unit tests.

        Show
        Mark Slater added a comment - I've attached a patch that allows adds a CustomNodeTypeDefinitions element to the repository configuration. This element is optional. If it is present, the file specified in the param sub-element is processed to extract custom node types. The client specifies the class used to process the file in the readerClass attribute of the CustomNodeTypeDefinitions element. === New Files === src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeReader.java > an interface that must be implemented by classes in order to process custom node type files when the repository is created. src/main/java/org/apache/jackrabbit/core/nodetype/xml/XmlNodeTypeReader.java > This is the new version of org.apache.jackrabbit.core.nodetype.xml.NodeTypeReader. The class name was changed to avoid confusion. It now implements the NodeTypeReader interface. src/main/java/org/apache/jackrabbit/core/nodetype/xml/XmlNodeTypeWriter.java > This is the new version of org.apache.jackrabbit.core.nodetype.xml.NodeTypeWriter. The class name was changed to avoid confusion. There is no new functionality here. src/main/java/org/apache/jackrabbit/core/config/CustomNodeTypeConfig.java > This is the class that manages the custom node type configuration. When it processes the configuration file, it adds any new namespaces to the NamespaceRegistryImpl. src/test/java/org/apache/jackrabbit/core/config/testCustomNodeTypes.xml > This file contains one very simple custom node type. The unit test repository.xml refers to it. === Altered files === src/test/java/org/apache/jackrabbit/core/config/repository.xml > Added a reference to the org/apache/jackrabbit/core/config/testCustomNodeTypes.xml file so it is processed during the the unit tests (as in the CustomNodeTypeConfig object is generated; I wasn't able to find a good way of testing the process of extracting the custom types from within the unit tests. See below for more information on testing.) src/test/java/org/apache/jackrabbit/core/nodetype/xml/TestAll.java > Now refers to XmlNodeTypeReader and XmlNodeTypeWriter. All tests pass. src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java > Checks the configuration for custom node type definition info. If no custom node types have been defined in the repository, it gets the NodeTypeDefs out of the file and adds them to the NodeTypeRegistry. If any errors occur while processing the file, they are logged and startup continues without the custom node type definitions. src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeManagerImpl.java > Now refers to XmlNodeTypeReader. src/main/java/org/apache/jackrabbit/core/nodetype/xml/NodeTypeReader.java > Added a @deprecated Javadoc Tag so as to not break existing clients. src/main/java/org/apache/jackrabbit/core/nodetype/xml/NodeTypeWriter.java > Added a @deprecated Javadoc Tag so as to not break existing clients. src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java > Added a function hasCustomNodeTypesDefined() that returns true if the custom node types resource file already exists. src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeDefStore.java > Now refers to XmlNodeTypeReader. src/main/java/org/apache/jackrabbit/core/config/config.dtd > Added the CustomNodeTypeDefinitions ELEMENT definition. src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java > Added a CustomNodeTypeConfig parameter to the constructor and an accessor for the member variable. Also added a call to the init() function. If the init fails, it throws a ConfigurationException; failure occurs when the NodeTypeReader specified by the user can't be instantiated. src/main/java/org/apache/jackrabbit/core/config/ConfigurationParser.java > Added code to parse the new CustomNodeTypeDefinitions ELEMENT and create the CustomNodeTypeConfig object. If the CustomNodeTypeDefinitions is not present, the null is passed for that parameter to RepositoryConfig. === Tests performed === I tested these changes with my own client's configuration and unit tests. If there are any problems in the specified node type file, the RepositoryImpl logs the exception to the output and continues as it had before. The file is not processed when the repository starts and the repository/nodetypes/custom_nodetypes.xml file already exists. I can try to come up with test cases for Jackrabbit, but I may need some help blending them into the existing unit tests.
        Mark Slater made changes -
        Field Original Value New Value
        Attachment customNodeTypeReaderConfig.patch [ 12323221 ]
        Hide
        Mark Slater added a comment -

        Forgot to mention, if the above patch is accepted, I'd be happy to update the site documentation with the new functionality and to update the org.apache.jackrabbit.core.nodetype.compact.CompactNodeTypeDefReader in contrib (assuming that's still being maintained).

        Show
        Mark Slater added a comment - Forgot to mention, if the above patch is accepted, I'd be happy to update the site documentation with the new functionality and to update the org.apache.jackrabbit.core.nodetype.compact.CompactNodeTypeDefReader in contrib (assuming that's still being maintained).
        Hide
        Jukka Zitting added a comment -

        This seems like a nice approach to the repository initialization issue. So far the general opinion has been that things like installing custom node types or importing an initial content structure are separate administrational tasks that should be performed manually after the repository has been created.

        Would you be interested in refactoring your approach a bit to make it more general? I was thinking that instead of limiting this feature to just custom node types, it could take care of all sorts of repository initialization. How about something like a general RepositoryInitializer interface?

        public interface RepositoryInitializer

        { void initialize(Session session) throws RepositoryException; }

        An instance could be configured using an optional <RepositoryInitializer> configuration element. If configured, the initialize method of the initializer instance would be called once with a system session after the other repository initialization has been performed but before any other sessions are created.

        For example:

        <RepositoryInitializer class="org.apache.jacrkrabbit.core.init.CustomNodeTypeInitializer">
        <param name="path" value="path/to/custom-nodetypes.xml"/>
        </RepositoryInitializer>

        Another example:

        <RepositoryInitializer class="org.apache.jacrkrabbit.core.init.ImportContentInitializer">
        <param name="path" value="path/to/initial-content.xml"/>
        </RepositoryInitializer>

        A combined version:

        <RepositoryInitializer class="org.apache.jacrkrabbit.core.init.CombinedInitializer">
        <param name="customNodetypes" value="path/to/custom-nodetypes.xml"/>
        <param name="initialContent" value="path/to/initial-content.xml"/>
        </RepositoryInitializer>

        Show
        Jukka Zitting added a comment - This seems like a nice approach to the repository initialization issue. So far the general opinion has been that things like installing custom node types or importing an initial content structure are separate administrational tasks that should be performed manually after the repository has been created. Would you be interested in refactoring your approach a bit to make it more general? I was thinking that instead of limiting this feature to just custom node types, it could take care of all sorts of repository initialization. How about something like a general RepositoryInitializer interface? public interface RepositoryInitializer { void initialize(Session session) throws RepositoryException; } An instance could be configured using an optional <RepositoryInitializer> configuration element. If configured, the initialize method of the initializer instance would be called once with a system session after the other repository initialization has been performed but before any other sessions are created. For example: <RepositoryInitializer class="org.apache.jacrkrabbit.core.init.CustomNodeTypeInitializer"> <param name="path" value="path/to/custom-nodetypes.xml"/> </RepositoryInitializer> Another example: <RepositoryInitializer class="org.apache.jacrkrabbit.core.init.ImportContentInitializer"> <param name="path" value="path/to/initial-content.xml"/> </RepositoryInitializer> A combined version: <RepositoryInitializer class="org.apache.jacrkrabbit.core.init.CombinedInitializer"> <param name="customNodetypes" value="path/to/custom-nodetypes.xml"/> <param name="initialContent" value="path/to/initial-content.xml"/> </RepositoryInitializer>
        Hide
        Mark Slater added a comment -

        Yes I can do that. I probably won't get to it until the end of the month though. I'm on a deadline for my own project.

        Show
        Mark Slater added a comment - Yes I can do that. I probably won't get to it until the end of the month though. I'm on a deadline for my own project.
        Hide
        Jukka Zitting added a comment -

        Mark Slater:
        > Yes I can do that. I probably won't get to it until the end of the month though. I'm on a deadline for my own project.

        Cool, thanks! This would be a nice feature to have in Jackrabbit 1.1.

        Show
        Jukka Zitting added a comment - Mark Slater: > Yes I can do that. I probably won't get to it until the end of the month though. I'm on a deadline for my own project. Cool, thanks! This would be a nice feature to have in Jackrabbit 1.1.
        Hide
        Jukka Zitting added a comment -

        Resolving as Won't Fix due to lack of activity.

        As mentioned above, I don't think it's a good idea to embed administrative tasks in the configuration file. The more generic repository initializer approach would be better.

        Show
        Jukka Zitting added a comment - Resolving as Won't Fix due to lack of activity. As mentioned above, I don't think it's a good idea to embed administrative tasks in the configuration file. The more generic repository initializer approach would be better.
        Jukka Zitting made changes -
        Status Open [ 1 ] Resolved [ 5 ]
        Assignee Jukka Zitting [ jukkaz ]
        Resolution Won't Fix [ 2 ]
        Jukka Zitting made changes -
        Workflow jira [ 12347300 ] no-reopen-closed, patch-avail [ 12468107 ]
        Jukka Zitting made changes -
        Status Resolved [ 5 ] Closed [ 6 ]

          People

          • Assignee:
            Jukka Zitting
            Reporter:
            Mark Slater
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development