HTTP Elastic API

HTTP Elastic API is an automated text communication entry point. It is used to call remotely enabled services. By default it is exposed by Main Server on port 8082.

Figure 1. Exposed HTTP Elastic API entry point for native microservice.

HTTP Elastic API is only exposed for native (nativeApp) microservices. For servlet (servletApp) microservices it is not possible to expose it as microservices are handling all incoming http requests by themselves.

Example application

For all examples in this chapter will be used example application which consists of files listed below:

Input object class:

package com.example.service.pojo;

import com.thoughtworks.xstream.annotations.XStreamAlias;

@XStreamAlias("mulInput")
public class MulInput {
    private Integer a;
    private Integer b;

    public void setA(Integer a) {
        this.a = a;
    }

    public Integer getA() {
        return a;
    }

    public void setB(Integer b) {
        this.b = b;
    }

    public Integer getB() {
        return b;
    }
}

Output object class:

package com.example.service.pojo;

import com.thoughtworks.xstream.annotations.XStreamAlias;

@XStreamAlias("mulOutput")
public class MulOutput {
    private Integer result;

    public void setResult(Integer result) {
        this.result = result;
    }

    public Integer getResult() {
        return result;
    }
}

Service interface:

package com.example.service.interfaces;

import com.example.service.pojo.MulInput;
import com.example.service.pojo.MulOutput;

public interface MultiplierService {
    Integer mulOne(Integer a, Integer b);
    MulOutput mulTwo(MulInput mulInput);
    Integer mulThree(MulInput mulInput);
    MulOutput mulFour(Integer a, Integer b);
}

Service implementation:

package com.example.service.impl;

import com.example.service.interfaces.MultiplierService;
import com.example.service.pojo.MulInput;
import com.example.service.pojo.MulOutput;
import org.springframework.stereotype.Service;

@Service(value = "multiplierService")
public class MultiplierServiceImpl implements MultiplierService {
    @Override
    public Integer mulOne(Integer a, Integer b) {
        return a * b;
    }

    @Override
    public MulOutput mulTwo(MulInput mulInput) {
        final MulOutput mulOutput = new MulOutput();
        mulOutput.setResult(mulInput.getA() * mulInput.getB());
        return mulOutput;
    }

    @Override
    public Integer mulThree(MulInput mulInput) {
        return mulInput.getA() * mulInput.getB();
    }

    @Override
    public MulOutput mulFour(Integer a, Integer b) {
        final MulOutput mulOutput = new MulOutput();
        mulOutput.setResult(a * b);
        return mulOutput;
    }
}

Spring configuration file:

package com.example.configuration;

import com.example.service.pojo.MulInput;
import com.example.service.pojo.MulOutput;
import com.jlupin.impl.client.util.JLupinClientUtil;
import com.jlupin.interfaces.client.delegator.JLupinDelegator;
import com.jlupin.interfaces.common.enums.PortType;
import com.thoughtworks.xstream.XStream;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PreDestroy;
import java.util.ArrayList;
import java.util.List;

@Configuration
@ComponentScan("com.example")
public class ExampleSpringConfiguration {

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


    @Bean(name = "jLupinRegularExpressionToRemotelyEnabled")
    public List getRemotelyBeanList() {
        List<String> list = new ArrayList<>();
        list.add("multiplierService");
        // list.add("<REMOTE_SERVICE_NAME>");
        return list;
    }

    @Bean(name = "xStreamXmlSerializer")
    public XStream getXStreamXmlSerializer() {
        XStream xStream = new XStream();
        xStream.processAnnotations(MulInput.class);
        xStream.processAnnotations(MulOutput.class);
        return xStream;
    }
}

JLupin Platform configuration file:

package com.example.configuration;

import com.jlupin.impl.container.application.spring.JLupinAbstractSpringApplicationContainer;
import com.jlupin.interfaces.configuration.microservice.container.application.JLupinAbstractApplicationContainerProducer;
import com.jlupin.interfaces.container.application.JLupinApplicationContainer;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;

public class ExampleJLupinConfiguration extends JLupinAbstractApplicationContainerProducer {
    @Override
    public JLupinApplicationContainer produceJLupinApplicationContainer() {
        return new JLupinAbstractSpringApplicationContainer() {
            @Override
            public AbstractApplicationContext getAbstractApplicationContext() {
                return new AnnotationConfigApplicationContext(ExampleSpringConfiguration.class);
            }
        };
    }
}

