Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Suggested design (draft)

New public API entities

...

  • ServiceCallContext -

...

  •   immutable map of custom parameters to be implicitly passed to the service.

...

  • ServiceCallInterceptor  -

...

  • intercepts service method calls.
  • ServiceInterceptorContext -  extended mutable version of caller context (interceptor obtains method call parameters from it and can use it to update the caller context).
  • ServiceInterceptException - unchecked exception that is used to highlight the exception that occurred during method interception (not execution).

Java API

Code Block
languagejava
themeConfluence
titleInterceptor
linenumberstrue
/**
 * Service method call interceptor.
 */
public interface ServiceCallInterceptor {
extends Serializable   /**
     * Executes before service method invocation.{

    public *
default void onInvoke(ServiceInterceptorContext ctx) throws * @param mtdName Method name.ServiceInterceptException {
     * @param args Method arguments.
     * @param ctx Service request context.
     * @return Listener of the call result or {@code null}.
     */// No-op.
    }

    public @Nullabledefault ServiceCallListenervoid interceptonComplete(String@Nullable mtdName, Object[] argsres, ServiceRequestContextServiceInterceptorContext ctx);
}
Code Block
languagejava
themeConfluence
titleListener
linenumberstrue
/**
 * Listener of the service method invocation.
 */
public interface ServiceCallListener {
 throws ServiceInterceptException {
        /**/ No-op.
     *}

    public *default @paramvoid res Service method call result, if any.onError(Throwable err, ServiceInterceptorContext ctx) {
     * @param t Error, if any// No-op.
     */
    public void onComplete(@Nullable Object res, @Nullable Throwable t);}

}

Implementation requirements/limitations

  • All specified interceptors are guaranteed to be executed before calling the service method.
  • Listeners are notified asynchronously.
  • The server interceptor binds to the service itself (it must be executed where the service is implemented, if on Java then in Java, if on Net then in Net).
  • If the interceptor throws an exception, the service method is not executed, but the rest of the interceptors are executed. This exception is passed to the user and to the listenersan interceptor has been specified, but the user has not passed the caller context through the proxy, it will be created dynamically.
  • Any interceptor can change the RequestContext ServiceCallContext.
  • RequestContext ServiceCallContext must be accessible inside the service(?).
  • Interceptor must support resource injection.
  • (question)If an interceptor throws an exception, then processing is aborted, but the exception is passed to all listed interceptors (onError) (question).

Example of usage (diagram)

...

Code Block
languagejava
themeConfluence
linenumberstrue
        ServiceCallInterceptor security = (mtd, args,new ServiceCallInterceptor() {
            @Override public void onInvoke(ServiceInterceptorContext ctx) ->throws ServiceInterceptException {
                // Check permission before execution of the method.
                if (!CustomSecurityProvider.get().access(mtdctx.method(), ctx.valueattribute("sessionId")))
                    throw new SecurityException("Method invocation is not permitted");

           return null;}
        }

        ServiceCallInterceptor audit = (mtd, args,new ServiceCallInterceptor() {
            @Override public void onInvoke(ServiceInterceptorContext ctx) -> {
                // Record an event before execution of the method.
                AuditProvider.get().recordStartEvent(mtdctx.method(), ctx.valueattribute("sessionId"));
            }

        return (    @Override public void onComplete(@Nullable Object res, err) -> {
  ServiceInterceptorContext ctx) {
                AuditProvider.get().recordFinishEvent(ctx.method(), ctx.attribute("sessionId"));
            }

          // Record an@Override eventpublic aftervoid the execution of the method.
           onError(Throwable err, ServiceInterceptorContext ctx) {
                AuditProvider.get().recordFinishEvent(mtdrecordError(ctx.method(), ctx.valueattribute("sessionId"), err != null.getMessage());
            }
        }

        // Set context parameters for service proxy.
        ServiceCallContext ctx = ServiceCallContext.builder().put("sessionId", sessionId).build();

        ServiceConfiguration svcCfg = new ServiceConfiguration()
            .setName("service")
            .setService(new MyServiceImpl())
            .setMaxPerNodeCount(1)
            .setInterceptors(Arrays.asList(security, audit));

        // Deploy service.
        ignite.services().deploy(svcCfg);

    ...

    // Set context parameters for service proxy.
    MyService proxy = ignite.services().serviceProxy("service", MyService.class, false, Collections.singletonMap("sessionId"ctx, sessionId), 0);

        // A business method call to be intercepted.
        proxy.placeOrder(order1);
        proxy.placeOrder(order2);
 

 


Risks and Assumptions

// Describe project risks, such as API or binary compatibility issues, major protocol changes, etc.

...