Server

Runtime and Component Model

Updated: November 15, 2024

This page describes how the Nuxeo Platform is modular, and how bundles, components and extension points relate to each other to let you create a fully customized application.

Easy Customization and Integration

One of the main goals of the Nuxeo Platform is to provide an easy and clean way to customize the platform for your application needs. That way:

  • No need to hack the system to make it run
  • Your custom code will be based on maintained extension points and interfaces, and will be able to be easily upgraded

For that, Nuxeo Platform provides the following patterns:

  • Bundle: A bundle is a "plugin". It is most of the time a ".jar" file with a specific structure that aims at deploying a new set of features on the Nuxeo server. Thanks to this "bundle" notion, developers can deliver their new features in a standalone JAR that the platform will know how to start. As a result, your customization is also delivered as a plug-in, like the tens of plug-ins that are part of the Nuxeo ecosystem, and that you can find on GitHub or the Nuxeo Marketplace.

  • Components and services: A component is a software object declared via XML (and that may reference a Java class) that is used to expose some services in the framework. Thanks to this architecture, it is possible to expose a new service anywhere in the Java code executed in the platform. Services are auto-documented: you can see the list on Nuxeo Platform Explorer.

  • Extensions: An extension is a mechanism leveraged by the services to let platform users inject customization in the core of the implementation. It is a pattern used frequently on products such as Mozilla, Chrome, or Eclipse. Thanks to this architecture, it is possible to go very deep in product customization, only with XML, or using our Nuxeo Studio visual environment, without any coding. You can see the list of all extension points in Nuxeo Platform Explorer. Contributions to extensions are usually delivered in a custom bundle.

Implementing your own bundle, you will be able to contribute to existing extensions so as to customize your application. A lot of these configurations are supported by Nuxeo Studio.

For instance, you can:

When existing extensions are not enough, you can declare your own services or leverage existing ones in Java code: this will allow your business logics to benefit from the same kind of configurability.

In Nuxeo, everything can be configured:

EP Stack

Bundles, Components, Services and Extension Points

Nuxeo Bundles

Inside Nuxeo Platform, software parts are packaged as Bundles. A bundle is a Java archive (JAR) packaged so that it works inside a Nuxeo Application.

It typically contains:

  • An OSGi-like manifest file,
  • Java classes,
  • XML components,
  • Resources,
  • A deployment descriptor.

The manifest file is used to:

  • Define an id for the bundle,
  • Define the dependencies of the bundles (i.e.: other bundles that should be present for this bundle to run),
  • List XML components that are part of the bundle.

Here is an example of a manifest file, located at src/main/resources/META-INF/MANIFEST.MF:

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: NXCoreConvert
Bundle-SymbolicName: org.nuxeo.ecm.core.convert
Bundle-Localization: plugin
Require-Bundle: org.nuxeo.ecm.core.api,
 org.nuxeo.ecm.core.convert.api
Bundle-Vendor: Nuxeo
Export-package: org.nuxeo.ecm.core.convert.cache,
 org.nuxeo.ecm.core.convert.extension,
 org.nuxeo.ecm.core.convert.service
Bundle-Category: runtime
Nuxeo-Component: OSGI-INF/convert-service-framework.xml

Here we can see that this bundle:

  • is named org.nuxeo.ecm.core.convert.
  • depends on two other bundles: core.api and convert.api.
  • contains one XML component: convert-service-framework.xml.

Nuxeo bundles are deployed on the Nuxeo server via the Nuxeo runtime, and provides:

  • A lifecycle model for Java modules,
  • A service model,
  • An extension model.

When the Nuxeo runtime starts, it will try to load all Nuxeo bundles installed in the system. When all dependencies of this bundle are resolved, the framework starts the bundle. Starting a bundle means invoking a bundle activator, if any is declared in the manifest file. It also means parsing all Nuxeo components declared in the MANIFEST, and scheduling them for deployment.

In the same way that activations are performed, deactivations are also handled: each step has an equivalent step to undo changes made to the system. This mechanism provides a flexible way to build modular applications, when some resources are made available or are removed.

The mechanism is usually triggered when starting and stopping the Nuxeo server, although hot-reload features are also supported.

Note that Nuxeo is using single class loader for all bundles.

To learn more about creating a bundle, see HOWTO: Create an empty bundle or HOWTO: Write a Bundle Manifest.

To access a service from Java code, see HOWTO: Use the Runtime Java API. Use the Runtime Java API.

Nuxeo Components

A component is a software object declared via XML (and that may reference a Java class). The corresponding XML file is usually held by a bundle, in the OSGI-INF directory, and referenced by the META-INF/MANIFEST.MF file.

Each component has a unique name and can be used to:

  • Declare requirements on other components,
  • Declare a Java component implementation,
  • Define a service interface,
  • Contribute some extensions.

When only contributing some extensions, the component is not backed by a custom Java class: it can be "pure XML" (although some contributions will, themselves, accept Java classes for configured objects). A component is usually made of several classes and XML configuration.

Here is a schema of all the possibilities:

Bundles

Some components are indeed holding all these different types of declarations, but we usually see the following pattern for "framework" components, defining a service and extension points: Framework Bundle

We usually see the following pattern for "contribution" components, defining contributions to other extension points: Configuration Bundle

Nuxeo Services