To deploy above microservice just go to automatic or manual deploy chapter.

Using Elastic API

For Elastic API all additional parameters of invocation had been moved to request headers. Request body contains only serialized data sent to method. These way it is easy to configure your client to send proper requests. You cannot overload method names when using ElasticAPI. There are two main options to invoke service methods:

  • Remote Object API (ROA) - requires called method to have only one parameter
  • Remote Method Call (RMC) - no limits.

Headers specification

Header Description Example value
X-JLNS-API-ID API ID to tell server which facade to use. ROA, RMC (case sensitive)
X-JLNS-Privilege-Names List of privileged names separated by semicolon used with JLupinPermissionResolver to check if call is privileged. privileged1;privileged2
X-JLNS-Locale Locale for translation. en
X-JLNS-Sequence-Name Sequence name to use for deserializing method parameters. xStreamParamArrayXmlInOutSequence, xStreamParamArrayJsonInOutSequence, jacksonParamArrayXmlInOutSequence, jacksonParamArrayJsonInOutSequence
X-JLNS-Request-ID Request ID. request1
X-JLNS-Session-ID Session ID. session1
X-JLNS-User User. user1
X-JLNS-Client-Application-Name Client application name. application1
X-JLNS-IP IP address. 127.0.0.1

All above parameters are optional. By default API ID and sequence name is taken from main server configuration file:

[...]
ENTRY_POINTS:
    WEB_SERVICE_FACADE_HTTP:
        [...]
        defaultSequenceName: jacksonParamArrayJsonInOutSequence
        defaultApiId: ROA
        [...]
[...]

URL structure:

/[microserviceName]/[serviceName]/[methodName]

All requests must be invoked with method POST (also support for options is added for web browsers). Content-Type or Accept must be send to determine serialization type. Also both headers must be consistent (you can’t send JSON data and as return get XML data).

Body specification

ROA

For ROA request body is a serialized method argument. As said before through ROA only methods with one argument can be called. For example from MultiplierService only mulTwo and mulThree methods can be called. As an input they accept MulInput object.

Example for JSON (when jacksonParamArrayJsonInOutSequence is used):

{
    "a": 3,
    "b": 4
}

Example for XML (when xStreamParamArrayXmlInOutSequence is used):

<mulInput>
    <a>3</a>
    <b>4</b>
</mulInput>

RMC

For RMC request body is an array, where objects are serialized arguments. As said before through RMC you can call all your methods (remember that method names overloading is forbidden). For example from MultiplierService all methods could be called.

Example for JSON (when jacksonParamArrayJsonInOutSequence is used) for methods mulTwo and mulThree:

[
    {
        "a": 3,
        "b": 4
    }
]

Example for JSON (when jacksonParamArrayJsonInOutSequence is used) for methods mulOne and mulFour:

[
    3,
    4
]

Example for XML (when xStreamParamArrayXmlInOutSequence is used) for methods mulTwo and mulThree:

<paramArray>
    <mulInput>
        <a>3</a>
        <b>4</b>
    </mulInput>
</paramArray>

Example for XML (when xStreamParamArrayXmlInOutSequence is used) for methods mulOne and mulFour:

<paramArray>
    <int>3</int>
    <int>4</int>
</paramArray>

Example calls

Below are showed full examples of requests including request headers, body and response.

ROA

JSON

mulTwo

Request:

POST /example/multiplierService/mulTwo HTTP/1.1
Host: localhost:8082
User-Agent: curl/7.52.1
Accept: application/json
Content-Type: application/json
Content-Length: 16

{"a": 3, "b": 4}

Curl command:

curl -X POST "http://localhost:8082/example/multiplierService/mulTwo" -H "Accept: application/json" -H "Content-Type: application/json" -d '{"a": 3, "b": 4}'

Response:

{"result":12}
mulThree

Request:

POST /example/multiplierService/mulThree HTTP/1.1
Host: localhost:8082
User-Agent: curl/7.52.1
Accept: application/json
Content-Type: application/json
Content-Length: 16

{"a": 3, "b": 4}

Curl command:

