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

Overview

This tutorial will show you how to create native microservice for JLupin Next Server 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 Next Server version 1.4.0.1. 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>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.shade.plugin.version>3.0.0</maven.shade.plugin.version>
        <jlupin.next.server.maven.plugin.version>1.0.0</jlupin.next.server.maven.plugin.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.9.RELEASE</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.jlupin</groupId>
            <artifactId>jlupin-client-assembly</artifactId>
            <version>1.4.0.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <!-- disable maven deploy plugin -->
        <plugins>
            <plugin>
                <artifactId>maven-deploy-plugin</artifactId>
                <version>2.8.2</version>
                <executions>
                    <execution>
                        <id>default-deploy</id>
                        <phase>none</phase>
                    </execution>
                </executions>
            </plugin>
        </plugins>

        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-shade-plugin</artifactId>
                    <version>${maven.shade.plugin.version}</version>
                    <executions>
                        <execution>
                            <id>include-all-artifacts-with-same-group-id</id>
                            <phase>package</phase>
                            <goals>
                                <goal>shade</goal>
                            </goals>
                            <configuration>
                                <filters>
                                    <filter>
                                        <artifact>${project.groupId}:*</artifact>
                                        <includes>
                                            <include>**</include>
                                        </includes>
                                    </filter>
                                </filters>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
                <plugin>
                    <groupId>com.jlupin</groupId>
                    <artifactId>jlupin-next-server-maven-plugin</artifactId>
                    <version>${jlupin.next.server.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>
                            <goals>
                                <goal>deploy</goal>
                            </goals>
                        </execution>
                    </executions>
                </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>

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

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>com.jlupin</groupId>
                <artifactId>jlupin-next-server-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 Next Server 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
|  |                 |
|  |                 +--configuration
|  |                 |
|  |                 +--service
|  |                    |
|  |                    +--impl
|  |
|  +--pom.xml
|
+--interfaces
|  |
|  +--src
|  |  |
|  |  +--main
|  |     |
|  |     +--java
|  |        |
|  |        +--com
|  |           |
|  |           +--example
|  |              |
|  |              +--application
|  |                 |
|  |                 +--service
|  |                    |
|  |                    +--interfaces
|  |
|  +--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. Also add method for asynchronous invocation. It should log name of user which requested 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);
    void logName(final String name);
}
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") + "!");
    }

    public void logName(final String name) {
        // do nothing for this tutorial
    }
}

Since now we haven't added anything special for JLupin Next Server, not even the smallest annotation. But now we want to expose our service for remote access so we need to tell JLupin Next Server 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 Next Server. 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: 0
    receiveBufferSize: 0
    isReuseAddress: false
    threadPoolSize: 128
    isLogPeriodicOnDebug: true
    isDestroyThreadOnTimeout: false
    threadExecutingTimeOut: 240000
  TRANSMISSION:
    readTimeout: 480000
    isWaitForFinishExecuteAllRequests: false
    waitToShutdownThreadsOnStop: 60000
    backlog: 0
    receiveBufferSize: 0
    isReuseAddress: false
    threadPoolSize: 8
    isLogPeriodicOnDebug: true
    isDestroyThreadOnTimeout: false
    threadExecutingTimeOut: 3600000
  QUEUE:
     readTimeout: 480000
     isWaitForFinishExecuteAllRequests: true
     waitToShutdownThreadsOnStop: 60000
     backlog: 0
     receiveBufferSize: 0
     isReuseAddress: false
     threadPoolSize: 128
     isLogPeriodicOnDebug: true
     isDestroyThreadOnTimeout: false
     threadExecutingTimeOut: 240000
PROPERTIES:
  #jvmOptions1: '-Xms128M -Xmx256M -agentlib:jdwp=transport=dt_socket,address=12998,server=y,suspend=y'
  jvmOptions1: '-Xms128M -Xmx256M' #jvmOptions_2 - default the same as jvmOptions_1
  #jvmOptions2: '-Xms128M -Xmx256M'
  switchDelayTime: 0
  connectionSocketTimeoutInMillis: 1000
  readTimeoutInMillis: 30000
  expectedCheckResponseTimeInMillis: 2000
  isKeepAlive: false
  isOOBInline: false
  isTcpNoDelay: false
  isReuseAddress: false
  sendBufferSize: 0
  receiveBufferSize: 0
  soLinger: 0
  trafficClass: 0
  #startProcessCommand: c:\\jvm\\bin\\java.exe -Xms128M -Xmx256M - for custom path to JVM
  waitForProcessInitResponseTimeInMillis: 90000
  waitForProcessStartResponseTimeInMillis: 90000
  waitForProcessDestroyResponseTimeInMillis: 30000
  isAllFilesToJVMAppClassLoader: false
  isStackDumping: true
  isArchiveOnStart: false
  startLogMode: INFO
