Plugins
Overview
The Ignite plugin system allows you to extend the core functionality of Ignite. Plugins have access to different internal Ignite components, such as security processor and others, and can extend the programmatic API of Ignite.
To add a custom plugin, implement the PluginProvider
interface and register the implementation in the node configuration.
The following is an overview of the steps involved in creating a plugin:
-
Implement the
PluginProvider
interface. This is the main interface for creating plugins. -
Implement the
IgnitePlugin
interface. If your plugin adds functionality that is meant to be triggered by end users, you should add public methods to this class. An instance of this class is available to end users at runtime viaIgnite.plugin(String pluginName)
. -
Register the plugin in
IgniteConfiguration.setPluginProviders(…)
either programmatically or via XML configuration. -
If your plugin has a public API, call
MyPlugin plugin = Ignite.plugin(pluginName)
at runtime and execute specific actions.
The following section gives an example of a plugin and goes into details about how plugins work in Ignite.
Example Plugin
Let’s create a simple Ignite plugin that prints information about the number of entries in every cache to the console periodically, on each node. In addition, it exposes a public method that the users can call programmatically from their application to print the cache size information on demand. The plugin has one configuration parameter: the time interval for printing the cache size information.
1. Implement PluginProvider
PluginProvider
is the main interface for creating Ignite plugins.
Ignite calls the methods of each registered plugin provider during initialization.
The following methods must return non-null values. Other methods are optional.
-
name()
- returns the name of the plugin -
plugin()
- returns the object of your plugin class
Below is an example implementation of a plugin provider.
We create an object of MyPlugin
class (see next step) in the initExtensions()
method.
Ignite passes a PluginContext
object as an argument to this method.
PluginContext
provides access to the Ignite APIs and node configuration.
See the PluginContext javadoc for more information.
Here we simply pass the PluginContext
and the time interval to the MyPlugin
constructor.
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ignite.snippets.plugin;
import java.io.Serializable;
import java.util.UUID;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.cluster.ClusterNode;
import org.apache.ignite.plugin.CachePluginContext;
import org.apache.ignite.plugin.CachePluginProvider;
import org.apache.ignite.plugin.ExtensionRegistry;
import org.apache.ignite.plugin.PluginConfiguration;
import org.apache.ignite.plugin.PluginContext;
import org.apache.ignite.plugin.PluginProvider;
import org.apache.ignite.plugin.PluginValidationException;
import org.jetbrains.annotations.Nullable;
public class MyPluginProvider implements PluginProvider<PluginConfiguration> {
/**
* The time interval in seconds for printing cache size information.
*/
private long interval = 10;
private MyPlugin plugin;
public MyPluginProvider() {
}
/**
*
* @param interval Time interval in seconds
*/
public MyPluginProvider(long interval) {
this.interval = interval;
}
@Override
public String name() {
//the name of the plugin
return "MyPlugin";
}
@Override
public String version() {
return "1.0";
}
@Override
public String copyright() {
return "MyCompany";
}
@Override
public MyPlugin plugin() {
return plugin;
}
@Override
public void initExtensions(PluginContext ctx, ExtensionRegistry registry)
throws IgniteCheckedException {
plugin = new MyPlugin(interval, ctx);
}
@Override
public void onIgniteStart() throws IgniteCheckedException {
//start the plugin when Ignite is started
plugin.start();
}
@Override
public void onIgniteStop(boolean cancel) {
//stop the plugin
plugin.stop();
}
/**
* The time interval (in seconds) for printing cache size information
* @return
*/
public long getInterval() {
return interval;
}
/**
* Sets the time interval (in seconds) for printing cache size information
* @param interval
*/
public void setInterval(long interval) {
this.interval = interval;
}
// other no-op methods of PluginProvider
}
The onIgniteStart()
method is invoked when Ignite is started.
We start the plugin by calling MyPlugin.start()
, which simply schedules periodic execution of the task that prints cache size information.
2. Implement IgnitePlugin
The implementation of the IgnitePlugin
returned by the plugin provider is available to the users via Ignite.plugin(String pluginName)
.
If you want to provide public API to end users, the API should be exposed in the class that implements IgnitePlugin
.
Strictly speaking, this step is not necessary if your plugin does not provide a public API.
Your plugin functionality may be implemented and initialized in the PluginProvider
implementation, and the PluginProvider.plugin()
method may return an empty implementation of the IgnitePlugin
interface.
In our case, we encapsulate the plugin functionality in the MyPlugin
class and provide one public method (MyPlugin.printCacheInfo()
).
The MyPlugin.java
implements the Runnable
interface.
The start()
and stop()
methods schedule periodic printing of cache size information.
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ignite.snippets.plugin;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.apache.ignite.IgniteCache;
import org.apache.ignite.plugin.IgnitePlugin;
import org.apache.ignite.plugin.PluginContext;
/**
*
* The plugin prints cache size information to console
*
*/
public class MyPlugin implements IgnitePlugin, Runnable {
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private PluginContext context;
private long interval;
/**
*
* @param context
*/
public MyPlugin(long interval, PluginContext context) {
this.interval = interval;
this.context = context;
}
private void print0() {
StringBuilder sb = new StringBuilder("\nCache Information: \n");
//get the names of all caches
context.grid().cacheNames().forEach(cacheName -> {
//get the specific cache
IgniteCache cache = context.grid().cache(cacheName);
if (cache != null) {
sb.append(" cacheName=").append(cacheName).append(", size=").append(cache.size())
.append("\n");
}
});
System.out.print(sb.toString());
}
/**
* Prints the information about caches to console.
*/
public void printCacheInfo() {
print0();
}
@Override
public void run() {
print0();
}
void start() {
scheduler.scheduleAtFixedRate(this, interval, interval, TimeUnit.SECONDS);
}
void stop() {
scheduler.shutdownNow();
}
}
3. Register your Plugin
Programmatically:
IgniteConfiguration cfg = new IgniteConfiguration();
//register a plugin that prints the cache size information every 100 seconds
cfg.setPluginProviders(new MyPluginProvider(100));
//start the node
Ignite ignite = Ignition.start(cfg);
Via XML Configuration:
Compile your plugin source code and add the classes to the classpath on each node. Then, you can register the plugin as follows:
<bean class="org.apache.ignite.configuration.IgniteConfiguration">
<property name="pluginProviders">
<bean class="org.apache.ignite.snippets.plugin.MyPluginProvider">
<property name="interval" value="100"/>
</bean>
</property>
</bean>
When you start the node, you should see the following message in the console:
[11:00:49] Initial heap size is 248MB (should be no less than 512MB, use -Xms512m -Xmx512m).
[11:00:49] Configured plugins:
[11:00:49] ^-- MyPlugin 1.0
[11:00:49] ^-- MyCompany
[11:00:49]
4. Access the Plugin at Runtime
You can access the instance of the plugin by calling Ignite.plugin(pluginName)
.
The pluginName
argument must be equal to the plugin name returned in MyPluginProvider.name()
.
//get an instance of the plugin
MyPlugin p = ignite.plugin("MyPlugin");
//print the cache size information
p.printCacheInfo();
Apache, Apache Ignite, the Apache feather and the Apache Ignite logo are either registered trademarks or trademarks of The Apache Software Foundation.