curl -X POST "http://localhost:8082/example/multiplierService/mulThree" -H "Accept: application/json" -H "Content-Type: application/json" -d '{"a": 3, "b": 4}'

Response:

12

XML

mulTwo

Request:

POST /example/multiplierService/mulTwo HTTP/1.1
Host: localhost:8082
User-Agent: curl/7.52.1
Accept: application/xml
Content-Type: application/xml
X-JLNS-Sequence-Name: xStreamParamArrayXmlInOutSequence
Content-Length: 37

<mulInput><a>3</a><b>4</b></mulInput>

Curl command:

curl -X POST "http://localhost:8082/example/multiplierService/mulTwo" -H "Accept: application/xml" -H "Content-Type: application/xml" -H "X-JLNS-Sequence-Name: xStreamParamArrayXmlInOutSequence" -d '<mulInput><a>3</a><b>4</b></mulInput>'

Response:

<mulOutput>
  <result>12</result>
</mulOutput>
mulThree

Request:

POST /example/multiplierService/mulThree HTTP/1.1
Host: localhost:8082
User-Agent: curl/7.52.1
Accept: application/xml
Content-Type: application/xml
X-JLNS-Sequence-Name: xStreamParamArrayXmlInOutSequence
Content-Length: 37

<mulInput><a>3</a><b>4</b></mulInput>

Curl command:

curl -X POST "http://localhost:8082/example/multiplierService/mulThree" -H "Accept: application/xml" -H "Content-Type: application/xml" -H "X-JLNS-Sequence-Name: xStreamParamArrayXmlInOutSequence" -d '<mulInput><a>3</a><b>4</b></mulInput>'

Response:

<int>12</int>

RMC

JSON

mulOne

Request:

POST /example/multiplierService/mulOne HTTP/1.1
Host: localhost:8082
User-Agent: curl/7.52.1
Accept: application/json
Content-Type: application/json
X-JLNS-API-ID: RMC
Content-Length: 6

[3, 4]

Curl command:

curl -X POST "http://localhost:8082/example/multiplierService/mulOne" -H "Accept: application/json" -H "Content-Type: application/json" -H "X-JLNS-API-ID: RMC" -d '[3, 4]'

Response:

12
mulTwo

Request:

POST /example/multiplierService/mulTwo HTTP/1.1
Host: localhost:8082
User-Agent: curl/7.52.1
Accept: application/json
Content-Type: application/json
X-JLNS-API-ID: RMC
Content-Length: 18

[{"a": 3, "b": 4}]

Curl command:

curl -X POST "http://localhost:8082/example/multiplierService/mulTwo" -H "Accept: application/json" -H "Content-Type: application/json" -H "X-JLNS-API-ID: RMC" -d '[{"a": 3, "b": 4}]'

Response:

{"result":12}
mulThree

Request:

POST /example/multiplierService/mulThree HTTP/1.1
Host: localhost:8082
User-Agent: curl/7.52.1
Accept: application/json
Content-Type: application/json
X-JLNS-API-ID: RMC
Content-Length: 18

[{"a": 3, "b": 4}]

Curl command:

curl -X POST "http://localhost:8082/example/multiplierService/mulThree" -H "Accept: application/json" -H "Content-Type: application/json" -H "X-JLNS-API-ID: RMC" -d '[{"a": 3, "b": 4}]'

Response:

12
mulFour

Request:

POST /example/multiplierService/mulFour HTTP/1.1
Host: localhost:8082
User-Agent: curl/7.52.1
Accept: application/json
Content-Type: application/json
X-JLNS-API-ID: RMC
Content-Length: 6

[3, 4]

Curl command:

curl -X POST "http://localhost:8082/example/multiplierService/mulFour" -H "Accept: application/json" -H "Content-Type: application/json" -H "X-JLNS-API-ID: RMC" -d '[3, 4]'

Response:

{"result":12}

XML

mulOne

Request:

POST /example/multiplierService/mulOne HTTP/1.1
Host: localhost:8082
User-Agent: curl/7.52.1
Accept: application/xml
Content-Type: application/xml
X-JLNS-API-ID: RMC
X-JLNS-Sequence-Name: xStreamParamArrayXmlInOutSequence
Content-Length: 49

<paramArray><int>3</int><int>4</int></paramArray>

Curl command:

