And Todays’s Quote Would Be..

Life begins at the end of your comfort zone.

Neale Donald Walsch

Exposing Openshift Prometheus API and Display it on External Monitoring Tools

Theres one question comes up during discussion with my colleague regarding on how we can monitor our application which are being deployed on top of Openshift. Actually Openshift has its own monitoring tools, but sometimes we need an external monitoring tools for monitor our distributed application especially when deployed in a multiple different clusters of Openshift.

In the end, the high level concept is pretty much like this.

But first in order to achieve it we need to make sure that our thanos-querier are both accesible by External Grafana, and also secure.

Before we go there, lets start by creating an “mw” namespace first and deploying a simple java apps there.

oc new-project mw

oc new-app registry.access.redhat.com/ubi8/openjdk-8~https://github.com/edwin/hello-world-fuse-on-ocp -n mw

Create a new serviceaccount,

oc create sa ext-monitor -n mw

And gives a “cluster-monitoring-view” role to it,

oc adm policy add-cluster-role-to-user cluster-monitoring-view -z ext-monitor -n mw

Next step is getting the ServiceAccount JWT token by using below command,

oc sa get-token ext-monitor -n mw

It will generate something like this, and save it somewhere.

Next is setuping our own External Monitoring tools by using grafana, and login with admin/admin credential.

docker pull grafana/grafana

docker run -d -p 3000:3000 grafana/grafana

Create a new Data sources, and select Prometheus as our new Datasource.

Fill in some data, and put our thanos-querier as our HTTP URL.

Create new HTTP Header, and put Authorization as the Key. And put “Bearer (your ServiceAccount JWT token)” as the value. We can add some custom query parameters for defining which namespace to be monitored.

Press Save and Test button after.

Next step is creating a dashboard,

And an empty Panel,

Change our Data source into our newly created Data source, and run below query in Metric Browser field

sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_rate{namespace='mw'}) by (pod)

The result should be seen on below image,

Fyi, on this tutorial Im using Openshift 4.8.

Deploying Fuse 7 on Top of Spring Boot to Openshift 4

Red Hat Fuse is an Open Source Integration platform which provide a very agile and lightweight artifact, which make it very suitable for a microservice deployment. And in this sample, im going to deploy Fuse on top of Red Hat OpenShift Container Platform.