APPLICATION:
  applicationContainerProducerClassName: 'com.example.application.configuration.JLupinConfiguration'
INITIALIZING_LOGGER:
  #directoryPath: '/logs/server'
  #fileName: 'file_name'
  fileExtension: 'log'
  fileSizeInMB: 20
  maxFiles: 10

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 (Log4j). Example configuration with asynchronous appender below. Put this into log4j.xml file inside additional-files directory.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<!-- ===================================================================== -->
<!--                                                                       -->
<!--  Log4j Configuration                                                  -->
<!--                                                                       -->
<!-- ===================================================================== -->

<!--
   | For more configuration information and examples see the Jakarta Log4j
   | owebsite: http://jakarta.apache.org/log4j
 -->

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">

    <!-- ================================= -->
    <!-- Preserve messages in a local file -->
    <!-- ================================= -->

    <!-- A time/startCommandExecuteDate based rolling appender -->
    <appender name="FILE" class="org.apache.log4j.DailyRollingFileAppender">
        <param name="File" value="../logs/server/microservice/welcome-microservice/microservice.log"/>
        <param name="Append" value="true"/>

        <!-- Rollover at the top of each hour -->
        <param name="DatePattern" value="'.'yyyy-MM-dd"/>
        <!--param name="MaxFileSize" value="200MB"/-->
        <!-- Keep one backup file -->
        <!--param name="MaxBackupIndex" value="10"/-->

        <layout class="org.apache.log4j.PatternLayout">
            <!-- The default pattern: Date Priority [Category] (Thread) Messagen -->
            <param name="ConversionPattern" value="%d %-5p [%c] (%t)  %m%n"/>
        </layout>
    </appender>

    <appender name="ASYNC_FILE" class="org.apache.log4j.AsyncAppender">
        <param name="BufferSize" value="1000"/>
        <appender-ref ref="FILE"/>
    </appender>

    <!-- ======================= -->
    <!-- Setup the Root category -->
    <!-- ======================= -->

    <root>
        <priority value="debug"/>
        <appender-ref ref="ASYNC_FILE"/>
    </root>

</log4j: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 deploy --projects implementation --also-make

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

./control.sh microservice list
Zone     Node    Microservice                                    #Services  Context
default  NODE_1  currency-converter-business-logic-microservice  1          /jlns/zone/default/NODE_1/currency-converter-business-logic-microservice
default  NODE_1  portal-access                                   N/A        /jlns/zone/default/NODE_1/portal-access
default  NODE_1  welcome-microservice                            1          /jlns/zone/default/NODE_1/welcome-microservice

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          Status
default  NODE_1  welcome-microservice  RUNNING

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
|  |     |           |
|  |     |           +--util
|  |     |
|  |     +--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>

    <dependencies>
        <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>1.4.0.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</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 util class which generates delegators.

package com.example.application.util;

import com.jlupin.common.communication.common.various.JLupinMainServerInZoneConfiguration;
import com.jlupin.impl.balancer.ext.impl.roundrobin.JLupinRoundRobinLoadBalancerImpl;
import com.jlupin.impl.balancer.structures.property.JLupinLoadBalancerProperties;
import com.jlupin.impl.balancer.structures.wrapper.JLupinLoadBalancerPropertiesWrapper;
import com.jlupin.impl.balancer.type.JLupinBalancerType;
import com.jlupin.impl.client.delegator.balance.JLupinQueueLoadBalancerDelegatorImpl;
import com.jlupin.impl.client.delegator.balance.JLupinRMCLoadBalancerDelegatorImpl;
import com.jlupin.impl.logger.impl.log4j.JLupinLoggerOverLog4jImpl;
import com.jlupin.impl.serialize.JLupinFSTSerializerImpl;
import com.jlupin.interfaces.logger.JLupinLogger;
import com.jlupin.interfaces.serialize.JLupinSerializer;

public class JLupinTestConfigurationUtil {
    public JLupinRMCLoadBalancerDelegatorImpl generateJLupinRMCLoadBalancerDelegatorImpl(int howOftenCheckingServerInMillis, int repeatsAmount,
                                                                                         int changeServerIntervalInMillis) {
        final JLupinSerializer jLupinSerializer = JLupinFSTSerializerImpl.getInstance();

        final JLupinRoundRobinLoadBalancerImpl jLupinLoadBalancer = generateJLupinRoundRobinLoadBalancerImpl(
                howOftenCheckingServerInMillis,
                repeatsAmount,
                changeServerIntervalInMillis
        );
        jLupinLoadBalancer.start();

        return new JLupinRMCLoadBalancerDelegatorImpl(jLupinLoadBalancer, jLupinSerializer);
    }

