The JLupin microservice is an application consisting of ordinary JAVA classes locked in a particular archive (jar) or archives. They do not implement any additional interfaces which determine the way of accessing them.

It is only required to provide an application container which will upload all classes and make them visible to JLupin itself. At this point, JLupin supports the default application container which is the Spring container.

Because of that, a programmer knowing Spring shall find the ideal environment to start their application on the JLupin Next Server platform.

The place of application container in the data transfer process is illustrated below:

Ok then, let’s create a simple class and share it outside.

In our favourite programing tool, we create a project and one interface and a class that implements it.

Code samples:

package com.jlupin.sampleapp.paramsfunction.service;

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

Implementation:

package com.jlupin.sampleapp.paramsfunction.service.impl;

import com.jlupin.interfaces.service.access.annotation.JLupinServiceAccessMode;
import com.jlupin.interfaces.service.access.enums.JLupinServiceAccessModeEnum;
import com.jlupin.sampleapp.paramsfunction.service.DigestService;
import org.springframework.stereotype.Service;

import java.security.MessageDigest;

@JLupinServiceAccessMode(mode = JLupinServiceAccessModeEnum.PUBLIC)
@Service("digestService")
public class DigestServiceImpl implements DigestService {

    public DigestService2Impl() {
    }

    @Override
    public String getMD5Digest(String name, String surname) throws Throwable {
            String stringToDigest = name+surname;
            MessageDigest  messageDigest = MessageDigest.getInstance("MD5");
            byte [] buffer = stringToDigest.getBytes();
            messageDigest.update(buffer);
            byte [] digestBuffer  = messageDigest.digest();
            return byteToHex(digestBuffer);
    }

    private String byteToHex(byte in[]) {
        byte ch = 0x00;
        int i = 0;
        if (in == null || in.length <= 0) {
            return null;
        }
        StringBuilder out = new StringBuilder(in.length * 2);

        while (i < in.length) {
            ch = (byte) (in[i] & 0xF0);
            ch = (byte) (ch >>> 4);
            ch = (byte) (ch & 0x0F);
            out.append(pseudo[ (int) ch]);
            ch = (byte) (in[i] & 0x0F);
            out.append(pseudo[ (int) ch]);
            i++;
        }
        return out.toString();

    }

    private char pseudo[] = {'0', '1', '2', '3', '4', '5', '6', '7','8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
}

Our example will use configuration by annotations provided by Spring. Our class will be available under the name of "digestService" – Spring annotation:

@Service("digestService")

Adding annotation:

@JLupinServiceAccessMode(mode = JLupinServiceAccessModeEnum.PUBLIC)

Informs the server that this class must be available outside as a service. Class and interface is compiled and digestMicroservice.jar file is created. Ok then, if we have our code written, we need to configure it and place on the server.

Create Spring configuratgion file: (spring-services.xml).

Content:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <import resource="spring-default-configuration.xml"/>

    <context:annotation-config/>
    <context:component-scan base-package=" com.jlupin.sampleapp.paramsfunction.service.impl"/>
</beans>

In the above file, we import a file with classes provided by default with the server and we also determine a pack with our service class. Our configuring file must import the file with default classes provided by Jlupin, and they are in spring-default-configuration.xml file.

!IMPORTANT NOTE classes activated on Jlupin may be shared as remote classes in two ways:

  1. By default all classes configured and loaded by IOC Spring container are remotely available – it is determined by a configuring file provided by the server distribution - spring-default-configuration.xml that must be imported by Spring configuring files of a given microservice. This is the following entry:

    PUBLIC

  2. If we do not want all classes to be remotely available, PUBLIC value needs to be changed to PRIVATE in the above entry, however in this case every class that needs to be a service for our microservice must have annotations on the scope of the class:@JLupinServiceAccessMode(mode = JLupinServiceAccessModeEnum.PUBLIC). As in the example above.

Ok, next step:

We edit the global configuration file of the main server and add a new definition for the microservice - location:

SERVERHOME/start/configuration/JLupinGlobalMultiProcessConfigurationImpl.java

The server configuration files are in the JAVA class format. In this configuration file, the method:

public JLupinMultiProcessManager getJLupinMultiProcessManager()

is responsible for the microservice configuration on the server. We add the configuration of the new microservice(digestMicroservice):

JLupinLocalServerProcessConfigurator digestMicroservice = new JLupinLocalServerProcessConfigurator();
        digestMicroservice.setLocalServerName("localhost");
        digestMicroservice.setPrimaryPort(3001);
        digestMicroservice.setSecondaryPort(3002);
        digestMicroservice.setPrimaryCommandPort(3003);
        digestMicroservice.setSecondaryCommandPort(3004);
        digestMicroservice.setConnectionSocketTimeout(30000);
        digestMicroservice.setWaitForProcessStartResponseTime(45000);
        digestMicroservice.setWaitForProcessDestroyResponseTime(10000);
        digestMicroservice.setPrimaryJvmOptions("-Xms128M -Xmx256M");
        digestMicroservice.setSecondaryJvmOptions("-Xms128M -Xmx256M");
        digestMicroservice.setConfigurationClassFileName("DigestMicroservice.java");
…
 jLupinDefaultMultiProcessManagerImpl.addApplicationConfiguration("digestMicroservice", digestMicroservice);

In the global configuration we chose configurationClassFileName. Now we add the new application file DigestMicroservice.java to the same location: SERVERHOME/start/configuration. The content of the configuration file of the application should look as follows:

public class DigestMicroservice implements JLupinLocalSingleProcessConfiguration{

