:toc: macro
toc::[]

= Implementing a new Plug-in

New plug-ins can implement an input reader, a merger, a matcher, a trigger interpreter, and/or a template engine as explained link:cobigen-core_development#extension-mechanism[here].

[NOTE]
====
It is discouraged to have `cobigen-core` dependencies at runtime, except for `cobigen-core-api` which definitely must be present.
====

== Plugin Activator

Each plug-in has to have an plug-in activator class implementing the interface `GeneratorPluginActivator` from the `core-api`. This class will be used to load the plug-in using the `PluginRegistry` as explained link:cobigen-core_development#loadplugin[here]. This class implements two methods:

. `bindMerger()` -> returns a mapping of merge strategies and its implementation to be registered.
. `bindTriggerInterpreter()`-> returns the trigger interpreters to be provided by this plug-in.

Both methods create and register instances of mergers and trigger interpreters to be provided by the new plug-in.

== Adding Trigger Interpreter

The trigger interpreter has to implement the `TriggerInterpreter` interface from the core. The trigger interpreter defines the type for the new plugin and creates new `InputReader` and new Matcher objects.

== Adding Input Reader

The input reader is responsible of read the input object and parse it into
 FreeMarker models. The input reader must be implemented for the type of the
 input file. If there is any existent plugin that has the same file type as input,
 there will be no need to add a new input reader to the new plug-in.

=== Input Reader Interface

The interface needed to add a new input reader is defined at the core. Each new
sub plug-in must implements this interface if is needed an input reader for it.

The interface implements the basic methods that an input reader must have,
but if additional methods are required, the developer must add a new interface
that extends the original interface *__`InputReader.java`__* from the `core-api`
and implement that on the sub plug-in.

The methods to be implemented by the input reader of the new sub plugin are:

[options="header"]
|======================
|Method | Return Type | Description
| `isValidInput(Object input)`  | `*boolean*` | This function will be called if matching triggers or matching templates should be retrieved for a given input object.
| `createModel(Object input)` | *Map<String, Object>*  |This function should create the FreeMarker object model from the given input.
| `combinesMultipleInputObjects(Object input)` | `*boolean*`  | States whether the given input object combines multiple input objects to be used for generation.
| `getInputObjects(Object input, Charset inputCharset)` |  *List<Object>*  |Will return the set of combined input objects if the given input combines multiple input objects.
| `getTemplateMethods(Object input)` | *Map<String, Object>* | This method returns available template methods from the plugins as Map. If the plugin which corresponds to the input does not provide any template methods an empty Map will be returned.
| `getInputObjectsRecursively(Object input, Charset inputCharset)` | *List<Object>* | Will return the set of combined input objects if the given input combines multiple input objects.
|======================

=== Model Constants

The Input reader will create a model for FreeMarker. A FreeMarker model must
have variables to use them at the `.ftl` template file. Refer to link:cobigen-javaplugin#java-input-reader[Java Model] to see the FreeMarker model example for java input files.

=== Registering the Input Reader

The input reader is an object that can be retrieved using the correspondent get
 method of the trigger interpreter object. The trigger interpreter object is
 loaded at the eclipse plug-in using the load plug-in method explained
 link:cobigen-core_development#loadplugin[here].
 That way, when the core needs the input reader, only needs to call that `getInputReader` method.

== Adding Matcher

The matcher implements the `MatcherInterpreter` interface from the `core-api`.
Should be implemented for providing a new input matcher. Input matcher are
defined as part of a trigger and provide the ability to restrict specific
inputs to a set of templates.
This restriction is implemented with a `MatcherType` `enum`.

E.g `JavaPlugin`

[source,java]
----
private enum MatcherType {
    /** Full Qualified Name Matching */
    FQN,
    /** Package Name Matching */
    PACKAGE,
    /** Expression interpretation */
    EXPRESSION
}
----

Furthermore, matchers may provide several variable assignments, which might be
dependent on any information of the matched input and thus should be resolvable
by the defined matcher.