curl -X POST "http://localhost:8082/example/multiplierService/mulOne" -H "Accept: application/xml" -H "Content-Type: application/xml" -H "X-JLNS-API-ID: RMC" -H "X-JLNS-Sequence-Name: xStreamParamArrayXmlInOutSequence" -d '<paramArray><int>3</int><int>4</int></paramArray>'

Response:

<int>12</int>
mulTwo

Request:

POST /example/multiplierService/mulTwo HTTP/1.1
Host: localhost:8082
User-Agent: curl/7.52.1
Accept: application/xml
Content-Type: application/xml
X-JLNS-API-ID: RMC
X-JLNS-Sequence-Name: xStreamParamArrayXmlInOutSequence
Content-Length: 62

<paramArray><mulInput><a>3</a><b>4</b></mulInput></paramArray>

Curl command:

curl -X POST "http://localhost:8082/example/multiplierService/mulTwo" -H "Accept: application/xml" -H "Content-Type: application/xml" -H "X-JLNS-API-ID: RMC" -H "X-JLNS-Sequence-Name: xStreamParamArrayXmlInOutSequence" -d '<paramArray><mulInput><a>3</a><b>4</b></mulInput></paramArray>'

Response:

<mulOutput>
  <result>12</result>
</mulOutput>
mulThree

Request:

POST /example/multiplierService/mulThree HTTP/1.1
Host: localhost:8082
User-Agent: curl/7.52.1
Accept: application/xml
Content-Type: application/xml
X-JLNS-API-ID: RMC
X-JLNS-Sequence-Name: xStreamParamArrayXmlInOutSequence
Content-Length: 62

<paramArray><mulInput><a>3</a><b>4</b></mulInput></paramArray>

Curl command:

curl -X POST "http://localhost:8082/example/multiplierService/mulThree" -H "Accept: application/xml" -H "Content-Type: application/xml" -H "X-JLNS-API-ID: RMC" -H "X-JLNS-Sequence-Name: xStreamParamArrayXmlInOutSequence" -d '<paramArray><mulInput><a>3</a><b>4</b></mulInput></paramArray>'

Response:

<int>12</int>
mulFour

Request:

POST /example/multiplierService/mulFour HTTP/1.1
Host: localhost:8082
User-Agent: curl/7.52.1
Accept: application/xml
Content-Type: application/xml
X-JLNS-API-ID: RMC
X-JLNS-Sequence-Name: xStreamParamArrayXmlInOutSequence
Content-Length: 49

<paramArray><int>3</int><int>4</int></paramArray>

Curl command:

curl -X POST "http://localhost:8082/example/multiplierService/mulFour" -H "Accept: application/xml" -H "Content-Type: application/xml" -H "X-JLNS-API-ID: RMC" -H "X-JLNS-Sequence-Name: xStreamParamArrayXmlInOutSequence" -d '<paramArray><int>3</int><int>4</int></paramArray>'

Response:

<mulOutput>
  <result>12</result>
</mulOutput>

Architecture

Below architecture of Elastic API is shown with detailed where deserialization is taking place.

ROA

Figure 2. HTTP Elastic API ROA serialization/deserialization.

Your request is send to Main Server (1). It takes it and extracts body into String variable. Then through JLRMC (binary communication) your serialized object as a String is send to your microservice. Where deserialization is taking place (2). Appropriate serializer/deserializer is used based on chosen sequence (can be set with appropriate header in request). When object is deserialized, method is called (3) and as an argument deserialized object is passed.

Example with JSON

Request:

POST /example/multiplierService/mulTwo HTTP/1.1
Host: localhost:8082
User-Agent: curl/7.52.1
Accept: application/json
Content-Type: application/json
Content-Length: 16

{"a": 3, "b": 4}

Response:

{"result":12}

Main Server handles HTTP request and changes it to JLRMC (binary communication). Microservice receives String "{\"a\": 3, \"b\": 4}" which is deserialized by jackson json serializer/deserializer (because default sequence is jacksonParamArrayJsonInOutSequence). Then method mulTwo is executed with argument being MulInput{a=3, b=4}. The result MulOutput{result=12} is serialized by jackson json serializer/deserializer (because default sequence is jacksonParamArrayJsonInOutSequence). Then serialized result is send back to Main Server which returns it.

Example with XML

Request:

POST /example/multiplierService/mulTwo HTTP/1.1
Host: localhost:8082
User-Agent: curl/7.52.1
Accept: application/xml
Content-Type: application/xml
X-JLNS-Sequence-Name: xStreamParamArrayXmlInOutSequence
Content-Length: 37

<mulInput><a>3</a><b>4</b></mulInput>

Response:

<mulOutput>
  <result>12</result>
</mulOutput>

Main Server handles HTTP request and changes it to JLRMC (binary communication). Microservice receives String "<mulInput><a>3</a><b>4</b></mulInput>" which is deserialized by xstream xml serializer/deserializer (because used sequence is xStreamParamArrayXmlInOutSequence). Then method mulTwo is executed with argument being MulInput{a=3, b=4}. The result MulOutput{result=12} is serialized by xstream xml serializer/deserializer (because used sequence is xStreamParamArrayXmlInOutSequence). Then serialized result is send back to Main Server which returns it.

RMC

Figure 3. HTTP Elastic API RMC serialization/deserialization.

Your request is send to Main Server (1). It takes it and extracts body and divides it into separate String objects. Each array argument becomes one String. Then through JLRMC (binary communication) your serialized objects as a Strings are send to your microservice. Where deserialization is taking place (2). Appropriate serializer/deserializer is used based on chosen sequence (can be set with appropriate header in request). When objects are deserialized, method is called (3) and as an arguments deserialized objects are passed.

Example with JSON

Request:

POST /example/multiplierService/mulFour HTTP/1.1
Host: localhost:8082
User-Agent: curl/7.52.1
Accept: application/json
Content-Type: application/json
X-JLNS-API-ID: RMC
Content-Length: 6

[3, 4]

Response:

{"result":12}

Main Server handles HTTP request and changes it to JLRMC (binary communication). Microservice receives array with two Strings: "3", "4". They are deserialized (each of them separately) by jackson json serializer/deserializer (because default sequence is jacksonParamArrayJsonInOutSequence). Then method mulFour is executed with arguments being Integer{3}, Integer{4}. The result MulOutput{result=12} is serialized by jackson json serializer/deserializer (because default sequence is jacksonParamArrayJsonInOutSequence). Then serialized result is send back to Main Server which returns it.

Example with XML

Request:

POST /example/multiplierService/mulFour HTTP/1.1
Host: localhost:8082
User-Agent: curl/7.52.1
Accept: application/xml
Content-Type: application/xml
X-JLNS-API-ID: RMC
X-JLNS-Sequence-Name: xStreamParamArrayXmlInOutSequence
Content-Length: 49

<paramArray><int>3</int><int>4</int></paramArray>

Response:

<mulOutput>
  <result>12</result>
</mulOutput>

Main Server handles HTTP request and changes it to JLRMC (binary communication). Microservice receives array with two Strings: "<int>3</int>", "<int>4</int>". They are deserialized (each of them separately) by xstream xml serializer/deserializer (because used sequence is xStreamParamArrayXmlInOutSequence). Then method mulFour is executed with arguments being Integer{3}, Integer{4}. The result MulOutput{result=12} is serialized by xstream xml serializer/deserializer (because used sequence is xStreamParamArrayXmlInOutSequence). Then serialized result is send back to Main Server which returns it.

Configuring serializer/deserializer

xStreamParamArrayXmlInOutSequence

Sequence xStreamParamArrayXmlInOutSequence is looking in your application context for a bean named xStreamXmlSerializer which type is XStream. If you do not define it by yourself JLupin will provide default definition which is:

@Bean(name = "xStreamXmlSerializer")
public XStream getXStreamXmlSerializer() {
    return new XStream();
}

But if you define it by yourself you are free to configure it as you want. JLupin will always use this bean for serialization/deserialization when sequence xStreamParamArrayXmlInOutSequence is used.

xStreamParamArrayJsonInOutSequence

Sequence xStreamParamArrayJsonInOutSequence is looking in your application context for a bean named xStreamJsonSerializer which type is XStream. If you do not define it by yourself JLupin will provide default definition which is:

@Bean(name = "xStreamJsonSerializer")
public XStream getXStreamJsonSerializer() {
    return new XStream(new JettisonMappedXmlDriver());
}

But if you define it by yourself you are free to configure it as you want. JLupin will always use this bean for serialization/deserialization when sequence xStreamParamArrayJsonInOutSequence is used.

