Book Image

Java EE 8 Cookbook

By : Elder Moraes
Book Image

Java EE 8 Cookbook

By: Elder Moraes

Overview of this book

Java EE is a collection of technologies and APIs to support Enterprise Application development. The choice of what to use and when can be dauntingly complex for any developer. This book will help you master this. Packed with easy to follow recipes, this is your guide to becoming productive with Java EE 8. You will begin by seeing the latest features of Java EE 8, including major Java EE 8 APIs and specifications such as JSF 2.3, and CDI 2.0, and what they mean for you. You will use the new features of Java EE 8 to implement web-based services for your client applications. You will then learn to process the Model and Streaming APIs using JSON-P and JSON-B and will learn to use the Java Lambdas support offered in JSON-P. There are more recipes to fine-tune your RESTful development, and you will learn about the Reactive enhancements offered by the JAX-RS 2.1 specification. Later on, you will learn about the role of multithreading in your enterprise applications and how to integrate them for transaction handling. This is followed by implementing microservices with Java EE and the advancements made by Java EE for cloud computing. The final set of recipes shows you how take advantage of the latest security features and authenticate your enterprise application. At the end of the book, the Appendix shows you how knowledge sharing can change your career and your life.
Table of Contents (14 chapters)

Running your first JAX-RS 2.1 code

JAX-RS is an API designed to give a portable and standard way for building RESTful web services in Java. This is one of the most used technologies for data transporting between different applications that uses some network (internet included) for communication.

One of the coolest features introduced by the 2.1 release is Server-Sent Events (SSE), which will be covered in this recipe. SSE is a specification created by HTML5 where it has established a channel between server and client, one way only from server to client. It is a protocol that transports a message containing some data.

Getting ready

Let's start by adding the right dependency to our project:

    <dependencies>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-grizzly2-http</artifactId>
<version>2.26-b09</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>2.26-b09</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-sse</artifactId>
<version>2.26-b09</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>8.0</version>
<scope>provided</scope>
</dependency>
</dependencies>

You surely noticed that we are using Jersey here. Why? Because Jersey is the reference implementation for JAX-RS, which means that all JAX-RS specifications are first implemented through Jersey.

Moreover, with Jersey we can use Grizzly to start a small local server, which will be useful for this recipe, as we need just a few server features to show the SSE behavior.

Further on in this book, we will use a full GlassFish to build more JAX-RS recipes.

How to do it...

  1. First, we create a class that will be our server:
public class ServerMock {

public static final URI CONTEXT =
URI.create("http://localhost:8080/");
public static final String BASE_PATH = "ssevents";

public static void main(String[] args) {
try {
final ResourceConfig resourceConfig = new
ResourceConfig(SseResource.class);

final HttpServer server =
GrizzlyHttpServerFactory.createHttpServer(CONTEXT,
resourceConfig, false);
server.start();

System.out.println(String.format("Mock Server started
at %s%s", CONTEXT, BASE_PATH));

Thread.currentThread().join();
} catch (IOException | InterruptedException ex) {
System.out.println(ex.getMessage());
}
}
}
  1. Then, we create a JAX-RS endpoint to send the events to the clients:
@Path(ServerMock.BASE_PATH)
public class SseResource {

private static volatile SseEventSink SINK = null;

@GET
@Produces(MediaType.SERVER_SENT_EVENTS)
public void getMessageQueue(@Context SseEventSink sink) {
SseResource.SINK = sink;
}

@POST
public void addMessage(final String message, @Context Sse sse)
throws IOException {
if (SINK != null) {
SINK.send(sse.newEventBuilder()
.name("sse-message")
.id(String.valueOf(System.currentTimeMillis()))
.data(String.class, message)
.comment("")
.build());
}
}
}
  1. Then, we create a client class to consume the events generated from the server:
public class ClientConsumer {

public static final Client CLIENT = ClientBuilder.newClient();
public static final WebTarget WEB_TARGET =
CLIENT.target(ServerMock.CONTEXT
+ BASE_PATH);

public static void main(String[] args) {
consume();
}

private static void consume() {

try (final SseEventSource sseSource =
SseEventSource
.target(WEB_TARGET)
.build()) {

sseSource.register(System.out::println);
sseSource.open();

for (int counter=0; counter < 5; counter++) {
System.out.println(" ");
for (int innerCounter=0; innerCounter < 5;
innerCounter++) {
WEB_TARGET.request().post(Entity.json("event "
+ innerCounter));
}
Thread.sleep(1000);
}

CLIENT.close();
System.out.println("\n All messages consumed");
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
}
}

To try it out, you have to first run the ServerMock class and then the ClientConsumer class. If everything worked well, you should see something like this:

InboundEvent{name='sse-message', id='1502228257736', comment='',    data=event 0}
InboundEvent{name='sse-message', id='1502228257753', comment='', data=event 1}
InboundEvent{name='sse-message', id='1502228257758', comment='', data=event 2}
InboundEvent{name='sse-message', id='1502228257763', comment='', data=event 3}
InboundEvent{name='sse-message', id='1502228257768', comment='', data=event 4}

These are the messages sent from the server to the client.

How it works...

This recipe is made up of three parts:

  • The server, represented by the ServerMock class
  • The SSE engine, represented by the SseResource class
  • The client, represented by the ClientConsumer class

So once ServerMock is instantiated, it registers the SseResource class:

final ResourceConfig resourceConfig = new ResourceConfig(SseResource.class);
final HttpServer server = GrizzlyHttpServerFactory.createHttpServer(CONTEXT, resourceConfig, false);
server.start();

Then two key methods from SseResource take place. The first one adds messages to the server queue:

addMessage(final String message, @Context Sse sse)

The second one consumes this queue and sends the messages to the clients:

@GET
@Produces(MediaType.SERVER_SENT_EVENTS)
public void getMessageQueue(@Context SseEventSink sink)

Note that this one has a media type SERVER_SENT_EVENTS, introduced in this version for this very purpose. And finally, we have our client. In this recipe, it is both posting and consuming messages.

It consumes here:

sseSource.register(System.out::println);
sseSource.open();

It posts here:

ServerMock.WEB_TARGET.request().post(Entity.json("event " + innerCounter));

See also

  • You can stay tuned with everything related to JAX-RS at https://github.com/jax-rs
  • The source code of this recipe is at https://github.com/eldermoraes/javaee8-cookbook/tree/master/chapter01/ch01-jaxrs