First as always, we need to create a simple pom file. In here im using the latest version of Fuse. And that is 7.9.

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

    <groupId>com.edw</groupId>
    <artifactId>hello-world-fuse-on-ocp</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <fuse.version>7.9.0.fuse-sb2-790065-redhat-00001</fuse.version>
        <spring-boot.version>2.1.4.RELEASE-redhat-00001</spring-boot.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.jboss.redhat-fuse</groupId>
                <artifactId>fuse-springboot-bom</artifactId>
                <version>${fuse.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-http-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-servlet-starter</artifactId>
        </dependency>
    </dependencies>

    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.jboss.redhat-fuse</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <version>${fuse.version}</version>
                </plugin>
            </plugins>
        </pluginManagement>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

Create a main class,

package com.edw;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

Create its route,

package com.edw.routes;

import org.apache.camel.Exchange;
import org.apache.camel.builder.RouteBuilder;
import org.springframework.stereotype.Component;

@Component
public class HelloWorldRoute extends RouteBuilder {

    @Override
    public void configure() throws Exception {
        rest()
                .get("hello")
                .route()
                .setHeader(Exchange.HTTP_RESPONSE_CODE, simple("200"))
                .setHeader(Exchange.CONTENT_TYPE, simple("application/json"))
                .setBody(constant("{\"hello\":\"world\"}"))
                .endRest()
        ;
    }
}

Set application.properties for our application’s configuration. One of the most important is settingup Camel’s context path for serving API endpoints.

# The Camel context name
camel.springboot.name=hello-world-fuse-on-ocp

# enable all management endpoints
endpoints.enabled=true
management.security.enabled=false

camel.component.servlet.mapping.contextPath=/api/*
logging.level.root=info

And a settings.xml file for providing Red Hat repository location,

<?xml version="1.0"?>
<settings>

    <profiles>
        <profile>
            <id>extra-repos</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <repositories>
                <repository>
                    <id>central</id>
                    <url>https://repo1.maven.org/maven2</url>
                    <releases>
                        <enabled>true</enabled>
                    </releases>
                    <snapshots>
                        <enabled>false</enabled>
                    </snapshots>
                </repository>
                <repository>
                    <id>redhatga</id>
                    <name>Enterprise Releases</name>
                    <url>https://maven.repository.redhat.com/ga</url>
                </repository>
                <repository>
                    <id>redhatearly</id>
                    <name>Enterprise Releases</name>
                    <url>https://maven.repository.redhat.com/earlyaccess/all</url>
                </repository>
            </repositories>

            <pluginRepositories>
                <pluginRepository>
                    <id>central</id>
                    <url>https://repo1.maven.org/maven2</url>
                    <releases>
                        <enabled>true</enabled>
                    </releases>
                    <snapshots>
                        <enabled>false</enabled>
                    </snapshots>
                </pluginRepository>
                <pluginRepository>
                    <id>redhatga</id>
                    <name>Enterprise Releases</name>
                    <url>https://maven.repository.redhat.com/ga</url>
                </pluginRepository>
                <pluginRepository>
                    <id>redhatearly</id>
                    <name>Enterprise Releases</name>
                    <url>https://maven.repository.redhat.com/earlyaccess/all</url>
                </pluginRepository>
            </pluginRepositories>
        </profile>
    </profiles>

</settings>

Execute below command to run on our local,

$ mvn spring-boot:run -s settings.xml

And run curl to see whether our application’s endpoint is ready to accept request or not,

$ curl -kv http://localhost:8080/api/hello

*   Trying ::1:8080...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> GET /api/hello HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.65.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200
< accept: */*
< breadcrumbId: 123
< user-agent: curl/7.65.0
< Content-Type: application/json
< Transfer-Encoding: chunked
< Date: Tue, 17 Aug 2021 14:21:05 GMT
<
* Connection #0 to host localhost left intact
{"hello":"world"} 

Once we are confident that the code is working, we can deploy it to Openshift Container Platform by using below command.

oc new-app registry.access.redhat.com/ubi8/openjdk-8~https://github.com/edwin/hello-world-fuse-on-ocp

Full code for this sample can be downloaded on below link.

https://github.com/edwin/hello-world-fuse-on-ocp

Thanks for reading and dont forget to have fun using Fuse.

Injecting Openshift Secret and Reading it as an Environment Variables in Spring Boot

In this writing, im planning to create a simple Spring Boot application but with a dynamic configuration that is going to be fetched from environment variables. Usually we are using this for securing some sensitive values such as Database credentials or endpoints.

For this scenario, im trying to make password variables as parameterized inside Spring Boot’s application.properties. Binds it with environment variables with the name of OPENSHIFT_APP_PASSWORD.

server.port=8080
server.password=${OPENSHIFT_APP_PASSWORD}

And call it from our controller,

package com.edw.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
public class IndexController {

    @Value("${server.password}")
    private String serverPassword;

    @GetMapping("/")
    public Map helloWorld() {
        return new HashMap() {{
            put("hello", "world");
            put("password", serverPassword);
        }};
    }
}

Dont forget setting up maven’s configuration,

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

    <groupId>com.edw</groupId>
    <artifactId>ocpsecret</artifactId>
    <version>1.0-SNAPSHOT</version>

    <repositories>
        <repository>
            <id>redhat-early-access</id>
            <name>Red Hat Early Access Repository</name>
            <url>https://maven.repository.redhat.com/earlyaccess/all/</url>
        </repository>
        <repository>
            <id>redhat-ga</id>
            <name>Red Hat GA Repository</name>
            <url>https://maven.repository.redhat.com/ga/</url>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>redhat-early-access</id>
            <name>Red Hat Early Access Repository</name>
            <url>https://maven.repository.redhat.com/earlyaccess/all/</url>
        </pluginRepository>
        <pluginRepository>
            <id>redhat-ga</id>
            <name>Red Hat GA Repository</name>
            <url>https://maven.repository.redhat.com/ga/</url>
        </pluginRepository>
    </pluginRepositories>

    <properties>
        <snowdrop-bom.version>2.3.6.Final-redhat-00001</snowdrop-bom.version>
        <spring-boot.version>2.1.4.RELEASE-redhat-00001</spring-boot.version>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <start-class>com.edw.Main</start-class>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>dev.snowdrop</groupId>
                <artifactId>snowdrop-dependencies</artifactId>
                <version>${snowdrop-bom.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

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

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

After we commit all the code into github, we can pull them from Openshift with a simple oc command.

$ oc new-app registry.access.redhat.com/ubi8/openjdk-11~https://github.com/edwin/spring-boot-and-ocp-secret

We can create a variable as a Secret by using below oc command

$ oc create secret generic mypassword --from-literal=OPENSHIFT_APP_PASSWORD=whatever

And inject it into our application,

$ oc set env --from=secret/mypassword dc/spring-boot-and-ocp-secret

Expose our app’s endpoint,

$ oc expose service spring-boot-and-ocp-secret

And do a curl to see that variable “password” has been filled with “whatever” which comes from our OCP Secret.

$ curl -kv http://ocp-endpoint/

* Mark bundle as not supporting multiuse
< HTTP/1.1 200
< Content-Type: application/json
<
{"password":"whatever","hello":"world"}

Code for this can be found on below link

https://github.com/edwin/spring-boot-and-ocp-secret

Creating an Embeddable JMS Server using Artemis for Unit Testing

In this blog now we are trying to implement an embeddable JMS server for doing testing in Java. Embeddable JMS server is needed to reduce the dependency to a third party, in this case is JMS provider like ActiveMQ, and it is very lightweight therefore we can run it very fast and in multiple times. It is also needed for integration test to see whether our code can integrate smoothly with others. For this scenario im using JUnit 5, which is perhaps the latest version of JUnit at this time.

So lets start with a pom file, for describing what libraries are needed to this. For this example, im using snowdrop bom from Red Hat.

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

    <groupId>com.edw</groupId>
    <artifactId>embeddable-artemis-mq-junit5</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <java.version>11</java.version>
        <spring-boot.version>2.1.6.RELEASE</spring-boot.version>
        <spring-boot-bom.version>2.3.6.Final-redhat-00001</spring-boot-bom.version>
        <junit-version>5.7.2</junit-version>

        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <!-- Exclude the Tomcat dependency -->
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

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

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

        <!-- artemis -->
        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>artemis-server</artifactId>
            <version>2.12.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>artemis-core-client</artifactId>
            <version>2.12.0</version>
        </dependency>
        <!-- artemis -->

        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>${junit-version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>${junit-version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-commons</artifactId>
            <version>1.7.2</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>junit</groupId>
                    <artifactId>junit</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>dev.snowdrop</groupId>
                <artifactId>snowdrop-dependencies</artifactId>
                <version>${spring-boot-bom.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>


    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.1.3.RELEASE</version>
                <configuration>
                    <mainClass>com.edw.Main</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.0.0-M5</version>
            </plugin>

        </plugins>
    </build>

</project>

One of the most important thing is we need to create an xml file called broker.xml. The purpose is to store configuration for our embeddable JMS, one of the most important configuration would be the roles and type of privileges.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<configuration xmlns="urn:activemq" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:activemq ../../../../src/schema/artemis-configuration.xsd">
    <core xmlns="urn:activemq:core">
        <bindings-directory>./data/messaging/bindings</bindings-directory>
        <journal-directory>./data/messaging/journal</journal-directory>
        <large-messages-directory>./data/messaging/largemessages</large-messages-directory>
        <paging-directory>./data/messaging/paging</paging-directory>
        <management-notification-address>notificationsTopic</management-notification-address>
        <acceptors>
            <acceptor name="netty">tcp://localhost:61616</acceptor>
        </acceptors>

        <max-disk-usage>100</max-disk-usage>

        <security-settings>
            <security-setting match="#">
                <permission roles="admin" type="createDurableQueue"/>
                <permission roles="admin" type="deleteDurableQueue"/>
                <permission roles="admin" type="createNonDurableQueue"/>
                <permission roles="admin" type="deleteNonDurableQueue"/>
                <permission roles="admin" type="consume"/>
                <permission roles="admin" type="browse"/>
                <permission roles="admin" type="send"/>
                <permission roles="admin" type="createAddress"/>
                <permission roles="admin" type="deleteAddress"/>
            </security-setting>
        </security-settings>
    </core>
</configuration>

Last step is creating a simple java files, dont forget to create a user and give them a role based on the defined roles in broker.xml.

package com.edw.jms;

import org.apache.activemq.artemis.core.config.impl.SecurityConfiguration;
import org.apache.activemq.artemis.core.server.embedded.EmbeddedActiveMQ;
import org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager;
import org.apache.activemq.artemis.spi.core.security.jaas.InVMLoginModule;
import org.junit.jupiter.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class JMSServiceTest {

    @Autowired
    private JMSService jmsService;

    private static EmbeddedActiveMQ embedded = new EmbeddedActiveMQ();

    @BeforeAll
    public static void before() throws Exception {
        SecurityConfiguration configuration = new SecurityConfiguration();
        configuration.addUser("user", "password");
        configuration.addRole("user", "admin");

        final ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager (InVMLoginModule.class.getName(), configuration);

        embedded.setSecurityManager(securityManager);
        embedded.start();
    }

    @AfterAll
    public static void after() throws Exception {
        embedded.stop();
    }

    /**
     * send message to local embeddable jms, and read it.
     *
     * @throws Exception
     */
    @Test
    @DisplayName("This test is to check if a valid message is being sent to MQ thru JMS is success, and we can read it after")
    public void sendJMSData_expectSuccess() throws Exception {
        Assertions.assertDoesNotThrow(()-> jmsService.send("trysmething"));
        Thread.sleep(2000);
        Assertions.assertEquals("trysmething", jmsService.read());
    }

}

Run the test cases by using below command,

$ mvn clean package -s settings.xml

And for the full code for this article can be found here,

https://github.com/edwin/embeddable-artemis-server-and-junit-5

Create a Simple CRUD REST API using Quarkus

Just several days ago, Quarkus release version 2.0, providing more features and some more improvements in this release. In this tutorial, we’ll try to see how can we use the latest Quarkus version to create a simple rest api, which is connect to an existing MySQL database by using hibernate.

Lets start with a simple pom.xml 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>

    <groupId>com.edw</groupId>
    <artifactId>hello-world-quarkus</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <compiler-plugin.version>3.8.1</compiler-plugin.version>
        <maven.compiler.parameters>true</maven.compiler.parameters>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <quarkus.platform.artifact-id>quarkus-universe-bom</quarkus.platform.artifact-id>
        <quarkus.platform.group-id>io.quarkus</quarkus.platform.group-id>
        <quarkus.platform.version>2.0.0.Final</quarkus.platform.version>
        <surefire-plugin.version>3.0.0-M5</surefire-plugin.version>
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>${quarkus.platform.group-id}</groupId>
                <artifactId>${quarkus.platform.artifact-id}</artifactId>
                <version>${quarkus.platform.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-hibernate-orm</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-resteasy</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-resteasy-jsonb</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-jdbc-mysql</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-arc</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-junit5</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.rest-assured</groupId>
            <artifactId>rest-assured</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>${quarkus.platform.group-id}</groupId>
                <artifactId>quarkus-maven-plugin</artifactId>
                <version>${quarkus.platform.version}</version>
                <extensions>true</extensions>
                <executions>
                    <execution>
                        <goals>
                            <goal>build</goal>
                            <goal>generate-code</goal>
                            <goal>generate-code-tests</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${compiler-plugin.version}</version>
                <configuration>
                    <parameters>${maven.compiler.parameters}</parameters>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>${surefire-plugin.version}</version>
                <configuration>
                    <systemPropertyVariables>
                        <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
                        <maven.home>${maven.home}</maven.home>
                    </systemPropertyVariables>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <profiles>
        <profile>
            <id>native</id>
            <activation>
                <property>
                    <name>native</name>
                </property>
            </activation>
            <build>
                <plugins>
                    <plugin>
                        <artifactId>maven-failsafe-plugin</artifactId>
                        <version>${surefire-plugin.version}</version>
                        <executions>
                            <execution>
                                <goals>
                                    <goal>integration-test</goal>
                                    <goal>verify</goal>
                                </goals>
                                <configuration>
                                    <systemPropertyVariables>
                                        <native.image.path>
                                            ${project.build.directory}/${project.build.finalName}-runner
                                        </native.image.path>
                                        <java.util.logging.manager>org.jboss.logmanager.LogManager
                                        </java.util.logging.manager>
                                        <maven.home>${maven.home}</maven.home>
                                    </systemPropertyVariables>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
            <properties>
                <quarkus.package.type>native</quarkus.package.type>
            </properties>
        </profile>
    </profiles>
</project>

Next is creating a simple java model, as table representation

package com.edw.model;

import javax.persistence.*;
import java.math.BigDecimal;
import java.util.Date;

@Entity
@Table(name = "T_TRANSFER")
public class Transfer {
    @Id
    @GeneratedValue(strategy= GenerationType.AUTO)
    private Long id;
    private String accountFrom;
    private String accountTo;
    private Date transferDate;
    private BigDecimal amount;

    public Transfer() {
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getAccountFrom() {
        return accountFrom;
    }

    public void setAccountFrom(String accountFrom) {
        this.accountFrom = accountFrom;
    }

    public String getAccountTo() {
        return accountTo;
    }

    public void setAccountTo(String accountTo) {
        this.accountTo = accountTo;
    }

    public Date getTransferDate() {
        return transferDate;
    }

    public void setTransferDate(Date transferDate) {
        this.transferDate = transferDate;
    }

    public BigDecimal getAmount() {
        return amount;
    }

    public void setAmount(BigDecimal amount) {
        this.amount = amount;
    }
}

After that we can create a simple class for querying using EntityManager,

package com.edw.service;

import com.edw.dto.TransferDto;
import com.edw.model.Transfer;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.transaction.Transactional;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

@Transactional
@ApplicationScoped
public class TransferService {
    @Inject
    EntityManager em;

    public List<Transfer> findAll() {
        return em.createQuery("select t from Transfer t", Transfer.class).getResultList();
    }

    public Long create(TransferDto transferDto) {
        Transfer transfer = new Transfer();
        transfer.setAccountFrom(transferDto.getAccountFrom());
        transfer.setAccountTo(transferDto.getAccountTo());
        transfer.setAmount(transferDto.getAmount());
        transfer.setTransferDate(new Date());
        em.persist(transfer);

        return transfer.getId();
    }

}

And a controller to handle rest api request,

package com.edw.controller;

import com.edw.dto.TransferDto;
import com.edw.service.TransferService;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.HashMap;

@Path("/transfer")
public class TransferController {

    @Inject
    TransferService transferService;

    @GET
    @Path("/")
    @Produces(MediaType.APPLICATION_JSON)
    public Response findAll() {
        return Response
                .ok(transferService.findAll())
                .build();
    }

    @POST
    @Path("/")
    @Produces(MediaType.APPLICATION_JSON)
    public Response create(TransferDto transferDto) {
        try {
            Long id = transferService.create(transferDto);
            return Response // 200
                    .ok(
                            new HashMap() {{
                                put("id", id);
                            }})
                    .build();
        } catch (Exception ex) {
            return Response // error 400
                    .status(400).entity(
                            new HashMap() {{
                                put("error", "failed to insert");
                            }})
                    .build();
        }
    }

}

Last step is configuring our database connection in application.properties file

quarkus.datasource.jdbc.url=jdbc:mysql://192.168.1.1:3306/db_test
quarkus.datasource.jdbc.driver=com.mysql.cj.jdbc.Driver
quarkus.datasource.jdbc.max-size=20
quarkus.datasource.jdbc.min-size=2

quarkus.datasource.username=root
quarkus.datasource.password=password

quarkus.hibernate-orm.database.generation=update

Finally, we can start our Quarkus app by running below command,

$ mvn compile quarkus:dev

And use curl to check whether API is accessible or not.

$ curl -L -X POST 'http://localhost:8080/transfer/' \
-H 'Content-Type: application/json' \
--data-raw '{
    "accountFrom":"4444",
    "accountTo": "55555",
    "amount" : 50000
}'

The full code for this can be accessed on below github link

https://github.com/edwin/quarkus-hello-world

Have fun with Quarkus 🙂