jacksonParamArrayXmlInOutSequence

Sequence jacksonParamArrayXmlInOutSequence is looking in your application context for a bean named jacksonXmlSerializer which type is XmlMapper. If you do not define it by yourself JLupin will provide default definition which is:

@Bean(name = "jacksonXmlSerializer")
public XmlMapper getJacksonXmlSerializer() {
    return new XmlMapper();
}

But if you define it by yourself you are free to configure it as you want. JLupin will always use this bean for serialization/deserialization when sequence jacksonParamArrayXmlInOutSequence is used.

jacksonParamArrayJsonInOutSequence

Sequence jacksonParamArrayJsonInOutSequence is looking in your application context for a bean named jacksonJsonSerializer which type is ObjectMapper. If you do not define it by yourself JLupin will provide default definition which is:

@Bean(name = "jacksonJsonSerializer")
public ObjectMapper getJacksonJsonSerializer() {
  return new ObjectMapper();
}

But if you define it by yourself you are free to configure it as you want. JLupin will always use this bean for serialization/deserialization when sequence jacksonParamArrayJsonInOutSequence is used.

Swagger integration

If you are using ROA you can integrate with swagger to generate documentation and client libraries. The example will use JSON message format with standard Jackson serializer. Below are shown project files:

Input object class:

package com.example.service.pojo;

public class OperationInput {
    private Integer a;
    private Integer b;

    public void setA(Integer a) {
        this.a = a;
    }

    public Integer getA() {
        return a;
    }

    public void setB(Integer b) {
        this.b = b;
    }

    public Integer getB() {
        return b;
    }
}

Output object class:

package com.example.service.pojo;

public class OperationOutput {
    private Integer result;

    public void setResult(Integer result) {
        this.result = result;
    }

    public Integer getResult() {
        return result;
    }
}

Service interface:

package com.example.service.interfaces;

import com.example.service.pojo.OperationInput;
import com.example.service.pojo.OperationOutput;

public interface CalculatorService {
    OperationOutput add(OperationInput operationInput);
    OperationOutput sub(OperationInput operationInput);
    OperationOutput mul(OperationInput operationInput);
    OperationOutput div(OperationInput operationInput);
}

Service implementation:

package com.example.service.impl;

import com.example.service.interfaces.CalculatorService;
import com.example.service.pojo.OperationInput;
import com.example.service.pojo.OperationOutput;
import org.springframework.stereotype.Service;

@Service(value = "calculaotrService")
public class CalculatorServiceImpl implements CalculatorService {
    @Override
    public OperationOutput add(OperationInput operationInput) {
        final OperationOutput operationOutput = new OperationOutput();
        operationOutput.setResult(operationInput.getA() * operationInput.getB());
        return operationOutput;
    }

    @Override
    public OperationOutput sub(OperationInput operationInput) {
        final OperationOutput operationOutput = new OperationOutput();
        operationOutput.setResult(operationInput.getA() * operationInput.getB());
        return operationOutput;
    }

    @Override
    public OperationOutput mul(OperationInput operationInput) {
        final OperationOutput operationOutput = new OperationOutput();
        operationOutput.setResult(operationInput.getA() * operationInput.getB());
        return operationOutput;
    }

    @Override
    public OperationOutput div(OperationInput operationInput) {
        final OperationOutput operationOutput = new OperationOutput();
        operationOutput.setResult(operationInput.getA() * operationInput.getB());
        return operationOutput;
    }
}

Spring configuration file:

package com.example.configuration;

import com.example.service.pojo.MulInput;
import com.example.service.pojo.MulOutput;
import com.jlupin.impl.client.util.JLupinClientUtil;
import com.jlupin.interfaces.client.delegator.JLupinDelegator;
import com.jlupin.interfaces.common.enums.PortType;
import com.thoughtworks.xstream.XStream;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PreDestroy;
import java.util.ArrayList;
import java.util.List;

@Configuration
@ComponentScan("com.example")
public class ExampleSpringConfiguration {
    @Bean
    public JLupinDelegator getJLupinDelegator() {
        return JLupinClientUtil.generateInnerMicroserviceLoadBalancerDelegator(PortType.JLRMC);
    }
    @Bean(name = "jLupinRegularExpressionToRemotelyEnabled")
    public List getRemotelyBeanList() {
        List<String> list = new ArrayList<>();
        list.add("calculatorService");
        // list.add("<REMOTE_SERVICE_NAME>");
        return list;
    }
}

