Groovy
Any language compiled into byte code which is run on JVM can be used to write microservices for JLupin. The example of such a language is Groovy. It also supports using Java libraries inside Groovy's code, so it is easy to use JLupin Client library.
Native microservice
You can use libraries written in Java in your Groovy code, so you won't see any plain Java class.
Project structure and dependencies
This is standard structure of Groovy project with Gradle. Create empty one (gradle init
). The structure should look like this:
Configure your build (build.gradle
):
group 'com.example'
version '1.0-SNAPSHOT'
apply plugin: 'groovy'
repositories {
mavenCentral()
maven {
url "http://support.jlupin.com/maven2"
}
}
dependencies {
compile 'org.codehaus.groovy:groovy-all:2.3.11'
testCompile group: 'junit', name: 'junit', version: '4.12'
compileOnly group: 'org.springframework', name: 'spring-context', version: '4.3.9.RELEASE'
compileOnly group: 'com.jlupin', name: 'jlupin-client-assembly', version: '1.4.1.0-RC6'
}
Spring-context and jlupin-client-assembly dependencies are set to scope compileOnly
because they are available on server by default. Also one reslover is added with JLupin Maven repository address for getting jlupin-client-assembly
library.
Microservice code
Add two files with configuration: one for JLupin (GroovyHelloWorldJLupinConfiguration
) and one for Spring container (GroovyHelloWorldSpringConfiguration
). Create package com.example.configuration
and put classed there.
package com.example.configuration
import com.jlupin.impl.container.application.spring.JLupinAbstractSpringApplicationContainer
import com.jlupin.interfaces.configuration.microservice.container.application.JLupinAbstractApplicationContainerProducer
import com.jlupin.interfaces.container.application.JLupinApplicationContainer
import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.context.support.AbstractApplicationContext
class GroovyHelloWorldJLupinConfiguration extends JLupinAbstractApplicationContainerProducer {
@Override
JLupinApplicationContainer produceJLupinApplicationContainer() {
return new JLupinAbstractSpringApplicationContainer() {
@Override
AbstractApplicationContext getAbstractApplicationContext() {
return new AnnotationConfigApplicationContext(GroovyHelloWorldSpringConfiguration.class)
}
}
}
}
package com.example.configuration
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.Configuration
@Configuration
@ComponentScan("com.example")
class GroovyHelloWorldSpringConfiguration {
@Bean("jLupinRegularExpressionToRemotelyEnabled")
def getRemotelyBeanList() {
def list = new ArrayList<String>()
list.add("exampleService")
return list
}
}
Microservice is configured but does nothing. Create two packages com.example.service.interfaces
and com.example.service.impl
and put service definitions in them:
package com.example.service.interfaces
interface ExampleService {
String hello(String name)
}
package com.example.service.impl
import com.example.service.interfaces.ExampleService
import org.springframework.stereotype.Service
@Service(value = "exampleService")
class ExampleServiceImpl implements ExampleService {
@Override
String hello(final String name) {
return "Hello, ${name}!"
}
}
Microservice is done. You only need to add configuration for it. Create special directory for it called additional-files
. Put in there two files: configuration.yml and log4j2.xml.
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
ENTRY_POINTS:
QUEUE:
threadAmount: 512
howOftenCheckingServerInMillis: 5000
repeatsAmount: 4
timeToWaitBetweenRepeatProbeInMillis: 1000
PROPERTIES:
#jvmOptions1: '-Xms128M -Xmx256M -agentlib:jdwp=transport=dt_socket,address=12998,server=y,suspend=n'
jvmOptions1: '-Xms64M -Xmx128M' #jvmOptions_2 - default the same as jvmOptions_1
#jvmOptions2: '-Xms128M -Xmx256M'
externalPort: '8000'
version: '1.0'
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
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.configuration.GroovyHelloWorldJLupinConfiguration'
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
<?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/groovy-hello-world</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>
<!-- 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>
To make it simpler to deploy out microservice add Maven definition pom.xml to use JLupin Next Server Maven Plugin to create deployable zip file and to deploy created microservice (you can of cource do it without it, but then it requires more work from you).
<?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>
<name>groovy-hello-world</name>
<artifactId>groovy-hello-world-implementation</artifactId>
<groupId>com.example</groupId>
<version>1.0-SNAPSHOT</version>
<properties>
<jlupin.next.server.maven.plugin.version>1.2.1</jlupin.next.server.maven.plugin.version>
</properties>
<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>
<dependencies>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>2.3.11</version>
</dependency>
</dependencies>
<!--
Enable shade and JCS JLupin Next Server Maven Plugin for this module.
They are configured in main project pom.xml file.
-->
<build>
<directory>build</directory>
<finalName>libs/${project.name}-${project.version}</finalName>
<plugins>
<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>
<outputFileName>${project.build.finalName}</outputFileName>
</configuration>
</execution>
<execution>
<id>jlupin-deploy</id>
<goals>
<goal>deploy</goal>
</goals>
<configuration>
<zipFile>${project.build.directory}/${project.build.finalName}.zip</zipFile>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
You may noticed two things. First is that there is groovy-all dependency added. By default server does not contain it and it is certain that our microservice requires it to run - ended up it is written in scala. By adding it here it will be automatically added to our microservice zip. Also <finalName>
and <directory>
parameters are changed to match path where jar file is generated by Gradle.
Microservice deployment
To deploy microservice make sure that you have started JLupin Platform and first compile your microservice to jar archive. It is done with command ./gradlew build
. Then create microservice deployable zip file with command mvn jlupin-next-server:zip@jlupin-zip
and in the end deploy it to server with command mvn jlupin-next-server:deploy@jlupin-deploy
. All three steps should succeeded.