[ 
https://issues.apache.org/jira/browse/IGNITE-15572?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Pavel Pereslegin updated IGNITE-15572:
--------------------------------------
    Description: 
In traditional microservices, we have the ability to set a custom execution 
context.
 For example, a REST service may obtain the session ID from the request. We can 
say that each client request, in this case, has a set of explicit and implicit 
parameters. One of the implicit parameters is a session identifier that can be 
passed to the service using request headers.

It would be nice to have a similar feature in Ignite services.

The basic idea behind the implementation:
 1. Allow the user to bind the "execution context" to the service proxy object.
 2. Pass this context as an additional implicit parameter each time the user 
service method is called.
h3. API proposal.
h4. 1. Using special class ServiceRequestContext (ServiceProxyContext).
{code:java}
MyService proxy = ignite.services().serviceProxy("svc", MyService.class, false, 
new ServiceRequestContext("login", "user1"), 0);

public class MyServiceImpl implements MyService {
    @Override public void businessMethod() {
        // Read thread local context.
        ServiceRequestContext ctx = ServiceRequestContext.current();

        String user = ctx.attribute("login");
    }
        ...
}
{code}
h4. 2. Pass Map directly and read it using special annotation.
{code:java}
MyService proxy = ignite.services().serviceProxy("svc", MyService.class, false, 
Collections.singletonMap("login", "user1"), 0);

public class MyServiceImpl implements MyService {
    @ServiceRequestContextResource
    Supplier<Map<String, Object>> ctxSupplier.
        
    @Override public void businessMethod() {
        Map<String, Object> ctx = ctxSupplier.get();

        String user = ctx.attribute("login");
    }
    ...
}
{code}
h4. 3. Pass Map directly and read it using the special ServiceContext method.
{code:java}
MyService proxy = ignite.services().serviceProxy("svc", MyService.class, false, 
Collections.singletonMap("login", "user1"), 0);

public class MyServiceImpl implements MyService {
    private ServiceContext svcCtx;

    @Override public void init(ServiceContext svcCtx) {
        this.ctx = svcCtx;
    }
        
    @Override public void businessMethod() {
        Map<String, Object> ctx = ctx.attributes();
                
        String user = ctx.attribute("login");
    }
    ...
}
{code}
 

 

 

 

 
h4. A more complex example of using "execution context".
{code:java}
    // Creating service proxy invocation context with two attributes.
    ServiceProxyContext ctx1 = new ServiceProxyContextBuilder("arg1", 
10).put("usr", "X").build();
    ServiceProxyContext ctx2 = new ServiceProxyContextBuilder("arg1", 
6).put("usr", "X").build();

    // Binding "execution context" to proxy invocation handler.
    MyService proxy1 = ignite.services().serviceProxy("svc", MyService.class, 
false, ctx1, 0);
    MyService proxy2 = ignite.services().serviceProxy("svc", MyService.class, 
false, ctx2, 0);

    // Invoke service methods with argument "10".
    assert proxy1.multiply(2) == 10 * 2;
    assert proxy1.divide(2) == 10 / 2;

    // Invoke service methods with argument "6".
    assert proxy2.multiply(2) == 6 * 2;
    assert proxy2.divide(2) == 6 / 2;
...
{code}
Sample code for reading "execution context".
{code:java}
class MyServiceImpl implements MyService {
    @LoggerResource
    private IgniteLogger log;

    @Override public int multiply(int arg2) {
        // Getting proxy context.
        ServiceProxyContext ctx = ServiceProxyContext.current();

        // Reading attributes.
        int arg1 = ctx.attribute("arg1");
        String userId = ctx.attribute("usr");

        log.info(String.format("user=%s, oper=%s, a=%d, b=%d", userId, 
"multiply", arg1, arg2));

        return arg1 * arg2;
    }

    @Override public int divide(int arg2) {
        // Getting proxy context.
        ServiceProxyContext ctx = ServiceProxyContext.current();

        // Reading attributes.
        int arg1 = ctx.attribute("arg1");
        String userId = ctx.attribute("usr");

        log.info(String.format("user=%s, oper=%s, a=%d, b=%d", userId, 
"divide", arg1, arg2));

        return arg1 / arg2;
    }

    ...
}
{code}

  was:
In traditional microservices, we have the ability to set a custom execution 
context.
 For example, a REST service may obtain the session ID from the request. We can 
say that each client request, in this case, has a set of explicit and implicit 
parameters. One of the implicit parameters is a session identifier that can be 
passed to the service using request headers.

It would be nice to have a similar feature in Ignite services.

The basic idea behind the implementation:
 1. Allow the user to bind the "execution context" to the service proxy object.
 2. Pass this context as an additional implicit parameter each time the user 
service method is called.
h3. API proposal.
h4. 1. Using special class ServiceRequestContext (ServiceProxyContext).
{code:java}
MyService proxy1 = ignite.services().serviceProxy("svc", MyService.class, 
false, new ServiceRequestContext("login", "user1"), 0);

public class MyServiceImpl implements MyService {
    @Override public void businessMethod() {
        // Read thread local context.
        ServiceRequestContext ctx = ServiceRequestContext.current();

        String user = ctx.attribute("login");
    }
        ...
}
{code}
h4. 2. Pass Map directly and read it using special annotation.
{code:java}
MyService proxy1 = ignite.services().serviceProxy("svc", MyService.class, 
false, Collections.singletonMap("login", "user1"), 0);

public class MyServiceImpl implements MyService {
    @ServiceRequestContextResource
    Supplier<Map<String, Object>> ctxSupplier.
        
    @Override public void businessMethod() {
        Map<String, Object> ctx = ctxSupplier.get();

        String user = ctx.attribute("login");
    }
    ...
}
{code}
h4. 3. Pass Map directly and read it using the special ServiceContext method.
{code:java}
public class MyServiceImpl implements MyService {
    private ServiceContext svcCtx;

    @Override public void init(ServiceContext svcCtx) {
        this.ctx = svcCtx;
    }
        
    @Override public void businessMethod() {
        Map<String, Object> ctx = ctx.attributes();
                
        String user = ctx.attribute("login");
    }
    ...
}
{code}
 

 

 

 

 
h4. A more complex example of using "execution context".
{code:java}
    // Creating service proxy invocation context with two attributes.
    ServiceProxyContext ctx1 = new ServiceProxyContextBuilder("arg1", 
10).put("usr", "X").build();
    ServiceProxyContext ctx2 = new ServiceProxyContextBuilder("arg1", 
6).put("usr", "X").build();

    // Binding "execution context" to proxy invocation handler.
    MyService proxy1 = ignite.services().serviceProxy("svc", MyService.class, 
false, ctx1, 0);
    MyService proxy2 = ignite.services().serviceProxy("svc", MyService.class, 
false, ctx2, 0);

    // Invoke service methods with argument "10".
    assert proxy1.multiply(2) == 10 * 2;
    assert proxy1.divide(2) == 10 / 2;

    // Invoke service methods with argument "6".
    assert proxy2.multiply(2) == 6 * 2;
    assert proxy2.divide(2) == 6 / 2;
...
{code}
Sample code for reading "execution context".
{code:java}
class MyServiceImpl implements MyService {
    @LoggerResource
    private IgniteLogger log;

    @Override public int multiply(int arg2) {
        // Getting proxy context.
        ServiceProxyContext ctx = ServiceProxyContext.current();

        // Reading attributes.
        int arg1 = ctx.attribute("arg1");
        String userId = ctx.attribute("usr");

        log.info(String.format("user=%s, oper=%s, a=%d, b=%d", userId, 
"multiply", arg1, arg2));

        return arg1 * arg2;
    }

    @Override public int divide(int arg2) {
        // Getting proxy context.
        ServiceProxyContext ctx = ServiceProxyContext.current();

        // Reading attributes.
        int arg1 = ctx.attribute("arg1");
        String userId = ctx.attribute("usr");

        log.info(String.format("user=%s, oper=%s, a=%d, b=%d", userId, 
"divide", arg1, arg2));

        return arg1 / arg2;
    }

    ...
}
{code}


> Ability to set custom execution context for Ignite service.
> -----------------------------------------------------------
>
>                 Key: IGNITE-15572
>                 URL: https://issues.apache.org/jira/browse/IGNITE-15572
>             Project: Ignite
>          Issue Type: New Feature
>          Components: managed services
>            Reporter: Pavel Pereslegin
>            Assignee: Pavel Pereslegin
>            Priority: Major
>              Labels: ise
>          Time Spent: 20m
>  Remaining Estimate: 0h
>
> In traditional microservices, we have the ability to set a custom execution 
> context.
>  For example, a REST service may obtain the session ID from the request. We 
> can say that each client request, in this case, has a set of explicit and 
> implicit parameters. One of the implicit parameters is a session identifier 
> that can be passed to the service using request headers.
> It would be nice to have a similar feature in Ignite services.
> The basic idea behind the implementation:
>  1. Allow the user to bind the "execution context" to the service proxy 
> object.
>  2. Pass this context as an additional implicit parameter each time the user 
> service method is called.
> h3. API proposal.
> h4. 1. Using special class ServiceRequestContext (ServiceProxyContext).
> {code:java}
> MyService proxy = ignite.services().serviceProxy("svc", MyService.class, 
> false, new ServiceRequestContext("login", "user1"), 0);
> public class MyServiceImpl implements MyService {
>     @Override public void businessMethod() {
>         // Read thread local context.
>         ServiceRequestContext ctx = ServiceRequestContext.current();
>         String user = ctx.attribute("login");
>     }
>       ...
> }
> {code}
> h4. 2. Pass Map directly and read it using special annotation.
> {code:java}
> MyService proxy = ignite.services().serviceProxy("svc", MyService.class, 
> false, Collections.singletonMap("login", "user1"), 0);
> public class MyServiceImpl implements MyService {
>     @ServiceRequestContextResource
>     Supplier<Map<String, Object>> ctxSupplier.
>       
>     @Override public void businessMethod() {
>         Map<String, Object> ctx = ctxSupplier.get();
>         String user = ctx.attribute("login");
>     }
>     ...
> }
> {code}
> h4. 3. Pass Map directly and read it using the special ServiceContext method.
> {code:java}
> MyService proxy = ignite.services().serviceProxy("svc", MyService.class, 
> false, Collections.singletonMap("login", "user1"), 0);
> public class MyServiceImpl implements MyService {
>     private ServiceContext svcCtx;
>     @Override public void init(ServiceContext svcCtx) {
>         this.ctx = svcCtx;
>     }
>       
>     @Override public void businessMethod() {
>         Map<String, Object> ctx = ctx.attributes();
>               
>         String user = ctx.attribute("login");
>     }
>     ...
> }
> {code}
>  
>  
>  
>  
>  
> h4. A more complex example of using "execution context".
> {code:java}
>     // Creating service proxy invocation context with two attributes.
>     ServiceProxyContext ctx1 = new ServiceProxyContextBuilder("arg1", 
> 10).put("usr", "X").build();
>     ServiceProxyContext ctx2 = new ServiceProxyContextBuilder("arg1", 
> 6).put("usr", "X").build();
>     // Binding "execution context" to proxy invocation handler.
>     MyService proxy1 = ignite.services().serviceProxy("svc", MyService.class, 
> false, ctx1, 0);
>     MyService proxy2 = ignite.services().serviceProxy("svc", MyService.class, 
> false, ctx2, 0);
>     // Invoke service methods with argument "10".
>     assert proxy1.multiply(2) == 10 * 2;
>     assert proxy1.divide(2) == 10 / 2;
>     // Invoke service methods with argument "6".
>     assert proxy2.multiply(2) == 6 * 2;
>     assert proxy2.divide(2) == 6 / 2;
> ...
> {code}
> Sample code for reading "execution context".
> {code:java}
> class MyServiceImpl implements MyService {
>     @LoggerResource
>     private IgniteLogger log;
>     @Override public int multiply(int arg2) {
>         // Getting proxy context.
>         ServiceProxyContext ctx = ServiceProxyContext.current();
>         // Reading attributes.
>         int arg1 = ctx.attribute("arg1");
>         String userId = ctx.attribute("usr");
>         log.info(String.format("user=%s, oper=%s, a=%d, b=%d", userId, 
> "multiply", arg1, arg2));
>         return arg1 * arg2;
>     }
>     @Override public int divide(int arg2) {
>         // Getting proxy context.
>         ServiceProxyContext ctx = ServiceProxyContext.current();
>         // Reading attributes.
>         int arg1 = ctx.attribute("arg1");
>         String userId = ctx.attribute("usr");
>         log.info(String.format("user=%s, oper=%s, a=%d, b=%d", userId, 
> "divide", arg1, arg2));
>         return arg1 / arg2;
>     }
>     ...
> }
> {code}



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

Reply via email to