JLupin Platform configuration file:

package com.example.configuration;

import com.jlupin.impl.container.application.spring.JLupinAbstractSpringApplicationContainer;
import com.jlupin.interfaces.configuration.microservice.container.application.JLupinAbstractApplicationContainerProducer;
import com.jlupin.interfaces.container.application.JLupinApplicationContainer;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;

public class ExampleJLupinConfiguration extends JLupinAbstractApplicationContainerProducer {
    @Override
    public JLupinApplicationContainer produceJLupinApplicationContainer() {
        return new JLupinAbstractSpringApplicationContainer() {
            @Override
            public AbstractApplicationContext getAbstractApplicationContext() {
                return new AnnotationConfigApplicationContext(ExampleSpringConfiguration.class);
            }
        };
    }
}

To deploy above microservice just go to automatic or manual deploy chapter.

So now we have prepared application with ROA api available. We want to create Swagger API specification file which then will be used by all Swagger tools. First of all we need to add annotations to our service implementation to tell which elements belong to API. We will use JCS Jlupin Platform Maven Plugin with goal generate-swagger.

Let's start with modifying CalculatorServiceImpl class:

package com.example.application.service.impl;

import com.example.application.service.interfaces.CalculatorService;
import com.example.application.service.pojo.OperationInput;
import com.example.application.service.pojo.OperationOutput;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.stereotype.Service;

@Api
@Service(value = "calculatorService")
public class CalculatorServiceImpl implements CalculatorService {
    @ApiOperation(value = "Add two numbers.")
    @Override
    public OperationOutput add(OperationInput operationInput) {
        final OperationOutput operationOutput = new OperationOutput();
        operationOutput.setResult(operationInput.getA() * operationInput.getB());
        return operationOutput;
    }

    @ApiOperation(value = "Subtract two numbers.")
    @Override
    public OperationOutput sub(OperationInput operationInput) {
        final OperationOutput operationOutput = new OperationOutput();
        operationOutput.setResult(operationInput.getA() * operationInput.getB());
        return operationOutput;
    }

    @ApiOperation(value = "Multiply two numbers.")
    @Override
    public OperationOutput mul(OperationInput operationInput) {
        final OperationOutput operationOutput = new OperationOutput();
        operationOutput.setResult(operationInput.getA() * operationInput.getB());
        return operationOutput;
    }

    @ApiOperation(value = "Divide two numbers.")
    @Override
    public OperationOutput div(OperationInput operationInput) {
        final OperationOutput operationOutput = new OperationOutput();
        operationOutput.setResult(operationInput.getA() * operationInput.getB());
        return operationOutput;
    }
}

@Api annotation tells that class is included into external API. @ApiOperation tells which methods are included.

Add configuration for generating Swagger API specification to pom.xml file of example microservice.

<project>
    [...]
    <build>
        [...]
        <plugins>
            [...]
            <plugin>
                <groupId>com.jlupin</groupId>
                <artifactId>jlupin-platform-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <id>default-cli</id>
                        <goals>
                            <goal>generate-swagger</goal>
                        </goals>
                        <configuration>
                            <apiSources>
                                <apiSource>
                                    <locations>${project.groupId}</locations>
                                    <info>
                                        <title>Calculator API</title>
                                        <version>${project.version}</version>
                                    </info>
                                    <swaggerDirectory>${build.directory}</swaggerDirectory>
                                </apiSource>
                            </apiSources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            [...]
        </plugins>
        [...]
    </build>
    [...]
</project>

Now generate Swagger API specification file with maven command mvn jlupin-platform:generate-swagger --projects example/implementation. You should see your swagger.json inside example-implementation target directory. Next step is to serve this file through HTTP server wich CORS support enabled. You can do this with our static-files-provider microservice. Just copy swagger.json to static directory inside microservice folder. Your file should be available at http://localhost:8000/jlupin-static-files-provider/swagger.json. Then go to Swagger UI page http://petstore.swagger.io/ and paste your url in top of the page and clock Explore. Your api should be loaded and ready to play with.

Figure 3. HTTP Elastic API with Swagger UI.