In the previous recipe we saw the site plugin, but ElasticSearch allows creating a most powerful type of plugin, the native JAR ones.
Native plugins allow extending several aspects of the ElasticSearch server, but they require good Java knowledge. Because they are compiled in native JVM, they are generally very fast.
In this recipe we will see how to set up a system to develop native plugins.
You need a working ElasticSearch node, a Maven built tool, and an optional Java IDE. The code of this recipe is available in the chapter12/simple_plugin
directory.
Generally ElasticSearch plugins are developed in Java using the Maven built tool and deployed as a ZIP file.
For creating a simple JAR plugin, we need to perform the following steps:
pom.xml
: This is used to define the build configuration for Maven.es-plugin.properties
: This defines the namespace of the plugin class that must be loaded.<name>Plugin.java
: This is the main plugin class, which is loaded at start up and initializes the plugin actions.plugin.xml
: These are the assemblies that define how to execute the assembly steps of Maven. It is used to build the ZIP file to deliver the plugin.pom.xml
file for creating a plugin contains the following code:maven pom.xml
header is as follows:<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <name>elasticsearch-simple-plugin</name> <modelVersion>4.0.0</modelVersion> <groupId>com.packtpub</groupId> <artifactId>simple-plugin</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <description>A simple plugin for ElasticSearch</description> <inceptionYear>2013</inceptionYear> <licenses>… </licenses>
parent pom.xml
file used to derive common properties or settings is as follows:<parent> <groupId>org.sonatype.oss</groupId> <artifactId>oss-parent</artifactId> <version>7</version> </parent>
<properties> <elasticsearch.version>0.90.5</elasticsearch.version> </properties>
<dependencies> <dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> <version>${elasticsearch.version}</version> <scope>compile</scope> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> <scope>runtime</scope> </dependency> <!—test dependencies --> </dependencies>
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.12.3</version> <configuration> <includes> <include>**/*Tests.java</include> </includes> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-source-plugin</artifactId> <version>2.1.2</version> <executions> <execution> <id>attach-sources</id> <goals> <goal>jar</goal> </goals> </execution> </executions> </plugin> <plugin> <artifactId>maven-assembly-plugin</artifactId> <version>2.3</version> <configuration> <appendAssemblyId>false</appendAssemblyId> <outputDirectory>${project.build.directory}/releases/</outputDirectory> <descriptors> <descriptor>${basedir}/src/main/assemblies/plugin.xml</descriptor> </descriptors> </configuration> <executions> <execution> <phase>package</phase> <goals><goal>single</goal></goals> </execution> </executions> </plugin> </plugins> </build> </project>
es-plugin.properties
file, which defines the entry point class that must be loaded during plugin initialization. It generally contains a single line of code. For example:plugin=org.elasticsearch.plugin.simple.SimplePlugin
SimplePlugin.java
class is an example of the base minimum required code to be compiled for executing a plugin and its definition is as follows:package org.elasticsearch.plugin.simple; import org.elasticsearch.plugins.AbstractPlugin; public class SimplePlugin extends AbstractPlugin { @Override public String name() { return "simple-plugin"; } @Override public String description() { return "A simple plugin implementation"; } }
plugin.xml
file used in Maven assembly step as follows:<?xml version="1.0"?> <assembly> <id>plugin</id> <formats> <format>zip</format> </formats> <includeBaseDirectory>false</includeBaseDirectory> <dependencySets> <dependencySet> <outputDirectory>/</outputDirectory> <useProjectArtifact>true</useProjectArtifact> <useTransitiveFiltering>true</useTransitiveFiltering> <excludes> <exclude>org.elasticsearch:elasticsearch</exclude> </excludes> </dependencySet> <dependencySet> <outputDirectory>/</outputDirectory> <useProjectArtifact>true</useProjectArtifact> <useTransitiveFiltering>true</useTransitiveFiltering> <includes></includes> </dependencySet> </dependencySets> </assembly>
This file defines the resources that must be packaged into the final ZIP archive.
Several parts compose the development lifecycle of a plugin, such as designing, coding, building, and deploying. To speed up the building and deploying parts, which are always common to every plugin, we need to create a Maven pom.xml
file.
The preceding pom.xml
file is a standard one to develop ElasticSearch plugins. This file is composed by:
elasticsearch-simple-plugin
)<name>elasticsearch-simple-plugin</name>
groupId
and artifactId
tags are used to define the plugin artifact name as follows:<groupId>com.packtpub</groupId> <artifactId>simple-plugin</artifactId>
version
tag:<version>0.0.1-SNAPSHOT</version>
packaging
tag:<packaging>jar</packaging>
<description>A simple plugin for ElasticSearch</description> <inceptionYear>2013</inceptionYear>
<licenses> <license> <name>The Apache Software License, Version 2.0</name> <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url> <distribution>repo</distribution> </license> </licenses>
<parent> <groupId>org.sonatype.oss</groupId> <artifactId>oss-parent</artifactId> <version>7</version> </parent>
<properties> <elasticsearch.version>0.90.5</elasticsearch.version> </properties>
log4j
library, and the list of dependencies are required in the compiling phase:<dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> <version>${elasticsearch.version}</version> <scope>compile</scope> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> <scope>runtime</scope> </dependency>
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin>
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-source-plugin</artifactId> <version>2.1.2</version> <executions> <execution> <id>attach-sources</id> <goals> <goal>jar</goal> </goals> </execution> </executions> </plugin>
plugin.xml
) and inserting the output in the releases directory is as follows:<plugin> <artifactId>maven-assembly-plugin</artifactId> <version>2.3</version> <configuration> <appendAssemblyId>false</appendAssemblyId> <outputDirectory>${project.build.directory}/releases/</outputDirectory> <descriptors> <descriptor>${basedir}/src/main/assemblies/plugin.xml</descriptor> </descriptors> </configuration> <executions> <execution> <phase>package</phase> <goals><goal>single</goal></goals> </execution> </executions> </plugin>
Related to pom.xml
, we have the plugin.xml
file, which describes how to assemble the final ZIP file. This file is usually contained in the /src/main/assemblies/
directory of the project.
The most important sections of this file are as follows:
formats
: In this section the destination format is defined as follows<formats><format>zip</format></formats>
excludes sets
in dependencySet
: This contains the artifacts to be excluded from the package. Generally, we exclude ElasticSearch JAR as it is already provided in the server install.<dependencySet> <outputDirectory>/</outputDirectory> <useProjectArtifact>true</useProjectArtifact> <useTransitiveFiltering>true</useTransitiveFiltering> <excludes> <exclude>org.elasticsearch:elasticsearch</exclude> </excludes> </dependencySet>
includes
sets in dependencySet
: This contains the artifacts to be included into the package. They are mainly the required JARs to run the plugin.<dependencySet> <outputDirectory>/</outputDirectory> <useProjectArtifact>true</useProjectArtifact> <useTransitiveFiltering>true</useTransitiveFiltering> <includes>…</includes> </dependencySet>
While packaging the plugin, the include and exclude rules are verified and only the files that are allowed to be distributed are put in the ZIP file.
After having configured Maven, we can start to write the main plugin class.
Every plugin class must be derived by the AbstractPlugin
one and it must be public
otherwise it cannot be loaded dynamically from the JAR.
import org.elasticsearch.plugins.AbstractPlugin; public class SimplePlugin extends AbstractPlugin {
The AbstractPlugin
class needs the two methods to be defined: the name
and description
.
The name
method must return a string and it's usually a short name. This value is shown in the plugin loading log as follows:
@Override public String name() { return "simple-plugin"; }
The description
method must return a string too. It is mainly a long description of the plugin.
@Override public String description() { return "A simple plugin implementation"; }
After defining all the required files, to generate a ZIP release of our plugin it is enough to invoke the maven package
command. This command will compile the code and create a ZIP package in the target/releases
directory of your project.
In this recipe we have configured a working environment to build, deploy, and test plugins. In the next recipes we will re-use this environment to develop several plugin types.
Compiling and packaging the plugin is not enough to define a good lifecycle for your plugin, you need to add a test phase.
Testing the plugin functionalities with test cases reduces the number of bugs that can affect the plugin when released.
It's possible to add a test phase in Maven build pom.xml
.
The ElasticSearch community mainly uses the testNG (http://testng.org/) and the hamcrest (https://code.google.com/p/hamcrest/) libraries. To use them you need to add their dependencies in the dependency
section of the pom.xml
file:
<dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>6.8</version> <scope>test</scope> <exclusions> <exclusion> <groupId>org.hamcrest</groupId> <artifactId>hamcrest-core</artifactId> </exclusion> <exclusion> <groupId>junit</groupId> <artifactId>junit</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.hamcrest</groupId> <artifactId>hamcrest-all</artifactId> <version>1.3</version> <scope>test</scope> </dependency>
These dependencies are not standard, because they are tuned to exclude some unwanted packages. Note that the compiling scope is test
, which means that these dependencies are only considered during the test phase.
To complete the test
part, a Maven plugin which executes the tests, must be defined as follows:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.12.3</version> <configuration> <includes><include>**/*Tests.java</include></includes> </configuration> </plugin>
The include section lists all the possible classes that contains test via glob expression.
18.190.159.164