◂ Back to Profiq blog

OpenDJ plugin development based on example-plugin

While OpenDS plugin development was fairly well documented, it has evolved with OpenDJ while available information has not. I will try here to share some of my experience which might help you save some time until the plugin API becomes stable enough to be officially documented.

The starting point for documentation is:

You should read the first document listed and try to understand it before you start developing your own plugin, otherwise the rest of the article would not make much sense.

Files, naming and dependencies

The good base to start developing your own extension is the example plugin delivered in the OpenDJ binary distribution as

example-plugin.zip

. You can start by unzipping it and renaming the folder to your custom name. This is a good moment to think about the name of the plugin since it affects the way supporting classes are generated. Although the folder name has no effect, you would normally use the same name on multiple places in the sources. The name ‘example-plugin’ would generate classes with name ‘ExamplePlugin*’, ‘my-custom-plugin’ would result in ‘MyCustomPlugin*’, while ‘mycustom-plugin’ would turn out to be ‘MycustomPlugin*’ - obviously, the ‘-’ sign would cause the class names to be generated with camel case and the framework would require the class names to follow the case in order to compile them. The most important thing here is to pick a name and stick to it.

unzip example-plugin.zip
mv example-plugin my-plugin

The plugin generation framework depends on

Xalan-Java

as a workaround for a JDK-related XML processing bug, hence you should download the latest distribution of it and unpack it to the

ext/

folder as

xalan-j

since that’s what

build.xml

expects to find.

unzip -d my-plugin/ext xalan-j*.zip
cd my-plugin/ext
mv xalan-j* xalan-j

Apart from Xalan-Java, the build framework depends on

ant-contrib

tasks which you have to download and deploy inside the folder where

ant

would find it (or specify the location with the

ant

command line parameters).

Next step could be to modify

build.xml

so it fits the purpose of your custom plugin. The properties to change could be:

  • name under project tag
  • <description> tag
  • pkg.name
  • pkg.description

Sources are inside the

src/

folder followed by the folders which mark the package name, as usual. You might want to rename the

com.example.opends

to something more fitting to your company or project. In

resource/

folder you would find

schema/

and

messages/

relevant. The schema file in

schema/

folder should follow the name you have chosen in the form ‘99-NAME.ldif’, for example: ‘99-my-example-plugin.ldif’ - although this would not impact the building process, the naming would be consistent. The

messages/

directory contains the properties file(s) with the error messages and their localisation organised in the folders that follow the name of the package. Again, another part which should be renamed following the chosen name.

Note that

resources/

folder contains

config/

which in turn has a file with LDIF representation of the configuration defined in the XML file. That file (and folder for that matter) is not needed contrary to what README file says. Previously this file was used to configure the plugin by injecting it to the

config.ldif

file, but as the software evolved, this step is now performed with the

dsconfig

command. More about that later.

You will find your development process bouncing between the: source files which implement the plugin functionality, the configuration file for the plugin which is used to generate dependent classes, the properties file which defines the messages and, to smaller extent, the schema file.

The files we find in the sources folder of the example plugin are:

ExamplePlugin.java, ExamplePluginConfiguration.xml, Package.xml

and

package-info.java

. ‘ExamplePlugin*’ files are the ones that should be renamed to match the name you have chosen, say, if you have chosen ‘my-example-plugin’ then they should be:

MyExamplePlugin.java

and

MyExamplePluginConfiguration.xml

. Next, you should modify

MyExamplePluginConfiguration.xml

not only to match your configuration needs but also your naming choice (‘name’ property, ‘package’ property, etc.). Based on the information in the configuration file, the build framework would generate classes in

src-generated/

folder which would follow the names and packages properties, so if you do not name everything consistently and refer to it in your sources, the compilation process would fail. Needless to say, the contents of

Packages.xml

should match the rest of the configuration.

The relationship of the most important files is the following:

  • _src/com/example/opends/_ExamplePlugin.java contains the functionality of the plugin;
  • _src/com/example/opends/_ExamplePluginConfiguration.xml defines the configuration parameters for the plugin (set with the _dsconfig_command) which can be accessed via ‘config’ object inside the code;
  • _resources/messages/com/example/opends/messages/_example_plugin.properties defines the localised messages (for the given locale) which can be accessed from the code in a generic way, and
  • _resources/schema/_99-example-plugin.ldif is the schema definition for the parameters defined in the configuration file.

As you develop the functionality of the plugin, you will find it necessary to update the configuration and/or the messages which would require you re-generate the dependant files, otherwise if you use an IDE for development, the changes would not be reflected.

Notes on the configuration