E.g `JavaPlugin`

[source,java]
----
private enum VariableType {
    /** Constant variable assignment */
    CONSTANT,
    /** Regular expression group assignment */
    REGEX
}
----

== Adding Merger

The merger is responsible to perform merge action between new output with the
existent data at the file if it already exists. Must implement the Merger
interface from the `core-api`.
The implementation of the Merge interface must override the following methods:

[options="header"]
|======================
|Method | Return Type | Description
| `getType()`  | *String* | Returns the type, this merger should handle.
| `merge(File base, String patch, String targetCharset)` | *String*  | Merges the patch into the base file.
|======================

Is important to know that any exception caused by the merger must throw a `MergeException` from the `core-api` to the eclipse-plugin handle it.

== Changes since Eclipse / Maven 3.x

Since version 3.x the Eclipse and Maven plugins of CobiGen utilize the Java `ServiceLoader` mechanic to find and register plugins at runtime. To enable a new plugin to be discovered by this mechanic the following steps are needed:

* create the file `META-INF/services/com.devonfw.cobigen.api.extension.GeneratorPluginActivator` containing just the full qualified name of the class implementing the `GeneratorPluginActivator` interface, if the plugin provides a `Merger` and/or a `TriggerInterpreter`
* create the file `META-INF/services/com.devonfw.cobigen.api.extension.TextTemplateEngine` containing just the full qualified name of the class implementing the `TextTemplateEngine` interface, if provided by the plugin
* include `META-INF` into the target bundle (i.e. the folder `META-INF` has to be present in the target jar file)

.Example: Java Plugin
****
The java plugin provides both a `Merger` and a `TriggerInterpreter`. It contains therefore a `com.devonfw.cobigen.api.extension.GeneratorPluginActivator` file with the following content:
```
com.devonfw.cobigen.javaplugin.JavaPluginActivator
```
This makes the `JavaPluginActivator` class discoverable by the `ServiceLoader` at runtime.
****

* to properly include the plugin into the current system and use existing infrastructure, you need to add the plugin as a module in `/cobigen/pom.xml` (in case of a `Merger`/`TriggerInterpreter` providing plugin) and declare that as the plugin's parent in it's own `pom.xml` via
[source,xml]
----
<parent>
    <groupId>com.devonfw</groupId>
    <artifactId>cobigen-parent</artifactId>
    <version>dev-SNAPSHOT</version>
</parent>
----
or `/cobigen/cobigen-templateengines/pom.xml` (in case of a `Merger`/`TriggerInterpreter` providing plugin) and declare that as the plugin's parent in it's own `pom.xml` via
[source,xml]
----
<parent>
    <groupId>com.devonfw</groupId>
    <artifactId>cobigen-tempeng-parent</artifactId>
    <version>dev-SNAPSHOT</version>
</parent>
----
If the plugin provides both just use the `/cobigen/pom.xml`.

* The dependencies of the plugin are included in the bundle

* To make the plugin available to the Eclipse plugin it must be included into the current `compositeContent.xml` and `compositeArtifacts.xml` files. Both files are located in link:https://github.com/devonfw/cobigen/tree/gh-pages/updatesite/stable[`https://github.com/devonfw/cobigen/tree/gh-pages/updatesite/{test|stable}`]. To do so, add an `<child>` entry to the `<children>` tag in both files and adapt the `size` attribute to match the new number of references. The `location` attribute of the new `<child>` tag needs to be the artifact id of the plugins `pom.xml`.

.Example: Java Plugin
****
In case of the Java plugin, the entry is
[source,xml]
----
<child location="cobigen-javaplugin"/>
----
****
=== Deployment

If you want to create a test release of eclipse you need to run the command
```shell
sh deploy.sh
```
on the cloned CobiGen repository while making sure, that your current version of CobiGen cloned is a snapshot version. This will automatically be detected by the deploy script. 