    public JLupinQueueLoadBalancerDelegatorImpl generateJLupinQueueLoadBalancerDelegatorImpl(int howOftenCheckingServerInMillis, int repeatsAmount,
                                                                                             int changeServerIntervalInMillis) {
        final JLupinSerializer jLupinSerializer = JLupinFSTSerializerImpl.getInstance();

        final JLupinRoundRobinLoadBalancerImpl jLupinLoadBalancer = generateJLupinRoundRobinLoadBalancerImpl(
                howOftenCheckingServerInMillis,
                repeatsAmount,
                changeServerIntervalInMillis
        );
        jLupinLoadBalancer.start();

        return new JLupinQueueLoadBalancerDelegatorImpl(jLupinLoadBalancer, jLupinSerializer);
    }

    private JLupinRoundRobinLoadBalancerImpl generateJLupinRoundRobinLoadBalancerImpl(int howOftenCheckingServerInMillis, int repeatsAmount,
                                                                                      int changeServerIntervalInMillis) {
        final JLupinLogger jLupinLogger = JLupinLoggerOverLog4jImpl.getInstance();

        final JLupinLoadBalancerProperties jLupinLoadBalancerProperties = new JLupinLoadBalancerProperties();
        jLupinLoadBalancerProperties.setJLupinMainServerInZoneConfigurations(new JLupinMainServerInZoneConfiguration[]{
                new JLupinMainServerInZoneConfiguration("NODE_1", "127.0.0.1", 9090, 9095, 9096, 9097)
        });

        final JLupinLoadBalancerPropertiesWrapper jLupinLoadBalancerPropertiesWrapper = new JLupinLoadBalancerPropertiesWrapper();
        jLupinLoadBalancerPropertiesWrapper.setJLupinLoadBalancerProperties(jLupinLoadBalancerProperties);

        final JLupinRoundRobinLoadBalancerImpl jLupinLoadBalancer = new JLupinRoundRobinLoadBalancerImpl(
                jLupinLogger,
                howOftenCheckingServerInMillis,
                repeatsAmount,
                changeServerIntervalInMillis
        );
        jLupinLoadBalancer.setJLupinBalancerType(JLupinBalancerType.OUTER_CLIENT);
        jLupinLoadBalancer.setJLupinLoadBalancerPropertiesWrapper(jLupinLoadBalancerPropertiesWrapper);

        return jLupinLoadBalancer;
    }
}

This util class is configured to make requests to localhost with default JLupin Next Server ports' configuration. You can also see that balancer with Round Robin algorithm is used. Now create test class.

package com.example.application;

import com.example.application.service.interfaces.WelcomeService;
import com.example.application.util.JLupinTestConfigurationUtil;
import com.jlupin.impl.client.proxy.remote.producer.ext.JLupinRemoteProxyObjectSupportsExceptionProducerImpl;
import com.jlupin.impl.logger.impl.log4j.JLupinLoggerOverLog4jImpl;
import com.jlupin.interfaces.client.delegator.JLupinDelegator;
import com.jlupin.interfaces.client.delegator.exception.JLupinDelegatorException;
import com.jlupin.interfaces.client.proxy.producer.JLupinProxyObjectProducer;
import com.jlupin.interfaces.common.to.JLupinInputParameter;
import com.jlupin.interfaces.common.to.JLupinOutputParameter;
import com.jlupin.interfaces.logger.JLupinLogger;
import org.junit.Test;

import java.util.Collections;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;

public class IntegrationTest {
    private static final int HOW_OFTEN_CHECKING_SERVER_IN_MILLIS = 5000;
    private static final int REPEATS_AMOUNT = 3;
    private static final int CHANGE_SERVER_INTERVAL_IN_MILLIS = 5000;

    private static JLupinLogger getJLupinLogger() {
        return JLupinLoggerOverLog4jImpl.getInstance();
    }

    private JLupinDelegator getJLupinRMCDelegator() {
        final JLupinTestConfigurationUtil jLupinConfigurationUtil = new JLupinTestConfigurationUtil();
        return jLupinConfigurationUtil.generateJLupinRMCLoadBalancerDelegatorImpl(
                HOW_OFTEN_CHECKING_SERVER_IN_MILLIS,
                REPEATS_AMOUNT,
                CHANGE_SERVER_INTERVAL_IN_MILLIS
        );
    }

    private JLupinDelegator getJLupinQueueDelegator() {
        final JLupinTestConfigurationUtil jLupinConfigurationUtil = new JLupinTestConfigurationUtil();
        return jLupinConfigurationUtil.generateJLupinQueueLoadBalancerDelegatorImpl(
                HOW_OFTEN_CHECKING_SERVER_IN_MILLIS,
                REPEATS_AMOUNT,
                CHANGE_SERVER_INTERVAL_IN_MILLIS
        );
    }

