| // 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. |
| = Extending Ignite.NET With Custom Plugins |
| |
| == Overview |
| |
| The Ignite.NET plugin system allows you to extend the core Ignite.NET functionality with custom plugins. The best way to |
| explain how Ignite plugins work is by looking at the life cycle of plugins. |
| |
| == IgniteConfiguration.PluginConfigurations |
| |
| First, an Apache Ignite plugin has to be registered via the `IgniteConfiguration.PluginConfigurations` property which is |
| a collection of the `IPluginConfiguration` implementations. From a user's perspective, this is a manual process - a |
| plugin's assembly has to be referenced and configured explicitly. |
| |
| The `IPluginConfiguration` interface has two members that interact with the Java part of Apache Ignite.NET. This is |
| described in the next section. Besides those two members, `IPluginConfiguration` implementation should contain all the |
| other plugin-specific configuration properties. |
| |
| Another part of an `IPluginConfiguration` implementation is the mandatory `[PluginProviderType]` attribute that tethers a |
| plugin configuration with a plugin implementation. For example: |
| |
| [tabs] |
| -- |
| tab:C#[] |
| [source,csharp] |
| ---- |
| [PluginProviderType(typeof(MyPluginProvider))] |
| public class MyPluginConfiguration : IPluginConfiguration |
| { |
| public string MyProperty { get; set; } // Plugin-specific property |
| |
| public int? PluginConfigurationClosureFactoryId |
| { |
| get { return null; } // No Java part |
| } |
| |
| public void WriteBinary(IBinaryRawWriter writer) |
| { |
| // No-op. |
| } |
| } |
| ---- |
| -- |
| |
| To recap, this is how plugins are added and initialized: |
| |
| * You add the `IPluginConfiguration` implementation instance to `IgniteConfiguration`. |
| * You start an Ignite node with the prepared configuration. |
| * Before the Ignite node initialization is finished, the Ignite plugin engine examines the `IPluginConfiguration` implementation |
| for the `[PluginProviderType]` attribute and instantiates the specified class. |
| |
| == IPluginProvider |
| |
| The `IPluginProvider` implementation is the work-horse of the newly added plugin. It deals with the Ignite node life cycle |
| by processing the calls to the `OnIgniteStart` and `OnIgniteStop` methods. In addition, it can provide an optional API |
| to be used by an end user via the `GetPlugin<T>()` method. |
| |
| The first method to be invoked on the `IPluginProvider` implementation by the Ignite.NET engine is |
| `Start(IPluginContext<TestIgnitePluginConfiguration> context)`. `IPluginContext` provides an access to an initial plugin |
| configuration and all means to interact with Ignite. |
| |
| When Ignite is being stopped, the `Stop` and `OnIgniteStop` methods are executed sequentially so that the plugin |
| implementation can accomplish all cleanup and shutdown-related tasks. |
| |
| == IIgnite.GetPlugin |
| |
| Plugins can expose user-facing API which is accessed via the `IIgnite.GetPlugin(string name)` method. The Ignite engine |
| will search for `IPluginProvider` with the passed name and call `GetPlugin` on it. |
| |
| == Interacting With Java |
| |
| The Ignite.NET plugin can interact with an Ignite Java plugin via the `PlatformTarget` & `IPlatformTarget` interface pair. |
| |
| === Java-Specific Logic |
| |
| . Implement the `PlatformTarget` interface, which is a communication point with .NET: |
| + |
| [tabs] |
| -- |
| tab:Java[] |
| [source,java] |
| ---- |
| class MyPluginTarget implements PlatformTarget { |
| @Override public long processInLongOutLong(int type, long val) throws IgniteCheckedException { |
| if (type == 1) |
| return val + 1; |
| else |
| return val - 1; |
| } |
| ... // Other methods here. |
| } |
| ---- |
| -- |
| |
| * Implement the `PlatformPluginExtension` interface: |
| + |
| [tabs] |
| -- |
| tab:Java[] |
| [source,java] |
| ---- |
| public class MyPluginExtension implements PlatformPluginExtension { |
| @Override public int id() { |
| return 42; // Unique id to be used from .NET side. |
| } |
| |
| @Override public PlatformTarget createTarget() { |
| return new MyPluginTarget(); // Return target from previous step. |
| } |
| } |
| ---- |
| -- |
| |
| * Implement the `PluginProvider.initExtensions` method and register the `PlatformPluginExtension` class: |
| + |
| [tabs] |
| -- |
| tab:Java[] |
| [source,java] |
| ---- |
| @Override public void initExtensions(PluginContext ctx, ExtensionRegistry registry) { |
| registry.registerExtension(PlatformPluginExtension.class, new MyPluginExtension()); |
| } |
| ---- |
| -- |
| |
| === .NET-specific Logic |
| |
| Call `IPluginContext.GetExtension` with a corresponding id. This will invoke the `createTarget` call on the Java side: |
| |
| [tabs] |
| -- |
| tab:C#[] |
| [source,csharp] |
| ---- |
| IPlatformTarget extension = pluginContext.GetExtension(42); |
| |
| long result = extension.InLongOutLong(1, 2); // processInLongOutLong is called in Java |
| ---- |
| -- |
| |
| Other `IPlatformTarget` methods provide an efficient way to exchange any kind of data between Java and .NET code. |
| |
| === Callbacks from Java |
| |
| .NET \-> Java call mechanism is described above; you can also do Java \-> .NET calls: |
| |
| * Register callback handler with some ID on the .NET side via the `IPluginContext.RegisterCallback` method. |
| * Call `PlatformCallbackGateway.pluginCallback` with that ID on the Java side. |
| |
| [NOTE] |
| ==== |
| [discrete] |
| === Complete Example |
| A detailed walk-through plugin example can be found in https://ptupitsyn.github.io/Ignite-Plugin/[this blog post, window=_blank]. |
| ==== |