Implicit arguments passing between microservices

There is an option to pass some additional arguments not by method call and it's arguments. There is special interface called JLupinInputParameterVariablesProducer which can be implemented to pass some additional parameters. Let's see example to show what it's all about.

Native microservice interface

public interface DigestService {
    MyDigest getMD5DigestWithParameters(String name, String surname) throws Throwable;
}

Native microservice implementation

@Service("digestService")
public class DigestServiceImpl implements DigestService {
    private final Logger logger = LoggerFactory.getLogger(DigestServiceImpl.class);

    @Override
    public MyDigest getMD5DigestWithParameters(String name, String surname) throws Throwable {
        final JLupinInputParameter jLupinInputParameter = JLupinUtil.getJLupinServiceContext().getJLupinInputParameter();
        final Object contextObject = jLupinInputParameter.getContextObject();

        final MyDigest myDigest = new MyDigest();
        myDigest.setDigest(JLupinSecurityUtil.getMD5DigestAsHexString(
            name + "|" + surname) + " toString() from contextObject=" + contextObject.toString()
        );

        return myDigest;
    }

As you can see from call context you can get JLupinInputParameter object which contains additional parameters. In this example contextObject is retrieved. But the question is how to set them by the calling microservice. Let's move to the servlet microservice which will call our service.

Servlet microservice configuration

Generate standard beans for configuration with native microservice. Below you can see implementation which produces implicit parameters for remote calls.

public class MicroserviceApplicationConfiguration {

    @Auto wired
    private HttpSession httpSession;

    @Bean
    public JLupinDelegator getJLupinDelegator() {
        return JLupinClientUtil.generateInnerMicroserviceLoadBalancerDelegator(PortType.JLRMC);
    }

    @Bean(name = "digestServiceWithParameterProducer")
    public DigestService getDigestServiceWithParameterProducer() {
        final JLupinProxyObjectProducer jLupinProxyObjectProducer = JLupinClientUtil.generateRemote(
            getJLupinDelegator(),
            "sampleNativeMicroservice",
            "digestService",
            DigestService.class,
            new JLupinInputParameterVariablesProducer() {
                @Override
                public String produceSessionId() {
                    return httpSession.getId();
                }

                @Override
                public String produceRequestId() {
                    return "requestId";
                }

                @Override
                public String produceClientApplicationName() {
                    return "clientApplicationName";
                }

                @Override
                public String produceIp() {
                    return "192.168.0.1";
                }

                @Override
                public Locale produceLocale() {
                    return "en";
                }

                @Override
                public String produceUser() {
                    return "user";
                }

                @Override
                public String[] producePrivilegesName() {
                    return new String[]{ "USER" };
                }

                @Override
                public Object produceTransactionObject() {
                    return "transactionObject";
                }

                @Override
                public Object produceContextObject() {
                    return new String("session id from spring controller:" + httpSession.getId());
                }

                @Override
                public String produceMonitoringId() {
                    return "monitoringId";
                }
            }
        );

        return jLupinProxyObjectProducer.produceObject(DigestService.class);
    }
}

Above only context object is generated. It can be any object, including lists, etc. The only requirement is that this object must serializable. Of course you can implement every method above to set parameters you want.

Servlet controller implementation

Service call looks same as without JLupinInputParameterVariablesProducer. You just call your microservice method. Methods of JLupinInputParameterVariablesProducer are executed for each method call by JLupin library.

@RestController
public class DigestController {
    private final Logger logger = LoggerFactory.getLogger(DigestController.class);

    @Autowired
    @Qualifier("digestServiceWithParameterProducer")
    private DigestService digestServiceWithParameters;

    @PostMapping("/digestRemoteWithParameters")
    public DigestResponse digestRemoteWithParameters(@RequestBody DigestRequest digestRequest) throws Throwable {
        final MyDigest myDigest = digestServiceWithParameters.getMD5DigestWithParameters(digestRequest.getName(), digestRequest.getSurname());
        return new DigestResponse(myDigest.getDigest());
    }
}

Flow description

Let's sum up what is happening when you make your request. Firstly DigestController is executing it's method digestRemoteWithParameters. Inside method generated proxy (with JLupinInputParameterVariablesProducer) is called. So JLupin library prepares serialized object to send to native microservice. It is calling each method of JLupinInputParameterVariablesProducer and put results into this prepared serialized object. Then object is send to your native microservice. Next step is to handle method invocation by native microservice. It receives serialized object, deserialize it and puts every variable inside it's call context. Then checks what method and what service is needed to execute. In our example it is digestService and method getMD5DigestWithParameters. So it is called by JLupin (remember that we are already on native microservice side of communication). Because received implicit parameters were set in call context they can be retrieved from JLupinInputParameter. Here we take context object and passes it into MyDigest with name and surname. So method execution is done. It's result is serialized and sent back to servlet microservice. On servlet microservice side generated remote deserializes received result and returns it. Result is saved to variable myDigest and returned from controller.