    private JLupinProxyObjectProducer getJLupinProxyObjectProducer() {
        return new JLupinRemoteProxyObjectSupportsExceptionProducerImpl(
                "welcome-microservice", getJLupinRMCDelegator(), getJLupinLogger()
        );
    }

    @Test
    public void exampleTest() {
        WelcomeService service = getJLupinProxyObjectProducer().produceObject(WelcomeService.class);
        assertEquals(Collections.singletonMap("message", "Hello Piotr!"), service.getWelcomeMessage(Collections.singletonMap("name", "Piotr")));
    }

    @Test
    public void exampleTestQueue() {
        final JLupinInputParameter jLupinInputParameter = new JLupinInputParameter();
        jLupinInputParameter.setApplicationName("welcome-microservice");
        jLupinInputParameter.setServiceName("welcomeService");
        jLupinInputParameter.setMethodName("logName");
        jLupinInputParameter.setAsynchronousBusName("simpleBus");
        jLupinInputParameter.setParamArray(new Object[] { "Piotr" });

        final JLupinOutputParameter jLupinOutputParameter;
        try { 
            jLupinOutputParameter = getJLupinQueueDelegator().delegate(jLupinInputParameter);
            final String taskId = (String) jLupinOutputParameter.getResultObject();
            assertNotNull(taskId);
        } catch (JLupinDelegatorException e) {
            e.printStackTrace();
            fail(e.getMessage());
        }
    }
}

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. Second test is using built-in queues. The queue called simpleBus is configured in JLupin Next Server by default. Test calls logName method asynchronously and gets its task id. This id can be useful when debugging or looking for particular request in log files.

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

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<!-- ===================================================================== -->
<!--                                                                       -->
<!--  Log4j Configuration                                                  -->
<!--                                                                       -->
<!-- ===================================================================== -->

<!--
   | For more configuration information and examples see the Jakarta Log4j
   | owebsite: http://jakarta.apache.org/log4j
 -->

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">

    <!-- ================================= -->
    <!-- Preserve messages in a local file -->
    <!-- ================================= -->

    <!-- A time/startCommandExecuteDate based rolling appender -->
    <appender name="FILE" class="org.apache.log4j.ConsoleAppender">
        <param name="Target" value="System.out"/>

        <layout class="org.apache.log4j.PatternLayout">
            <!-- The default pattern: Date Priority [Category] (Thread) Messagen -->
            <param name="ConversionPattern" value="%d %-5p [%c] (%t)  %m%n"/>
        </layout>
    </appender>

    <appender name="ASYNC_FILE" class="org.apache.log4j.AsyncAppender">
        <param name="BufferSize" value="1000"/>
        <appender-ref ref="FILE"/>
    </appender>

    <!-- ======================= -->
    <!-- Setup the Root category -->
    <!-- ======================= -->

    <root>
        <priority value="debug"/>
        <appender-ref ref="ASYNC_FILE"/>
    </root>

</log4j:configuration>

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

mvn clean test --projects integration-test --also-make
[INFO] Scanning for projects...
[..]
-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running com.example.application.IntegrationTest
2017-07-21 15:20:42,552 INFO  [com.jlupin.impl.balancer.base.JLupinBaseLoadLoadBalancer$2] (pool-1-thread-1)  MESSAGE ID:142 METHOD:call LINE:507 LOG:microservice discovery control thread started correctly
2017-07-21 15:20:42,552 INFO  [com.jlupin.impl.balancer.ext.impl.roundrobin.JLupinRoundRobinLoadBalancerImpl$1] (pool-2-thread-1)  MESSAGE ID:52 METHOD:call LINE:83 LOG:compute current node thread started correctly
2017-07-21 15:20:42,908 INFO  [com.jlupin.impl.balancer.base.JLupinBaseLoadLoadBalancer$2] (pool-4-thread-1)  MESSAGE ID:142 METHOD:call LINE:507 LOG:microservice discovery control thread started correctly
2017-07-21 15:20:42,908 INFO  [com.jlupin.impl.balancer.ext.impl.roundrobin.JLupinRoundRobinLoadBalancerImpl$1] (pool-5-thread-1)  MESSAGE ID:52 METHOD:call LINE:83 LOG:compute current node thread started correctly
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.764 sec
Results :
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 13.498 s
[INFO] Finished at: 2017-07-21T15:20:42+02:00
[INFO] Final Memory: 21M/218M
[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 Next Server 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 Next Server 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.

RATE & DISCUSS (0)

No comments found.