You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by al...@apache.org on 2021/02/05 14:40:11 UTC
[ignite] branch master updated: IGNITE-14020 .NET: Services
exceptions interoperability between java and .NET - Fixes #8746.
This is an automated email from the ASF dual-hosted git repository.
alexpl pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/master by this push:
new 82d2a2c IGNITE-14020 .NET: Services exceptions interoperability between java and .NET - Fixes #8746.
82d2a2c is described below
commit 82d2a2c66a03db6678d2fa332475200316fda5a6
Author: Aleksey Plekhanov <pl...@gmail.com>
AuthorDate: Fri Feb 5 17:36:51 2021 +0300
IGNITE-14020 .NET: Services exceptions interoperability between java and .NET - Fixes #8746.
Signed-off-by: Aleksey Plekhanov <pl...@gmail.com>
---
.../platform/services/PlatformServices.java | 13 +---
.../processors/service/GridServiceProxy.java | 14 ++--
.../ignite/platform/PlatformDeployServiceTask.java | 36 +++++++++
.../Services/IJavaService.cs | 3 +
.../Services/JavaServiceDynamicProxy.cs | 6 ++
.../Services/ServicesTest.cs | 88 +++++++++++++++++++++-
.../Impl/Plugin/PluginProcessor.cs | 34 ++++++++-
7 files changed, 171 insertions(+), 23 deletions(-)
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/services/PlatformServices.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/services/PlatformServices.java
index f183637..421b35e 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/services/PlatformServices.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/services/PlatformServices.java
@@ -41,7 +41,6 @@ import org.apache.ignite.internal.processors.platform.utils.PlatformUtils;
import org.apache.ignite.internal.processors.platform.utils.PlatformWriterBiClosure;
import org.apache.ignite.internal.processors.platform.utils.PlatformWriterClosure;
import org.apache.ignite.internal.processors.service.GridServiceProxy;
-import org.apache.ignite.internal.util.IgniteUtils;
import org.apache.ignite.internal.util.typedef.T3;
import org.apache.ignite.lang.IgniteFuture;
import org.apache.ignite.lang.IgnitePredicate;
@@ -291,7 +290,7 @@ public class PlatformServices extends PlatformAbstractTarget {
PlatformUtils.writeInvocationResult(writer, result, null);
}
- catch (Exception e) {
+ catch (Throwable e) {
PlatformUtils.writeInvocationResult(writer, null, e);
}
@@ -610,8 +609,7 @@ public class PlatformServices extends PlatformAbstractTarget {
* @throws IgniteCheckedException On error.
* @throws NoSuchMethodException On error.
*/
- public Object invoke(String mthdName, boolean srvKeepBinary, Object[] args)
- throws IgniteCheckedException, NoSuchMethodException {
+ public Object invoke(String mthdName, boolean srvKeepBinary, Object[] args) throws Throwable {
if (isPlatformService())
return ((PlatformService)proxy).invokeMethod(mthdName, srvKeepBinary, args);
else {
@@ -624,12 +622,7 @@ public class PlatformServices extends PlatformAbstractTarget {
Method mtd = getMethod(serviceClass, mthdName, args);
convertArrayArgs(args, mtd);
- try {
- return ((GridServiceProxy)proxy).invokeMethod(mtd, args);
- }
- catch (Throwable t) {
- throw IgniteUtils.cast(t);
- }
+ return ((GridServiceProxy)proxy).invokeMethod(mtd, args);
}
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProxy.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProxy.java
index 3c92ebc..cc65f34 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProxy.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProxy.java
@@ -191,14 +191,8 @@ public class GridServiceProxy<T> implements Serializable {
if (svcCtx != null) {
Service svc = svcCtx.service();
- if (svc != null) {
- try {
- return callServiceLocally(svc, mtd, args);
- }
- catch (InvocationTargetException e) {
- throw e.getTargetException();
- }
- }
+ if (svc != null)
+ return callServiceLocally(svc, mtd, args);
}
}
else {
@@ -214,6 +208,10 @@ public class GridServiceProxy<T> implements Serializable {
true).get();
}
}
+ catch (InvocationTargetException e) {
+ // For local services rethrow original exception.
+ throw e.getTargetException();
+ }
catch (RuntimeException | Error e) {
throw e;
}
diff --git a/modules/core/src/test/java/org/apache/ignite/platform/PlatformDeployServiceTask.java b/modules/core/src/test/java/org/apache/ignite/platform/PlatformDeployServiceTask.java
index 5208f7d..449de12 100644
--- a/modules/core/src/test/java/org/apache/ignite/platform/PlatformDeployServiceTask.java
+++ b/modules/core/src/test/java/org/apache/ignite/platform/PlatformDeployServiceTask.java
@@ -622,6 +622,18 @@ public class PlatformDeployServiceTask extends ComputeTaskAdapter<String, Object
}
/** */
+ public void testException(String exCls) throws Exception {
+ switch (exCls) {
+ case "InterruptedException": throw new InterruptedException("Test");
+ case "IllegalArgumentException": throw new IllegalArgumentException("Test");
+ case "TestMapped1Exception": throw new TestMapped1Exception("Test");
+ case "TestMapped2Exception": throw new TestMapped2Exception("Test");
+ case "TestUnmappedException": throw new TestUnmappedException("Test");
+ default: throw new IgniteException("Unexpected exception class: " + exCls);
+ }
+ }
+
+ /** */
public void sleep(long delayMs) {
try {
U.sleep(delayMs);
@@ -631,4 +643,28 @@ public class PlatformDeployServiceTask extends ComputeTaskAdapter<String, Object
}
}
}
+
+ /** */
+ public static class TestMapped1Exception extends RuntimeException {
+ /** */
+ public TestMapped1Exception(String msg) {
+ super(msg);
+ }
+ }
+
+ /** */
+ public static class TestMapped2Exception extends RuntimeException {
+ /** */
+ public TestMapped2Exception(String msg) {
+ super(msg);
+ }
+ }
+
+ /** */
+ public static class TestUnmappedException extends RuntimeException {
+ /** */
+ public TestUnmappedException(String msg) {
+ super(msg);
+ }
+ }
}
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/IJavaService.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/IJavaService.cs
index 6942c89..ebd727f 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/IJavaService.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/IJavaService.cs
@@ -205,6 +205,9 @@ namespace Apache.Ignite.Core.Tests.Services
void testLocalDateFromCache();
/** */
+ void testException(string exceptionClass);
+
+ /** */
void sleep(long delayMs);
}
}
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/JavaServiceDynamicProxy.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/JavaServiceDynamicProxy.cs
index bab002f..d3c5b21 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/JavaServiceDynamicProxy.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/JavaServiceDynamicProxy.cs
@@ -384,6 +384,12 @@ namespace Apache.Ignite.Core.Tests.Services
}
/** <inheritDoc /> */
+ public void testException(string exceptionClass)
+ {
+ _svc.testException(exceptionClass);
+ }
+
+ /** <inheritDoc /> */
public void sleep(long delayMs)
{
_svc.sleep(delayMs);
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesTest.cs
index f5dfb17..d557bc6 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesTest.cs
@@ -987,6 +987,42 @@ namespace Apache.Ignite.Core.Tests.Services
Assert.AreEqual(dt1, cache.Get(3));
Assert.AreEqual(dt2, cache.Get(4));
+ // Test standard java checked exception.
+ Exception ex = Assert.Throws<ServiceInvocationException>(() => svc.testException("InterruptedException"));
+ ex = ex.InnerException;
+ Assert.IsInstanceOf<ThreadInterruptedException>(ex);
+ Assert.AreEqual("Test", ex.Message);
+
+ // Test standard java unchecked exception.
+ ex = Assert.Throws<ServiceInvocationException>(() => svc.testException("IllegalArgumentException"));
+ ex = ex.InnerException;
+ Assert.IsInstanceOf<ArgumentException>(ex);
+ Assert.AreEqual("Test", ex.Message);
+
+ // Test user defined exception mapping by pattern.
+ ((IIgniteInternal)Grid1).PluginProcessor.RegisterExceptionMapping(
+ "org.apache.ignite.platform.PlatformDeployServiceTask$TestMapped*",
+ (c, m, e, i) => new TestServiceException(m, e));
+
+ ex = Assert.Throws<ServiceInvocationException>(() => svc.testException("TestMapped1Exception"));
+ ex = ex.InnerException;
+ Assert.IsInstanceOf<TestServiceException>(ex);
+ Assert.AreEqual("Test", ex.Message);
+
+ ex = Assert.Throws<ServiceInvocationException>(() => svc.testException("TestMapped2Exception"));
+ ex = ex.InnerException;
+ Assert.IsInstanceOf<TestServiceException>(ex);
+ Assert.AreEqual("Test", ex.Message);
+
+ // Test user defined unmapped exception.
+ ex = Assert.Throws<ServiceInvocationException>(() => svc.testException("TestUnmappedException"));
+ ex = ex.InnerException;
+ Assert.IsInstanceOf<IgniteException>(ex);
+ var javaEx = ex.InnerException as JavaException;
+ Assert.IsNotNull(javaEx);
+ Assert.AreEqual("Test", javaEx.JavaMessage);
+ Assert.AreEqual("org.apache.ignite.platform.PlatformDeployServiceTask$TestUnmappedException", javaEx.JavaClassName);
+
#if NETCOREAPP
//This Date in Europe/Moscow have offset +4.
DateTime dt3 = new DateTime(1982, 4, 1, 1, 0, 0, 0, DateTimeKind.Local);
@@ -1106,6 +1142,42 @@ namespace Apache.Ignite.Core.Tests.Services
Assert.AreEqual(dt1, cache.Get(3));
Assert.AreEqual(dt2, cache.Get(4));
+
+ // Test standard java checked exception.
+ Exception ex = Assert.Throws<ServiceInvocationException>(() => svc.testException("InterruptedException"));
+ ex = ex.InnerException;
+ Assert.IsInstanceOf<ThreadInterruptedException>(ex);
+ Assert.AreEqual("Test", ex.Message);
+
+ // Test standard java unchecked exception.
+ ex = Assert.Throws<ServiceInvocationException>(() => svc.testException("IllegalArgumentException"));
+ ex = ex.InnerException;
+ Assert.IsInstanceOf<ArgumentException>(ex);
+ Assert.AreEqual("Test", ex.Message);
+
+ // Test user defined exception mapping by pattern.
+ ((IIgniteInternal)Grid1).PluginProcessor.RegisterExceptionMapping(
+ "org.apache.ignite.platform.PlatformDeployServiceTask$TestMapped*",
+ (c, m, e, i) => new TestServiceException(m, e));
+
+ ex = Assert.Throws<ServiceInvocationException>(() => svc.testException("TestMapped1Exception"));
+ ex = ex.InnerException;
+ Assert.IsInstanceOf<TestServiceException>(ex);
+ Assert.AreEqual("Test", ex.Message);
+
+ ex = Assert.Throws<ServiceInvocationException>(() => svc.testException("TestMapped2Exception"));
+ ex = ex.InnerException;
+ Assert.IsInstanceOf<TestServiceException>(ex);
+ Assert.AreEqual("Test", ex.Message);
+
+ // Test user defined unmapped exception.
+ ex = Assert.Throws<ServiceInvocationException>(() => svc.testException("TestUnmappedException"));
+ ex = ex.InnerException;
+ Assert.IsInstanceOf<IgniteException>(ex);
+ var javaEx = ex.InnerException as JavaException;
+ Assert.IsNotNull(javaEx);
+ Assert.AreEqual("Test", javaEx.JavaMessage);
+ Assert.AreEqual("org.apache.ignite.platform.PlatformDeployServiceTask$TestUnmappedException", javaEx.JavaClassName);
}
/// <summary>
@@ -1635,7 +1707,21 @@ namespace Apache.Ignite.Core.Tests.Services
/** */
public int Field { get; set; }
}
-
+
+ /// <summary>
+ /// Test exception.
+ /// </summary>
+ private class TestServiceException : Exception
+ {
+ /// <summary>
+ /// Constructor.
+ /// </summary>
+ public TestServiceException(string message, Exception cause) : base(message, cause)
+ {
+ // No-op.
+ }
+ }
+
#if NETCOREAPP
/// <summary>
/// Adds support of the local dates to the Ignite timestamp serialization.
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/PluginProcessor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/PluginProcessor.cs
index 11100ff..b33911b 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/PluginProcessor.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Plugin/PluginProcessor.cs
@@ -42,8 +42,12 @@ namespace Apache.Ignite.Core.Impl.Plugin
private readonly Dictionary<string, IPluginProviderProxy> _pluginProvidersByName
= new Dictionary<string, IPluginProviderProxy>();
- /** Plugin exception mappings. */
- private readonly CopyOnWriteConcurrentDictionary<string, ExceptionFactory> _exceptionMappings
+ /** Plugin exception mappings by exact class name. */
+ private readonly CopyOnWriteConcurrentDictionary<string, ExceptionFactory> _exactExceptionMappings
+ = new CopyOnWriteConcurrentDictionary<string, ExceptionFactory>();
+
+ /** Plugin exception mappings by class name pattern. */
+ private readonly CopyOnWriteConcurrentDictionary<string, ExceptionFactory> _patternExceptionMappings
= new CopyOnWriteConcurrentDictionary<string, ExceptionFactory>();
/** Plugin callbacks. */
@@ -145,18 +149,40 @@ namespace Apache.Ignite.Core.Impl.Plugin
ExceptionFactory res;
- return _exceptionMappings.TryGetValue(className, out res) ? res : null;
+ if (_exactExceptionMappings.TryGetValue(className, out res))
+ {
+ return res;
+ }
+
+ foreach (var mapping in _patternExceptionMappings)
+ {
+ if (className.StartsWith(mapping.Key, StringComparison.Ordinal))
+ {
+ return mapping.Value;
+ }
+ }
+
+ return null;
}
/// <summary>
/// Registers the exception mapping.
/// </summary>
+ /// <param name="className">Full class name of java exception or class name pattern (if ends with '*').</param>
+ /// <param name="factory">Exception factory for matched java class name.</param>
public void RegisterExceptionMapping(string className, ExceptionFactory factory)
{
Debug.Assert(className != null);
Debug.Assert(factory != null);
- _exceptionMappings.GetOrAdd(className, _ => factory);
+ if (className.EndsWith("*", StringComparison.Ordinal))
+ {
+ _patternExceptionMappings.GetOrAdd(className.Substring(0, className.Length - 1), _ => factory);
+ }
+ else
+ {
+ _exactExceptionMappings.GetOrAdd(className, _ => factory);
+ }
}
/// <summary>