DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workkloads.

Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Beyond Linguistics: Real-Time Domain Event Mapping with WebSocket and Spring Boot
  • Jakarta WebSocket Essentials: A Guide to Full-Duplex Communication in Java
  • Leveling Up My GraphQL Skills: Real-Time Subscriptions
  • WebSocket vs. Server-Sent Events: Choosing the Best Real-Time Communication Protocol

Trending

  • Rust and WebAssembly: Unlocking High-Performance Web Apps
  • *You* Can Shape Trend Reports: Join DZone's Software Supply Chain Security Research
  • Chaos Engineering for Microservices
  • Zero Trust for AWS NLBs: Why It Matters and How to Do It
  1. DZone
  2. Coding
  3. Tools
  4. Building and Testing a WebSocket Server with Undertow

Building and Testing a WebSocket Server with Undertow

By 
Martin Mois user avatar
Martin Mois
·
Dec. 23, 13 · Interview
Likes (0)
Comment
Save
Tweet
Share
27.0K Views

Join the DZone community and get the full member experience.

Join For Free

the upcoming version of jboss application server will no longer use tomcat as the integrated webserver, but instead, will replace it with undertow . the architecture of undertow is based on handlers that can be added dynamically via a builder api to the server. this approach is similar to the way of constructing a webserver in node.js . it allows developers to embed the undertow webserver easily into their applications. as the addition of features is done via the builder api, one can only add the features that are really required in one’s application. beyond that undertow supports websockets and the servlet api in version 3.1. it can be run as a blocking or non-blocking server and it is reported that first benchmarks have proven that undertow is the fastest webserver written in java.

as all of this sounds very promising, so let’s try to set up a simple websocket server. as usual we start by creating a simple java project and add the undertow maven dependency:

<dependency>
  <groupid>io.undertow</groupid>
  <artifactid>undertow-core</artifactid>
  <version>1.0.0.beta20</version>
</dependency>

with undertow’s builder api our buildandstartserver() method looks like this:

public void buildandstartserver(int port, string host) {
    server = undertow.builder()
            .addlistener(port, host)
            .sethandler(getwebsockethandler())
            .build();
    server.start();
}

we just add a listener that specifies the port and host to listen for incoming connections and afterwards add a websocket handler. as the websocket handler code is a little bit more comprehensive, i have put it into its own method:

private pathhandler getwebsockethandler() {
    return path().addpath("/websocket", websocket(new websocketconnectioncallback() {
        @override
        public void onconnect(websockethttpexchange exchange, websocketchannel channel) {
            channel.getreceivesetter().set(new abstractreceivelistener() {
                @override
                protected void onfulltextmessage(websocketchannel channel, bufferedtextmessage message) {
                    string data = message.getdata();
                    lastreceivedmessage = data;
                    logger.info("received data: "+data);
                    websockets.sendtext(data, channel, null);
                }
            });
            channel.resumereceives();
        }
    }))
    .addpath("/", resource(new classpathresourcemanager(websocketserver.class.getclassloader(), websocketserver.class.getpackage()))
            .addwelcomefiles("index.html"));
}

let’s go line by line through this code snippet. first of all, we add a new path: /websocket. the second argument of the addpath() methods lets us specify what kind of protocol we want to use for this path. in our case we create a new websocket. the anonymous implementation has a onconnect() method in which we set an implementation of abstractreceivelistener. here we have a convenient method onfulltextmessage() that is called when a client has sent us a text message. a call of getdata() fetches the actual message we have received. in this simple example we just echo this string back to client to validate that the roundtrip from the client to server and back works.

to perform some simple manual tests we also add a second resource under the path / which serves some static html and javascript files. the directory that contains these files is given as an instance of classpathresourcemanager. the call of addwelcomefiles() tells undertow which file to server when the client asks for the path /.

the index.html looks like this:

<html>
<head><title>web socket test</title></head>
<body>
  <script src="jquery-2.0.3.min.js"></script>
  <script src="jquery.gracefulwebsocket.js"></script>
  <script src="websocket.js"></script>
  <form onsubmit="return false;">
    <input type="text" name="message" value="hello, world!"/>
    <input type="button" value="send web socket data" onclick="send(this.form.message.value)"/>
  </form>
  <div id="output"></div>
</body>
</html>

our javascript code is swapped out to the websocket.js file. we use jquery and the jquery-plugin gracefulwebsocket to ease the client side development:

var ws = $.gracefulwebsocket("ws://127.0.0.1:8080/websocket");
ws.onmessage = function(event) {
    var messagefromserver = event.data;
    $('#output').append('received: '+messagefromserver+'');
}
 
function send(message) {
    ws.send(message);
}

after having created a websocket object by calling $.gracefulwebsocket() we can register a callback function for incoming messages. in this method we only append the message string to the dom of the page. the send() method is just a call to gracefulwebsocket’s send() method.

when we now start our application and open the url http://127.0.0.1:8080/ in our webbrowser we see the following page:


entering some string and hitting the “send web socket data” button sends the message to the server, which in response echos it back to the client.

now that we know that everything works as expected, we want to protect our code against regression with a junit test case. as a websocket client i have chosen the library jetty-websocket:

<dependency>
    <groupid>org.eclipse.jetty</groupid>
    <artifactid>jetty-websocket</artifactid>
    <version>8.1.0.rc5</version>
    <scope>test</scope>
</dependency>

in the test case we build and start the websocket server to open a new connection to the websocket port. the websocket implementation of jetty-websocket allows us to implement two callback methods for the open and close events. within the open callback we send the test message to the client. the rest of the code waits for the connection to be established, closes it and asserts that the server has received the message:

@test
public void teststartandbuild() throws exception {
    subject = new websocketserver();
    subject.buildandstartserver(8080, "127.0.0.1");
    websocketclient client = new websocketclient();
    future connectionfuture = client.open(new uri("ws://localhost:8080/websocket"), new websocket() {
        @override
        public void onopen(connection connection) {
            logger.info("onopen");
            try {
                connection.sendmessage("testmessage");
            } catch (ioexception e) {
                logger.error("failed to send message: "+e.getmessage(), e);
            }
        }
        @override
        public void onclose(int i, string s) {
            logger.info("onclose");
        }
    });
    websocket.connection connection = connectionfuture.get(2, timeunit.seconds);
    assertthat(connection, is(notnullvalue()));
    connection.close();
    subject.stopserver();
    thread.sleep(1000);
    assertthat(subject.lastreceivedmessage, is("testmessage"));
}

as usual you can find the source code on github .

conclusion: undertow’s builder api makes it easy to construct a websocket server and in general an embedded webserver that fits your needs. this also eases automatic testing as you do not need any specific maven plugin that starts and stops your server before and after your integration tests. beyond that the jquery plugin jquery-graceful-websocket lets you send and receive messages over websockets with only a few lines of code.

WebSocket

Opinions expressed by DZone contributors are their own.

Related

  • Beyond Linguistics: Real-Time Domain Event Mapping with WebSocket and Spring Boot
  • Jakarta WebSocket Essentials: A Guide to Full-Duplex Communication in Java
  • Leveling Up My GraphQL Skills: Real-Time Subscriptions
  • WebSocket vs. Server-Sent Events: Choosing the Best Real-Time Communication Protocol

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!