Create microservice

Servlet (webApp) microservice

JLupin Platform supports creating web application with use of servlet containers. For this Spring Boot is used. Application created this way is also a microservice but with exposed full http API.

Simple example is shown below

package com.jlupin.sample.springboot;

import org.springframework.boot.*;
import org.springframework.boot.autoconfigure.*;
import org.springframework.stereotype.*;
import org.springframework.web.bind.annotation.*;

@Controller
@EnableAutoConfiguration
public class ExampleController {
    private final static Logger logger = LoggerFactory.getLogger(ExampleController.class);

    @RequestMapping("/")
    @ResponseBody
    String home() {
        logger.info("called home() method");
        return "Hello JLupin";
    }

    public static void main(String[] args) throws Exception {
        SpringApplication.run(ExampleController.class, args);
    }
}

Read more about Spring Boot.

Running microservice

When your microservice is done compile it into war file. Then put this file with all other required by your microservice (like servlet_configuration.yml, jlupin logger configuration file, properties file, etc.) into directory which name is your microservice name inside server/application directory. To start it just run control.sh/.cmd and type in command microservice start [your_microservice_name].

Example microservice configuration file is shown below full configuration file description:

SERVERS:
  HTTP:
    type: spring_boot
    httpPrimaryPort: -1
    httpSecondaryPort: -1
    waitForFinishExecuteAllRequests: true
    waitToShutdownThreadsOnStop: 5000
    springBootLoaderClassName: org.springframework.boot.loader.WarLauncher
    contextName: /exchange
    isStartOnMainServerInitialize: true
    httpStickySession: false
  TRANSMISSION:
    readTimeout: 480000
    isWaitForFinishExecuteAllRequests: false
    waitToShutdownThreadsOnStop: 60000
    backlog: 0
    receiveBufferSize: 0
    isReuseAddress: false
    threadPoolSize: 8
    isLogPeriodicOnDebug: true
    isDestroyThreadOnTimeout: false
    threadExecutingTimeOut: 3600000
    isStartOnMainServerInitialize: true
PROPERTIES:
  #jvmOptions1: '-Xms128M -Xmx256M -agentlib:jdwp=transport=dt_socket,address=12998,server=y,suspend=n'
  jvmOptions1: '-Xms64M -Xmx192M' #jvmOptions_2 - default the same as jvmOptions_1
  #jvmOptions2: '-Xms128M -Xmx256M'
  externalPort: '8000'
  version: '1.5.0.0'
  switchDelayTime: 1000
  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: true
  #isStackDumping: true
  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;
                           }'
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

Servlet (webApp) microservice - more complex example with Maven

JLupin Platform supports creating web application with use of servlet containers. For this Spring Boot is used. Application created this way is also a microservice but with exposed full http API.

Microservice pom.xml configuration file:

<?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>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.2.RELEASE</version>
    </parent>

    <name>example</name>
    <groupId>com.jlupin.sample.springboot</groupId>
    <artifactId>example-implementation</artifactId>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>

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

    <properties>
        <jlupin.server.version>1.5.0.0</jlupin.server.version>
        <jlupin.servlet.monitor.version>1.0.0</jlupin.servlet.monitor.version>
    </properties>

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

        <dependency>
            <groupId>com.jlupin</groupId>
            <artifactId>jlupin-spring-boot-2-servlet-monitor</artifactId>
            <version>${jlupin.servlet.monitor.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </dependency>
    </dependencies>

    <build>
        <finalName>${project.name}</finalName>

        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Section with exclusion of spring-boot-starter-logging is described in chapter Logging.

Spring Boot starter class:

package com.jlupin.sample.springboot;

import com.jlupin.sample.springboot.configuration.ExampleSpringConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootApplicationStarter {
    public static void main(String[] args) throws Exception {
        SpringApplication.run(ExampleSpringConfiguration.class, args);
    }
}

Configuration class:

package com.jlupin.sample.springboot.configuration;

import com.jlupin.impl.client.util.JLupinClientUtil;
import com.jlupin.interfaces.client.delegator.JLupinDelegator;
import com.jlupin.interfaces.common.enums.PortType;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan({
        "com.jlupin.sample.springboot",
        "com.jlupin.servlet.monitor.configuration"
})

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

Part with added package com.jlupin.servlet.monitor.configuration for component scan is to enable serlvet microservice monitoring for JLupin. For this purpose also depency to jlupin-servlet-monitor is added in pom.xml file.

Example controller class:

package com.jlupin.sample.springboot.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class ExampleController {
    private final static Logger logger = LoggerFactory.getLogger(ExampleController.class);

    @RequestMapping("/")
    @ResponseBody
    String home() {
        logger.info("called home() method");
        return "Hello JLupin";
    }
}

Create servler_configuration.yml file with microservice configuration full configuration file description:

SERVERS:
  HTTP:
    type: spring_boot
    httpPrimaryPort: -1
    httpSecondaryPort: -1
    waitForFinishExecuteAllRequests: true
    waitToShutdownThreadsOnStop: 5000
    springBootLoaderClassName: org.springframework.boot.loader.WarLauncher
    contextName: /exchange
    isStartOnMainServerInitialize: true
    httpStickySession: false
  TRANSMISSION:
    readTimeout: 480000
    isWaitForFinishExecuteAllRequests: false
    waitToShutdownThreadsOnStop: 60000
    backlog: 0
    receiveBufferSize: 0
    isReuseAddress: false
    threadPoolSize: 8
    isLogPeriodicOnDebug: true
    isDestroyThreadOnTimeout: false
    threadExecutingTimeOut: 3600000
    isStartOnMainServerInitialize: true
PROPERTIES:
  #jvmOptions1: '-Xms128M -Xmx256M -agentlib:jdwp=transport=dt_socket,address=12998,server=y,suspend=n'
  jvmOptions1: '-Xms64M -Xmx192M' #jvmOptions_2 - default the same as jvmOptions_1
  #jvmOptions2: '-Xms128M -Xmx256M'
  externalPort: '8000'
  version: '1.5.0.0'
  switchDelayTime: 1000
  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: true
  #isStackDumping: true
  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;
                           }'
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

It is important to configure context path for microservice (see paramter SERVERS -> HTTP -> contextName above) and not to set it inside application or with properties file. JLupin will take care of it and will know context path this way.

Log configuration file should be placed in resource directory and also in microservice directory (described here):

<?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">
    <!-- Extract log directory and file name into variables -->
    <Properties>
        <Property name="logDirectory">../logs/microservice/example</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>/.%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>

            <!-- 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>

If you want you can also put application.properties file in your microservice folder and JLupin will provide these setting for Spring BOOT application.

Running microservice

When your microservice is done compile it into war file. Then put this file with all other required by your microservice (like servlet_configuration.yml, jlupin logger configuration file, properties file, etc.) into directory which name is your microservice name inside server/application directory. To start it just run control.sh/.cmd and type in command microservice start [your_microservice_name].