Server

HOWTO: Contribute to an Extension

Updated: December 19, 2024

Watch the related courses on Hyland University:
Course on Handling Service Extension Points

Finding the Extension Point Where to Contribute

Regardless of the tool you're using (Nuxeo Studio or Nuxeo CLI), the first step is to find the open door configuration where you want to contribute. We call these open doors Extension points.

Nuxeo lists all extension points for a given version in the Nuxeo Explorer:

  1. Click on Extension points.

  2. Maybe use the search filter.

  3. Click on the extension point you're interested in.
    The documentation of this extension point is displayed.

  4. Then, if you click on any link in the Contributions section, you will see all the default contributions implemented into the documented Nuxeo instance.
    There are hundreds of configuration possibilities.

Contributing Using Nuxeo Studio

  1. In the Advanced Settings > XML extensions, click on the Ok button.

  2. Give the extension an ID and click on the Next button.

  3. Type the content of your extension directly in the area.
    The editor helps you: start typing < and it will suggest possible values. While you are typing, some suggestion happens sometimes when typing on space, and you can always call the suggester using the key CTRL+space.

  4. Click on Save.

XML Format
XML declaration should always start with an <extension> element.
There is a minimal check done so as to avoid defining incorrect XML.
In some particular situations, the <require> element can also be used, see overriding contributions.
The documentation element can also be used, alongside the <extension> element (that will document the whole feature), or inside it (that will document the contributions to the target extension point). This documentation is extracted for display by the Explorer addon.

Several extension points can be contributed to the same XML Extensions feature. This is useful to group extensions that are contributed for the same high-level functional goal.

Contributions to the same extension point can also be stacked inside the same <extension> tag, although they can also be duplicated for specific documentation.

Thus, you can have:

<extension target="component_A" point="point_A">
  <!-- here goes the configuration XML fragment -->
</extension>

or

<extension target="component_A" point="point_A">
  <!-- here goes the first configuration XML fragment -->
  <!-- here goes the second configuration XML fragment -->
</extension>

or

<documentation>
  Documentation for all contributions below
</documentation>
<extension target="component_A" point="point_A">
  <documentation>
    Documentation for this contribution
  </documentation>
  <!-- here goes the configuration XML fragment -->
</extension>
<extension target="component_A" point="point_A">
  <documentation>
    Documentation for this contribution
  </documentation>
  <!-- here goes the configuration XML fragment -->
</extension>
<extension target="component_B" point="point_B">
  <documentation>
    Documentation for this contribution
  </documentation>
  <!-- here goes the configuration XML fragment -->
</extension>

or

<extension target="component_A" point="point_A">
  <documentation>
    Documentation for contributions below
  </documentation>
  <!-- here goes the first configuration XML fragment -->
  <!-- here goes the second configuration XML fragment -->
</extension>
<extension target="component_B" point="point_B">
  <!-- here goes the configuration XML fragment -->
</extension>

etc.

Contributing Using Nuxeo CLI

Contributing to an extension using Nuxeo CLI requires more steps than using Nuxeo Studio.

Here we assume that you have installed Nuxeo CLI and follow the page Develop with Nuxeo Platform to understand the basics.

Creating an XML Extension in Nuxeo CLI

Once you have found the extension point that you want to contribute to:

  1. Create a file named like service-to-contribute-to-contrib.xml into the src/main/resources/OSGI-INF/ directory of your project.

  2. Declare an empty component into this file, with a unique name within the target application, you can follow the suggested naming conventions to avoid conflicts:

    <?xml version="1.0"?>
    <component name="org.mycompany.myproject.target-extension-point-to-contribute-to.contrib">
    </component>
    

    Naming your component
    In Nuxeo bundles, we tend to follow this naming convention:
    org.mycompany.myproject.target-extension-point-to-contribute-to.distinctive-words.
    You can follow your way but should be careful to avoid conflicts.
    If the component name is not unique, it will not be deployed, and the server startup will be aborted.

  3. Add the XML fragment for the contribution expressing the target configuration. The format is the following:

     <?xml version="1.0"?>
     <component name="org.mycompany.myproject.target-extension-point-to-contribute-to.contrib">
       <!-- target and point attributes below are given by the extension point definition -->
       <extension target="name.of.the.component.declaring.the.extension.point" point="point.name">
         <!-- here goes the configuration XML fragment -->
       </extension>
     </component>
    

    Here is a sample:

     <?xml version="1.0"?>
     <component name="org.mycompany.myproject.DocumentAdapterService.contrib">
       <extension point="adapters" target="org.nuxeo.ecm.core.api.DocumentAdapterService">
         <documentation>
           Adapter mapping for persisted documents using type NXBundleGroup.
         </documentation>
         <adapter class="org.nuxeo.apidoc.api.BundleGroup" factory="org.nuxeo.apidoc.adapters.AdapterFactory"
           type="NXBundleGroup"/>
       </extension>
     </component>
    

Declaring a Contribution in a Bundle

In the previous section, the configuration has been created. Now it needs to be declared by the containing bundle, so that it's deployed by the Nuxeo server. This declaration is made through the src/main/resources/META-INF/MANIFEST.MF file.

  1. Create a new entry Nuxeo-Component, if it does not exist:

     Manifest-Version: 1.0
     Bundle-ManifestVersion: 2
     Bundle-SymbolicName: org.mycompany.myproject.mybundle
     Nuxeo-Component: OSGI-INF/extensions/doctypes-contrib.xml
    
    
  2. If the Nuxeo-Component entry already existed with another component declaration, separate them by commas:

     Manifest-Version: 1.0
     Bundle-ManifestVersion: 2
     Bundle-SymbolicName: org.mycompany.myproject.mybundle
     Nuxeo-Component: OSGI-INF/extensions/doctypes-contrib.xml,
      OSGI-INF/extensions/adapters-contrib.xml,
    
    

Formatting

The trickiest and most important part of a MANIFEST.MF file is its formatting. One mistake and the OSGi context can't be correctly started, leading to unexpected issues and an unreachable bundle. Here are the three formatting rules to respect:

  1. Each property name:
    • begins at the first character of the line;
    • ends with a colon without space between the name of the property and the colon itself.
  2. Each value:
    • must be preceded by a space;
    • ends with a "end of line" with eventually a comma before it.
  3. There MUST be an EMPTY LINE at the END OF THE FILE.

Overriding the Nuxeo Default Configurations

The Nuxeo application comes with runtime contributions, relying on the extension point system for default settings.

Changing one of these configurations can be done by overriding the XML fragment from an existing Nuxeo component, by following the steps for your preferred tool (see above) combined with the specific steps below:

  1. Identify this component: using Nuxeo Explorer, go to the extension point definition (see the first section), for instance.

  2. Click on the contribution to be overridden: the explorer provides a dedicated link to help with overrides, that you can take as an example.

  3. Notice the contributing component name: you will need to require it to make sure this new configuration is applied after the original one.

  4. Write a custom component with a specific name, and declare it in your bundle.
    You should have something like:

    <?xml version="1.0"?>
    <component name="org.mycompany.myproject.extension.point.where.we.contribute">
    <require>name.of.the.original.component.to.be.overridden</require>
      <!-- target and point attributes below are given by the extension point definition -->
      <extension target="name.of.the.component.declaring.the.extension.point" point="point.name">
        <!-- here goes the new configuration XML fragment -->
      </extension>
    </component>
    

If you are adding this contribution from Nuxeo Studio, you do not need the require tag, as Studio contributions are added after all other contributions have been deployed. You might need it if you are overriding a contribution from another Studio project, though.