Plugin types
Almost everything in Hop is a plugin. Transforms and actions are the obvious ones, but so are the data types flowing through a pipeline, the engines that run it, the databases it talks to, the metadata objects you edit in the GUI, the perspectives of that GUI, and the hop commands you type in a terminal.
There are just over thirty plugin types. This section is the catalogue: one entry per type, saying what it does, what you annotate, what you implement, and the things that are easy to get wrong.
If you already know which type you need, jump straight to its group:
-
Pipelines and workflows — transforms, actions, engines, partitioners, row distribution
-
Data and connectivity — value types, databases, compression, VFS, data streams
-
Metadata and configuration — metadata objects, CLI commands and options, variable resolvers, password encoders, authentication
-
Execution and observability — extension points, logging, execution information, data samplers, lineage sinks, server servlets
-
GUI — GUI plugins, perspectives, file types, search analysers, dialog tabs
The rest of this page is the part that is the same for all of them.
How a plugin is found
There is no registration file to edit and no service loader. A plugin is a class with an annotation, in a jar, in a folder Hop looks at.
Discovery works in two passes, both driven by a Jandex annotation index:
- Native plugins
-
Everything on the classpath whose jar carries a
META-INF/jandex.idx. This is how the plugins built intohop-core,hop-engineandhop-uiare found. - Plugin folders
-
Every jar under
plugins/(configurable with theHOP_PLUGIN_BASE_FOLDERSvariable, defaultplugins) that carries aMETA-INF/jandex.idx. This is how everything in theplugins/folder of the distribution is found, and how anything a user drops in later is found.
| No index, no plugin. The index is produced by the |
Each plugin found in a plugin folder gets its own URLClassLoader covering the plugin jar plus the jars in its lib/ folder, with the Hop classloader as parent. Two consequences worth remembering:
-
Anything already shipped in
lib/coremust not be shipped again inside the plugin — the child classloader sees the parent’s copy, and a duplicate is at best waste and at worst a subtle version conflict. -
Two plugins that need to see each other’s classes (a database dialect and its bulk loader, an SFTP connection type and the actions using it) must declare the same
classLoaderGroup. Plugins in one group share a single classloader.
The registry
All of this ends up in one place:
PluginRegistry.getInstance() The registry keeps the plugins per type, along with the classloaders it created for them, so a plugin is loaded once no matter how many times it is asked for. You look plugins up by type and id, and load their main class:
PluginRegistry registry = PluginRegistry.getInstance();
IPlugin plugin = registry.findPluginWithId(TransformPluginType.class, "TableInput");
ITransformMeta meta = registry.loadClass(plugin, ITransformMeta.class); The registry is filled by the environment classes at startup, and which environment you start decides which plugin types exist:
HopClientEnvironment.init()-
the eight core types — logging, value types, databases, database type rules, extension points, password encoders, variable resolvers and VFS.
HopEnvironment.init()-
the above plus everything engine-side: transforms, actions, engines, metadata, server servlets, and the rest.
HopGuiEnvironment.init()-
the above plus the four GUI types.
That layering is why a headless tool that only calls HopClientEnvironment.init() cannot load transforms, and why a plugin type is useless until something adds it with PluginRegistry.addPluginType(…).
What every plugin type has in common
Each plugin type is a class implementing IPluginType<T extends Annotation>, in practice by extending BasePluginType<T>. It declares two things:
@PluginMainClassType(ITransformMeta.class) // the interface your class must implement
@PluginAnnotationType(Transform.class) // the annotation that marks your class
public class TransformPluginType extends BasePluginType<Transform> { ... } The annotations differ per type, but most of them draw from the same set of attributes, which the plugin type copies into the IPlugin object in the registry:
| Attribute | Meaning |
|---|---|
| Unique within the plugin type, and written into |
| Shown in the user interface. |
| Shown in the user interface, usually as a tooltip. |
| Path to the SVG icon inside the plugin jar. See SVG Files. |
| Groups the plugin in the UI, for transforms, actions, metadata types and perspectives. |
| Extra search terms for the context dialog and the search perspective. |
| Path on the Hop documentation site, opened by the help button in the dialog. |
| Plugins sharing this string share one classloader. |
| A fresh classloader per instantiation. Rarely what you want. |
Any of the text attributes can be an i18n key instead of a literal, using a three-part i18n:<package>:<key> syntax. An empty package means "the package of the annotated class":
@Transform(
id = "DetectEmptyStream",
image = "detectemptystream.svg",
name = "i18n::DetectEmptyStream.Name",
description = "i18n::DetectEmptyStream.Description",
categoryDescription = "i18n:org.apache.hop.pipeline.transform:BaseTransform.Category.Flow",
keywords = "i18n::DetectEmptyStreamMeta.keyword",
documentationUrl = "/pipeline/transforms/detectemptystream.html") See Internationalisation for the message bundles behind those keys.
The catalogue
| Plugin type | Annotation | Implement | What it does |
|---|---|---|---|
|
|
| A transform: the unit of work in a pipeline. |
|
| (fragment) | Declares engine compatibility for a transform you do not own. |
|
|
| An action: the unit of work in a workflow. |
|
|
| A runtime that executes pipelines. |
|
|
| A runtime that executes workflows. |
|
|
| Decides which partition a row belongs to. |
|
|
| Decides which target copy a row is sent to. |
|
|
| A data type in the row stream. |
|
|
| A database dialect. |
|
|
| Column type mapping rules, also for dialects you do not own. |
|
|
| A compression codec for file transforms. |
|
|
| A URL scheme for Apache VFS. |
|
|
| A named source or target of rows outside a pipeline. |
|
|
| A metadata object type, editable in the GUI and serialised as JSON. |
|
|
| Extra options on an existing Hop command line tool. |
|
|
| A new |
|
|
| An importer from another tool into a Hop project. |
|
|
| Resolves values from a vault or secret manager. |
|
|
| How passwords are obfuscated or encrypted in metadata. |
|
|
| A kind of credential. |
|
|
| Something that consumes such a credential. |
|
|
| Code that runs at one of Hop’s named hook points. |
|
|
| Participates in the logging subsystem lifecycle. |
|
|
| Where execution information, logs and metrics are stored. |
|
|
| Which rows are captured while a pipeline runs. |
|
|
| Where lineage events are delivered. |
|
|
| An HTTP endpoint on Hop Server. |
|
| (none) | Menus, toolbars, context actions and widgets in the Hop GUI. |
|
|
| A perspective: a full screen in the Hop GUI. |
|
|
| A file type the GUI recognises, opens and searches. |
|
|
| Makes one kind of object searchable. |
|
|
| An extra tab in the pipeline properties dialog. |
|
|
| An extra tab in the workflow properties dialog. |
Where plugins live, and how they ship
Plugins that are part of Hop live under plugins/, grouped by what they are:
plugins/transforms-
pipeline transforms
plugins/actions-
workflow actions
plugins/databases-
database dialects
plugins/engines-
pipeline and workflow engines
plugins/tech-
everything belonging to one technology (Azure, Google, AWS, FTP, SFTP, Arrow, …), often several plugin types in one module
plugins/vfs-
VFS plugins that are not part of a
techmodule plugins/valuetypes-
value types
plugins/resolvers-
variable resolvers
plugins/misc-
everything else
Adding one is three edits and one new file:
-
A new Maven module under the right category, with the category pom as its parent, added to that pom’s
<modules>. The parent already provideshop-core,hop-engine,hop-uiand SWT asprovideddependencies, the Jandex index, and the SWTBot test stack. -
src/assembly/assembly.xmlin the module. Its presence activates the assembly profile that turns the module into a plugin zip. Copy one from a comparable plugin: it declares the zip id, shipsversion.xml, and pulls in the sharedassemblies/shared/hop-plugin-libs.xmlcomponent that routes the plugin jar and its dependencies to the right folders. -
src/main/resources/version.xml, a one-liner containing${project.version}. -
A
<dependency>on the module with<type>zip</type>inassemblies/plugins/pom.xml, which is what actually puts the plugin in the distribution.
The shared assembly component decides where each dependency lands based on its Maven scope: provided dependencies that are not part of Hop itself go to the shared lib/core, runtime dependencies go to the plugin’s own lib/ folder, and JDBC drivers go to lib/jdbc. Review what ends up in the zip. Anything already in lib/core should be excluded.
Plugins that are not part of Hop follow the same shape but build and release on their own — see Creating your own plugin and Publishing a plugin to Nexus. That route is the one to take when a dependency is not Apache category A.
Documenting and sampling a plugin
Two things are easy to forget and are expected of plugins in the Hop repository:
-
A documentation page under
docs/hop-user-manual, referenced from the plugin’sdocumentationUrl. -
A sample pipeline or workflow, see Plugin samples.