# Extending OpenNLP

In OpenNLP extension can be used to add new functionality and to heavily customize an existing component. Most components define a factory class which can be implemented to customize the creation of it. And some components allow to add new feature generators.

## Writing an extension

In many places it is possible to pass in an extension class name to customize some aspect of OpenNLP. The implementation class needs to implement the specified interface and should have a public no-argument constructor.

## Extension Class Allowlist

Extension classes are loaded by `ExtensionLoader` via reflection. Only classes whose fully-qualified name starts with a registered package prefix are permitted. The default prefix is `opennlp.`, covering all built-in factories and serializers.

To use a custom class outside `opennlp.`, register its package before loading any model that references it:

    ExtensionLoader.registerAllowedPackage("com.example.nlp");

Alternatively, set the system property at JVM startup:

    -DOPENNLP_EXT_ALLOWED_PACKAGES=com.example.nlp.,com.other.factories.

A registered prefix can be removed with `ExtensionLoader.unregisterAllowedPackage(String)`.

## Running in an OSGi container

The traditional way of loading an extension via Class.forName does not work in an OSGi environment because the class paths of the OpenNLP Tools and extension bundle are isolated. OSGi uses services to provide functionality from one bundle to another. The extension bundle must register its extensions as services so that the OpenNLP tools bundle can use them. The following code illustrates how that can be done:

    Dictionary<String, String> props = new Hashtable<String, String>();
    props.put(ExtensionServiceKeys.ID, "org.test.SuperTokenizer");
    context.registerService(Tokenizer.class.getName(), new org.test.SuperTokenizer(), props);

The service OpenNLP is looking for might not be (yet) available. In this case OpenNLP waits until a timeout is reached. If loading the extension fails an ExtensionNotLoadedException is thrown. This exception is also thrown when the thread is interrupted while it is waiting for the extension, the interrupted flag will be set again and the calling code has a chance to handle it.