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 2021/11/22 07:55:43 UTC
[ignite] branch master updated: IGNITE-15795 .NET: Add ServiceCallContext (#9526)
This is an automated email from the ASF dual-hosted git repository.
ptupitsyn 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 cca909c IGNITE-15795 .NET: Add ServiceCallContext (#9526)
cca909c is described below
commit cca909ca92965aa12dca5139ec2803df4ffbc4d4
Author: Pavel Pereslegin <xx...@gmail.com>
AuthorDate: Mon Nov 22 10:55:24 2021 +0300
IGNITE-15795 .NET: Add ServiceCallContext (#9526)
ServiceCallContext provides a way to pass additional data implicitly with all service method calls issued by the current service proxy.
---
.../client/service/ClientServiceInvokeRequest.java | 2 +-
.../platform/services/PlatformAbstractService.java | 19 ++--
.../platform/services/PlatformService.java | 25 +++--
.../platform/services/PlatformServices.java | 13 ++-
.../processors/service/GridServiceProxy.java | 11 ++-
.../processors/service/ServiceCallContextImpl.java | 23 ++---
.../ignite/services/ServiceCallContextBuilder.java | 12 +--
.../platform/AbstractPlatformServiceCallTask.java | 9 +-
.../ignite/platform/PlatformDeployServiceTask.java | 10 ++
.../ignite/platform/PlatformServiceCallTask.java | 6 ++
.../platform/PlatformServiceCallThinTask.java | 4 +
.../Services/CallPlatformServiceTest.cs | 13 ++-
.../Services/IJavaService.cs | 3 +
.../Services/JavaServiceDynamicProxy.cs | 6 ++
.../Services/PlatformTestService.cs | 10 ++
.../Services/ServiceProxyTest.cs | 5 +-
.../Services/ServicesAsyncWrapper.cs | 13 +++
.../Services/ServicesTest.cs | 107 +++++++++++++++++++--
.../Common/IgniteExperimentalAttribute.cs | 4 +-
.../Impl/Services/ServiceCallContext.cs | 64 ++++++++++++
.../Impl/Services/ServiceContext.cs | 18 ++++
.../Impl/Services/ServiceProxySerializer.cs | 12 ++-
.../Apache.Ignite.Core/Impl/Services/Services.cs | 36 ++++---
.../Impl/Unmanaged/UnmanagedCallbacks.cs | 23 ++++-
.../Services/IServiceCallContext.cs | 78 +++++++++++++++
.../Apache.Ignite.Core/Services/IServiceContext.cs | 9 ++
.../Apache.Ignite.Core/Services/IServices.cs | 31 ++++++
.../Services/ServiceCallContextBuilder.cs | 82 ++++++++++++++++
28 files changed, 568 insertions(+), 80 deletions(-)
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/service/ClientServiceInvokeRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/service/ClientServiceInvokeRequest.java
index acf0b80..7cace9c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/service/ClientServiceInvokeRequest.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/service/ClientServiceInvokeRequest.java
@@ -154,7 +154,7 @@ public class ClientServiceInvokeRequest extends ClientRequest {
// Never deserialize platform service arguments and result: may contain platform-only types.
PlatformService proxy = services.serviceProxy(name, PlatformService.class, false, timeout);
- res = proxy.invokeMethod(methodName, keepBinary(), false, args);
+ res = proxy.invokeMethod(methodName, keepBinary(), false, args, null);
}
else {
// Deserialize Java service arguments when not in keepBinary mode.
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/services/PlatformAbstractService.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/services/PlatformAbstractService.java
index 59d87cb..e9eae0b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/services/PlatformAbstractService.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/services/PlatformAbstractService.java
@@ -21,6 +21,7 @@ import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
+import java.util.Map;
import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.internal.binary.BinaryRawReaderEx;
@@ -33,6 +34,7 @@ import org.apache.ignite.internal.processors.platform.utils.PlatformUtils;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.resources.IgniteInstanceResource;
import org.apache.ignite.services.ServiceContext;
+import org.jetbrains.annotations.Nullable;
/**
* Base platform service implementation.
@@ -180,14 +182,13 @@ public abstract class PlatformAbstractService implements PlatformService, Extern
}
/** {@inheritDoc} */
- @Override public Object invokeMethod(String mthdName, boolean srvKeepBinary, Object[] args)
- throws IgniteCheckedException {
- return invokeMethod(mthdName, srvKeepBinary, false, args);
- }
-
- /** {@inheritDoc} */
- @Override public Object invokeMethod(String mthdName, boolean srvKeepBinary, boolean deserializeResult, Object[] args)
- throws IgniteCheckedException {
+ @Override public Object invokeMethod(
+ String mthdName,
+ boolean srvKeepBinary,
+ boolean deserializeResult,
+ @Nullable Object[] args,
+ @Nullable Map<String, Object> callAttrs
+ ) throws IgniteCheckedException {
assert ptr != 0;
assert platformCtx != null;
@@ -209,6 +210,8 @@ public abstract class PlatformAbstractService implements PlatformService, Extern
writer.writeObjectDetached(arg);
}
+ writer.writeMap(callAttrs);
+
out.synchronize();
platformCtx.gateway().serviceInvokeMethod(mem.pointer());
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/services/PlatformService.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/services/PlatformService.java
index de0b142..68f1716 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/services/PlatformService.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/services/PlatformService.java
@@ -17,8 +17,10 @@
package org.apache.ignite.internal.processors.platform.services;
+import java.util.Map;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.services.Service;
+import org.jetbrains.annotations.Nullable;
/**
* Base class for all platform services.
@@ -29,24 +31,19 @@ public interface PlatformService extends Service {
*
* @param mthdName Method name.
* @param srvKeepBinary Server keep binary flag.
- * @param args Arguments.
- * @return Resulting data.
- * @throws org.apache.ignite.IgniteCheckedException If failed.
- */
- public Object invokeMethod(String mthdName, boolean srvKeepBinary, Object[] args) throws IgniteCheckedException;
-
- /**
- * Invokes native service method.
- *
- * @param mthdName Method name.
- * @param srvKeepBinary Server keep binary flag.
- * @param args Arguments.
* @param deserializeResult If {@code true}, call service in cross-platform compatible manner.
+ * @param args Arguments.
+ * @param callAttrs Service call context attributes.
* @return Resulting data.
* @throws org.apache.ignite.IgniteCheckedException If failed.
*/
- public Object invokeMethod(String mthdName, boolean srvKeepBinary, boolean deserializeResult, Object[] args)
- throws IgniteCheckedException;
+ public Object invokeMethod(
+ String mthdName,
+ boolean srvKeepBinary,
+ boolean deserializeResult,
+ @Nullable Object[] args,
+ @Nullable Map<String, Object> callAttrs
+ ) throws IgniteCheckedException;
/**
* Gets native pointer.
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 8e62494..864075c 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,6 +41,7 @@ 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.processors.service.ServiceCallContextImpl;
import org.apache.ignite.internal.util.typedef.T3;
import org.apache.ignite.lang.IgniteFuture;
import org.apache.ignite.lang.IgnitePredicate;
@@ -285,8 +286,10 @@ public class PlatformServices extends PlatformAbstractTarget {
else
args = null;
+ Map<String, Object> callAttrs = reader.readMap();
+
try {
- Object result = svc.invoke(mthdName, srvKeepBinary, args);
+ Object result = svc.invoke(mthdName, srvKeepBinary, args, callAttrs);
PlatformUtils.writeInvocationResult(writer, result, null);
}
@@ -605,13 +608,14 @@ public class PlatformServices extends PlatformAbstractTarget {
* @param mthdName Method name.
* @param srvKeepBinary Binary flag.
* @param args Args.
+ * @param callAttrs Service call context attributes.
* @return Invocation result.
* @throws IgniteCheckedException On error.
* @throws NoSuchMethodException On error.
*/
- public Object invoke(String mthdName, boolean srvKeepBinary, Object[] args) throws Throwable {
+ public Object invoke(String mthdName, boolean srvKeepBinary, Object[] args, Map<String, Object> callAttrs) throws Throwable {
if (isPlatformService())
- return ((PlatformService)proxy).invokeMethod(mthdName, srvKeepBinary, args);
+ return ((PlatformService)proxy).invokeMethod(mthdName, srvKeepBinary, false, args, callAttrs);
else {
assert proxy instanceof GridServiceProxy;
@@ -622,7 +626,8 @@ public class PlatformServices extends PlatformAbstractTarget {
Method mtd = getMethod(serviceClass, mthdName, args);
convertArrayArgs(args, mtd);
- return ((GridServiceProxy)proxy).invokeMethod(mtd, args, null);
+ return ((GridServiceProxy)proxy)
+ .invokeMethod(mtd, args, callAttrs == null ? null : new ServiceCallContextImpl(callAttrs));
}
}
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 e101b6c..fba2f41 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
@@ -74,7 +74,7 @@ public class GridServiceProxy<T> implements Serializable {
static {
try {
PLATFORM_SERVICE_INVOKE_METHOD = PlatformService.class.getMethod("invokeMethod", String.class,
- boolean.class, Object[].class);
+ boolean.class, boolean.class, Object[].class, Map.class);
}
catch (NoSuchMethodException e) {
throw new ExceptionInInitializerError("'invokeMethod' is not defined in " + PlatformService.class.getName());
@@ -287,8 +287,11 @@ public class GridServiceProxy<T> implements Serializable {
Object[] args,
@Nullable ServiceCallContext callCtx
) throws Exception {
- if (svc instanceof PlatformService && !PLATFORM_SERVICE_INVOKE_METHOD.equals(mtd))
- return ((PlatformService)svc).invokeMethod(methodName(mtd), false, true, args);
+ if (svc instanceof PlatformService && !PLATFORM_SERVICE_INVOKE_METHOD.equals(mtd)) {
+ Map<String, Object> callAttrs = callCtx == null ? null : ((ServiceCallContextImpl)callCtx).values();
+
+ return ((PlatformService)svc).invokeMethod(methodName(mtd), false, true, args, callAttrs);
+ }
else
return callServiceMethod(svc, mtd, args, callCtx);
}
@@ -531,7 +534,7 @@ public class GridServiceProxy<T> implements Serializable {
/** */
private Object callPlatformService(PlatformService srv) {
try {
- return srv.invokeMethod(mtdName, false, true, args);
+ return srv.invokeMethod(mtdName, false, true, args, callCtx != null ? ((ServiceCallContextImpl)callCtx).values() : null);
}
catch (PlatformNativeException ne) {
throw new ServiceProxyException(U.convertException(ne));
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceCallContextImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceCallContextImpl.java
index aceedca..ab53c12b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceCallContextImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceCallContextImpl.java
@@ -20,7 +20,6 @@ package org.apache.ignite.internal.processors.service;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
-import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import org.apache.ignite.internal.util.typedef.internal.U;
@@ -34,7 +33,7 @@ public class ServiceCallContextImpl implements ServiceCallContext {
private static final long serialVersionUID = 0L;
/** Service call context attributes. */
- private Map<String, byte[]> attrs;
+ private Map<String, Object> attrs;
/**
* Default contructor.
@@ -46,23 +45,18 @@ public class ServiceCallContextImpl implements ServiceCallContext {
/**
* @param attrs Service call context attributes.
*/
- public ServiceCallContextImpl(Map<String, byte[]> attrs) {
- this.attrs = new HashMap<>(attrs);
+ public ServiceCallContextImpl(Map<String, Object> attrs) {
+ this.attrs = attrs;
}
/** {@inheritDoc} */
@Override public String attribute(String name) {
- byte[] bytes = attrs.get(name);
-
- if (bytes == null)
- return null;
-
- return new String(bytes, StandardCharsets.UTF_8);
+ return (String)attrs.get(name);
}
/** {@inheritDoc} */
@Override public byte[] binaryAttribute(String name) {
- return attrs.get(name);
+ return (byte[])attrs.get(name);
}
/** {@inheritDoc} */
@@ -74,4 +68,11 @@ public class ServiceCallContextImpl implements ServiceCallContext {
@Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
attrs = U.readMap(in);
}
+
+ /**
+ * @return Service call context attributes.
+ */
+ Map<String, Object> values() {
+ return attrs;
+ }
}
diff --git a/modules/core/src/main/java/org/apache/ignite/services/ServiceCallContextBuilder.java b/modules/core/src/main/java/org/apache/ignite/services/ServiceCallContextBuilder.java
index bbb221a..9ba40df 100644
--- a/modules/core/src/main/java/org/apache/ignite/services/ServiceCallContextBuilder.java
+++ b/modules/core/src/main/java/org/apache/ignite/services/ServiceCallContextBuilder.java
@@ -17,8 +17,6 @@
package org.apache.ignite.services;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.apache.ignite.internal.processors.service.ServiceCallContextImpl;
@@ -31,7 +29,7 @@ import org.apache.ignite.lang.IgniteExperimental;
@IgniteExperimental
public class ServiceCallContextBuilder {
/** Service call context attributes. */
- private final Map<String, byte[]> attrs = new HashMap<>();
+ private final Map<String, Object> attrs = new HashMap<>();
/**
* Put string attribute.
@@ -44,13 +42,15 @@ public class ServiceCallContextBuilder {
A.notNullOrEmpty(name, "name");
A.notNull(value, "value");
- attrs.put(name, value.getBytes(StandardCharsets.UTF_8));
+ attrs.put(name, value);
return this;
}
/**
* Put binary attribute.
+ * <p>
+ * <b>Note:</b> it is recommended to pass a copy of the array if the original can be changed later.
*
* @param name Attribute name.
* @param value Attribute value.
@@ -60,7 +60,7 @@ public class ServiceCallContextBuilder {
A.notNullOrEmpty(name, "name");
A.notNull(value, "value");
- attrs.put(name, Arrays.copyOf(value, value.length));
+ attrs.put(name, value);
return this;
}
@@ -72,6 +72,6 @@ public class ServiceCallContextBuilder {
if (attrs.isEmpty())
throw new IllegalStateException("Cannot create an empty context.");
- return new ServiceCallContextImpl(attrs);
+ return new ServiceCallContextImpl(new HashMap<>(attrs));
}
}
diff --git a/modules/core/src/test/java/org/apache/ignite/platform/AbstractPlatformServiceCallTask.java b/modules/core/src/test/java/org/apache/ignite/platform/AbstractPlatformServiceCallTask.java
index bb5239b..ce39347 100644
--- a/modules/core/src/test/java/org/apache/ignite/platform/AbstractPlatformServiceCallTask.java
+++ b/modules/core/src/test/java/org/apache/ignite/platform/AbstractPlatformServiceCallTask.java
@@ -42,6 +42,7 @@ import org.apache.ignite.configuration.ClientConfiguration;
import org.apache.ignite.internal.processors.odbc.ClientListenerProcessor;
import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.resources.IgniteInstanceResource;
+import org.apache.ignite.services.ServiceCallContext;
import org.apache.ignite.services.ServiceDescriptor;
import org.jetbrains.annotations.Nullable;
@@ -133,7 +134,9 @@ public abstract class AbstractPlatformServiceCallTask extends ComputeTaskAdapter
* Gets service proxy.
*/
TestPlatformService serviceProxy() {
- return ignite.services().serviceProxy(srvcName, TestPlatformService.class, false);
+ ServiceCallContext callCtx = ServiceCallContext.builder().put("attr", "value").build();
+
+ return ignite.services().serviceProxy(srvcName, TestPlatformService.class, false, callCtx, 0);
}
/**
@@ -209,6 +212,10 @@ public abstract class AbstractPlatformServiceCallTask extends ComputeTaskAdapter
/** */
@PlatformServiceMethod("AddOne")
BinarizableTestValue addOne(BinarizableTestValue val);
+
+ /** */
+ @PlatformServiceMethod("contextAttribute")
+ String contextAttribute(String name);
}
/** */
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 bdb4823..dfeea31 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
@@ -123,6 +123,9 @@ public class PlatformDeployServiceTask extends ComputeTaskAdapter<String, Object
/** */
private boolean isExecuted;
+ /** */
+ private ServiceContext svcCtx;
+
/** {@inheritDoc} */
@Override public void cancel(ServiceContext ctx) {
isCancelled = true;
@@ -130,6 +133,8 @@ public class PlatformDeployServiceTask extends ComputeTaskAdapter<String, Object
/** {@inheritDoc} */
@Override public void init(ServiceContext ctx) throws Exception {
+ svcCtx = ctx;
+
isInitialized = true;
}
@@ -643,6 +648,11 @@ public class PlatformDeployServiceTask extends ComputeTaskAdapter<String, Object
throw new IgniteException(e);
}
}
+
+ /** */
+ public Object contextAttribute(String name) {
+ return svcCtx.currentCallContext().attribute(name);
+ }
}
/** */
diff --git a/modules/core/src/test/java/org/apache/ignite/platform/PlatformServiceCallTask.java b/modules/core/src/test/java/org/apache/ignite/platform/PlatformServiceCallTask.java
index 97c0d54..43f8201 100644
--- a/modules/core/src/test/java/org/apache/ignite/platform/PlatformServiceCallTask.java
+++ b/modules/core/src/test/java/org/apache/ignite/platform/PlatformServiceCallTask.java
@@ -49,6 +49,7 @@ public class PlatformServiceCallTask extends AbstractPlatformServiceCallTask {
checkUuidProp(srv);
checkObjectProp(srv);
checkErrorMethod(srv);
+ checkContextAttribute(srv);
}
/** */
@@ -79,5 +80,10 @@ public class PlatformServiceCallTask extends AbstractPlatformServiceCallTask {
assertTrue(nativeEx.toString().contains("Failed method"));
}
+
+ /** */
+ protected void checkContextAttribute(TestPlatformService srv) {
+ assertEquals("value", srv.contextAttribute("attr"));
+ }
}
}
diff --git a/modules/core/src/test/java/org/apache/ignite/platform/PlatformServiceCallThinTask.java b/modules/core/src/test/java/org/apache/ignite/platform/PlatformServiceCallThinTask.java
index a1c840f..efe8841 100644
--- a/modules/core/src/test/java/org/apache/ignite/platform/PlatformServiceCallThinTask.java
+++ b/modules/core/src/test/java/org/apache/ignite/platform/PlatformServiceCallThinTask.java
@@ -72,5 +72,9 @@ public class PlatformServiceCallThinTask extends AbstractPlatformServiceCallTask
}, ClientException.class, "Failed to invoke platform service");
}
+ /** {@inheritDoc} */
+ @Override protected void checkContextAttribute(TestPlatformService srv) {
+ // TODO IGNITE-15829 Remove this method override.
+ }
}
}
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/CallPlatformServiceTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/CallPlatformServiceTest.cs
index 8bd55a1..78dc48e 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/CallPlatformServiceTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/CallPlatformServiceTest.cs
@@ -163,6 +163,9 @@ namespace Apache.Ignite.Core.Tests.Services
/** */
BinarizableTestValue AddOne(BinarizableTestValue val);
+
+ /** */
+ string contextAttribute(string name);
}
#pragma warning disable 649
@@ -174,6 +177,9 @@ namespace Apache.Ignite.Core.Tests.Services
[InstanceResource]
private IIgnite _grid;
+ /** */
+ private IServiceContext _ctx;
+
/** <inheritdoc /> */
public Guid NodeId
{
@@ -247,10 +253,15 @@ namespace Apache.Ignite.Core.Tests.Services
};
}
+ public string contextAttribute(string name)
+ {
+ return _ctx.CurrentCallContext.GetAttribute(name);
+ }
+
/** <inheritdoc /> */
public void Init(IServiceContext context)
{
- // No-op.
+ _ctx = context;
}
/** <inheritdoc /> */
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 fe714c1..890b68d 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/IJavaService.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/IJavaService.cs
@@ -209,5 +209,8 @@ namespace Apache.Ignite.Core.Tests.Services
/** */
void sleep(long delayMs);
+
+ /** */
+ object contextAttribute(string name);
}
}
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 e5840e0..37dec5c 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/JavaServiceDynamicProxy.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/JavaServiceDynamicProxy.cs
@@ -394,5 +394,11 @@ namespace Apache.Ignite.Core.Tests.Services
{
_svc.sleep(delayMs);
}
+
+ /** <inheritDoc /> */
+ public object contextAttribute(string name)
+ {
+ return _svc.contextAttribute(name);
+ }
}
}
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/PlatformTestService.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/PlatformTestService.cs
index 1ed48fe..733cb28 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/PlatformTestService.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/PlatformTestService.cs
@@ -45,6 +45,9 @@ namespace Apache.Ignite.Core.Tests.Services
private bool _cancelled;
/** */
+ private IServiceContext _context;
+
+ /** */
public PlatformTestService()
{
// No-Op.
@@ -60,6 +63,7 @@ namespace Apache.Ignite.Core.Tests.Services
/** <inheritDoc /> */
public void Init(IServiceContext context)
{
+ _context = context;
_initialized = true;
}
@@ -617,5 +621,11 @@ namespace Apache.Ignite.Core.Tests.Services
{
throw new NotImplementedException();
}
+
+ /** <inheritDoc /> */
+ public object contextAttribute(string name)
+ {
+ return _context.CurrentCallContext.GetAttribute(name);
+ }
}
}
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServiceProxyTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServiceProxyTest.cs
index 51a79fc..37ca0f7 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServiceProxyTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServiceProxyTest.cs
@@ -284,7 +284,7 @@ namespace Apache.Ignite.Core.Tests.Services
inStream.WriteBool(SrvKeepBinary); // WriteProxyMethod does not do this, but Java does
ServiceProxySerializer.WriteProxyMethod(_marsh.StartMarshal(inStream), method.Name,
- method, args, PlatformType.DotNet);
+ method, args, PlatformType.DotNet, null);
inStream.SynchronizeOutput();
@@ -293,8 +293,9 @@ namespace Apache.Ignite.Core.Tests.Services
// 2) call InvokeServiceMethod
string mthdName;
object[] mthdArgs;
+ IServiceCallContext callCtx;
- ServiceProxySerializer.ReadProxyMethod(inStream, _marsh, out mthdName, out mthdArgs);
+ ServiceProxySerializer.ReadProxyMethod(inStream, _marsh, out mthdName, out mthdArgs, out callCtx);
var result = ServiceProxyInvoker.InvokeServiceMethod(_svc, mthdName, mthdArgs);
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesAsyncWrapper.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesAsyncWrapper.cs
index cf058a9..a99ca37 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesAsyncWrapper.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesAsyncWrapper.cs
@@ -18,6 +18,7 @@
namespace Apache.Ignite.Core.Tests.Services
{
using System;
+ using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using Apache.Ignite.Core.Cluster;
@@ -192,6 +193,12 @@ namespace Apache.Ignite.Core.Tests.Services
{
return _services.GetServiceProxy<T>(name, sticky);
}
+
+ /** <inheritDoc /> */
+ public T GetServiceProxy<T>(string name, bool sticky, IServiceCallContext callCtx) where T : class
+ {
+ return _services.GetServiceProxy<T>(name, sticky, callCtx);
+ }
/** <inheritDoc /> */
public dynamic GetDynamicServiceProxy(string name)
@@ -204,6 +211,12 @@ namespace Apache.Ignite.Core.Tests.Services
{
return _services.GetDynamicServiceProxy(name, sticky);
}
+
+ /** <inheritDoc /> */
+ public dynamic GetDynamicServiceProxy(string name, bool sticky, IServiceCallContext callCtx)
+ {
+ return _services.GetDynamicServiceProxy(name, sticky, callCtx);
+ }
/** <inheritDoc /> */
public IServices WithKeepBinary()
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 af0f4bd..d393259 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesTest.cs
@@ -27,10 +27,12 @@ namespace Apache.Ignite.Core.Tests.Services
using Apache.Ignite.Core.Cluster;
using Apache.Ignite.Core.Common;
using Apache.Ignite.Core.Impl;
+ using Apache.Ignite.Core.Impl.Binary;
using Apache.Ignite.Core.Resource;
using Apache.Ignite.Core.Services;
- using NUnit.Framework;
+ using Apache.Ignite.Core.Tests.Compute;
using Apache.Ignite.Platform.Model;
+ using NUnit.Framework;
/// <summary>
/// Services tests.
@@ -266,6 +268,58 @@ namespace Apache.Ignite.Core.Tests.Services
}
/// <summary>
+ /// Tests service call context.
+ /// </summary>
+ [Test]
+ public void TestServiceCallContext([Values(true, false)] bool binarizable)
+ {
+ var svc = binarizable
+ ? new TestIgniteServiceBinarizable {TestProperty = 17}
+ : new TestIgniteServiceSerializable {TestProperty = 17};
+
+ Services.DeployClusterSingleton(SvcName, svc);
+
+ foreach (var grid in Grids)
+ {
+ var nodeId = grid.GetCluster().ForLocal().GetNode().Id;
+
+ var attrName = grid.Name;
+ var attrBinName = "bin-" + grid.Name;
+ var attrValue = nodeId.ToString();
+ var attrBinValue = nodeId.ToByteArray();
+
+ var svc0 = grid.GetServices().GetService<ITestIgniteService>(SvcName);
+
+ if (svc0 != null)
+ Assert.IsNull(svc0.ContextAttribute(attrName));
+
+ var ctx = new ServiceCallContextBuilder()
+ .Set(attrName, attrValue)
+ .Set(attrBinName, attrBinValue)
+ .Build();
+
+ var proxy = grid.GetServices().GetServiceProxy<ITestIgniteService>(SvcName, false, ctx);
+
+ Assert.IsNull(proxy.ContextAttribute("not-exist-attribute"));
+ Assert.IsNull(proxy.ContextBinaryAttribute("not-exist-attribute"));
+
+ var stickyProxy = grid.GetServices().GetServiceProxy<ITestIgniteService>(SvcName, true, ctx);
+ var dynamicProxy = grid.GetServices().GetDynamicServiceProxy(SvcName, false, ctx);
+ var dynamicStickyProxy = grid.GetServices().GetDynamicServiceProxy(SvcName, true, ctx);
+
+ Assert.AreEqual(attrValue, proxy.ContextAttribute(attrName));
+ Assert.AreEqual(attrValue, stickyProxy.ContextAttribute(attrName));
+ Assert.AreEqual(attrValue, dynamicProxy.ContextAttribute(attrName));
+ Assert.AreEqual(attrValue, dynamicStickyProxy.ContextAttribute(attrName));
+
+ Assert.AreEqual(attrBinValue, proxy.ContextBinaryAttribute(attrBinName));
+ Assert.AreEqual(attrBinValue, stickyProxy.ContextBinaryAttribute(attrBinName));
+ Assert.AreEqual(attrBinValue, dynamicProxy.ContextBinaryAttribute(attrBinName));
+ Assert.AreEqual(attrBinValue, dynamicStickyProxy.ContextBinaryAttribute(attrBinName));
+ }
+ }
+
+ /// <summary>
/// Tests service proxy.
/// </summary>
[Test]
@@ -872,7 +926,7 @@ namespace Apache.Ignite.Core.Tests.Services
var descriptor = _client.GetServices().GetServiceDescriptors().Single(x => x.Name == javaSvcName);
Assert.AreEqual(javaSvcName, descriptor.Name);
- var svc = _client.GetServices().GetServiceProxy<IJavaService>(javaSvcName, false);
+ var svc = _client.GetServices().GetServiceProxy<IJavaService>(javaSvcName, false, callContext());
var binSvc = _client.GetServices().WithKeepBinary().WithServerKeepBinary()
.GetServiceProxy<IJavaService>(javaSvcName, false);
@@ -898,7 +952,7 @@ namespace Apache.Ignite.Core.Tests.Services
var descriptor = Services.GetServiceDescriptors().Single(x => x.Name == javaSvcName);
Assert.AreEqual(javaSvcName, descriptor.Name);
- var svc = Services.GetServiceProxy<IJavaService>(javaSvcName, false);
+ var svc = Services.GetServiceProxy<IJavaService>(javaSvcName, false, callContext());
var binSvc = Services.WithKeepBinary().WithServerKeepBinary()
.GetServiceProxy<IJavaService>(javaSvcName, false);
@@ -920,7 +974,7 @@ namespace Apache.Ignite.Core.Tests.Services
// Deploy Java service
var javaSvcName = TestUtils.DeployJavaService(Grid1);
- var svc = new JavaServiceDynamicProxy(Grid1.GetServices().GetDynamicServiceProxy(javaSvcName, true));
+ var svc = new JavaServiceDynamicProxy(Grid1.GetServices().GetDynamicServiceProxy(javaSvcName, true, callContext()));
DoTestService(svc);
@@ -954,7 +1008,7 @@ namespace Apache.Ignite.Core.Tests.Services
Services.DeployClusterSingleton(platformSvcName, new PlatformTestService());
- var svc = svcsForProxy.GetServiceProxy<IJavaService>(platformSvcName);
+ var svc = svcsForProxy.GetServiceProxy<IJavaService>(platformSvcName, false, callContext());
DoTestService(svc);
@@ -1092,6 +1146,7 @@ namespace Apache.Ignite.Core.Tests.Services
Assert.AreEqual(dt1, cache.Get(3));
Assert.AreEqual(dt2, cache.Get(4));
+ Assert.AreEqual("value", svc.contextAttribute("attr"));
#if NETCOREAPP
//This Date in Europe/Moscow have offset +4.
@@ -1117,6 +1172,15 @@ namespace Apache.Ignite.Core.Tests.Services
}
/// <summary>
+ /// Creates a test caller context.
+ /// </summary>
+ /// <returns>Caller context.</returns>
+ private IServiceCallContext callContext()
+ {
+ return new ServiceCallContextBuilder().Set("attr", "value").Build();
+ }
+
+ /// <summary>
/// Tests handling of the Java exception in the .Net.
/// </summary>
public void DoTestJavaExceptions(IJavaService svc, bool isClient = false)
@@ -1290,7 +1354,7 @@ namespace Apache.Ignite.Core.Tests.Services
{
if (!CompactFooter)
{
- springConfigUrl = Compute.ComputeApiTestFullFooter.ReplaceFooterSetting(springConfigUrl);
+ springConfigUrl = ComputeApiTestFullFooter.ReplaceFooterSetting(springConfigUrl);
}
return new IgniteConfiguration(TestUtils.GetTestConfiguration())
@@ -1461,6 +1525,12 @@ namespace Apache.Ignite.Core.Tests.Services
/** */
int TestOverload(int count, Parameter[] param);
+
+ /** */
+ object ContextAttribute(string name);
+
+ /** */
+ object ContextBinaryAttribute(string name);
}
/// <summary>
@@ -1492,6 +1562,9 @@ namespace Apache.Ignite.Core.Tests.Services
// ReSharper disable once UnassignedField.Local
private IIgnite _grid;
+ // Service context.
+ private IServiceContext _context;
+
/** <inheritdoc /> */
public int TestProperty { get; set; }
@@ -1584,6 +1657,22 @@ namespace Apache.Ignite.Core.Tests.Services
}
/** <inheritdoc /> */
+ public object ContextAttribute(string name)
+ {
+ IServiceCallContext ctx = _context.CurrentCallContext;
+
+ return ctx == null ? null : ctx.GetAttribute(name);
+ }
+
+ /** <inheritdoc /> */
+ public object ContextBinaryAttribute(string name)
+ {
+ IServiceCallContext ctx = _context.CurrentCallContext;
+
+ return ctx == null ? null : ctx.GetBinaryAttribute(name);
+ }
+
+ /** <inheritdoc /> */
public void Init(IServiceContext context)
{
lock (this)
@@ -1596,6 +1685,8 @@ namespace Apache.Ignite.Core.Tests.Services
Assert.IsFalse(context.IsCancelled);
Initialized = true;
}
+
+ _context = context;
}
/** <inheritdoc /> */
@@ -1773,14 +1864,14 @@ namespace Apache.Ignite.Core.Tests.Services
if (date.Kind == DateTimeKind.Local)
date = date.ToUniversalTime();
- Impl.Binary.BinaryUtils.ToJavaDate(date, out high, out low);
+ BinaryUtils.ToJavaDate(date, out high, out low);
}
/** <inheritdoc /> */
public DateTime FromJavaTicks(long high, int low)
{
return new DateTime(
- Impl.Binary.BinaryUtils.JavaDateTicks + high * TimeSpan.TicksPerMillisecond + low / 100,
+ BinaryUtils.JavaDateTicks + high * TimeSpan.TicksPerMillisecond + low / 100,
DateTimeKind.Utc);
}
}
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Common/IgniteExperimentalAttribute.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Common/IgniteExperimentalAttribute.cs
index 81b0e51..e5fd46f 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Common/IgniteExperimentalAttribute.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Common/IgniteExperimentalAttribute.cs
@@ -28,8 +28,8 @@ namespace Apache.Ignite.Core.Common
/// allowed for such APIs: API may be removed, changed or stabilized in future Ignite releases
/// (both minor and maintenance).
/// </summary>
- [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Enum |
- AttributeTargets.Property | AttributeTargets.Field)]
+ [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class | AttributeTargets.Method |
+ AttributeTargets.Enum | AttributeTargets.Property | AttributeTargets.Field)]
public sealed class IgniteExperimentalAttribute : Attribute
{
// No-op.
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/ServiceCallContext.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/ServiceCallContext.cs
new file mode 100644
index 0000000..8f5d61b
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/ServiceCallContext.cs
@@ -0,0 +1,64 @@
+/*
+ * 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.Services
+{
+ using System.Collections;
+ using Apache.Ignite.Core.Impl.Common;
+ using Apache.Ignite.Core.Services;
+
+ /// <summary>
+ /// Service call context implementation.
+ /// </summary>
+ internal class ServiceCallContext : IServiceCallContext
+ {
+ /** Context attributes. */
+ private IDictionary _attrs;
+
+ /// <summary>
+ /// Constructs context from dictionary.
+ /// </summary>
+ /// <param name="attrs">Context attributes.</param>
+ internal ServiceCallContext(IDictionary attrs)
+ {
+ IgniteArgumentCheck.NotNull(attrs, "attrs");
+
+ _attrs = attrs;
+ }
+
+ /** <inheritDoc /> */
+ public string GetAttribute(string name)
+ {
+ return (string) _attrs[name];
+ }
+
+ /** <inheritDoc /> */
+ public byte[] GetBinaryAttribute(string name)
+ {
+ return (byte[]) _attrs[name];
+ }
+
+ /// <summary>
+ /// Gets call context attributes.
+ /// </summary>
+ /// <returns>Service call context attributes.</returns>
+ internal IDictionary Values()
+ {
+ return _attrs;
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/ServiceContext.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/ServiceContext.cs
index 2532b70..94a6ac8 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/ServiceContext.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/ServiceContext.cs
@@ -19,6 +19,7 @@ namespace Apache.Ignite.Core.Impl.Services
{
using System;
using System.Diagnostics;
+ using System.Threading;
using Apache.Ignite.Core.Binary;
using Apache.Ignite.Core.Services;
@@ -27,6 +28,9 @@ namespace Apache.Ignite.Core.Impl.Services
/// </summary>
internal class ServiceContext : IServiceContext
{
+ /** Service call context of the current thread. */
+ private static readonly ThreadLocal<IServiceCallContext> locCallCtx = new ThreadLocal<IServiceCallContext>();
+
/// <summary>
/// Initializes a new instance of the <see cref="ServiceContext"/> class.
/// </summary>
@@ -56,5 +60,19 @@ namespace Apache.Ignite.Core.Impl.Services
/** <inheritdoc /> */
public object AffinityKey { get; private set; }
+
+ /** <inheritdoc /> */
+ public IServiceCallContext CurrentCallContext
+ {
+ get { return locCallCtx.Value; }
+ }
+
+ /// <summary>
+ /// Sets service call context for the current thread.
+ /// </summary>
+ /// <param name="callCtx">Service call context for the current thread.</param>
+ internal static void SetCurrentCallContext(IServiceCallContext callCtx) {
+ locCallCtx.Value = callCtx;
+ }
}
}
\ No newline at end of file
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/ServiceProxySerializer.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/ServiceProxySerializer.cs
index e28f4d7..5614fd5 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/ServiceProxySerializer.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/ServiceProxySerializer.cs
@@ -41,8 +41,9 @@ namespace Apache.Ignite.Core.Impl.Services
/// <param name="method">Method (optional, can be null).</param>
/// <param name="arguments">Arguments.</param>
/// <param name="platformType">The platform.</param>
+ /// <param name="callCtx">Service call context.</param>
public static void WriteProxyMethod(BinaryWriter writer, string methodName, MethodBase method,
- object[] arguments, PlatformType platformType)
+ object[] arguments, PlatformType platformType, IServiceCallContext callCtx)
{
Debug.Assert(writer != null);
@@ -76,6 +77,8 @@ namespace Apache.Ignite.Core.Impl.Services
}
else
writer.WriteBoolean(false);
+
+ writer.WriteDictionary(callCtx == null ? null : ((ServiceCallContext) callCtx).Values());
}
/// <summary>
@@ -85,8 +88,9 @@ namespace Apache.Ignite.Core.Impl.Services
/// <param name="marsh">Marshaller.</param>
/// <param name="mthdName">Method name.</param>
/// <param name="mthdArgs">Method arguments.</param>
+ /// <param name="callCtx">Service call context.</param>
public static void ReadProxyMethod(IBinaryStream stream, Marshaller marsh,
- out string mthdName, out object[] mthdArgs)
+ out string mthdName, out object[] mthdArgs, out IServiceCallContext callCtx)
{
var reader = marsh.StartUnmarshal(stream);
@@ -106,6 +110,10 @@ namespace Apache.Ignite.Core.Impl.Services
}
else
mthdArgs = null;
+
+ var attrs = reader.ReadDictionary();
+
+ callCtx = attrs == null ? null : new ServiceCallContext(attrs);
}
/// <summary>
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/Services.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/Services.cs
index 3d5f4eb..7ec4b3a 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/Services.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Services/Services.cs
@@ -366,15 +366,21 @@ namespace Apache.Ignite.Core.Impl.Services
/** <inheritDoc /> */
public T GetServiceProxy<T>(string name, bool sticky) where T : class
{
+ return GetServiceProxy<T>(name, sticky, null);
+ }
+
+ /** <inheritDoc /> */
+ public T GetServiceProxy<T>(string name, bool sticky, IServiceCallContext callCtx) where T : class
+ {
IgniteArgumentCheck.NotNullOrEmpty(name, "name");
IgniteArgumentCheck.Ensure(typeof(T).IsInterface, "T",
"Service proxy type should be an interface: " + typeof(T));
+ T locInst;
+
// In local scenario try to return service instance itself instead of a proxy
// Get as object because proxy interface may be different from real interface
- var locInst = GetService<object>(name) as T;
-
- if (locInst != null)
+ if (callCtx == null && (locInst = GetService<object>(name) as T) != null)
return locInst;
var javaProxy = DoOutOpObject(OpServiceProxy, w =>
@@ -386,7 +392,7 @@ namespace Apache.Ignite.Core.Impl.Services
var platform = GetServiceDescriptors().Cast<ServiceDescriptor>().Single(x => x.Name == name).PlatformType;
return ServiceProxyFactory<T>.CreateProxy((method, args) =>
- InvokeProxyMethod(javaProxy, method.Name, method, args, platform));
+ InvokeProxyMethod(javaProxy, method.Name, method, args, platform, callCtx));
}
/** <inheritDoc /> */
@@ -398,14 +404,21 @@ namespace Apache.Ignite.Core.Impl.Services
/** <inheritDoc /> */
public dynamic GetDynamicServiceProxy(string name, bool sticky)
{
+ return GetDynamicServiceProxy(name, sticky, null);
+ }
+
+ /** <inheritDoc /> */
+ public dynamic GetDynamicServiceProxy(string name, bool sticky, IServiceCallContext callCtx)
+ {
IgniteArgumentCheck.NotNullOrEmpty(name, "name");
// In local scenario try to return service instance itself instead of a proxy
- var locInst = GetService<object>(name);
-
- if (locInst != null)
+ if (callCtx == null)
{
- return locInst;
+ var locInst = GetService<object>(name);
+
+ if (locInst != null)
+ return locInst;
}
var javaProxy = DoOutOpObject(OpServiceProxy, w =>
@@ -417,7 +430,7 @@ namespace Apache.Ignite.Core.Impl.Services
var platform = GetServiceDescriptors().Cast<ServiceDescriptor>().Single(x => x.Name == name).PlatformType;
return new DynamicServiceProxy((methodName, args) =>
- InvokeProxyMethod(javaProxy, methodName, null, args, platform));
+ InvokeProxyMethod(javaProxy, methodName, null, args, platform, callCtx));
}
/// <summary>
@@ -428,11 +441,12 @@ namespace Apache.Ignite.Core.Impl.Services
/// <param name="method">Method to invoke.</param>
/// <param name="args">Arguments.</param>
/// <param name="platformType">The platform.</param>
+ /// <param name="callCtx">Service call context.</param>
/// <returns>
/// Invocation result.
/// </returns>
private object InvokeProxyMethod(IPlatformTargetInternal proxy, string methodName,
- MethodBase method, object[] args, PlatformType platformType)
+ MethodBase method, object[] args, PlatformType platformType, IServiceCallContext callCtx)
{
bool locRegisterSameJavaType = Marshaller.RegisterSameJavaTypeTl.Value;
@@ -444,7 +458,7 @@ namespace Apache.Ignite.Core.Impl.Services
try
{
return DoOutInOp(OpInvokeMethod,
- writer => ServiceProxySerializer.WriteProxyMethod(writer, methodName, method, args, platformType),
+ writer => ServiceProxySerializer.WriteProxyMethod(writer, methodName, method, args, platformType, callCtx),
(stream, res) => ServiceProxySerializer.ReadInvocationResult(stream, Marshaller, _keepBinary),
proxy);
}
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 f6d90b3..c26a441 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbacks.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbacks.cs
@@ -18,6 +18,7 @@
namespace Apache.Ignite.Core.Impl.Unmanaged
{
using System;
+ using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
@@ -1105,16 +1106,28 @@ namespace Apache.Ignite.Core.Impl.Unmanaged
string mthdName;
object[] mthdArgs;
+ IServiceCallContext callCtx;
- ServiceProxySerializer.ReadProxyMethod(stream, _ignite.Marshaller, out mthdName, out mthdArgs);
+ ServiceProxySerializer.ReadProxyMethod(stream, _ignite.Marshaller, out mthdName, out mthdArgs, out callCtx);
+
+ if (callCtx != null)
+ ServiceContext.SetCurrentCallContext(callCtx);
- var result = ServiceProxyInvoker.InvokeServiceMethod(svc, mthdName, mthdArgs);
+ try
+ {
+ var result = ServiceProxyInvoker.InvokeServiceMethod(svc, mthdName, mthdArgs);
- stream.Reset();
+ stream.Reset();
- ServiceProxySerializer.WriteInvocationResult(stream, _ignite.Marshaller, result.Key, result.Value);
+ ServiceProxySerializer.WriteInvocationResult(stream, _ignite.Marshaller, result.Key, result.Value);
- stream.SynchronizeOutput();
+ stream.SynchronizeOutput();
+ }
+ finally
+ {
+ if (callCtx != null)
+ ServiceContext.SetCurrentCallContext(null);
+ }
return 0;
}
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Services/IServiceCallContext.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Services/IServiceCallContext.cs
new file mode 100644
index 0000000..d5d7c6d
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Services/IServiceCallContext.cs
@@ -0,0 +1,78 @@
+/*
+ * 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.Services
+{
+ using Apache.Ignite.Core.Common;
+
+ /// <summary>
+ /// Represents service call context.
+ /// <para />
+ /// This context is implicitly passed to the service and can be retrieved inside the service
+ /// using <see cref="IServiceContext.CurrentCallContext()"/>. It is accessible only
+ /// from the local thread during the execution of a service method.
+ /// <para />
+ /// Use <see cref="ServiceCallContextBuilder"/> to instantiate the context.
+ /// <para />
+ /// <b>Note</b>: passing the context to the service may lead to performance overhead,
+ /// so it should only be used for "middleware" tasks.
+ /// <para />
+ /// Usage example:
+ /// <code>
+ /// // Service implementation.
+ /// public class HelloServiceImpl : HelloService
+ /// {
+ /// private IServiceContext ctx;
+ ///
+ /// public void Init(IServiceContext ctx)
+ /// {
+ /// this.ctx = ctx;
+ /// }
+ ///
+ /// public string Call(string msg)
+ /// {
+ /// return msg + ctx.CurrentCallContext.Attribute("user");
+ /// }
+ /// ...
+ /// }
+ /// ...
+ ///
+ /// // Call this service with context.
+ /// IServiceCallContext callCtx = new ServiceCallContextBuilder().Set("user", "John").build();
+ /// HelloService helloSvc = ignite.GetServices().GetServiceProxy<HelloService>("hello-service", false, callCtx);
+ /// // Print "Hello John".
+ /// Console.WriteLine( helloSvc.call("Hello ") );
+ /// </code>
+ /// </summary>
+ [IgniteExperimental]
+ public interface IServiceCallContext
+ {
+ /// <summary>
+ /// Gets the string attribute.
+ /// </summary>
+ /// <param name="name">Attribute name.</param>
+ /// <returns>String attribute value.</returns>
+ string GetAttribute(string name);
+
+ /// <summary>
+ /// Gets the binary attribute.
+ /// </summary>
+ /// <param name="name">Attribute name.</param>
+ /// <returns>Binary attribute value.</returns>
+ byte[] GetBinaryAttribute(string name);
+ }
+}
\ No newline at end of file
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Services/IServiceContext.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Services/IServiceContext.cs
index 50c3f14..927ba70 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Services/IServiceContext.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Services/IServiceContext.cs
@@ -18,6 +18,7 @@
namespace Apache.Ignite.Core.Services
{
using System;
+ using Apache.Ignite.Core.Common;
/// <summary>
/// Represents service execution context.
@@ -65,5 +66,13 @@ namespace Apache.Ignite.Core.Services
/// Affinity key, possibly null.
/// </value>
object AffinityKey { get; }
+
+ /// <summary>
+ /// Gets context of the current service call.
+ /// </summary>
+ /// <returns>Context of the current service call.</returns>
+ /// <seealso cref="IServiceCallContext"/>
+ [IgniteExperimental]
+ IServiceCallContext CurrentCallContext { get; }
}
}
\ No newline at end of file
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Services/IServices.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Services/IServices.cs
index 84c23fa..569712e 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Services/IServices.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Services/IServices.cs
@@ -21,6 +21,7 @@ namespace Apache.Ignite.Core.Services
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
using Apache.Ignite.Core.Cluster;
+ using Apache.Ignite.Core.Common;
/// <summary>
/// Defines functionality to deploy distributed services in the Ignite.
@@ -272,6 +273,20 @@ namespace Apache.Ignite.Core.Services
T GetServiceProxy<T>(string name, bool sticky) where T : class;
/// <summary>
+ /// Gets a remote handle on the service with the specified caller context.
+ /// The proxy is dynamically created and provided for the specified service.
+ /// </summary>
+ /// <typeparam name="T">Service type.</typeparam>
+ /// <param name="name">Service name.</param>
+ /// <param name="sticky">Whether or not Ignite should always contact the same remote
+ /// service or try to load-balance between services.</param>
+ /// <param name="callCtx">Service call context.</param>
+ /// <returns>Proxy over service.</returns>
+ /// <seealso cref="IServiceCallContext"/>
+ [IgniteExperimental]
+ T GetServiceProxy<T>(string name, bool sticky, IServiceCallContext callCtx) where T : class;
+
+ /// <summary>
/// Gets a remote handle on the service as a dynamic object. If service is available locally,
/// then local instance is returned, otherwise, a remote proxy is dynamically
/// created and provided for the specified service.
@@ -296,6 +311,22 @@ namespace Apache.Ignite.Core.Services
/// service or try to load-balance between services.</param>
/// <returns>Either proxy over remote service or local service if it is deployed locally.</returns>
dynamic GetDynamicServiceProxy(string name, bool sticky);
+
+ /// <summary>
+ /// Gets a remote handle on the service with the specified caller context.
+ /// The proxy is dynamically created and provided for the specified service.
+ /// <para />
+ /// This method utilizes <c>dynamic</c> feature of the language and does not require any
+ /// service interfaces or classes. Java services can be accessed as well as .NET services.
+ /// </summary>
+ /// <param name="name">Service name.</param>
+ /// <param name="sticky">Whether or not Ignite should always contact the same remote
+ /// service or try to load-balance between services.</param>
+ /// <param name="callCtx">Service call context.</param>
+ /// <returns>Proxy over service.</returns>
+ /// <seealso cref="IServiceCallContext"/>
+ [IgniteExperimental]
+ dynamic GetDynamicServiceProxy(string name, bool sticky, IServiceCallContext callCtx);
/// <summary>
/// Returns an instance with binary mode enabled.
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Services/ServiceCallContextBuilder.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Services/ServiceCallContextBuilder.cs
new file mode 100644
index 0000000..2f0604c
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Services/ServiceCallContextBuilder.cs
@@ -0,0 +1,82 @@
+/*
+ * 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.Services
+{
+ using System;
+ using System.Collections;
+ using System.Linq;
+ using Apache.Ignite.Core.Common;
+ using Apache.Ignite.Core.Impl.Common;
+ using Apache.Ignite.Core.Impl.Services;
+
+ /// <summary>
+ /// Service call context builder.
+ /// </summary>
+ [IgniteExperimental]
+ public class ServiceCallContextBuilder
+ {
+ /** Context attributes. */
+ private readonly Hashtable _attrs = new Hashtable();
+
+ /// <summary>
+ /// Set string attribute.
+ /// </summary>
+ /// <param name="name">Attribute name.</param>
+ /// <param name="value">Attribute value.</param>
+ /// <returns>This for chaining.</returns>
+ public ServiceCallContextBuilder Set(string name, string value)
+ {
+ IgniteArgumentCheck.NotNullOrEmpty(name, "name");
+ IgniteArgumentCheck.NotNull(value, "value");
+
+ _attrs[name] = value;
+
+ return this;
+ }
+
+ /// <summary>
+ /// Set binary attribute.
+ /// <p/>
+ /// <b>Note:</b> it is recommended to pass a copy of the array if the original can be changed later.
+ /// </summary>
+ /// <param name="name">Attribute name.</param>
+ /// <param name="value">Attribute value.</param>
+ /// <returns>This for chaining.</returns>
+ public ServiceCallContextBuilder Set(string name, byte[] value)
+ {
+ IgniteArgumentCheck.NotNullOrEmpty(name, "name");
+ IgniteArgumentCheck.NotNull(value, "value");
+
+ _attrs[name] = value;
+
+ return this;
+ }
+
+ /// <summary>
+ /// Create context.
+ /// </summary>
+ /// <returns>Service call context.</returns>
+ public IServiceCallContext Build()
+ {
+ if (_attrs.Count == 0)
+ throw new InvalidOperationException("Cannot create an empty context.");
+
+ return new ServiceCallContext((Hashtable)_attrs.Clone());
+ }
+ }
+}
\ No newline at end of file