You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by pt...@apache.org on 2017/01/19 14:10:49 UTC
ignite git commit: IGNITE-4441 Define plugin API in .NET
Repository: ignite
Updated Branches:
refs/heads/ignite-2.0 4cd332b78 -> d0a6c57aa
IGNITE-4441 Define plugin API in .NET
This closes #1362
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/d0a6c57a
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/d0a6c57a
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/d0a6c57a
Branch: refs/heads/ignite-2.0
Commit: d0a6c57aa26bca64ef68370c0ebdb5ce45bcc765
Parents: 4cd332b
Author: Pavel Tupitsyn <pt...@apache.org>
Authored: Thu Jan 19 17:10:41 2017 +0300
Committer: Pavel Tupitsyn <pt...@apache.org>
Committed: Thu Jan 19 17:10:41 2017 +0300
----------------------------------------------------------------------
.../ignite/internal/GridKernalContextImpl.java | 5 +-
.../apache/ignite/internal/IgniteKernal.java | 4 +
.../callback/PlatformCallbackGateway.java | 28 +++
.../platform/callback/PlatformCallbackOp.java | 6 +
.../plugin/PlatformPluginProcessor.java | 46 ++++
.../Apache.Ignite.Core.Tests.csproj | 4 +
.../IgniteConfigurationSerializerTest.cs | 14 +-
.../IgniteConfigurationTest.cs | 13 +-
.../Plugin/PluginTest.cs | 212 +++++++++++++++++
.../Plugin/TestIgnitePlugin.cs | 39 +++
.../Plugin/TestIgnitePluginConfiguration.cs | 33 +++
.../Plugin/TestIgnitePluginProvider.cs | 132 +++++++++++
.../Apache.Ignite.Core.csproj | 9 +
.../dotnet/Apache.Ignite.Core/IIgnite.cs | 10 +
.../Apache.Ignite.Core/IgniteConfiguration.cs | 8 +
.../IgniteConfigurationSection.xsd | 21 ++
.../Common/IgniteConfigurationXmlSerializer.cs | 3 +
.../dotnet/Apache.Ignite.Core/Impl/Ignite.cs | 24 ++
.../Apache.Ignite.Core/Impl/IgniteProxy.cs | 6 +
.../Impl/Plugin/IPluginProviderProxy.cs | 74 ++++++
.../Impl/Plugin/PluginContext.cs | 60 +++++
.../Impl/Plugin/PluginProcessor.cs | 235 +++++++++++++++++++
.../Impl/Plugin/PluginProviderProxy.cs | 90 +++++++
.../Impl/Unmanaged/UnmanagedCallbackOp.cs | 4 +-
.../Impl/Unmanaged/UnmanagedCallbacks.cs | 25 +-
.../Plugin/IPluginConfiguration.cs | 48 ++++
.../Apache.Ignite.Core/Plugin/IPluginContext.cs | 40 ++++
.../Plugin/IPluginProvider.cs | 69 ++++++
.../Plugin/PluginNotFoundException.cs | 65 +++++
.../Plugin/PluginProviderTypeAttribute.cs | 51 ++++
30 files changed, 1369 insertions(+), 9 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java
index 2f681ac..569460e 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java
@@ -70,6 +70,7 @@ import org.apache.ignite.internal.processors.nodevalidation.DiscoveryNodeValidat
import org.apache.ignite.internal.processors.odbc.OdbcProcessor;
import org.apache.ignite.internal.processors.offheap.GridOffHeapProcessor;
import org.apache.ignite.internal.processors.platform.PlatformProcessor;
+import org.apache.ignite.internal.processors.platform.plugin.PlatformPluginProcessor;
import org.apache.ignite.internal.processors.plugin.IgnitePluginProcessor;
import org.apache.ignite.internal.processors.pool.PoolProcessor;
import org.apache.ignite.internal.processors.port.GridPortProcessor;
@@ -563,7 +564,9 @@ public class GridKernalContextImpl implements GridKernalContext, Externalizable
platformProc = (PlatformProcessor)comp;
else if (comp instanceof PoolProcessor)
poolProc = (PoolProcessor) comp;
- else if (!(comp instanceof DiscoveryNodeValidationProcessor || comp instanceof GridMarshallerMappingProcessor))
+ else if (!(comp instanceof DiscoveryNodeValidationProcessor
+ || comp instanceof GridMarshallerMappingProcessor
+ || comp instanceof PlatformPluginProcessor))
assert (comp instanceof GridPluginComponent) : "Unknown manager class: " + comp.getClass();
if (addToList)
http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
index 20926f9..d883ff1 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
@@ -125,6 +125,7 @@ import org.apache.ignite.internal.processors.odbc.OdbcProcessor;
import org.apache.ignite.internal.processors.offheap.GridOffHeapProcessor;
import org.apache.ignite.internal.processors.platform.PlatformNoopProcessor;
import org.apache.ignite.internal.processors.platform.PlatformProcessor;
+import org.apache.ignite.internal.processors.platform.plugin.PlatformPluginProcessor;
import org.apache.ignite.internal.processors.plugin.IgnitePluginProcessor;
import org.apache.ignite.internal.processors.pool.PoolProcessor;
import org.apache.ignite.internal.processors.port.GridPortProcessor;
@@ -913,6 +914,9 @@ public class IgniteKernal implements IgniteEx, IgniteMXBean, Externalizable {
provider.start(ctx.plugins().pluginContextForProvider(provider));
}
+ // Start platform plugins.
+ startProcessor(new PlatformPluginProcessor(ctx));
+
fillNodeAttributes(clusterProc.updateNotifierEnabled());
gw.writeLock();
http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/callback/PlatformCallbackGateway.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/callback/PlatformCallbackGateway.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/callback/PlatformCallbackGateway.java
index a9268fe..9842068 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/callback/PlatformCallbackGateway.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/callback/PlatformCallbackGateway.java
@@ -1117,6 +1117,34 @@ public class PlatformCallbackGateway {
}
/**
+ * Stops plugin processor.
+ */
+ public void pluginProcessorStop(boolean cancel) {
+ enter();
+
+ try {
+ PlatformCallbackUtils.inLongOutLong(envPtr, PlatformCallbackOp.PluginProcessorStop, cancel ? 1 : 0);
+ }
+ finally {
+ leave();
+ }
+ }
+
+ /**
+ * Notifies plugin processor about Ignite stop.
+ */
+ public void pluginProcessorIgniteStop(boolean cancel) {
+ enter();
+
+ try {
+ PlatformCallbackUtils.inLongOutLong(envPtr, PlatformCallbackOp.PluginProcessorIgniteStop, cancel ? 1 : 0);
+ }
+ finally {
+ leave();
+ }
+ }
+
+ /**
* Redirects the console output to platform.
*
* @param str String to write.
http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/callback/PlatformCallbackOp.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/callback/PlatformCallbackOp.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/callback/PlatformCallbackOp.java
index 973ba51..b0bd3a5 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/callback/PlatformCallbackOp.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/callback/PlatformCallbackOp.java
@@ -203,4 +203,10 @@ class PlatformCallbackOp {
/** */
public static final int ComputeJobExecuteLocal = 61;
+
+ /** */
+ public static final int PluginProcessorStop = 62;
+
+ /** */
+ public static final int PluginProcessorIgniteStop = 63;
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/plugin/PlatformPluginProcessor.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/plugin/PlatformPluginProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/plugin/PlatformPluginProcessor.java
new file mode 100644
index 0000000..458ec31
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/plugin/PlatformPluginProcessor.java
@@ -0,0 +1,46 @@
+/*
+ * 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.internal.processors.platform.plugin;
+
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.internal.GridKernalContext;
+import org.apache.ignite.internal.processors.GridProcessorAdapter;
+
+/**
+ * Platform plugin processor
+ */
+public class PlatformPluginProcessor extends GridProcessorAdapter {
+ /**
+ * Ctor.
+ *
+ * @param ctx Kernal context.
+ */
+ public PlatformPluginProcessor(GridKernalContext ctx) {
+ super(ctx);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void stop(boolean cancel) throws IgniteCheckedException {
+ ctx.platform().context().gateway().pluginProcessorStop(cancel);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void onKernalStop(boolean cancel) {
+ ctx.platform().context().gateway().pluginProcessorIgniteStop(cancel);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
index e09c682..d48c8c8 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
@@ -89,6 +89,10 @@
<Compile Include="Log\DefaultLoggerTest.cs" />
<Compile Include="Log\Log4NetLoggerTest.cs" />
<Compile Include="Log\NLogLoggerTest.cs" />
+ <Compile Include="Plugin\PluginTest.cs" />
+ <Compile Include="Plugin\TestIgnitePlugin.cs" />
+ <Compile Include="Plugin\TestIgnitePluginConfiguration.cs" />
+ <Compile Include="Plugin\TestIgnitePluginProvider.cs" />
<Compile Include="TestAppConfig.cs" />
<Compile Include="Binary\BinaryBuilderSelfTestFullFooter.cs" />
<Compile Include="Binary\BinaryCompactFooterInteropTest.cs" />
http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationSerializerTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationSerializerTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationSerializerTest.cs
index 26e04a9..3a0a4b5 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationSerializerTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationSerializerTest.cs
@@ -51,6 +51,7 @@ namespace Apache.Ignite.Core.Tests
using Apache.Ignite.Core.Log;
using Apache.Ignite.Core.SwapSpace.File;
using Apache.Ignite.Core.Tests.Binary;
+ using Apache.Ignite.Core.Tests.Plugin;
using Apache.Ignite.Core.Transactions;
using Apache.Ignite.NLog;
using NUnit.Framework;
@@ -128,6 +129,9 @@ namespace Apache.Ignite.Core.Tests
<transactionConfiguration defaultTransactionConcurrency='Optimistic' defaultTransactionIsolation='RepeatableRead' defaultTimeout='0:1:2' pessimisticTransactionLogSize='15' pessimisticTransactionLogLinger='0:0:33' />
<logger type='Apache.Ignite.Core.Tests.IgniteConfigurationSerializerTest+TestLogger, Apache.Ignite.Core.Tests' />
<swapSpaceSpi type='FileSwapSpaceSpi' baseDirectory='abcd' maximumSparsity='0.7' maximumWriteQueueSize='25' readStripesNumber='36' writeBufferSize='47' />
+ <pluginConfigurations>
+ <iPluginConfiguration type='Apache.Ignite.Core.Tests.Plugin.TestIgnitePluginConfiguration, Apache.Ignite.Core.Tests' />
+ </pluginConfigurations>
</igniteConfig>";
var cfg = IgniteConfiguration.FromXml(xml);
@@ -234,6 +238,10 @@ namespace Apache.Ignite.Core.Tests
Assert.IsInstanceOf<IdMapper>(binType.IdMapper);
Assert.IsInstanceOf<NameMapper>(binType.NameMapper);
Assert.IsInstanceOf<TestSerializer>(binType.Serializer);
+
+ var plugins = cfg.PluginConfigurations;
+ Assert.IsNotNull(plugins);
+ Assert.IsNotNull(plugins.Cast<TestIgnitePluginConfiguration>().SingleOrDefault());
}
/// <summary>
@@ -278,6 +286,9 @@ namespace Apache.Ignite.Core.Tests
foreach (var prop in type.GetProperties())
{
+ if (!prop.CanWrite)
+ continue; // Read-only properties are not configured in XML.
+
var propType = prop.PropertyType;
var isCollection = propType.IsGenericType &&
@@ -761,7 +772,8 @@ namespace Apache.Ignite.Core.Tests
WriteBufferSize = 66,
ReadStripesNumber = 77,
BaseDirectory = "test"
- }
+ },
+ PluginConfigurations = new[] {new TestIgnitePluginConfiguration() }
};
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs
index 86ece98..3d9732d 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs
@@ -36,6 +36,7 @@ namespace Apache.Ignite.Core.Tests
using Apache.Ignite.Core.Impl;
using Apache.Ignite.Core.Impl.Binary;
using Apache.Ignite.Core.SwapSpace.File;
+ using Apache.Ignite.Core.Tests.Plugin;
using Apache.Ignite.Core.Transactions;
using NUnit.Framework;
@@ -192,8 +193,11 @@ namespace Apache.Ignite.Core.Tests
Assert.AreEqual("affKey", typ.AffinityKeyFieldName);
Assert.AreEqual(false, typ.KeepDeserialized);
- CollectionAssert.AreEqual(new[] {"fld1", "fld2"},
+ CollectionAssert.AreEqual(new[] {"fld1", "fld2"},
((BinaryFieldEqualityComparer)typ.EqualityComparer).FieldNames);
+
+ Assert.IsNotNull(resCfg.PluginConfigurations);
+ Assert.AreEqual(cfg.PluginConfigurations, resCfg.PluginConfigurations);
}
}
@@ -481,7 +485,7 @@ namespace Apache.Ignite.Core.Tests
JvmOptions = TestUtils.TestJavaOptions(),
JvmClasspath = TestUtils.CreateTestClasspath(),
Localhost = "127.0.0.1",
- IsDaemon = true,
+ IsDaemon = false,
IsLateAffinityAssignment = false,
UserAttributes = Enumerable.Range(1, 10).ToDictionary(x => x.ToString(), x => (object) x),
AtomicConfiguration = new AtomicConfiguration
@@ -525,7 +529,7 @@ namespace Apache.Ignite.Core.Tests
MaximumWriteQueueSize = 8,
WriteBufferSize = 9,
BaseDirectory = Path.GetTempPath(),
- MaximumSparsity = 11.22f
+ MaximumSparsity = 0.123f
},
BinaryConfiguration = new BinaryConfiguration
{
@@ -541,7 +545,8 @@ namespace Apache.Ignite.Core.Tests
EqualityComparer = new BinaryFieldEqualityComparer("fld1", "fld2")
}
}
- }
+ },
+ PluginConfigurations = new[] { new TestIgnitePluginConfiguration() }
};
}
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Plugin/PluginTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Plugin/PluginTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Plugin/PluginTest.cs
new file mode 100644
index 0000000..44ba196
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Plugin/PluginTest.cs
@@ -0,0 +1,212 @@
+\ufeff/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Tests.Plugin
+{
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using Apache.Ignite.Core.Common;
+ using Apache.Ignite.Core.Plugin;
+ using NUnit.Framework;
+
+ /// <summary>
+ /// Ignite plugin test.
+ /// </summary>
+ public class PluginTest
+ {
+ /** Plugin log. */
+ private static readonly List<string> PluginLog = new List<string>();
+
+ /// <summary>
+ /// Tests the plugin life cycle.
+ /// </summary>
+ [Test]
+ public void TestIgniteStartStop()
+ {
+ var cfg = new IgniteConfiguration(TestUtils.GetTestConfiguration())
+ {
+ PluginConfigurations = new[] {new TestIgnitePluginConfiguration {PluginProperty = "barbaz"}}
+ };
+
+ TestIgnitePlugin plugin;
+
+ using (var ignite = Ignition.Start(cfg))
+ {
+ Assert.Throws<PluginNotFoundException>(() => ignite.GetPlugin<object>("foobar"));
+ Assert.Throws<Exception>(() => ignite.GetPlugin<string>(TestIgnitePluginProvider.PluginName));
+
+ plugin = ignite.GetPlugin<TestIgnitePlugin>(TestIgnitePluginProvider.PluginName);
+ Assert.IsNotNull(plugin);
+
+ var prov = plugin.Provider;
+ Assert.IsTrue(prov.Started);
+ Assert.AreEqual(null, prov.Stopped);
+ Assert.AreEqual(TestIgnitePluginProvider.PluginName, prov.Name);
+ Assert.IsNotNullOrEmpty(prov.Copyright);
+ Assert.IsNotNull(prov.Context);
+
+ var ctx = prov.Context;
+ Assert.IsNotNull(ctx.Ignite);
+ Assert.AreEqual(cfg, ctx.IgniteConfiguration);
+ Assert.AreEqual("barbaz", ctx.PluginConfiguration.PluginProperty);
+
+ var plugin2 = ignite.GetPlugin<TestIgnitePlugin>(TestIgnitePluginProvider.PluginName);
+ Assert.AreEqual(plugin, plugin2);
+ }
+
+ Assert.AreEqual(true, plugin.Provider.Stopped);
+ Assert.AreEqual(true, plugin.Provider.IgniteStopped);
+ }
+
+ /// <summary>
+ /// Tests invalid plugins.
+ /// </summary>
+ [Test]
+ public void TestInvalidPlugins()
+ {
+ Action<ICollection<IPluginConfiguration>> check = x => Ignition.Start(
+ new IgniteConfiguration(TestUtils.GetTestConfiguration()) {PluginConfigurations = x});
+
+ // Missing attribute.
+ var ex = Assert.Throws<IgniteException>(() => check(new[] { new NoAttributeConfig(), }));
+ Assert.AreEqual(string.Format("{0} of type {1} has no {2}", typeof(IPluginConfiguration),
+ typeof(NoAttributeConfig), typeof(PluginProviderTypeAttribute)), ex.Message);
+
+ // Empty plugin name.
+ ex = Assert.Throws<IgniteException>(() => check(new[] {new EmptyNameConfig()}));
+ Assert.AreEqual(string.Format("{0}.Name should not be null or empty: {1}", typeof(IPluginProvider<>),
+ typeof(EmptyNamePluginProvider)), ex.Message);
+
+ // Duplicate plugin name.
+ ex = Assert.Throws<IgniteException>(() => check(new[]
+ {
+ new TestIgnitePluginConfiguration(),
+ new TestIgnitePluginConfiguration()
+ }));
+ Assert.AreEqual(string.Format("Duplicate plugin name 'TestPlugin1' is used by plugin providers " +
+ "'{0}' and '{0}'", typeof(TestIgnitePluginProvider)), ex.Message);
+
+ // Provider throws an exception.
+ PluginLog.Clear();
+
+ var ioex = Assert.Throws<IOException>(() => check(new IPluginConfiguration[]
+ {
+ new NormalConfig(), new ExceptionConfig()
+ }));
+ Assert.AreEqual("Failure in plugin provider", ioex.Message);
+
+ // Verify that plugins are started and stopped in correct order:
+ Assert.AreEqual(
+ new[]
+ {
+ "normalPlugin.Start", "errPlugin.Start",
+ "errPlugin.OnIgniteStop", "normalPlugin.OnIgniteStop",
+ "errPlugin.Stop", "normalPlugin.Stop"
+ }, PluginLog);
+ }
+
+ private class NoAttributeConfig : IPluginConfiguration
+ {
+ // No-op.
+ }
+
+ [PluginProviderType(typeof(EmptyNamePluginProvider))]
+ private class EmptyNameConfig : IPluginConfiguration
+ {
+ // No-op.
+ }
+
+ private class EmptyNamePluginProvider : IPluginProvider<EmptyNameConfig>
+ {
+ public string Name { get { return null; } }
+ public string Copyright { get { return null; } }
+ public T GetPlugin<T>() where T : class { return default(T); }
+ public void Start(IPluginContext<EmptyNameConfig> context) { /* No-op. */ }
+ public void Stop(bool cancel) { /* No-op. */ }
+ public void OnIgniteStart() { /* No-op. */ }
+ public void OnIgniteStop(bool cancel) { /* No-op. */ }
+ }
+
+ [PluginProviderType(typeof(ExceptionPluginProvider))]
+ private class ExceptionConfig : IPluginConfiguration
+ {
+ // No-op.
+ }
+
+ private class ExceptionPluginProvider : IPluginProvider<ExceptionConfig>
+ {
+ public string Name { get { return "errPlugin"; } }
+ public string Copyright { get { return null; } }
+ public T GetPlugin<T>() where T : class { return default(T); }
+
+ public void Stop(bool cancel)
+ {
+ PluginLog.Add(Name + ".Stop");
+ }
+
+ public void OnIgniteStart()
+ {
+ PluginLog.Add(Name + ".OnIgniteStart");
+ }
+
+ public void OnIgniteStop(bool cancel)
+ {
+ PluginLog.Add(Name + ".OnIgniteStop");
+ }
+
+ public void Start(IPluginContext<ExceptionConfig> context)
+ {
+ PluginLog.Add(Name + ".Start");
+ throw new IOException("Failure in plugin provider");
+ }
+ }
+
+ [PluginProviderType(typeof(NormalPluginProvider))]
+ private class NormalConfig : IPluginConfiguration
+ {
+ // No-op.
+ }
+
+ private class NormalPluginProvider : IPluginProvider<NormalConfig>
+ {
+ public string Name { get { return "normalPlugin"; } }
+ public string Copyright { get { return null; } }
+ public T GetPlugin<T>() where T : class { return default(T); }
+
+ public void Stop(bool cancel)
+ {
+ PluginLog.Add(Name + ".Stop");
+ }
+
+ public void OnIgniteStart()
+ {
+ PluginLog.Add(Name + ".OnIgniteStart");
+ }
+
+ public void OnIgniteStop(bool cancel)
+ {
+ PluginLog.Add(Name + ".OnIgniteStop");
+ }
+
+ public void Start(IPluginContext<NormalConfig> context)
+ {
+ PluginLog.Add(Name + ".Start");
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Plugin/TestIgnitePlugin.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Plugin/TestIgnitePlugin.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Plugin/TestIgnitePlugin.cs
new file mode 100644
index 0000000..2a876ab
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Plugin/TestIgnitePlugin.cs
@@ -0,0 +1,39 @@
+\ufeff/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Tests.Plugin
+{
+ /// <summary>
+ /// Test Ignite plugin.
+ /// </summary>
+ public class TestIgnitePlugin
+ {
+ /// <summary>
+ /// Gets the provider.
+ /// </summary>
+ public TestIgnitePluginProvider Provider { get; private set; }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="TestIgnitePlugin"/> class.
+ /// </summary>
+ /// <param name="provider">The provider.</param>
+ public TestIgnitePlugin(TestIgnitePluginProvider provider)
+ {
+ Provider = provider;
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Plugin/TestIgnitePluginConfiguration.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Plugin/TestIgnitePluginConfiguration.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Plugin/TestIgnitePluginConfiguration.cs
new file mode 100644
index 0000000..4856ccb
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Plugin/TestIgnitePluginConfiguration.cs
@@ -0,0 +1,33 @@
+\ufeff/*
+ * 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.
+ */
+
+ namespace Apache.Ignite.Core.Tests.Plugin
+{
+ using Apache.Ignite.Core.Plugin;
+
+ /// <summary>
+ /// Plugin configuration.
+ /// </summary>
+ [PluginProviderType(typeof(TestIgnitePluginProvider))]
+ public class TestIgnitePluginConfiguration : IPluginConfiguration
+ {
+ /// <summary>
+ /// Custom plugin property.
+ /// </summary>
+ public string PluginProperty { get; set; }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Plugin/TestIgnitePluginProvider.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Plugin/TestIgnitePluginProvider.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Plugin/TestIgnitePluginProvider.cs
new file mode 100644
index 0000000..bc21540
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Plugin/TestIgnitePluginProvider.cs
@@ -0,0 +1,132 @@
+\ufeff/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Tests.Plugin
+{
+ using System;
+ using Apache.Ignite.Core.Plugin;
+ using NUnit.Framework;
+
+ /// <summary>
+ /// Test provider.
+ /// </summary>
+ // ReSharper disable once ClassNeverInstantiated.Global
+ public class TestIgnitePluginProvider : IPluginProvider<TestIgnitePluginConfiguration>
+ {
+ /** */
+ public const string PluginName = "TestPlugin1";
+
+ /** */
+ private readonly TestIgnitePlugin _plugin;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="TestIgnitePluginProvider"/> class.
+ /// </summary>
+ public TestIgnitePluginProvider()
+ {
+ Name = PluginName;
+ _plugin = new TestIgnitePlugin(this);
+ }
+
+ /** <inheritdoc /> */
+ public string Name { get; set; }
+
+ /** <inheritdoc /> */
+ public string Copyright
+ {
+ get { return "Copyright (c) FooBar."; }
+ }
+
+ /** <inheritdoc /> */
+ public T GetPlugin<T>() where T : class
+ {
+ var p = _plugin as T;
+
+ if (p != null)
+ return p;
+
+ throw new Exception("Invalid plugin type: " + typeof(T));
+ }
+
+ /** <inheritdoc /> */
+ public void Start(IPluginContext<TestIgnitePluginConfiguration> context)
+ {
+ Context = context;
+
+ EnsureIgniteWorks();
+ }
+
+ /** <inheritdoc /> */
+ public void Stop(bool cancel)
+ {
+ Stopped = cancel;
+
+ EnsureIgniteWorks();
+ }
+
+ /** <inheritdoc /> */
+ public void OnIgniteStart()
+ {
+ Started = true;
+
+ EnsureIgniteWorks();
+ }
+
+ /** <inheritdoc /> */
+ public void OnIgniteStop(bool cancel)
+ {
+ IgniteStopped = cancel;
+
+ EnsureIgniteWorks();
+ }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this <see cref="TestIgnitePluginProvider"/> is started.
+ /// </summary>
+ public bool Started { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this <see cref="TestIgnitePluginProvider"/> is stopped.
+ /// </summary>
+ public bool? Stopped { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this <see cref="TestIgnitePluginProvider"/> is stopped.
+ /// </summary>
+ public bool? IgniteStopped { get; set; }
+
+ /// <summary>
+ /// Gets the context.
+ /// </summary>
+ public IPluginContext<TestIgnitePluginConfiguration> Context { get; private set; }
+
+ /// <summary>
+ /// Ensures that Ignite instance is functional.
+ /// </summary>
+ private void EnsureIgniteWorks()
+ {
+ Assert.NotNull(Context);
+ Assert.NotNull(Context.Ignite);
+ Assert.NotNull(Context.IgniteConfiguration);
+ Assert.NotNull(Context.PluginConfiguration);
+
+ var cache = Context.Ignite.GetOrCreateCache<int, int>("pluginCache");
+
+ Assert.AreEqual(0, cache.GetSize());
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
index d58c872..5c0ac94 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
@@ -420,6 +420,10 @@
<Compile Include="Impl\Binary\Structure\BinaryStructureJumpTable.cs" />
<Compile Include="Impl\Binary\Structure\BinaryStructureUpdate.cs" />
<Compile Include="Impl\Binary\TypeResolver.cs" />
+ <Compile Include="Impl\Plugin\IPluginProviderProxy.cs" />
+ <Compile Include="Impl\Plugin\PluginContext.cs" />
+ <Compile Include="Impl\Plugin\PluginProcessor.cs" />
+ <Compile Include="Impl\Plugin\PluginProviderProxy.cs" />
<Compile Include="Impl\Resource\IResourceInjector.cs" />
<Compile Include="Impl\Resource\ResourceFieldInjector.cs" />
<Compile Include="Impl\Resource\ResourceMethodInjector.cs" />
@@ -476,6 +480,11 @@
<Compile Include="Binary\BinaryObjectException.cs" />
<Compile Include="Binary\BinaryTypeConfiguration.cs" />
<Compile Include="Binary\BinaryTypeNames.cs" />
+ <Compile Include="Plugin\IPluginConfiguration.cs" />
+ <Compile Include="Plugin\IPluginContext.cs" />
+ <Compile Include="Plugin\IPluginProvider.cs" />
+ <Compile Include="Plugin\PluginNotFoundException.cs" />
+ <Compile Include="Plugin\PluginProviderTypeAttribute.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Resource\InstanceResourceAttribute.cs" />
<Compile Include="Resource\Package-Info.cs" />
http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs b/modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs
index 91aa1dd..2996039 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs
@@ -32,6 +32,7 @@ namespace Apache.Ignite.Core
using Apache.Ignite.Core.Log;
using Apache.Ignite.Core.Lifecycle;
using Apache.Ignite.Core.Messaging;
+ using Apache.Ignite.Core.Plugin;
using Apache.Ignite.Core.Services;
using Apache.Ignite.Core.Transactions;
@@ -307,5 +308,14 @@ namespace Apache.Ignite.Core
/// runs in client mode (<see cref="IgniteConfiguration.ClientMode"/>).
/// </summary>
event EventHandler<ClientReconnectEventArgs> ClientReconnected;
+
+ /// <summary>
+ /// Gets the plugin by name.
+ /// </summary>
+ /// <typeparam name="T">Plugin type</typeparam>
+ /// <param name="name">Plugin name.</param>
+ /// <exception cref="PluginNotFoundException">When plugin with specified name has not been found.</exception>
+ /// <returns>Plugin instance.</returns>
+ T GetPlugin<T>(string name) where T : class;
}
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs
index ce9fcf6..036b05f 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs
@@ -42,6 +42,7 @@
using Apache.Ignite.Core.Impl.SwapSpace;
using Apache.Ignite.Core.Lifecycle;
using Apache.Ignite.Core.Log;
+ using Apache.Ignite.Core.Plugin;
using Apache.Ignite.Core.SwapSpace;
using Apache.Ignite.Core.Transactions;
using BinaryReader = Apache.Ignite.Core.Impl.Binary.BinaryReader;
@@ -488,6 +489,7 @@
Logger = cfg.Logger;
JvmInitialMemoryMb = cfg.JvmInitialMemoryMb;
JvmMaxMemoryMb = cfg.JvmMaxMemoryMb;
+ PluginConfigurations = cfg.PluginConfigurations;
}
/// <summary>
@@ -856,5 +858,11 @@
/// Gets or sets the swap space SPI.
/// </summary>
public ISwapSpaceSpi SwapSpaceSpi { get; set; }
+
+ /// <summary>
+ /// Gets or sets the configurations for plugins to be started.
+ /// </summary>
+ [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
+ public ICollection<IPluginConfiguration> PluginConfigurations { get; set; }
}
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd
index d54a200..7ba02c1 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd
@@ -1180,6 +1180,27 @@
</xs:attribute>
</xs:complexType>
</xs:element>
+ <xs:element name="pluginConfigurations" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>Plugin configurations.</xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="iPluginConfiguration" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation>Plugin configuration.</xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:attribute name="type" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>Assembly-qualified type name.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
</xs:all>
<xs:attribute name="gridName" type="xs:string">
<xs:annotation>
http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/IgniteConfigurationXmlSerializer.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/IgniteConfigurationXmlSerializer.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/IgniteConfigurationXmlSerializer.cs
index bb9cbfc..7ca654f 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/IgniteConfigurationXmlSerializer.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/IgniteConfigurationXmlSerializer.cs
@@ -84,6 +84,9 @@ namespace Apache.Ignite.Core.Impl.Common
private static void WriteElement(object obj, XmlWriter writer, string rootElementName, Type valueType,
PropertyInfo property = null)
{
+ if (property != null && !property.CanWrite)
+ return;
+
if (valueType == typeof(IgniteConfiguration))
writer.WriteStartElement(rootElementName, Schema); // write xmlns for the root element
else
http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Ignite.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Ignite.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Ignite.cs
index 1747df2..651fb83 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Ignite.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Ignite.cs
@@ -39,6 +39,7 @@ namespace Apache.Ignite.Core.Impl
using Apache.Ignite.Core.Impl.Datastream;
using Apache.Ignite.Core.Impl.DataStructures;
using Apache.Ignite.Core.Impl.Handle;
+ using Apache.Ignite.Core.Impl.Plugin;
using Apache.Ignite.Core.Impl.Transactions;
using Apache.Ignite.Core.Impl.Unmanaged;
using Apache.Ignite.Core.Lifecycle;
@@ -97,6 +98,9 @@ namespace Apache.Ignite.Core.Impl
private volatile TaskCompletionSource<bool> _clientReconnectTaskCompletionSource =
new TaskCompletionSource<bool>();
+ /** Plugin processor. */
+ private readonly PluginProcessor _pluginProcessor;
+
/// <summary>
/// Constructor.
/// </summary>
@@ -142,6 +146,8 @@ namespace Apache.Ignite.Core.Impl
_clientReconnectTaskCompletionSource.SetResult(false);
SetCompactFooter();
+
+ _pluginProcessor = new PluginProcessor(this);
}
/// <summary>
@@ -165,6 +171,8 @@ namespace Apache.Ignite.Core.Impl
/// </summary>
internal void OnStart()
{
+ PluginProcessor.OnIgniteStart();
+
foreach (var lifecycleBean in _lifecycleBeans)
lifecycleBean.OnStart(this);
}
@@ -698,6 +706,14 @@ namespace Apache.Ignite.Core.Impl
/** <inheritdoc /> */
public event EventHandler<ClientReconnectEventArgs> ClientReconnected;
+ /** <inheritdoc /> */
+ public T GetPlugin<T>(string name) where T : class
+ {
+ IgniteArgumentCheck.NotNullOrEmpty(name, "name");
+
+ return PluginProcessor.GetProvider(name).GetPlugin<T>();
+ }
+
/// <summary>
/// Gets or creates near cache.
/// </summary>
@@ -818,5 +834,13 @@ namespace Apache.Ignite.Core.Impl
if (handler != null)
handler.Invoke(this, new ClientReconnectEventArgs(clusterRestarted));
}
+
+ /// <summary>
+ /// Gets the plugin processor.
+ /// </summary>
+ internal PluginProcessor PluginProcessor
+ {
+ get { return _pluginProcessor; }
+ }
}
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteProxy.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteProxy.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteProxy.cs
index 98a2d47..5e17853 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteProxy.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteProxy.cs
@@ -427,6 +427,12 @@ namespace Apache.Ignite.Core.Impl
}
/** <inheritdoc /> */
+ public T GetPlugin<T>(string name) where T : class
+ {
+ return _ignite.GetPlugin<T>(name);
+ }
+
+ /** <inheritdoc /> */
public IAtomicSequence GetAtomicSequence(string name, long initialValue, bool create)
{
return _ignite.GetAtomicSequence(name, initialValue, create);
http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/IPluginProviderProxy.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/IPluginProviderProxy.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/IPluginProviderProxy.cs
new file mode 100644
index 0000000..91e0e45
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/IPluginProviderProxy.cs
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Impl.Plugin
+{
+ using Apache.Ignite.Core.Plugin;
+
+ /// <summary>
+ /// Non-generic proxy interface.
+ /// </summary>
+ internal interface IPluginProviderProxy
+ {
+ /// <summary>
+ /// Gets the plugin name. Plugins can be retrieved by name via <see cref="IIgnite.GetPlugin{T}"/>.
+ /// </summary>
+ string Name { get; }
+
+ /// <summary>
+ /// Gets the copyright information.
+ /// </summary>
+ string Copyright { get; }
+
+ /// <summary>
+ /// Gets the plugin instance.
+ /// </summary>
+ /// <typeparam name="T">Plugin instance type.</typeparam>
+ /// <returns>Plugin instance.</returns>
+ T GetPlugin<T>() where T : class;
+
+ /// <summary>
+ /// Starts the plugin provider.
+ /// <para />
+ /// <see cref="IPluginContext{T}.Ignite"/> can be null until <see cref="OnIgniteStart"/> is called.
+ /// </summary>
+ /// <param name="processor">Plugin processor.</param>
+ void Start(PluginProcessor processor);
+
+ /// <summary>
+ /// Stops the plugin provider.
+ /// </summary>
+ /// <param name="cancel">if set to <c>true</c>, all ongoing operations should be canceled.</param>
+ void Stop(bool cancel);
+
+ /// <summary>
+ /// Called when Ignite has been started and is fully functional.
+ /// </summary>
+ void OnIgniteStart();
+
+ /// <summary>
+ /// Callback to notify that Ignite is about to stop.
+ /// </summary>
+ /// <param name="cancel">if set to <c>true</c>, all ongoing operations should be canceled.</param>
+ void OnIgniteStop(bool cancel);
+
+ /// <summary>
+ /// Gets the underlying provider.
+ /// </summary>
+ object Provider { get; }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/PluginContext.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/PluginContext.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/PluginContext.cs
new file mode 100644
index 0000000..6b3eaca
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/PluginContext.cs
@@ -0,0 +1,60 @@
+\ufeff/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Impl.Plugin
+{
+ using Apache.Ignite.Core.Plugin;
+
+ /// <summary>
+ /// Plugin context.
+ /// </summary>
+ internal class PluginContext<T> : IPluginContext<T> where T : IPluginConfiguration
+ {
+ /** */
+ private readonly T _pluginConfiguration;
+
+ /** */
+ private readonly PluginProcessor _pluginProcessor;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="PluginContext{T}"/> class.
+ /// </summary>
+ public PluginContext(PluginProcessor pluginProcessor, T pluginConfiguration)
+ {
+ _pluginProcessor = pluginProcessor;
+ _pluginConfiguration = pluginConfiguration;
+ }
+
+ /** <inheritdoc /> */
+ public IIgnite Ignite
+ {
+ get { return _pluginProcessor.Ignite; }
+ }
+
+ /** <inheritdoc /> */
+ public IgniteConfiguration IgniteConfiguration
+ {
+ get { return _pluginProcessor.IgniteConfiguration; }
+ }
+
+ /** <inheritdoc /> */
+ public T PluginConfiguration
+ {
+ get { return _pluginConfiguration; }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/PluginProcessor.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/PluginProcessor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/PluginProcessor.cs
new file mode 100644
index 0000000..ba2d401
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/PluginProcessor.cs
@@ -0,0 +1,235 @@
+\ufeff/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Impl.Plugin
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Linq;
+ using Apache.Ignite.Core.Common;
+ using Apache.Ignite.Core.Log;
+ using Apache.Ignite.Core.Plugin;
+
+ /// <summary>
+ /// Plugin processor.
+ /// </summary>
+ internal class PluginProcessor
+ {
+ /** Ordered list of plugin providers. */
+ private readonly IList<IPluginProviderProxy> _pluginProviders = new List<IPluginProviderProxy>();
+
+ /** Plugin providers by name. */
+ private readonly Dictionary<string, IPluginProviderProxy> _pluginProvidersByName
+ = new Dictionary<string, IPluginProviderProxy>();
+
+ /** */
+ private readonly Ignite _ignite;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="PluginProcessor"/> class.
+ /// </summary>
+ /// <param name="ignite">The ignite.</param>
+ public PluginProcessor(Ignite ignite)
+ {
+ Debug.Assert(ignite != null);
+
+ _ignite = ignite;
+ }
+
+ /// <summary>
+ /// Gets the Ignite.
+ /// </summary>
+ public IIgnite Ignite
+ {
+ get { return _ignite; }
+ }
+
+ /// <summary>
+ /// Gets the Ignite configuration.
+ /// </summary>
+ public IgniteConfiguration IgniteConfiguration
+ {
+ get { return _ignite.Configuration; }
+ }
+
+ /// <summary>
+ /// Called when Ignite has started.
+ /// </summary>
+ public void OnIgniteStart()
+ {
+ LoadPlugins();
+
+ // Notify plugins.
+ foreach (var provider in _pluginProviders)
+ provider.OnIgniteStart();
+ }
+
+ /// <summary>
+ /// Stops the plugin processor.
+ /// </summary>
+ public void Stop(bool cancel)
+ {
+ foreach (var provider in _pluginProviders.Reverse())
+ provider.Stop(cancel);
+ }
+
+ /// <summary>
+ /// Called when Ignite is about to stop.
+ /// </summary>
+ public void OnIgniteStop(bool cancel)
+ {
+ foreach (var provider in _pluginProviders.Reverse())
+ provider.OnIgniteStop(cancel);
+ }
+
+ /// <summary>
+ /// Gets the provider.
+ /// </summary>
+ public IPluginProviderProxy GetProvider(string name)
+ {
+ Debug.Assert(!string.IsNullOrEmpty(name));
+
+ IPluginProviderProxy provider;
+
+ if (!_pluginProvidersByName.TryGetValue(name, out provider))
+ throw new PluginNotFoundException(
+ string.Format("Ignite plugin with name '{0}' not found. Make sure that containing assembly " +
+ "is in '{1}' folder or configure IgniteConfiguration.PluginPaths.",
+ name, GetType().Assembly.Location));
+
+ return provider;
+ }
+
+ /// <summary>
+ /// Loads the plugins.
+ /// </summary>
+ private void LoadPlugins()
+ {
+ var log = _ignite.Logger.GetLogger(GetType().Name);
+
+ log.Info("Configured .NET plugins:");
+
+ var pluginConfigurations = IgniteConfiguration.PluginConfigurations;
+
+ if (pluginConfigurations != null && pluginConfigurations.Count > 0)
+ {
+ foreach (var cfg in pluginConfigurations)
+ {
+ var provider = CreateProviderProxy(cfg);
+
+ ValidateProvider(provider, _pluginProvidersByName);
+
+ LogProviderInfo(log, provider);
+
+ _pluginProviders.Add(provider);
+ _pluginProvidersByName[provider.Name] = provider;
+
+ provider.Start(this);
+ }
+ }
+ else
+ {
+ log.Info(" ^-- None");
+ }
+ }
+
+ /// <summary>
+ /// Logs the provider information.
+ /// </summary>
+ private static void LogProviderInfo(ILogger log, IPluginProviderProxy provider)
+ {
+ log.Info(" ^-- " + provider.Name + " " + provider.GetType().Assembly.GetName().Version);
+
+ if (!string.IsNullOrEmpty(provider.Copyright))
+ log.Info(" ^-- " + provider.Copyright);
+
+ log.Info(string.Empty);
+ }
+
+ /// <summary>
+ /// Validates the provider.
+ /// </summary>
+ private static void ValidateProvider(IPluginProviderProxy provider,
+ Dictionary<string, IPluginProviderProxy> res)
+ {
+ if (provider == null)
+ {
+ throw new IgniteException(string.Format("{0}.CreateProvider can not return null",
+ typeof(IPluginConfiguration).Name));
+ }
+
+ if (string.IsNullOrEmpty(provider.Name))
+ {
+ throw new IgniteException(string.Format("{0}.Name should not be null or empty: {1}",
+ typeof(IPluginProvider<>), provider.Provider.GetType()));
+ }
+
+ if (res.ContainsKey(provider.Name))
+ {
+ throw new IgniteException(string.Format("Duplicate plugin name '{0}' is used by " +
+ "plugin providers '{1}' and '{2}'", provider.Name,
+ provider.Provider.GetType(), res[provider.Name].Provider.GetType()));
+ }
+ }
+
+ /// <summary>
+ /// Creates the provider proxy.
+ /// </summary>
+ private static IPluginProviderProxy CreateProviderProxy(IPluginConfiguration pluginConfiguration)
+ {
+ Debug.Assert(pluginConfiguration != null);
+
+ var cfgType = pluginConfiguration.GetType();
+
+ var attributes = cfgType.GetCustomAttributes(true).OfType<PluginProviderTypeAttribute>().ToArray();
+
+ if (attributes.Length == 0)
+ {
+ throw new IgniteException(string.Format("{0} of type {1} has no {2}",
+ typeof(IPluginConfiguration), cfgType, typeof(PluginProviderTypeAttribute)));
+
+ }
+
+ if (attributes.Length > 1)
+ {
+ throw new IgniteException(string.Format("{0} of type {1} has more than one {2}",
+ typeof(IPluginConfiguration), cfgType, typeof(PluginProviderTypeAttribute)));
+ }
+
+ var providerType = attributes[0].PluginProviderType;
+
+ var iface = providerType.GetInterfaces()
+ .SingleOrDefault(i => i.IsGenericType &&
+ i.GetGenericTypeDefinition() == typeof(IPluginProvider<>) &&
+ i.GetGenericArguments()[0] == cfgType);
+
+ if (iface == null)
+ {
+ throw new IgniteException(string.Format("{0} does not implement {1}",
+ providerType, typeof(IPluginProvider<>).MakeGenericType(cfgType)));
+ }
+
+ var pluginProvider = Activator.CreateInstance(providerType);
+
+ var providerProxyType = typeof(PluginProviderProxy<>).MakeGenericType(cfgType);
+
+ return (IPluginProviderProxy) Activator.CreateInstance(
+ providerProxyType, pluginConfiguration, pluginProvider);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/PluginProviderProxy.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/PluginProviderProxy.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/PluginProviderProxy.cs
new file mode 100644
index 0000000..dff7c4e
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/PluginProviderProxy.cs
@@ -0,0 +1,90 @@
+\ufeff/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Impl.Plugin
+{
+ using Apache.Ignite.Core.Plugin;
+
+ /// <summary>
+ /// Wraps user-defined generic <see cref="IPluginProvider{TConfig}"/>.
+ /// </summary>
+ internal class PluginProviderProxy<T> : IPluginProviderProxy where T : IPluginConfiguration
+ {
+ /** */
+ private readonly T _pluginConfiguration;
+
+ /** */
+ private readonly IPluginProvider<T> _pluginProvider;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="PluginProviderProxy{T}"/> class.
+ /// </summary>
+ public PluginProviderProxy(T pluginConfiguration, IPluginProvider<T> pluginProvider)
+ {
+ _pluginConfiguration = pluginConfiguration;
+ _pluginProvider = pluginProvider;
+ }
+
+ /** <inheritdoc /> */
+ public void Start(PluginProcessor pluginProcessor)
+ {
+ _pluginProvider.Start(new PluginContext<T>(pluginProcessor, _pluginConfiguration));
+ }
+
+ /** <inheritdoc /> */
+ public string Name
+ {
+ get { return _pluginProvider.Name; }
+ }
+
+ /** <inheritdoc /> */
+ public string Copyright
+ {
+ get { return _pluginProvider.Copyright; }
+ }
+
+ /** <inheritdoc /> */
+ public TPlugin GetPlugin<TPlugin>() where TPlugin : class
+ {
+ return _pluginProvider.GetPlugin<TPlugin>();
+ }
+
+ /** <inheritdoc /> */
+ public void Stop(bool cancel)
+ {
+ _pluginProvider.Stop(cancel);
+ }
+
+ /** <inheritdoc /> */
+ public void OnIgniteStart()
+ {
+ _pluginProvider.OnIgniteStart();
+ }
+
+ /** <inheritdoc /> */
+ public void OnIgniteStop(bool cancel)
+ {
+ _pluginProvider.OnIgniteStop(cancel);
+ }
+
+ /** <inheritdoc /> */
+ public object Provider
+ {
+ get { return _pluginProvider; }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbackOp.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbackOp.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbackOp.cs
index 0b766de..da61319 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbackOp.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbackOp.cs
@@ -81,6 +81,8 @@ namespace Apache.Ignite.Core.Impl.Unmanaged
AffinityFunctionRemoveNode = 58,
AffinityFunctionDestroy = 59,
ComputeTaskLocalJobResult = 60,
- ComputeJobExecuteLocal = 61
+ ComputeJobExecuteLocal = 61,
+ PluginProcessorStop = 62,
+ PluginProcessorIgniteStop = 63
}
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbacks.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbacks.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbacks.cs
index 09933be..a42342b 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbacks.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbacks.cs
@@ -22,6 +22,7 @@ namespace Apache.Ignite.Core.Impl.Unmanaged
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
+ using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using Apache.Ignite.Core.Cache.Affinity;
@@ -78,12 +79,15 @@ namespace Apache.Ignite.Core.Impl.Unmanaged
// ReSharper disable once CollectionNeverQueried.Local
private readonly List<Delegate> _delegates = new List<Delegate>(5);
+ /** Max op code. */
+ private static readonly int MaxOpCode = Enum.GetValues(typeof(UnmanagedCallbackOp)).Cast<int>().Max();
+
/** Handlers array. */
- private readonly InLongOutLongHandler[] _inLongOutLongHandlers = new InLongOutLongHandler[62];
+ private readonly InLongOutLongHandler[] _inLongOutLongHandlers = new InLongOutLongHandler[MaxOpCode + 1];
/** Handlers array. */
private readonly InLongLongLongObjectOutLongHandler[] _inLongLongLongObjectOutLongHandlers
- = new InLongLongLongObjectOutLongHandler[62];
+ = new InLongLongLongObjectOutLongHandler[MaxOpCode + 1];
/** Initialized flag. */
private readonly ManualResetEventSlim _initEvent = new ManualResetEventSlim(false);
@@ -133,6 +137,7 @@ namespace Apache.Ignite.Core.Impl.Unmanaged
public UnmanagedCallbacks(ILogger log)
{
Debug.Assert(log != null);
+
_log = log;
var cbs = new UnmanagedCallbackHandlers
@@ -232,6 +237,8 @@ namespace Apache.Ignite.Core.Impl.Unmanaged
AddHandler(UnmanagedCallbackOp.AffinityFunctionDestroy, AffinityFunctionDestroy);
AddHandler(UnmanagedCallbackOp.ComputeTaskLocalJobResult, ComputeTaskLocalJobResult);
AddHandler(UnmanagedCallbackOp.ComputeJobExecuteLocal, ComputeJobExecuteLocal);
+ AddHandler(UnmanagedCallbackOp.PluginProcessorStop, PluginProcessorStop);
+ AddHandler(UnmanagedCallbackOp.PluginProcessorIgniteStop, PluginProcessorIgniteStop);
}
/// <summary>
@@ -1126,6 +1133,20 @@ namespace Apache.Ignite.Core.Impl.Unmanaged
}
}
+ private long PluginProcessorIgniteStop(long val)
+ {
+ _ignite.PluginProcessor.OnIgniteStop(val != 0);
+
+ return 0;
+ }
+
+ private long PluginProcessorStop(long val)
+ {
+ _ignite.PluginProcessor.Stop(val != 0);
+
+ return 0;
+ }
+
#endregion
#region AffinityFunction
http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/IPluginConfiguration.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/IPluginConfiguration.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/IPluginConfiguration.cs
new file mode 100644
index 0000000..09f3f4a
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/IPluginConfiguration.cs
@@ -0,0 +1,48 @@
+\ufeff/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Plugin
+{
+ using System.Diagnostics.CodeAnalysis;
+
+ /// <summary>
+ /// Plugin configuration marker interface.
+ /// <para />
+ /// Implementations should be linked to corresponding <see cref="IPluginProvider{TConfig}"/>
+ /// via <see cref="PluginProviderTypeAttribute"/>.
+ /// <example>
+ /// Example plugin implementation:
+ /// <code>
+ /// [PluginProviderType(typeof(MyPluginProvider))]
+ /// class MyPluginConfig : IPluginConfiguration
+ /// {
+ /// int CustomProperty { get; set; }
+ /// }
+ ///
+ /// class MyPluginProvider : IPluginProvider<MyPluginConfig>
+ /// {
+ /// ...
+ /// }
+ /// </code>
+ /// </example>
+ /// </summary>
+ [SuppressMessage("Microsoft.Design", "CA1040:AvoidEmptyInterfaces")]
+ public interface IPluginConfiguration
+ {
+ // No-op.
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/IPluginContext.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/IPluginContext.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/IPluginContext.cs
new file mode 100644
index 0000000..e91bdbf
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/IPluginContext.cs
@@ -0,0 +1,40 @@
+\ufeff/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Plugin
+{
+ /// <summary>
+ /// Plugin execution context.
+ /// </summary>
+ public interface IPluginContext<out T> where T : IPluginConfiguration
+ {
+ /// <summary>
+ /// Gets the Ignite.
+ /// </summary>
+ IIgnite Ignite { get; }
+
+ /// <summary>
+ /// Gets the Ignite configuration.
+ /// </summary>
+ IgniteConfiguration IgniteConfiguration { get; }
+
+ /// <summary>
+ /// Gets the plugin configuration.
+ /// </summary>
+ T PluginConfiguration { get; }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/IPluginProvider.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/IPluginProvider.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/IPluginProvider.cs
new file mode 100644
index 0000000..3ea5cff
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/IPluginProvider.cs
@@ -0,0 +1,69 @@
+\ufeff/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Plugin
+{
+ /// <summary>
+ /// Pluggable Ignite component. Should have parameterless constructor.
+ /// <para />
+ /// Ignite plugins are loaded according to <see cref="IgniteConfiguration.PluginConfigurations"/>.
+ /// </summary>
+ public interface IPluginProvider<in TConfig> where TConfig : IPluginConfiguration
+ {
+ /// <summary>
+ /// Gets the plugin name. Plugins can be retrieved by name via <see cref="IIgnite.GetPlugin{T}"/>.
+ /// </summary>
+ string Name { get; }
+
+ /// <summary>
+ /// Gets the copyright information.
+ /// </summary>
+ string Copyright { get; }
+
+ /// <summary>
+ /// Gets the plugin instance.
+ /// </summary>
+ /// <typeparam name="T">Plugin instance type.</typeparam>
+ /// <returns>Plugin instance.</returns>
+ T GetPlugin<T>() where T : class;
+
+ /// <summary>
+ /// Starts the plugin provider.
+ /// <para />
+ /// <see cref="IPluginContext{T}.Ignite"/> can be null until <see cref="OnIgniteStart"/> is called.
+ /// </summary>
+ /// <param name="context">The context.</param>
+ void Start(IPluginContext<TConfig> context);
+
+ /// <summary>
+ /// Stops the plugin provider.
+ /// </summary>
+ /// <param name="cancel">if set to <c>true</c>, all ongoing operations should be canceled.</param>
+ void Stop(bool cancel);
+
+ /// <summary>
+ /// Called when Ignite has been started and is fully functional.
+ /// </summary>
+ void OnIgniteStart();
+
+ /// <summary>
+ /// Callback to notify that Ignite is about to stop.
+ /// </summary>
+ /// <param name="cancel">if set to <c>true</c>, all ongoing operations should be canceled.</param>
+ void OnIgniteStop(bool cancel);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/PluginNotFoundException.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/PluginNotFoundException.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/PluginNotFoundException.cs
new file mode 100644
index 0000000..e6c869f
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/PluginNotFoundException.cs
@@ -0,0 +1,65 @@
+\ufeff/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Plugin
+{
+ using System;
+ using System.Runtime.Serialization;
+
+ /// <summary>
+ /// Indicates missing Ignite plugin.
+ /// </summary>
+ [Serializable]
+ public class PluginNotFoundException : Exception
+ {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="PluginNotFoundException"/> class.
+ /// </summary>
+ public PluginNotFoundException()
+ {
+ // No-op.
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="PluginNotFoundException"/> class.
+ /// </summary>
+ /// <param name="message">The message that describes the error.</param>
+ public PluginNotFoundException(string message) : base(message)
+ {
+ // No-op.
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="PluginNotFoundException"/> class.
+ /// </summary>
+ /// <param name="message">The error message that explains the reason for the exception.</param>
+ /// <param name="innerException">The exception that is the cause of the current exception,
+ /// or a null reference if no inner exception is specified.</param>
+ public PluginNotFoundException(string message, Exception innerException) : base(message, innerException)
+ {
+ // No-op.
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="PluginNotFoundException"/> class.
+ /// </summary>
+ protected PluginNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context)
+ {
+ // No-op.
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/d0a6c57a/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/PluginProviderTypeAttribute.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/PluginProviderTypeAttribute.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/PluginProviderTypeAttribute.cs
new file mode 100644
index 0000000..64dcfd4
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Plugin/PluginProviderTypeAttribute.cs
@@ -0,0 +1,51 @@
+\ufeff/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Plugin
+{
+ using System;
+ using Apache.Ignite.Core.Impl.Common;
+
+ /// <summary>
+ /// When applied to <see cref="IPluginConfiguration"/>, defines the type of
+ /// <see cref="IPluginProvider{T}"/> to instantiate.
+ /// </summary>
+ public class PluginProviderTypeAttribute : Attribute
+ {
+ /** */
+ private readonly Type _pluginProviderType;
+
+ /// <summary>
+ /// Initializes new instance of <see cref="PluginProviderTypeAttribute"/> class.
+ /// </summary>
+ /// <param name="pluginProviderType">Type of the plugin provider.</param>
+ public PluginProviderTypeAttribute(Type pluginProviderType)
+ {
+ IgniteArgumentCheck.NotNull(pluginProviderType, "pluginProviderType");
+
+ _pluginProviderType = pluginProviderType;
+ }
+
+ /// <summary>
+ /// Gets the plugin provider type.
+ /// </summary>
+ public Type PluginProviderType
+ {
+ get { return _pluginProviderType; }
+ }
+ }
+}
\ No newline at end of file