Java / .Net Gateways in InterSystems IRIS Integration Products
Gateways in InterSystems IRIS are the communication mechanism between the InterSystems IRIS core and the Java / .Net application code. With the help of gateways, you can work with both Java / .NET objects from ObjectScript and ObjectScript objects and globals from Java / .NET. Gateways can be run anywhere – locally, on a remote server, in docker.
In this article, I’ll show you how you can easily develop and containerize integration products with .Net / Java code. And to interact with code in Java / .Net languages we will use PEX, which provides an opportunity to implement any element of integration products in Java / .Net languages.
For our example, we will develop an integration with Apache Kafka…
Architecture
Apache Kafka is a popular message broker. Kafka has topic (topic) messages to which publishers (publisher) write messages and eat subscribers (consumer) to the topics that read these posts.
First, we will write a Java business operation that will post messages to Apache Kafka. Then we will add a business service in C # that will read, save and transmit messages for further processing in InterSystems IRIS.
Our solution will work in docker and looks like this:
Java Gateway
First of all, we will develop a Business Operation in Java for sending messages to Apache Kafka. The code can be written in any Java IDE and look like this:
To develop a new PEX business operation, you need to implement an abstract class
com.intersystems.enslib.pex.BusinessOperation
…The public properties of the class are the settings of our business host
Method
OnInit
used to establish a connection with Apache Kafka and get a pointer to InterSystems IRISOnTearDown
used to disconnect from Apache Kafka (when the process stops).OnMessage
receives message dc.KafkaRequest and sends it to Apache Kafka.
Now let’s pack our business operation into a Docker container.
Here is our docker file:
FROM openjdk:8 AS builder
ARG APP_HOME=/tmp/app
COPY src $APP_HOME/src
COPY --from=intersystemscommunity/jgw:latest /jgw/*.jar $APP_HOME/jgw/
WORKDIR $APP_HOME/jar/
ADD https://repo1.maven.org/maven2/org/apache/kafka/kafka-clients/2.5.0/kafka-clients-2.5.0.jar .
ADD https://repo1.maven.org/maven2/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar .
ADD https://repo1.maven.org/maven2/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3.jar .
ADD https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.30/slf4j-api-1.7.30.jar .
WORKDIR $APP_HOME/src
RUN javac -classpath $APP_HOME/jar/*:$APP_HOME/jgw/* dc/rmq/KafkaOperation.java &&
jar -cvf $APP_HOME/jar/KafkaOperation.jar dc/rmq/KafkaOperation.class
FROM intersystemscommunity/jgw:latest
COPY --from=builder /tmp/app/jar/*.jar $GWDIR/
Let’s see what’s going on here (I’m assuming you’re familiar with multistage docker builds):
FROM openjdk:8 AS builder
JDK8 is the base image in which we will compile our application.
ARG APP_HOME=/tmp/app
COPY src $APP_HOME/src
Copy the source code from the folder /src
at /tmp/app
…
COPY --from=intersystemscommunity/jgw:latest /jgw/*.jar $APP_HOME/jgw/
Copy the Java Gateway libraries to the folder /tmp/app/jgw
…
WORKDIR $APP_HOME/jar/
ADD https://repo1.maven.org/maven2/org/apache/kafka/kafka-clients/2.5.0/kafka-clients-2.5.0.jar .
ADD https://repo1.maven.org/maven2/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar .
ADD https://repo1.maven.org/maven2/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3.jar .
ADD https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.30/slf4j-api-1.7.30.jar .
WORKDIR $APP_HOME/src
RUN javac -classpath $APP_HOME/jar/*:$APP_HOME/jgw/* dc/rmq/KafkaOperation.java &&
jar -cvf $APP_HOME/jar/KafkaOperation.jar dc/rmq/KafkaOperation.class
All dependencies are downloaded – we call javac/jar
to compile the jar file. For real projects it is recommended to use a full maven or gradle build system.
FROM intersystemscommunity/jgw:latest
COPY --from=builder /tmp/app/jar/*.jar $GWDIR/
Finally, the jar files are copied into the base Java gateway image, which contains all the required dependencies and enables the Java gateway to run.
.Net Gateway
Next, we will develop a .Net service that will receive messages from Apache Kafka. The code can be written in any .Net IDE and look like this…
Features:
To develop a new PEX business service, you need to implement an abstract class
InterSystems.EnsLib.PEX.BusinessService
…The public properties of the class are the settings of our business host
Method
OnInit
used to establish a connection to Apache Kafka, subscribe to Apache Kafka topics, and get a pointer to InterSystems IRISOnTearDown
used to disconnect from Apache Kafka (when the process stops)OnMessage
receives messages from Apache Kafka and sends message to classEns.StringContainer
to target business hosts of products
Now let’s pack our business operation into a Docker container.
Here is our docker file:
FROM mcr.microsoft.com/dotnet/core/sdk:2.1 AS build
ENV ISC_PACKAGE_INSTALLDIR /usr/irissys
ENV GWLIBDIR lib
ENV ISC_LIBDIR ${ISC_PACKAGE_INSTALLDIR}/dev/dotnet/bin/Core21
WORKDIR /source
COPY --from=store/intersystems/iris-community:2020.2.0.211.0 $ISC_LIBDIR/*.nupkg $GWLIBDIR/
# copy csproj and restore as distinct layers
COPY *.csproj ./
RUN dotnet restore
# copy and publish app and libraries
COPY . .
RUN dotnet publish -c release -o /app
# final stage/image
FROM mcr.microsoft.com/dotnet/core/runtime:2.1
WORKDIR /app
COPY --from=build /app ./
# Configs to start the Gateway Server
RUN cp KafkaConsumer.runtimeconfig.json IRISGatewayCore21.runtimeconfig.json &&
cp KafkaConsumer.deps.json IRISGatewayCore21.deps.json
ENV PORT 55556
CMD dotnet IRISGatewayCore21.dll $PORT 0.0.0.0
Let’s see what’s going on here:
FROM mcr.microsoft.com/dotnet/core/sdk:2.1 AS build
We use the .Net Core 2.1 SDK image to build our application.
ENV ISC_PACKAGE_INSTALLDIR /usr/irissys
ENV GWLIBDIR lib
ENV ISC_LIBDIR ${ISC_PACKAGE_INSTALLDIR}/dev/dotnet/bin/Core21
WORKDIR /source
COPY --from=store/intersystems/iris-community:2020.2.0.211.0 $ISC_LIBDIR/*.nupkg $GWLIBDIR/
We copy the .Net Gateway libraries from the official InterSystems IRIS image:
# copy csproj and restore as distinct layers
COPY *.csproj ./
RUN dotnet restore
# copy and publish app and libraries
COPY . .
RUN dotnet publish -c release -o /app
We compile our business operation.
FROM mcr.microsoft.com/dotnet/core/runtime:2.1
WORKDIR /app
COPY --from=build /app ./
Copy the libraries into the final container.
RUN cp KafkaConsumer.runtimeconfig.json IRISGatewayCore21.runtimeconfig.json &&
cp KafkaConsumer.deps.json IRISGatewayCore21.deps.json
Net gateway currently has to load all dependencies at startup, so we inform it about all possible dependencies.
ENV PORT 55556
CMD dotnet IRISGatewayCore21.dll $PORT 0.0.0.0
We start the gateway on the port 55556
, we listen to all network interfaces.
Done!
Here is the complete configuration docker-composeto run the whole demo (including the UI for Apache Kafka, to view messages).
Demo launch
To run the demo locally:
Install:
Run:
git clone https://github.com/intersystems-community/pex-demo.git
cd pex-demo
docker-compose pull
docker-compose up -d
conclusions
InterSystems IRIS integration products now have the ability to create any product elements in Java / .Net languages
Java / .Net code can be called from InterSystems ObjectScript and vice versa, InterSystems ObjectScript code from Java / .Net
Proxy class generation is no longer required
Both classic delivery of the solution and delivery in Docker are possible
Links
Documentation
PEX webinar based on this article