JavaScript
JavaScript is not compiled into by code but there are available JavaScript engines which runs on JVM. Example of such a engine is Nashorn (it is available by default since Java 8).
Native microservice
You can use JavaScript engine to execute service definition which will be written in JavaScript. But it is necessary to include both languages: Java and JavaScript.
Project structure and dependencies
This is standard structure of Java project with Maven. The structure should look like this:
+--+ additional-files
| |
| +--- configuration.yml
| |
| +--- log4j2.xml
|
+--+ src
| |
| +--+ main
| | |
| | +--+ java
| | | |
| | | +--+ com
| | | |
| | | +--+ example
| | | |
| | | +--+ configuration
| | | | |
| | | | +--+ JavaScriptHelloWorldJLupinConfiguration.java
| | | | |
| | | | +--+ JavaScriptHelloWorldSpringConfiguration.java
| | | |
| | | +--+ service
| | | |
| | | +--+ impl
| | | | |
| | | | +--+ ExampleServiceImpl.java
| | | |
| | | +--+ interfaces
| | | |
| | | +--+ ExampleService.java
| | |
| | +--+ js
| | |
| | +--+ com
| | |
| | +--+ example
| | |
| | +--+ service
| | |
| | +--+ impl
| | |
| | +--+ ExampleServiceImpl.js
| |
| +--+ test
| |
| +--+ java
|
+--- pom.xml
Configure your pom (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>jlupin-platform-parent</artifactId>
<groupId>com.jlupin</groupId>
<version>1.6.0.2</version>
</parent>
<name>javascript-hello-world</name>
<groupId>com.example</groupId>
<artifactId>javascript-hello-world-implementation</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<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>
<dependencies>
<dependency>
<groupId>com.jlupin</groupId>
<artifactId>jlupin-platform-native</artifactId>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/js</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>com.jlupin</groupId>
<artifactId>jlupin-platform-maven-plugin</artifactId>
<executions>
<execution>
<id>jlupin-repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
<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>
</build>
</project>
It is default pom.xml
for single native module microservice.
Microservice code
Add two files with configuration: one for JLupin (JavaScriptHelloWorldJLupinConfiguration
) and one for Spring container (JavaScriptHelloWorldSpringConfiguration
). 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;
public class JavaScriptHelloWorldJLupinConfiguration extends JLupinAbstractApplicationContainerProducer {
public JLupinApplicationContainer produceJLupinApplicationContainer() {
return new JLupinAbstractSpringApplicationContainer() {
@Override
public AbstractApplicationContext getAbstractApplicationContext() {
return new AnnotationConfigApplicationContext(JavaScriptHelloWorldSpringConfiguration.class);
}
};
}
}
package com.example.configuration;
import com.example.service.interfaces.ExampleService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;
import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
@Configuration
@ComponentScan("com.example")
public class JavaScriptHelloWorldSpringConfiguration {
@Bean("jLupinRegularExpressionToRemotelyEnabled")
public List<String> getRemotelyBeanList() {
final List<String> list = new ArrayList<>();
list.add("exampleService");
return list;
}
@Bean("exampleService")
public ExampleService getExampleService() throws FileNotFoundException, ScriptException {
return getService(ExampleService.class, "com/example/service/impl/ExampleServiceImpl.js");
}
private <T> T getService(Class<T> interfaceClass, final String implementationPath) throws FileNotFoundException, ScriptException {
final InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream(implementationPath);
if (resourceAsStream == null) {
throw new IllegalStateException("Cannot find implementation for interface " + interfaceClass.getName() + " and implementation path " + implementationPath + ".");
}
final InputStreamReader inputStreamReader = new InputStreamReader(resourceAsStream);
final ScriptEngineManager scriptEngineManager = new ScriptEngineManager(NashornScriptEngineFactory.class.getClassLoader());
final ScriptEngine nashorn = scriptEngineManager.getEngineByName("nashorn");
if (nashorn == null) {
throw new IllegalStateException("Cannot find nashorn javascript engine.");
}
nashorn.eval(inputStreamReader);
Invocable invocable = (Invocable) nashorn;
return invocable.getInterface(interfaceClass);
}
}
As you can see special function is defined in configuration to easily add new services defined in JavaScript. Because JavaScript files are also not annotated it is required to define service as a bean.
Microservice is configured but does nothing. Create two packages: com.example.service.interfaces
in Java sources and com.example.service.impl
in JavaScript sources. Put service definitions in them:
package com.example.service.interfaces;
import javax.script.ScriptException;
public interface ExampleService {
String hello(final String name) throws ScriptException, NoSuchMethodException;
}
function hello(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.
Put default configuration (link) in configuration.yml
and update it's application section with proper class:
[...]
APPLICATION:
applicationContainerProducerClassName: 'com.example.configuration.JavaScriptHelloWorldJLupinConfiguration
[...]
Also put default configuration for Log4j2 (link).
Microservice deployment
You can deploy your microservice manually or automatically. Just follow instructions in documentation.
Checking microservice
You can check if your microservice is running using HTTP Elastic API and cURL for example:
curl -X POST http://localhost:8082/java-script-hello-world/exampleService/hello -H 'Content-Type: application/json' -H 'X-JLNS-API-ID: ROA' -d '"Peter"'
As output you should see:
"Hello, Peter!"