Categories
Development Java

Quarkus in Codespace

Set up Quarkus in Codespace environment

Setup

Create a repository “workshop”:

Open codespace and setup Linux in Terminal:

sudo apt update && \
sudo apt upgrade -y && \
sudo apt install httpie -y

Setup Quarkus Project

Quarkus Homepage

Getting started → 4. Bootstrapping the project → Maven

copy and change ArtifactId to workshop

cd ..
# pwd -> /workspaces
mvn io.quarkus.platform:quarkus-maven-plugin:3.10.2:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=workshop

We can not just delete the workshop folder, because GIT information are inside this folder.

Workaround:

cd /workspaces/workshop/

mvn io.quarkus.platform:quarkus-maven-plugin:3.10.2:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=workshop

mv workshop/* .
ls -lisah workshop/
# hidden files/directory still there
mv workshop/.* .
ls -lisah workshop/
# now everthing has moved
rmdir workshop

Stage, commit and push to repository:

Open GreetingResource, this will force Visual Code to ask to install Extension Pack for Java:

Go to Explorer → Java Projects → Import Projects

It takes a minute or two to show our workshop project:

Start Quarkus

./mvnw quarkus:dev

In Ports Port 5005 is automatically added, but not Port 8080.

We need to add Port 8080 manually.

Click on the Globus Icon and Quarkus welcome page opens:

Go to Visit the dev UI → Endpoints

Click on /hello:

Test from terminal

Open new Terminal

## "&& echo" for additional linebreak
curl localhost:8080/hello && echo
http localhost:8080/hello

WebSockets with Quarkus

Quarkus Guide for using WebSockets

Setup ChatSocket

First we need to install extensions:

./mvnw quarkus:add-extension -Dextensions='websockets'
./mvnw quarkus:add-extension -Dextensions='websockets-next'

Create simple ChatSocket:

package org.acme;

import io.quarkus.websockets.next.OnTextMessage;
import io.quarkus.websockets.next.WebSocket;

@WebSocket(path = "/chatsocket")
public class ChatSocket {
    @OnTextMessage
    public String onMessage(String userMessage){
        return "You said: " + userMessage;
    }
}

Test from terminal

npm install -g wscat
wscat -c ws://localhost:8080/chatsocket

wscat -c ws://localhost:8080/chatsocket
> Hello World!
< You said: Hello World!

Build html client

mkdir -p src/main/resources/META-INF/resources
touch src/main/resources/META-INF/resources/chat.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebSocket Chat Example</title>
    <style>
        #chat {
            resize: none;
            overflow: hidden;
            min-width: 70%;
            min-height: 300px;
            max-height: 300px;
            overflow-y: scroll;
        }
        #msg {
            min-width: 40%;
        }
    </style>
</head>
<body>
    <h1>WebSocket Chat Example</h1>
    <p id="message">Connecting...</p>
    <br/>
    <div class="container">
        <br/>
        <div class="row">
            <textarea id="chat"></textarea>
        </div>
        <div class="row">
            <input id="msg" type="text" placeholder="enter your message">
            <button id="send" type="button" disabled>send</button>
        </div>
    
    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <script>
        var connected = false;
        var socket;

        $( document ).ready(function() {
            connect();
            $("#send").click(sendMessage);

            $("#name").keypress(function(event){
                if(event.keyCode == 13 || event.which == 13) {
                    connect();
                }
            });

            $("#msg").keypress(function(event) {
                if(event.keyCode == 13 || event.which == 13) {
                    sendMessage();
                }
            });

            $("#chat").change(function() {
                scrollToBottom();
            });

            $("#name").focus();
        });

        var connect = function() {
            if (! connected) {
                socket = new WebSocket('wss://' + location.host + '/chatsocket');
                socket.onopen = function(m) {
                    connected = true;
                    console.log("Connected to the web socket");
                    $("#send").attr("disabled", false);
                    $("#connect").attr("disabled", true);
                    $("#name").attr("disabled", true);
                    $("#chat").append("[Chatbot] Howdy, how may I help you? \n");
                    $("#msg").focus();
                    $("#message").text('Connected');
                };
                socket.onmessage = function(m) {
                    console.log("Got message: " + m.data);
                    $("#message").text('Received: ' + m.data);
                    $("#chat").append("[Chatbot] " + m.data + "\n");
                    scrollToBottom();
                };
                socket.onclose = function(event) {
                    console.log("Disconnected");
                    $("#message").text('Disconnected');
                    $("#chat").append("[Chatbot] Disconnected" + "\n");
                    scrollToBottom();
                };
                socket.onerror = function(error) {
                    console.log("Error: " + error.message);
                    $("#message").text('Error: ' + error.message);
                    $("#chat").append("[Chatbot] Error: " + error.message + "\n");
                    scrollToBottom();
                };
            }
        };

        var sendMessage = function() {
            if (connected) {
                var value = $("#msg").val();
                console.log("Sending " + value);
                $("#chat").append("[You] " + value + "\n")
                socket.send(value);
                $("#msg").val("");
            }
        };

        var scrollToBottom = function () {
            $('#chat').scrollTop($('#chat')[0].scrollHeight);
        };

    </script>
</body>
</html>

CONTEXTS AND DEPENDENCY INJECTION Example

Add a ChatService for the 'logic' and inject it into the Chat Socket:

package org.acme;

import io.quarkus.runtime.StartupEvent;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.Observes;

@ApplicationScoped
public class ChatService {
    protected void startup(@Observes StartupEvent event) { 
        System.out.println("Startuuuuuuuuuup event");
    }

    public String chat(String message) {
        return message + " you said.";
    }
}
package org.acme;

import io.quarkus.websockets.next.OnTextMessage;
import io.quarkus.websockets.next.WebSocket;
import jakarta.inject.Inject;

@WebSocket(path = "/chatsocket")
public class ChatSocket {
    @Inject
    ChatService chatService;

    @OnTextMessage
    public String onMessage(String userMessage){
        return chatService.chat(userMessage);
    }
}

Build and run native Image

Building a Native Executable - Quarkus

Build:

# Ich muss vermutlich nur den zweiten Befehl ausführen?
# ./mvnw install -Dnative 
./mvnw package -Dnative -Dquarkus.native.container-build=true -Dquarkus.container-image.build=true

Open another terminal and see how much codespace machine is sweating:

htop

Run:

target/workshop-1.0.0-SNAPSHOT-runner

The project generation has provided a Dockerfile.native-micro in the src/main/docker directory.

# build
docker build -f src/main/docker/Dockerfile.native-micro -t deringo/workshop .

# run
docker run -i --rm -p 8080:8080 deringo/workshop

Leave a Reply

Your email address will not be published. Required fields are marked *