Chapter 18. Developing Nexus Plugins

Among the many benefits of using an technology with an open source core is the ability to customize behavior and create extensions. To this end, Sonatype has spent a great deal of time designing an intuitive Plugin API that will allow you to take Nexus where you need it to go. This chapter summarizes some of these extension points and presents a walk through of how you would start to develop your own Nexus plugins.

Our community has already created a number of compelling and useful plugins, some of which have been integrated into the set of plugins that are distributed with both Nexus Open Source and Nexus Professional. Sonatype tried to make the Plugin API as lightweight and extensible as possible with the following goals in mind:

  • Providing a clear set of extension points for plugin developers

  • Providing isolated plugin classpaths to avoid compatibility issues between plugins and to prevent a plugin from disturbing another, unrelated part of Nexus.

  • Giving developers the ability to load and unload Nexus plugins at runtime

18.1. Nexus Plugins

The Nexus API is contained in a module named nexus-api. If you are developing a Nexus plugin, you will need to familiarize yourself with the extension points that are defined in this project.

18.1.1. Nexus Plugin API

Nexus provides an extra module for plugin developers - the "nexus-plugin-api". This module provides some extra annotations for plugins developers, and it allows a plugin developer to implement a plugin without having to know anything about Plexus or Nexus internals.

The Plugin API uses the @Inject annotation, an emerging standard for dependency injection which allows Nexus plugins to be developed in a way that is container-neutral.

The Nexus Plugin API introduces some annotations to make things easier:

@Managed

When a @Managed annotation is present on an interface, it marks the interface as "component contract" (Plexus role). Any non-abstract classes implementing it will be made managed by current container.

@RepositoryType

Used on interfaces, to mark it as new repository type, and to be registered with other core repository types in Nexus Repository Type Registry. It holds the basic information about the new type (the path where to mount it).

@RestResource

Used on classes, to mark them as REST Resources.

18.1.2. Nexus Extension Points

The simplest Nexus plugin contain a single class, SampleEventInjector, which contributes an EventInspector to Nexus Application. This simple event inspector will do nothing more than print a message every time it accepts and inspects an event.

Example 18.1. A Simple Event Inspector

package org.sample.plugin;

import javax.inject.Inject;

import org.sonatype.nexus.proxy.events.EventInspector;
import org.sonatype.plexus.appevents.Event;

public class SampleEventInspector
    implements EventInspector
{
    public boolean accepts( Event<?> evt )
    {
        return true;
    }

    public void inspect( Event<?> evt )
    {
        System.out.println( "invoked with event: " + 
              evt.toString() + " with sender " + 
              evt.getEventSender().toString() );
    }
}

During the build of this nexus plugin, this class is compiled and then scanned for concrete classes that implement extension point interfaces defined in the following section. The EventInspector interface in the nexus-api project has been marked with the @ExtensionPoint annotation. The plugin build takes the @ExtensionPoint, @Named, and @Inject annotations that may be present and generates a plugin descriptor which is packaged in the plugin's JAR.

When the plugin is present in Nexus during startup, the Nexus plugin manager reads the plugin metadata and instantiates the appropriate components. To implement a plugin, you simply implement some of these interfaces.

18.1.3. Nexus Plugin Extension Points

The following sections outline the available Nexus extension points.

18.1.3.1. Nexus Plugin Extension

  • Interface: org.sonatype.nexus.plugins.NexusPlugin

This extension component is meant to be used in Nexus plugins only. If it is found in a plugin, it will be invoked during install/uninstall/init phases of a plugin installation/uninstallation/initialization. Typical usage would be a need to perform some specific tasks on plugin install (ie. it uses native code to do some magic and those needs to be copied somewhere, register them with OS, etc).

18.1.3.2. Nexus Index HTML Customizer

  • Interface: org.sonatype.nexus.plugins.rest.NexusIndexHtmlCustomizer

This extension is able to customize the "index.html" returned by Nexus. Using this component, a plugin is able to add markup or Javascript to the pages generated by the Nexus web application. Every plugin that has a UI component uses this extension point to add Javascript customizations to the interface.

18.1.3.3. Static Plugin Resources

  • Interface: org.sonatype.nexus.plugins.rest.NexusResourceBundle

This extension gathers and publishes static resources over HTTP. These resources are usually JS files, CSS files, images, etc. Plugin developers do not need to use this extension directly since some of the features it exposes are automatic for all plugins. When the Nexus plugin manager discovers resources in plugin JAR under the path "/static", the Plugin Manager will create a special "plugin NexusResourceBundle" component on the fly.

If you do not want the plugin manager to automatically add a resource bundle you can define your own resource bundle implementation. The plugin manager will not add a resource bundle if:

  • no resources found on "/static" path within plugin classpath, or

  • a user created component of NexusResourceBundle exists within plugin

