JLUPIN PLATFORM WEBSITE
tutorials
  • Rating:
  • Views: 52
  • Author: JLupin
  • Skill level: easy
  • Comments: 0

Overview

This tutorial will show you how to create native microservice for JLupin Platform. What is native microservice? It is just a microservice which uses built-in communication mechanism and Spring container to expose beans for remote calls. It sounds simple and it is. Let's start coding now.

Requirements

To complete this tutorial you will need JLupin Platform version 1.5.0.3. You can download it from here.

Configure project

When you create service which will be available to other users of your system, you probably want to tell them how to use it. If you want to allow them to call it easily you should also share your interface classes with them. But you don't want to share your implementation with them! You want to hide it from various reasons. That's why we are going to create two modules for every microservice: interfaces and implementation. Your users will have access only to interfaces module.

We will use Maven feature called reactor. It is built-in mechanism for handling multi-module project. So we are going to start with standard Maven structure.

+--implementation
|  |
|  +--src
|  |  |
|  |  +--main
|  |     |
|  |     +--java
|  |
|  +--pom.xml
|
+--interfaces
|  |
|  +--src
|  |  |
|  |  +--main
|  |     |
|  |     +--java
|  |
|  +--pom.xml
|
+--pom.xml

Below are presented pom files with proper configuration.

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <artifactId>welcome-microservice</artifactId>
    <groupId>com.example.application</groupId>
    <version>1.0.0</version>
    <packaging>pom</packaging>

    <repositories>
        <!-- Repository is also accessible using https connection: -->
        <!-- https://support.jlupin.com/maven2/ -->
        <repository>
            <id>jlupin-central</id>
            <name>jlupin</name>
            <url>http://support.jlupin.com/maven2/</url>
        </repository>
    </repositories>

    <pluginRepositories>
        <!-- Repository is also accessible using https connection: -->
        <!-- https://support.jlupin.com/maven2/ -->
        <pluginRepository>
            <id>jlupin-central</id>
            <name>jlupin</name>
            <url>http://support.jlupin.com/maven2/</url>
        </pluginRepository>
    </pluginRepositories>

    <modules>
        <module>interfaces</module>
        <module>implementation</module>
    </modules>

    <properties>
        <jlupin.platform.client.version>1.5.0.3</jlupin.platform.client.version>
        <jlupin.platform.maven.plugin.version>1.5.0.0</jlupin.platform.maven.plugin.version>
        <jlupin.skipDeploy>true</jlupin.skipDeploy>
        <maven.surefire.skipTests>false</maven.surefire.skipTests>

        <spring.context.version>5.0.8.RELEASE</spring.context.version>
        <slf4j.version>1.8.0-alpha2</slf4j.version>
        <log4j.slf4j.bridge.version>2.11.0</log4j.slf4j.bridge.version>
        <maven.failsafe.plugin.version>2.20</maven.failsafe.plugin.version>
        <maven.surefire.plugin.version>2.20</maven.surefire.plugin.version>

        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>${maven.surefire.plugin.version}</version>
                <configuration>
                    <skipTests>${maven.surefire.skipTests}</skipTests>
                </configuration>
            </plugin>
        </plugins>

        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>com.jlupin</groupId>
                    <artifactId>jlupin-platform-maven-plugin</artifactId>
                    <version>${jlupin.platform.maven.plugin.version}</version>
                    <executions>
                        <execution>
                            <id>jlupin-zip</id>
                            <goals>
                                <goal>zip</goal>
                            </goals>
                            <configuration>
                                <additionalFilesDirectories>
                                    <param>../additional-files</param>
                                </additionalFilesDirectories>
                            </configuration>
                        </execution>
                        <execution>
                            <id>jlupin-deploy</id>
                            <phase>pre-integration-test</phase>
                            <goals>
                                <goal>deploy</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>

                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-failsafe-plugin</artifactId>
                    <version>${maven.failsafe.plugin.version}</version>
                    <executions>
                        <execution>
                            <id>integration-test</id>
                            <goals>
                                <goal>integration-test</goal>
                                <goal>verify</goal>
                            </goals>
                        </execution>
                    </executions>
                    <configuration>
                        <includes>
                            <include>**/Test*.java</include>
                            <include>**/*Test.java</include>
                            <include>**/*Tests.java</include>
                            <include>**/*TestCase.java</include>
                        </includes>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

implementation/pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <artifactId>welcome-microservice</artifactId>
        <groupId>com.example.application</groupId>
        <version>1.0.0</version>
        <relativePath>../pom.xml</relativePath>
    </parent>

    <name>welcome-microservice</name>
    <artifactId>welcome-microservice-implementation</artifactId>

    <properties>
        <jlupin.skipDeploy>false</jlupin.skipDeploy>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.context.version}</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>com.example.application</groupId>
            <artifactId>welcome-microservice-interfaces</artifactId>
            <version>1.0.0</version>
        </dependency>

        <!-- JLupin dependencies -->
        <dependency>
            <groupId>com.jlupin</groupId>
            <artifactId>jlupin-client-assembly</artifactId>
            <version>${jlupin.platform.client.version}</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j-impl</artifactId>
            <version>${log4j.slf4j.bridge.version}</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>com.jlupin</groupId>
                <artifactId>jlupin-platform-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

interfaces/pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <artifactId>welcome-microservice</artifactId>
        <groupId>com.example.application</groupId>
        <version>1.0.0</version>
        <relativePath>../pom.xml</relativePath>
    </parent>

    <artifactId>welcome-microservice-interfaces</artifactId>
</project>

JLupin Maven repository is configured to get access to required artifacts. Also dependencies required for this tutorial and development are added. JLupin Platform Maven Plugin is configured to zip microservice and deploy it. Also content of additional-files is added to created zip file. You need to create this directory on same level as implementation directory. Configuration files will be placed here. You should end up with structure:

+--additional-files
|
+--implementation
|  |
|  +--src
|  |  |
|  |  +--main
|  |     |
|  |     +--java
|  |
|  +--pom.xml
|
+--interfaces
|  |
|  +--src
|  |  |
|  |  +--main
|  |     |
|  |     +--java
|  |
|  +--pom.xml
|
+--pom.xml

Microservice implementation

At first create suitable package structure. In this tutorial com.example.application will be used as main package. Recommended structure (also used by this tutorial) is presented below.

+--additional-files
|
+--implementation
|  |
|  +--src
|  |  |
|  |  +--main
|  |     |
|  |     +--java
|  |        |
|  |        +--com
|  |           |
|  |           +--example
|  |              |
|  |              +--application
|  |                 |
|  |                 +--bean
|  |                 |  |
|  |                 |  +--impl
|  |                 |  |
|  |                 |  +--interfaces
|  |                 |  |
|  |                 |  +--pojo
|  |                 |
|  |                 +--configuration
|  |                 |
|  |                 +--dao
|  |                 |  |
|  |                 |  +--impl
|  |                 |  |
|  |                 |  +--interfaces
|  |                 |  |
|  |                 |  +--pojo
|  |                 |
|  |                 +--service
|  |                    |
|  |                    +--impl
|  |
|  +--pom.xml
|
+--interfaces
|  |
|  +--src
|  |  |
|  |  +--main
|  |     |
|  |     +--java
|  |        |
|  |        +--com
|  |           |
|  |           +--example
|  |              |
|  |              +--application
|  |                 |
|  |                 +--service
|  |                    |
|  |                    +--interfaces
|  |                    |
|  |                    +--pojo
|  |
|  +--pom.xml
|
+--pom.xml

When you done with package structure create basic Spring configuration file under configuration package.

package com.example.application.configuration;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.List;

@Configuration
@ComponentScan("com.example.application")
public class SpringConfiguration {
}

Ok, we have Spring configuration file created. But our microservice does nothing. Create simple service interface and provide its implementation. Service should accept name as parameter and return welcome message. Put everything inside interfaces module.

package com.example.application.service.interfaces;

import java.util.Map;

public interface WelcomeService {
    Map<String, String> getWelcomeMessage(final Map<String, String> map);
}
package com.example.application.service.impl;

import com.example.application.service.interfaces.WelcomeService;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.Map;

@Service(value = "welcomeService")
public class WelcomeServiceImpl implements WelcomeService {
    public Map<String, String> getWelcomeMessage(final Map<String, String> map) {
        return Collections.singletonMap("message", "Hello " + map.get("name") + "!");
    }
}

Since now we haven't added anything special for JLupin Platform, not even the smallest annotation. But now we want to expose our service for remote access so we need to tell JLupin Platform that this particular service can be externally called. To do so we need to change Spring configuration file and define bean named jLupinRegularExpressionToRemotelyEnabled. This bean is just a list of strings which are regular expressions. If service name matches any of regular expressions on the list then it is exposed for external usage. Modified class is showed below.

package com.example.application.configuration;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.List;

@Configuration
@ComponentScan("com.example.application")
public class SpringConfiguration {
    @Bean(name = "jLupinRegularExpressionToRemotelyEnabled")
    public List getRemotelyBeanList() {
        List<String> list = new ArrayList<>();
        list.add("welcomeService");
        return list;
    }
}

Now we have configured Spring container with single service exposed as a remote bean. When we look at the description in the overview section it looks like everything is done. However one additional file is required. Through JLupinApplicationContainerProducer we need to create Spring ApplicationContext and return it to JLupin Platform. Required file can be found below.

package com.example.application.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 JLupinConfiguration extends JLupinAbstractApplicationContainerProducer {
    @Override
    public JLupinApplicationContainer produceJLupinApplicationContainer() {
        return new JLupinAbstractSpringApplicationContainer() {
            @Override
            public AbstractApplicationContext getAbstractApplicationContext() {
                return new AnnotationConfigApplicationContext(SpringConfiguration.class);
            }
        };
    }
}

We used annotations to configure Spring container and that's why we had created AnnotationConfigApplicationContext. You may want to use any other ApplicationContext, for example WebXmlApplicationContext. It is up to you.

Now you can create configuration.yml file and setup your microservice - example below. Put this file inside additional-files directory.

SERVERS:
  JLRMC: #JLupin Remote Method Calls Fast Protocol
    readTimeout: 480000
    isWaitForFinishExecuteAllRequests: true
    waitToShutdownThreadsOnStop: 60000
    backlog: 256
    receiveBufferSize: 256
    isReuseAddress: false
    threadPoolSize: 128
    isLogPeriodicOnDebug: true
    isDestroyThreadOnTimeout: false
    threadExecutingTimeOut: 240000
    isStartOnMainServerInitialize: true
  TRANSMISSION:
    readTimeout: 480000
    isWaitForFinishExecuteAllRequests: false
    waitToShutdownThreadsOnStop: 60000
    backlog: 0
    receiveBufferSize: 0
    isReuseAddress: false
    threadPoolSize: 8
    isLogPeriodicOnDebug: true
    isDestroyThreadOnTimeout: false
    threadExecutingTimeOut: 3600000
    isStartOnMainServerInitialize: true
  QUEUE:
    readTimeout: 480000
    isWaitForFinishExecuteAllRequests: true
    waitToShutdownThreadsOnStop: 60000
    backlog: 256
    receiveBufferSize: 256
    isReuseAddress: false
    threadPoolSize: 128
    isLogPeriodicOnDebug: true
    isDestroyThreadOnTimeout: false
    threadExecutingTimeOut: 240000
    isStartOnMainServerInitialize: true
ENTRY_POINTS:
  QUEUE:
    threadAmount: 128
    howOftenCheckingServerInMillis: 5000
    repeatsAmount: 4
    timeToWaitBetweenRepeatProbeInMillis: 1000
TRANSMISSION:
  MICROSERVICES_GRANT_ACCESS:
    MICROSERVICES_LIST:
      #- microserviceName: 'sampleMicroservice'
      #  serviceName: 'sampleServiceName'
      #  methodName: 'sampleMethodName'
      #- microserviceName: 'sampleMicroservice2'
      #  serviceName: 'sampleServiceName2'
      #  methodName: 'sampleMethodName2'
PROPERTIES:
  platformVersion: '1.5.0.3'
  #jvmOptions1: '-Xms128M -Xmx256M -agentlib:jdwp=transport=dt_socket,address=12998,server=y,suspend=n'
  jvmOptions1: '-Xms128M -Xmx256M' #jvmOptions_2 - default the same as jvmOptions_1
  #jvmOptions2: '-Xms128M -Xmx256M'
  externalPort: '8000'
  version: '1.5.0.3'
  switchDelayTime: 0
  connectionSocketTimeoutInMillis: 1000
  readTimeoutInMillis: 30000
  isKeepAlive: false
  isOOBInline: false
  isTcpNoDelay: false
  isReuseAddress: false
  sendBufferSize: 0
  receiveBufferSize: 0
  soLinger: 0
  trafficClass: 0
  #javaExecutablePath: 'c:\\jvm\\bin\\java.exe'
  #additionalClassPath: 'c:\\temp\\*'
  isStartOnMainServerInitialize: true
  priorityStartOnMainServerInitialize: 4
  waitForProcessInitResponseTimeInMillis: 90000
  waitForProcessStartResponseTimeInMillis: 90000
  waitForProcessDestroyResponseTimeInMillis: 30000
  isAllFilesToJVMAppClassLoader: false
  isArchiveOnStart: false
  startLogMode: INFO
  isInitErrorCauseWithNetworkInformation: true
  isJmxEnabled: true
  jmxOptions: '-Dcom.sun.management.jmxremote.local.only=false -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false'
  jmxPrimaryPort: -1
  jmxSecondaryPort: -1
  checkAvailableScript: 'function isAvailable(checkResponseTimeInMillis, jrmcActiveThreads, jrmcMaxThreads,
                                              queueActiveThreads, queueMaxThreads, servletActiveThreads, servletMaxThreads,
                                              jvmMaxMemoryInBytes, jvmTotalMemoryInBytes, jvmFreeMemoryInBytes,
                                              jvmProcessCpuLoadInPercentage, userAvailableFlag) {
                           var isAvailableByUser = Boolean(userAvailableFlag);
                           if(checkResponseTimeInMillis > 20000 || !isAvailableByUser) {
                             return false;
                           }
                           return true;
                         }'
APPLICATION:
  applicationContainerProducerClassName: 'com.example.application.configuration.JLupinConfiguration'
INITIALIZING_LOGGER:
  #directoryPath: '/logs/server'
  #fileName: 'file_name'
  fileExtension: 'log'
  fileSizeInMB: 20
  maxFiles: 10
MEMORY_ERRORS:
  isRestartOnError: true
  howManyTimes: 4
  percentageGrowth: 15
  isHeapDump: true
THREAD_POOLS:
  THREAD_POOL_1:
    size: 8
    waitingTimeForTasksCompletionInMillis: 10000
  #THREAD_POOL_2:
  #  size: 8
  #  waitingTimeForTasksCompletionInMillis: 10000

As you can see you must provide full name of class extending JLupinAbstractApplicationContainerProducer. And that's all. Now your microservice is ready to deploy.

You should also configure logging system (Log4j2). Example configuration with asynchronous appender below. Put this into log4j2.xml file inside additional-files directory.

<?xml version="1.0" encoding="UTF-8"?>

<!-- ===================================================================== -->
<!--                                                                       -->
<!--  Log4j2 Configuration                                                  -->
<!--                                                                       -->
<!-- ===================================================================== -->

<!--
   | For more configuration information and examples see the Apache Log4j2
   | website: https://logging.apache.org/log4j/2.x/index.html
-->

<Configuration status="WARN" dest="errors/welcome-microservice_log4j2_status.log">
    <!-- Extract log directory and file name into variables -->
    <Properties>
        <Property name="logDirectory">../logs/microservice/welcome-microservice</Property>
        <Property name="logFileName">microservice</Property>
    </Properties>

    <Appenders>
        <!-- RollingFileAppender configured to role every day -->
        <RollingFile name="FILE">
            <FileName>\${logDirectory}/\${logFileName}.log</FileName>
            <FilePattern>\${logDirectory}/\${logFileName}.%d{yyyy-MM-dd}.log</FilePattern>

            <!-- Compress log files to gzip -->
            <!-- More configuration https://logging.apache.org/log4j/2.x/manual/appenders.html#DefaultRolloverStrategy -->
            <!-- <FilePattern>${logDirectory}/${logFileName}.%d{yyyy-MM-dd}.log.gz</FilePattern> -->

            <!-- Do not truncate file -->
            <Append>true</Append>

            <!-- The default pattern: Date Priority [Category] (Thread) Message\n -->
            <PatternLayout pattern="%d %-5p [%c] (%t) %m%n" />

            <Policies>
                <!-- Rollover every microservice start - very useful for debugging -->
                <!-- <OnStartupTriggeringPolicy /> -->

                <!-- Rollover at the top of each day -->
                <TimeBasedTriggeringPolicy interval="1" modulate="true" />

                <!-- Rollover if file size is greater than 200 MB -->
                <!-- <SizeBasedTriggeringPolicy size="200 MB"/> -->
            </Policies>
            <CreateOnDemand>true</CreateOnDemand>

            <!-- Keep last 10 log files -->
            <!-- More configuration https://logging.apache.org/log4j/2.x/manual/appenders.html#DefaultRolloverStrategy -->
            <!-- <DefaultRolloverStrategy max="10" /> -->
        </RollingFile>

        <!-- AsyncAppender for high performance -->
        <Async name="ASYNC_FILE">
            <BufferSize>1000</BufferSize>
            <AppenderRef ref="FILE" />
        </Async>
    </Appenders>

    <Loggers>
        <!-- Setup for root logger with AsyncAppender -->
        <Root level="info">
            <AppenderRef ref="ASYNC_FILE" />
        </Root>
    </Loggers>
</Configuration>

Deploying microservice

Run server (start/start.sh or start/start.cmd in main server directory). Then run maven command to deploy your microservice:

mvn clean package jlupin-platform:deploy@jlupin-deploy --projects implementation --also-make

Check microservice's list to see your microservice (start/control.sh):

./control.sh microservice list
Zone    Node   Microservice            Type    Version #Services
default NODE_1 queueMicroservice       native  1.5.0.3 1
default NODE_1 exchange-rates          native  1.5.0.3 1
default NODE_1 welcome-microservice    native  1.0.0   1
default NODE_1 channelMicroservice     native  1.5.0.3 1
default NODE_1 currency-converter-gbp  native  1.5.0.3 1
default NODE_1 exchange                servlet 1.5.0.3 4
default NODE_1 http-session-repository native  1.5.0.2 2
default NODE_1 currency-converter-chf  native  1.5.0.3 1
default NODE_1 currency-converter-eur  native  1.5.0.3 1

You can see your microservice on the list. You can check its status to see if it is running.

./control.sh microservice status welcome-microservice
Zone    Node   Microservice         ProcessID Status  Available Activated
default NODE_1 welcome-microservice 9822      RUNNING yes       yes

Integration tests

Now it is time to add some integration tests and check our microservice. We will put them into separate module called integration test. Let's add it with proper test package structure:

+--additional-files
|
+--implementation
|  |
|  +--[...]
|
+--integration-test
|  |
|  +--src
|  |  |
|  |  +--test
|  |     |
|  |     +--java
|  |     |  |
|  |     |  +--com
|  |     |     |
|  |     |     +--example
|  |     |        |
|  |     |        +--application
|  |     |           |
|  |     |           +--base
|  |     |
|  |     +--resources
|  |
|  +--pom.xml
|
+--interfaces
|  |
|  +--[...]
|
+--pom.xml

integration-test/pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <artifactId>welcome-microservice</artifactId>
        <groupId>com.example.application</groupId>
        <version>1.0.0</version>
        <relativePath>../pom.xml</relativePath>
    </parent>

    <artifactId>welcome-microservice-integration-test</artifactId> 

    <properties>
        <maven.surefire.skipTests>true</maven.surefire.skipTests>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.example.application</groupId>
            <artifactId>welcome-microservice-interfaces</artifactId>
            <version>1.0.0</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.jlupin</groupId>
            <artifactId>jlupin-client-assembly</artifactId>
            <version>${jlupin.platform.client.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j-impl</artifactId>
            <version>${log4j.slf4j.bridge.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-failsafe-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

Add module into modules section inside top level pom.xml file:

[...]
    <modules>
        <module>interfaces</module>
        <module>implementation</module>
        <module>integration-test</module>
    </modules>
[...]

Now create base class with delegators.

package com.example.application.base;

import com.jlupin.common.various.JLupinMainServerInZoneConfiguration;
import com.jlupin.impl.client.util.JLupinClientUtil;
import com.jlupin.interfaces.client.delegator.JLupinDelegator;
import com.jlupin.interfaces.client.delegator.exception.JLupinDelegatorException;
import com.jlupin.interfaces.common.enums.PortType;
import org.junit.After;
import org.junit.Before;

public abstract class BaseTest {
    private final JLupinMainServerInZoneConfiguration[] mainServerInZoneConfigurations;
    private final JLupinDelegator jLupinDelegator;

    public BaseTest() {
        mainServerInZoneConfigurations = new JLupinMainServerInZoneConfiguration[]{
                new JLupinMainServerInZoneConfiguration("NODE_1", "127.0.0.1", 9090, 9095, 9096, 9097)
        };
        jLupinDelegator = JLupinClientUtil.generateOuterMicroserviceLoadBalancerDelegator(PortType.JLRMC, mainServerInZoneConfigurations);
    }

    public JLupinDelegator getJLupinDelegator() {
        return jLupinDelegator;
    }

    @Before
    public void before() {
        try {
            jLupinDelegator.start();
        } catch (JLupinDelegatorException e) {
            throw new IllegalStateException("can not start jlupin delegator caused by:", e);
        }
    }

    @After
    public void after() {
        try {
            jLupinDelegator.stop();
        } catch (JLupinDelegatorException e) {
            throw new IllegalStateException("can not stop jlupin delegator caused by:", e);
        }
        JLupinClientUtil.closeResources();
    }
}

This base class is configured to make requests to localhost with default JLupin Platform ports' configuration. You can also see that default balancer is used. Now create test class.

package com.example.application;

import com.example.application.base.BaseTest;
import com.example.application.service.interfaces.WelcomeService;
import com.jlupin.impl.client.util.JLupinClientUtil;
import org.junit.Test;

import java.util.Collections;

import static org.junit.Assert.assertEquals;

public class CurrencyConverterTest extends BaseTest {
    @Test
    public void exampleTest() {
        WelcomeService service = JLupinClientUtil.generateRemote(getJLupinDelegator(), "welcome-microservice", WelcomeService.class);
        assertEquals(Collections.singletonMap("message", "Hello Piotr!"), service.getWelcomeMessage(Collections.singletonMap("name", "Piotr")));
    }
}

Test class contains two tests. One is using JLRMC entry point (built-in remote method call protocol) to call service. Through JLupinProxyObjectProducer appropriate stub is created and assigned to service interfaces. This way remote calls are extremely easy to use. With combined power of Spring and Inversion of Control joining and splitting microservice is a piece of cake.

The last thing is to again configure logger (Log4j2) for this tests. Add log4j2.xml file to test resources.

<?xml version="1.0" encoding="UTF-8"?>

<!-- ===================================================================== -->
<!--                                                                       -->
<!--  Log4j2 Configuration                                                  -->
<!--                                                                       -->
<!-- ===================================================================== -->

<!--
   | For more configuration information and examples see the Apache Log4j2
   | website: https://logging.apache.org/log4j/2.x/index.html
-->

<Configuration status="WARN">
    <Appenders>
        <Console name="STDOUT" target="SYSTEM_OUT">
            <!-- The default pattern: Date Priority [Category] (Thread) Message\n -->
            <PatternLayout pattern="%d %-5p [%c] (%t) %m%n" />
        </Console>

        <!-- AsyncAppender for high performance -->
        <Async name="ASYNC_STDOUT">
            <BufferSize>1000</BufferSize>
            <AppenderRef ref="STDOUT" />
        </Async>
    </Appenders>

    <Loggers>
        <!-- Setup for root logger with AsyncAppender -->
        <Root level="info">
            <AppenderRef ref="ASYNC_STDOUT" />
        </Root>
    </Loggers>
</Configuration>

It is configured to write logs to standard out. Now you're ready to run tests.

mvn clean integration-test --projects integration-test --also-make
[INFO] Scanning for projects...
[..]
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.example.application.CurrencyConverterTest
2018-10-11 09:35:14,650 INFO  [com.jlupin.impl.balancer.base.JLupinBaseLoadBalancer] (main) MESSAGE ID:22 METHOD:start LINE:897 LOG:load balancer type:OUTER_CLIENT with settings:
connectionConfigurationToConnectWithLocalMicroservicesMap:{}
jLupinBalancerConnectionToMainServersAsPeersConfiguration:JLupinBalancerConnectionToServerConfiguration{address='null', jlrmcPort=0, queuePort=0, transmissionPort=0, informationPort=0, connectionTimeoutInMilliseconds=2000, readTimeoutInMilliseconds=300000, checkAvailableScript='null', isKeepAlive=false, isOOBInline=false, isTcpNoDelay=false, isReuseAddress=false, sendBufferSize=0, receiveBufferSize=0, soLinger=0, trafficClass=0} invoked from:
java.lang.Thread;getStackTrace;1559
com.jlupin.impl.util.JLupinUtil;getCurrentFullStackAsString;634
com.jlupin.impl.balancer.base.JLupinBaseLoadBalancer;<init>;128
com.jlupin.impl.balancer.ext.impl.repeat.JLupinAbstractRepeatLoadBalancer;<init>;26
com.jlupin.impl.balancer.ext.impl.roundrobin.JLupinRoundRobinLoadBalancerImpl;<init>;43
com.jlupin.impl.client.util.JLupinClientUtil;generateLoadBalancer;66
com.jlupin.impl.client.util.JLupinClientUtil;generateOuterMicroserviceLoadBalancerDelegator;131
com.example.application.base.BaseTest;<init>;19
com.example.application.CurrencyConverterTest;<init>;12
sun.reflect.NativeConstructorAccessorImpl;newInstance0;-2
sun.reflect.NativeConstructorAccessorImpl;newInstance;62
sun.reflect.DelegatingConstructorAccessorImpl;newInstance;45
java.lang.reflect.Constructor;newInstance;423
org.junit.runners.BlockJUnit4ClassRunner;createTest;217
org.junit.runners.BlockJUnit4ClassRunner$1;runReflectiveCall;266
org.junit.internal.runners.model.ReflectiveCallable;run;12
org.junit.runners.BlockJUnit4ClassRunner;methodBlock;263
org.junit.runners.BlockJUnit4ClassRunner;runChild;78
org.junit.runners.BlockJUnit4ClassRunner;runChild;57
org.junit.runners.ParentRunner$3;run;290
org.junit.runners.ParentRunner$1;schedule;71
org.junit.runners.ParentRunner;runChildren;288
org.junit.runners.ParentRunner;access$000;58
org.junit.runners.ParentRunner$2;evaluate;268
org.junit.runners.ParentRunner;run;363
org.apache.maven.surefire.junit4.JUnit4Provider;execute;365
org.apache.maven.surefire.junit4.JUnit4Provider;executeWithRerun;272
org.apache.maven.surefire.junit4.JUnit4Provider;executeTestSet;236
org.apache.maven.surefire.junit4.JUnit4Provider;invoke;159
org.apache.maven.surefire.booter.ForkedBooter;invokeProviderInSameClassLoader;386
org.apache.maven.surefire.booter.ForkedBooter;runSuitesInProcess;323
org.apache.maven.surefire.booter.ForkedBooter;main;143
started correctly
2018-10-11 09:35:14,663 INFO  [com.jlupin.impl.balancer.ext.impl.roundrobin.JLupinRoundRobinLoadBalancerImpl] (main) MESSAGE ID:52 METHOD:start LINE:111 LOG:computing node thread started correctly
2018-10-11 09:35:14,708 INFO  [com.jlupin.impl.balancer.base.JLupinBaseLoadBalancer] (main) MESSAGE ID:26 METHOD:stop LINE:1014 LOG:load balancer type:OUTER_CLIENT, load balancer type:OUTER_CLIENT correctly stopped
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.844 s - in com.example.application.CurrencyConverterTest
[INFO] 
[INFO] Results:
[INFO] 
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] 
[WARNING] File encoding has not been set, using platform encoding UTF-8, i.e. build is platform dependent! The file encoding for reports output files should be provided by the POM property ${project.reporting.outputEncoding}.
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] 
[INFO] welcome-microservice ............................... SUCCESS [  0.213 s]
[INFO] welcome-microservice-interfaces .................... SUCCESS [  2.079 s]
[INFO] welcome-microservice-integration-test .............. SUCCESS [  3.967 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 6.444 s
[INFO] Finished at: 2018-10-11T09:35:15+02:00
[INFO] Final Memory: 19M/209M
[INFO] ------------------------------------------------------------------------

Elastic API

If you want you can call same services and their methods with text communication with use of built-in Elastic API. Let's start with ROA (Remote Object Access) call:

curl -X POST -H "Content-Type: application/json" -d "{\"name\":\"Piotr\"}" localhost:8082/welcome-microservice/welcomeService/getWelcomeMessage

As a result you should see:

{"message":"Hello Piotr!"}

This way JLupin Platform deserialize whole request body into method argument and serialize its result into response body. It is similar to RestController used by Spring.

Other option is to used RMC (Remote Method Call). JLupin Platform is configured to use ROA by default, that's why we must specify api id in request header.

curl -X POST -H "Content-Type: application/json" -H "X-JLNS-Api-Id: RMC" -d "[{\"name\":\"Piotr\"}]" localhost:8082/welcome-microservice/welcomeService/getWelcomeMessage

The result is same as for ROA - return value is serialized into response body.

{"message":"Hello Piotr!"}

Elastic API calls are more precisely described in this tutorial.

Done tutorial

You can download project which is result of making this tutorial from GitHub: https://github.com/jlupin/creating-native-microservice-jlp-1503

RATE & DISCUSS (0)

No comments found.