Components usually derive from a base class provided by Nuxeo Runtime and will be available as a singleton via a simple Nuxeo Runtime call:

import org.nuxeo.runtime.api.Framework;

[...]

Framework.getRuntime().getComponent(componentName)

Usually, components are not used directly, they are used via a service interface. For that, the XML components can declare which service interfaces are provided by a given component. The component can directly implement the service interface, or can delegate service interface implementation to an other class. Components must be accessed using the interfaces they provide and not through real implementation classes. Once declared the service will be available through a simple Nuxeo Runtime call:

import org.nuxeo.runtime.api.Framework;

[...]

Framework.getService(ServiceInterface.class)

To learn more about creating a service, see HOWTO: Create a service.

The list of existing services can be found on the Nuxeo Platform Explorer.

Nuxeo Extension Points and Contributions

One of the corner stones of the Nuxeo Platform is to provide components and services that can easily be configured or extended. For that, we use the extension point system provided by Nuxeo Runtime.

This extension point system allows you to:

  • Configure the behavior of components (by contributing XML configurations),
  • Extend the behavior of components (by contributing Java code or scripting).

Basically, inside the Nuxeo Platform, the pattern is always the same:

  • Services are provided by components,
  • Components expose extension points.

The same extension point system is used all over the platform:

  • Inside Nuxeo Runtime itself,
  • Inside Nuxeo Core (configure and extend document storage),
  • Inside the Nuxeo Service layer (configure and extend ECM services).

Each Java component can declare one or several extension points, served by one or several service interfaces.

These extension points can be used to provide:

  • Configuration,
  • Additional code (i.e. plug-in system).

So, most Nuxeo services are configurable and pluggable via the underlying component.

Extension Points

Declaring an Extension Point

Extension points are declared via the XML component that declares the corresponding Java component.

Here is a simple example:

<?xml version="1.0"?>
<component name="org.nuxeo.ecm.core.convert.service.ConversionServiceImpl">
  <documentation>
    Service to handle conversions
  </documentation>
  <implementation class="org.nuxeo.ecm.core.convert.service.ConversionServiceImpl"/>
  <service>
    <provide interface="org.nuxeo.ecm.core.convert.api.ConversionService"/>
  </service>
  <extension-point name="converters">
    <documentation>
      This extension point can be used to register new converters
    </documentation>
    <object class="org.nuxeo.ecm.core.convert.extension.ConverterDescriptor"/>
  </extension-point>
  <extension-point name="configuration">
    <documentation>
      This extension point can be used to configure conversion service
    </documentation>
    <object class="org.nuxeo.ecm.core.convert.extension.GlobalConfigDescriptor"/>
  </extension-point>
</component>

What we can read in this XML component is:

  • A Java component (via the <component> tag) with a unique id (into the name attribute) is declared;
  • This component declares a new service interface (via the <implementation> tag) -- the component name and service interface do not need to be identical, like in this example;
  • The declaration of the ConvertService interface (used to also fetch it) implemented by ConvertServiceImpl Java implementation,
  • This service expose two extension points:
    • One to contribute configuration (configuration),
    • One to contribute some Java code (new converter plugin).

Each extension point has his own XML structure descriptor, to specify the XML fragment expected for this extension point:

  • org.nuxeo.ecm.core.convert.extension.ConverterDescriptor
  • org.nuxeo.ecm.core.convert.extension.GlobalConfigDescriptor

This description is defined directly into these classes by annotations. Nuxeo Runtime instanced descriptors and delivers it to the Java component implementation each time a new contribution to these extension points is detected.

Each Nuxeo extension point uses this pattern to declare configuration possibilities, service integration, extension behavior, merge, override, etc. This pattern is used by all extension points in Nuxeo, and you can use this same infrastructure to declare your own business services.

To learn more about creating an extension point and a related service, see HOWTO: Create a service.

Contributing to an Extension Point

XML components can also be used to contribute to extension points.

For that, the XML component needs to:

  • Be referenced in a manifest bundle,
  • Specify a target extension point,
  • Provide the XML content expected by the target extension point.

Expected XML syntax is defined by the XMap object referenced in the extension point declaration. This object's javadoc is also visible on the extension point page in the Explorer, see Contribution Descriptors on a sample page.

Here is an example contribution to the extension point presented above:

<?xml version="1.0"?>
<component name="org.nuxeo.ecm.platform.convert.plugins">
  <extension target="org.nuxeo.ecm.core.convert.service.ConversionServiceImpl" point="converter">
    <converter name="zip2html" class="org.nuxeo.ecm.platform.convert.plugins.Zip2HtmlConverter">
      <destinationMimeType>text/html</destinationMimeType>
      <sourceMimeType>application/zip</sourceMimeType>
    </converter>
  </extension>
</component>

To learn more about contributing to existing extension points, see HOWTO: Contribute to an Extension.

Extension Points Everywhere

The Nuxeo Platform uses extension points extensively, to let you extend and configure most of the features provided by the platform.

The list of existing extension points can be found on the Nuxeo Platform Explorer.

Nuxeo Packages

The Nuxeo main bundles are made available on the Nuxeo server by default. To deploy custom bundles, a Nuxeo Package can be created.

This package can hold bundles, related libraries, as well as configuration templates.

Now, you may want to understand how those packages are deployed on a Nuxeo server.