The "default plugin" resource bundle component uses MimeUtil from core to select MIME types of resources found within plugin, and will use same path to publish them (ie. in plugin JAR "/static/image.png" will be published on "http://nexushost/nexus/static/image.png").

18.1.3.4. Plugin Templates

  • Interface: org.sonatype.nexus.templates.TemplateProvider

Template provider is a component providing repository templates to Nexus. Every plugin which provides a "new" repository type should add a TemplateProvider as it is the only way to instantiate a repository instance. The core of Nexus provides a "default" template provider with templates for all core repository types, and all custom repository plugins (P2, OBR) provide template providers for their types.

18.1.3.5. Event Inspectors

  • Interface: org.sonatype.nexus.proxy.events.EventInspector

Event inspectors are used to inspect events in Nexus. One example of where this extension point is used is the index generation. To generate a Nexus index, there is an event inspector which listens for RepositoryItemEvent subclasses and updates the index in response to repository activity.

18.1.3.6. Content Generators

  • Interface: org.sonatype.nexus.proxy.item.ContentGenerator

A content generator is a component that is able to generate content dynamically, on the fly, instead of just serving a static resource. The content generator is registered to respond to a path that corresponds to a file. When the resource is retrieved, Nexus discards the file content and uses the registered content generator to generate content. The Nexus Archetype plugin uses a content generator to generate the archetype-catalog.xml. Every time a client requests the archetype-catalog.xml, the archetype catalog is generated using information from the index.

18.1.3.7. Content Classes

  • Interface: org.sonatype.nexus.proxy.registry.ContentClass

Content class controls the compatibility between repository types. It defines the type of content that can be stored in a repository, and it also affects how repositories can be grouped into repository groups. Every plugin contributing a new repository type should provide an instance of this extension point. Nexus has a ContentClass implementation for every core supported repository type, and the P2 and OBR plugins define custom ContentClass implementations.

18.1.3.8. Storage Implementations

  • Interface: org.sonatype.nexus.proxy.storage.local.LocalRepositoryStorage

  • Interface: org.sonatype.nexus.proxy.storage.remote.RemoteRepositoryStorage

A plugin developer can override the default file-based local repository storage and the default remote HTTP repository storage interface. If your plugin needs to stores repository artifacts and information in something other than a filesystem, or if your remote repository isn't accessible via HTTP, your plugin would provide an implementation of one of these interfaces. Nexus provides one of the each: a file-system LocalRepositoryStorage and CommonsHttpClient 3.x based RemoteRepositoryStorage.

18.1.3.9. Repository Customization

  • Interface: org.sonatype.nexus.plugins.RepositoryCustomizer

This extension component will be invoked during configuration of every Repository instance, and may be used to add some "extra" configuration to repositories The procurement plugin uses this mechanism to "inject" RequestProcessor that will evaluate rules before allowing execution of request.

18.1.3.10. Item and File Inspectors

  • Interface: org.sonatype.nexus.proxy.attributes.StorageItemInspector

  • Interface: org.sonatype.nexus.proxy.attributes.StorageFileItemInspector

Attribute storage ItemInspectors are able to "decorate" items in repositories with custom attributes. Every file stored/cached/uploaded in Nexus will be sent to these components for inspection and potentially decoration. The StorageItemInspector will get all item types for inspection (file, collections, links), while StorageFileItemInspector will get only file items. Currently only one ItemInspector is used in Nexus: the checksumming inspector, that decorates all file items in Nexus with SHA1 checksum and stores it into item attributes.

18.1.3.11. Nexus Feeds

  • Interface: org.sonatype.nexus.rest.feeds.sources.FeedSource

To add new RSS feeds, a plugin may provide implementation of this extension point. Nexus provides implementation for all the "core" RSS feeds.

18.1.3.12. Nexus Tasks and Task Configuration

  • Interface: org.sonatype.nexus.scheduling.NexusTask<T>

  • Interface: org.sonatype.nexus.tasks.descriptors.ScheduledTaskDescriptor

NexusTask is an extension point to implement new Nexus Scheduled Tasks.

If a contributed task needs UI, then the plugin which provides the NexusTask should provide a ScheduledTaskDescriptor which allows the UI customization for the task creation and management interface.

18.1.3.13. Application Customization

  • Interface: org.sonatype.nexus.rest.NexusApplicationCustomizer

This extension component is able to intercept URLs routed in the Nexus REST API layer.

18.1.3.14. Request Processing

  • Interface: org.sonatype.nexus.proxy.repository.RequestProcessor

This extension point can affect how a repository reacts to an item request.