    @Override
    public void before() {

    }

    @Override
    public void after() {

    }
    @Override
    public JLupinBaseServer getJLupinLocalBaseServer() {
        JLupinDefaultBaseServerImpl jLupinDefaultBaseServer = new JLupinDefaultBaseServerImpl("default");
        jLupinDefaultBaseServer.setThreadPoolSize(64);
        return jLupinDefaultBaseServer;
    }

    @Override
    public JLupinBaseServer getJLupinLocalCommandServer() {
        JLupinDefaultBaseServerImpl jLupinDefaultBaseServer = new JLupinDefaultBaseServerImpl("command");
        jLupinDefaultBaseServer.setThreadPoolSize(4);
        jLupinDefaultBaseServer.setWaitForFinishExecuteAllRequests(false);
        return jLupinDefaultBaseServer;
    }

    @Override
    public JLupinEntryPoint getJLupinLocalCommandEntryPoint() {
        return new JLupinLocalCommandEntryPointImpl();
    }

    @Override
    public JLupinEntryPoint getJLupinLocalEntryPoint() {
        JLupinDefaultEntryPointImpl jLupinDefaultEntryPoint = new JLupinDefaultEntryPointImpl();
        return jLupinDefaultEntryPoint;
    }

    public  JLupinServiceProcessor getJLupinServiceProcessor() {
        JLupinServiceProcessor jLupinServiceProcessor = new JLupinDefaultServiceProcessorImpl();
        return jLupinServiceProcessor;
    }

    @Override
    public JLupinInnerServiceProcessor getJLupinInnerServiceProcessor() {
        return new JLupinDefaultInnerServiceProcessorImpl();
    }

    @Override
    public JLupinApplicationInvoker getJLupinApplicationInvoker() {

        JLupinClientSocketConfiguration clientSocketConfServer = new JLupinClientSocketConfiguration();
        clientSocketConfServer.setSocketAddressToConnectServer(new InetSocketAddress("localhost", 9090));
        clientSocketConfServer.setSoTimeout(30000);

        JLupinBalancer jLupinBalancer = new JLupinOutputParameterAnalyzerAlgSocketBalancerImpl(
                4, getJLupinLogger(), getJLupinSerializer(),clientSocketConfServer);

        JLupinDelegator jLupinBalanceDelegator = new JLupinDefaultBalanceProxyDelegatorImpl(jLupinBalancer);

        return new JLupinDefaultApplicationInvokerImpl(new JLupinDelegator[] {jLupinBalanceDelegator});
    }

    @Override
    public JLupinApplicationContainer getJLupinApplicationContainer() {
        JLupinSingleApplicationContainerForLocalProcessImpl jLupinSingleApplicationContainerForLocalProcess =
                new JLupinSingleApplicationContainerForLocalProcessImpl(
                        new String[] {"classpath:spring-services.xml"});
        return jLupinSingleApplicationContainerForLocalProcess;
    }

    @Override
    public JLupinLogger getJLupinLogger() {
        return JLupinLoggerOverLog4jImpl.getInstance();
    }

    @Override
    public JLupinSerializer getJLupinSerializer() {
        return JLupinFSTSerializerImpl.getInstance();
    }
}

Create the digestMicroservice directory in the location: SERVERHOME/application/

Upload the following files to the created application directory above:

  • the application library (jar files) - in this case: digestMicroservice-1.0.jar.

This JAR includes:
- DigestService.class
- DigestService Impl.class
- spring-services.xml

- log4j.xml

Content of the file log4j.xml:

<?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/local/digestMicroservice/run/sample.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>

Start the server or, if it is started, start the command of appStart digestMicroservice.

From now, your microservice works on the server as an independent JVM process and remotely shares one service under the name of "digestService". Microservice Invocation chapter describes how to invoke a written class by different interfaces