The configuration parameters defined in the configuration file are represented in the directory as LDAP entries, hence when you define new parameters you are really defining new object class and new attributes. Logically, in order to have the directory updated with the plugin configuration, it has to contain the schema with the definition of the object classes and attributes you want to add. The parameters need not be reflected in the schema files during the time of development - it is only important to update it before you install the plugin, as the schema definition is important for the directory server to be able to create the plugin and create it’s configuration.

To get the better idea of how to set up the schema file, you can compare the

ExamplePluginConfiguration.xml

with

99-example-plugin.ldif.

Another helpful example might be found in the Samba password syncronisation plugin:

SambaPasswordPluginConfiguration.xml

,

99-samba-password-plugin.ldif

.

Creating a NetBeans project

If you want to develop your plugin as a NetBeans project, here is a simple way to do it:

  1. click on the New Project button;
  2. choose _Java Free-form Project_from the _Java_category;
  3. set the Location to the folder of your plugin;
  4. click Next
  5. click Next
  6. uncheck Separate Classpath…, and add OpenDJ.jar
  7. click Finish

This configuration would relay on the existing

build.xml

script to build everything, so you might want to update the menu with relevant targets such as

compileadmin, generate-messages, package, install

, etc.

Compiling and installing

If your code relies on external libraries, such as

OpenDJ SDK

, they should go to the

ext/

directory.

The most relevant

ant

targets are:

  • compileadmin- generates the dependent classes (based on the XML file);
  • generate-messages - generates the messages (based on the properties file);
  • _compile/package -_compiles the sources/creates the jar ready to install, and
  • install - installs the plugin

Installation of the plugin is not a single step which depends on the

ant

target, but requires various actions. Running the

install

target with

ant

would copy the plugin JAR, the schema and the configuration LDIF to the relevant folders under the location specified by the

opends.install.dir

property in

build.xml

(respectively, by default: ../lib/extensions, ../config)

.

As noted previously, the configuration LDIF is obsolete and should be removed so that it is not copied at all. The external libraries would not be copied (you would have to do that by hand), and the installation would have effect only upon the restart. Startup messages would indicate if the plugin was loaded and if there were any errors with the schema file.

The installation does not end here as the plugin has to be registered, configured and enabled in order to be used. All of that can be done in a single line with the

dsconfig

tool. For example:

dsconfig -X -n create-plugin --plugin-name "My Example Plugin"
--type my-example-plugin --set enabled:true --set some-property:value

Debugging

Most of the time, when a problem occurs, you would want to know what is happening inside your code. For this purpose you can define a debug logger and log whatever you find useful. To do that, you should create a

DebugTracer

object as a static member of your class:

  private static final DebugTracer TRACER = DebugLogger.getTracer();

The messages logged with the

TRACER

need debugging to be enabled in the directory and you can do that with the

dsconfig

command:

  • create the debug target:
dsconfig -X -n create-debug-target
--publisher-name "File-Based Debug Logger"
--target-name com.example.opends.ExamplePlugin --set debug-level:all
  • enable the debug log:
dsconfig -X -n set-log-publisher-prop
--publisher-name "File-Based Debug Logger" --set enabled:true

Easier way

Although still work in progress,

Maven archetype for OpenDJ plugins

is an easier alternative. It will perform all the steps necessary to keep you focused on coding and less on the internal dependencies of the example plugin.

Useful resources

Nemanja Lukic

Written by

Nemanja Lukic

Comments

Leave a Reply

Online comments are not active during the static migration phase.
AI Function Blog Image

Is The Most Valuable AI Function Asking Better Questions?

How the "Grill Me" method became a key part of Project Weaver's approach to AI-assisted software development. We've shared some of the thinking behind Project Weaver—the internal engineering framework we've developed at profiq to help our teams and AI work together more effectively. Rather than treating AI as a magic code generator, Weaver is built around a simple idea: the better the structure, context, and engineering discipline, the better the outcomes.

Posted 4 weeks ago by Anke Corbin

Weaver Prototype Image

From Vibe-Coded Prototype to Production-Ready App Using Weaver

There's an important distinction between a prototype that demonstrates an idea and a system that can support a real business. Recently, we had the opportunity to explore that distinction firsthand while working with Ginger & Nash on an application called c.h.i.p. using profiq Weaver as an AI assistant.

Posted 5 weeks ago by Anke Corbin

Project Weaver Recap

Quick Recap: Project Weaver Engineering Series

We wanted to do another quick recap of the Weaver journey so far for those of you who are just learning about the project, from the first idea through the latest automation and workflow experiments.

Posted 2 months ago by Anke Corbin

Read the Blog