Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds
Java EE 8 High Performance
Java EE 8 High Performance

Java EE 8 High Performance: Master techniques such as memory optimization, caching, concurrency, and multithreading to achieve maximum performance from your enterprise applications.

Arrow left icon
Profile Icon Romain Manni-Bucau
Arrow right icon
$19.99 per month
Full star icon Full star icon Full star icon Half star icon Empty star icon 3.9 (36 Ratings)
Paperback Jan 2018 350 pages 1st Edition
eBook
€28.99 €32.99
Paperback
€41.99
Subscription
Free Trial
Renews at $19.99p/m
Arrow left icon
Profile Icon Romain Manni-Bucau
Arrow right icon
$19.99 per month
Full star icon Full star icon Full star icon Half star icon Empty star icon 3.9 (36 Ratings)
Paperback Jan 2018 350 pages 1st Edition
eBook
€28.99 €32.99
Paperback
€41.99
Subscription
Free Trial
Renews at $19.99p/m
eBook
€28.99 €32.99
Paperback
€41.99
Subscription
Free Trial
Renews at $19.99p/m

What do you get with a Packt Subscription?

Free for first 7 days. $19.99 p/m after that. Cancel any time!
Product feature icon Unlimited ad-free access to the largest independent learning library in tech. Access this title and thousands more!
Product feature icon 50+ new titles added per month, including many first-to-market concepts and exclusive early access to books as they are being written.
Product feature icon Innovative learning tools, including AI book assistants, code context explainers, and text-to-speech.
Product feature icon Thousands of reference materials covering every tech concept you need to stay up to date.
Subscribe now
View plans & pricing
Table of content icon View table of contents Preview book icon Preview Book

Java EE 8 High Performance

Money – The Quote Manager Application

Before working on evaluating and enhancing the performance of your application, you need to indeed have an application. In this part, we will create a small application that we will use to illustrate every part of the book. This chapter doesn't intend to explain all the steps required to create a Java EE application. It will give you the overall steps and ensure that the references to the steps will be obvious later.

The use case of this application will be a microservice that provides a set of web services to manage stocks and shares. This chapter will, therefore, introduce you to the application environment:

  • Application code structure
  • Database setup
  • Data persistence
  • Exposing data over HTTP
  • Deploying your application

Setting up the environment

Before starting with writing code, make sure that you have an environment ready to work with Java EE. We need a Java Virtual Machine 8 (JVM 8) and, more particularly, the Java Development Kit 8 (JDK 8). As a quick reminder, Java EE version V is based on Java Standalone Edition (Java SE) version V as well. You can download the JDK on the Oracle website (http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html).

Alternatively, you can download the OpenJDK version of the JDK on the OpenJDK project website (http://openjdk.java.net/install/), but I recommend that you use the Oracle version. We will discuss this later in the book.

Don't forget to accept the license agreement and select the right distribution for your operating system (Windows, Linux, or macOS).

Now that we have a JDK, we need a tool to build our application and convert it into a format that we will be able to deploy in our Java EE server. This book will use Apache Maven (https://maven.apache.org/) to build the application. It can be downloaded on the Apache Maven download page (https://maven.apache.org/download.cgi). We need the binary distribution; Linux users have to select the tar.gz format while Windows users have to select the .zip archive.

At this point, we have everything we need to create our application. You will probably want to have an Integrated Development Environment (IDE), such as NetBeans (https://netbeans.org/), Eclipse (https://eclipse.org/ide/), or Intellij Idea (https://www.jetbrains.com/idea/). Since this book is more about performance than development, we won't go into much detail about IDEs. If you need one, just select the one you are the most familiar with.

To ensure that the environment is ready, we will set variables to define where to find the software without having to use the full path to the binary or script each time. JAVA_HOME will point to the folder you extracted from the JDK, and MAVEN_HOME will point to the folder you extracted from the Apache Maven archive. Here is an example for Linux (replace export with set for a DOS shell):

$ export JAVA_HOME=/home/developer/jdk1.8.0_144
$ export MAVEN_HOME=/home/developer/apache-maven-3.5.0

Now, we need to ensure that the JDK and Maven tools are available. For this, we add them to PATH on Linux and Path on Windows:

# On Linux
$ export PATH=$JAVA_HOME/bin:$MAVEN_HOME/bin:$PATH

# On Windows
$ set Path=%JAVA_HOME%\bin;%MAVEN_HOME%\bin;%Path%

You can validate your setup by executing the following command:

$ mvn -version
Maven home: /home/developer/apache-maven-3.5.0
Java version: 1.8.0_144, vendor: Oracle Corporation
Java home: /home/developer/jdk1.8.0_144/jre
Default locale: fr_FR, platform encoding: UTF-8
OS name: "linux", version: "4.10.0-32-generic", arch: "amd64", family: "unix"

To run a Java EE application, we also need a container, such as GlassFish, WildFly, WebSphere Liberty Profile, or Apache TomEE. The deployment being specific and Java EE 8 being very recent, we will use GlassFish in this book.

Finally, to get everything ready, we will use a database. We will use MySQL as a very common case, but any other relational database will work as well. You can download MySQL from https://dev.mysql.com/downloads/mysql/, but most Linux distributions will have a package ready to install. For instance, on Ubuntu you can just execute the following line:

sudo apt install mysql-server

The application architecture

Our application will import some stock quotations daily; it will then expose them and allow you to update them through a web service.

To implement it, we will use a standard Java EE architecture:

  • The persistence layer will use JPA 2.2 and store the data in a MySQL database.
  • A service layer will implement the business logic and orchestrate the persistence layer. It will rely on the following:
    • Java Transaction API (JTA) 1.2 for transactionality
    • Context and Dependency Injection 2.0 (CDI) for Inversion of Control (IoC)
    • Bean Validation 2.0 for validations
  • A front layer will expose a part of the service layer through HTTP. It will rely on the following:
    • JAX-RS 2.1 for stateless endpoints
    • WebSocket 1.1 for stateful communications
    • JSON-B 1.0 for marshalling/unmarshalling

Here is a picture summarizing this structure:

Application project highlights

To be able to create and run this application, we will need to set up a build tool. For this book, it will be Apache Maven; however, Gradle, Ant, or any other alternative will work perfectly as well. We will then identify some key parts of the application code and, finally, we will insert some data to ensure that our application is usable before investigating its performance.

The build

The only dependency Java EE requires is the Java EE API:

<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>${javaee-api.version}</version> <!-- 8.0 -->
<scope>provided</scope>
</dependency>
If you prefer, you can indeed register all the individual specifications, but it will require more work to maintain the list with Java EE upgrades. For this reason, the bundle is often preferred.

Here, the point is to ensure that the API is provided, which means it will not be packaged in the deliverable and will inherit from the server API. The server providing the services associated with the API also provides the API with the right supported version and the right defaults matching the built-in implementations.

Since Java EE 6, there are two main flavors of Java EE: the web profile and the full profile. The web profile is a light version, with only half the specifications compared with the full profile, more or less. The web profile supports only web applications and, therefore, war files. Most of this book will work with a web profile server, so we will package our application as war:

<packaging>war</packaging>

Since we need Java 8, don't forget to configure the Java source and target version in the build. It can be done in different ways, but configuring maven-compiler-plugin as follows is an efficient one:

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>

The persistence layer

Our data model will be simple: a quote will be linked to a customer. This means that a customer can see a set of quotes, and quotes can be seen by a set of customers. In terms of use cases, we want to be able to monetize our API and make the customers pay to access some quote prices. To do so, we will need a sort of whitelist of quotes per customer.

JPA uses a descriptor called persistence.xml, placed in the META-INF repository of resources (or WEB-INF), which defines how EntityManager, which is a class that allows the manipulation of our model, will be instantiated. Here is what it looks like for our application:

<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd"
version="2.2">
<persistence-unit name="quote">
<class>com.github.rmannibucau.quote.manager.model.Customer</class>
<class>com.github.rmannibucau.quote.manager.model.Quote</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="avax.persistence.schema
-generation.database.action"
value="create"/>
</properties>
</persistence-unit>
</persistence>

The link between the database and the Java code is done through entities. An entity is a plain old java object (POJO) that is decorated with the javax.persistence annotations. They mainly define the mapping between the database and the Java model. For instance, @Id marks a Java field that must match the database identifier.

Here is an example of our Quote entity:

@Entity
public class Quote {
@Id
@GeneratedValue
private long id;

private String name;

private double value;

@ManyToMany
private Set<Customer> customers;

// getters/setters
}

This simple model implicitly defines a QUOTE table with three columns, ID, NAME, and VALUE (the casing can depend on the database), and a table to manage the relationship with the CUSTOMER table, which is named QUOTE_CUSTOMER by default.

In the same spirit, our Customer entity just defines an identifier and name as columns and also the reverse relationship to the Quote entity:

@Entity
public class Customer {
@Id
@GeneratedValue
private long id;

private String name;

@ManyToMany(mappedBy = "customers")
private Set<Quote> quotes;

// getters/setters
}

What is important here is to notice the relationships in the model. We will deal with this later on.

The service layer

The goal of the book being to discuss the performance and not how to write a Java EE application, we will not detail the whole service layer here. However, to ensure a common knowledge of what we are dealing with, we will illustrate the code with one service.

We are using JTA 1.2 with JPA 2.2 to establish a link between our database and the Java model. The QuoteService bean, responsible for managing the Quote persistence, can therefore look like the following:

@Transactional
@ApplicationScoped
public class QuoteService {
@PersistenceContext
private EntityManager entityManager;

public Optional<Quote> findByName(final String name) {
return entityManager.createQuery("select q from Quote q where
q.name = :name"
, Quote.class)
.setParameter("name", name)
.getResultStream()
.findFirst();
}

public Optional<Quote> findById(final long id) {
return Optional.ofNullable(entityManager.find(Quote.class, id));
}

public long countAll() {
return entityManager.createQuery("select count(q) from Quote
q"
, Number.class)
.getSingleResult()
.longValue();
}

public Quote create(final Quote newQuote) {
entityManager.persist(newQuote);
entityManager.flush();
return newQuote;
}

// ... other methods based on the same model
}

JPA may or may not be used in a transactional context, depending on the kind of operation you do. When you read data, you can often do it without any transaction until you need some lazy loading. However, when you write data (insert/update/delete entities), JPA requires a running transaction to be able to execute the action. This is to ensure consistency of data but also has some implications on the code. To respect that requirement, and have an active transaction, we use @Transactional on methods instead of relying on Enterprise Java Bean 3.2 (EJB 3.2), so we can reuse the power of CDI (@ApplicationScoped, for instance, which will avoid creating a new instance per injection).

Our finders are very simple and directly use the EntityManager API. The only new thing Java 8 brings us in this code is the ability to wrap the result with Optional which offers a programmatic way to deal with the presence or absense of the entity instead of relying on a null check. Concretely, the caller can use our finder this way:

final int quoteCount = getCustomer().getCountFor("myquote");
final double quotesPrice = quoteService.findByName("myquote")
.map(quote -> quote.getValue() * quoteCount)
.orElse(0);

This kind of code hides the conditional branches behind a fluent API, which makes it more expressive and readable, while the lambdas stay small enough.

Finally, we used inline queries in this code, not static ones like in the @NamedQuery API.

The JAX-RS layer

If we step back one second and think about which stopover the application will execute, we can identify a few of them:

  • HTTP communication handling
  • Payload (un)marshalling
  • Routing
  • Service invocation

Because of the separation of concern principles, or simply for technical constraints between layers, it is very common to use a Data Transfer Object between the JAX-RS/front layer and the CDI/business layer. Of course, this statement can be applied to the business sub-layers as well, but in the case of this book, we will just do it in the JAX-RS layer. To make it obvious in the book, we will prefix the JAX-RS model with Json. Check out the following code snippet:

@JsonbPropertyOrder({"id", "name", "customerCount"})
public class JsonQuote {
private long id;
private String name;
private double value;

@JsonbProperty("customer_count")
private long customerCount;

// getters/setters
}

In this context, the front layer role is to delegate most of the logic to the service layer and convert the business model to the front model (it can almost be seen as a Java to JavaScript conversion for a lot of modern applications):

@Path("quote")
@RequestScoped
public class QuoteResource {
@Inject
private QuoteService quoteService;

@GET
@Path("{id}")
public JsonQuote findById(@PathParam("id") final long id) {
return quoteService.findById(id) // delegation to the business
layer
.map(quote -> { // the model conversion
final JsonQuote json = new JsonQuote();
json.setId(quote.getId());
json.setName(quote.getName());
json.setValue(quote.getValue());

json.setCustomerCount(ofNullable(quote.getCustomers())
.map(Collection::size).orElse(0));
return json;
})
.orElseThrow(() -> new
WebApplicationException(Response.Status.NO_CONTENT));
}

// other methods
}
We set the JAX-RS @ApplicationPath to /api to ensure that our endpoints are deployed under the /api subcontext.

The WebSocket layer

Why use JAX-RS and WebSocket? Don't they serve the same purpose? Not exactly, in fact, it is becoming more and more common to use both in the same application even if WebSocket is still a bit recent.

JAX-RS (and, more generally, HTTP/1 and the brand new HTTP/2) is generally web application oriented. Understand that it is often used for applications with a user interface (which needs to be compatible with all browsers). It is also commonly used in environments where you cannot assume much about the network setup. More particularly, in environments where you cannot assume the network setup, the proxies will let WebSocket connections work properly (either preventing them completely or disconnecting them too early). The last common case where HTTP-based solutions make a lot of sense is to try to target a market where clients can be developed in any language (Java, Python, Ruby, Go, Node.js, and so on). The fact that the technology is today spreading all over the world and works well with stateless connections, makes it easier to get started with, and it is therefore more accessible than WebSocket, which requires some care from client developers.

However, WebSocket will fit cases where you have higher performance or reactivity constraints, a state to maintain in order to handle the business use case, or you simply want to push the information from the server without requiring a client operation (such as polling).

When you start using a connected protocol such as WebSocket, the first thing to define is your own communication protocol: the format of the message you send/receive and the order of the messages (if needed).

Our WebSocket layer will be responsible for enabling a client to quickly access the quote prices. Therefore, we will react on a client's request (it will contain the name of the quote that we want to get the price for) and we will respond with two pieces of information: whether we found the quote and the current price, if existing.

Then, you need to pick a format to prepare the content sent through the WebSocket over the wire. Here, the choice is often guided by a trade-off between the client (consumers of the service), the requirements, the performances, and the ease of implementation. In our case, we will consider that our clients can be written in Java as well as in JavaScript. That is why we will use JSON.

To summarize the protocol, here is a full communication round-trip, as shown in the following diagram:

The communication protocol is based on a single message type in our case, so a full client/server communication looks like these steps:

  1. The client will connect to the server.
  2. The client will request the price of a quote N times, based on its symbol (name/identifier).
  3. Assuming there is no I/O error or timeout, the client will trigger a disconnect, which will end the communication.

In terms of code, we need multiple bricks of Java EE and we need the following to put them together:

  • The WebSocket API, obviously
  • JSON-B (we could use JSON-P, but it is less friendly) for the Java to JSON conversion
  • CDI, to link the WebSocket to the business layer

To start easy, we can modelize our payloads. Our request has only one name attribute, so JSON-B allows us to define it this way:

public class ValueRequest {
private String name;

// getter/setter
}

On the other side (that is, the response), we have to return a value attribute with the price of the quote and a found Boolean marking value as filled or not. Here again, JSON-B allows us to do a direct mapping of this model with a plain POJO:

public static class ValueResponse {
private double value;
private boolean found;

// getters/setters
}

Now, we need to ensure that the WebSocket will be able to deserialize and serialize these objects as required. The specification defines Encoder and Decoder APIs for this purpose. Since we will back our implementation by JSON-B, we can directly implement it using the (I/O) stream flavors of these APIs (called TextStream). Actually, before doing so, we need to get a Jsonb instance. Considering that we have already created one and made it available in CDI, we can then simply inject the instance in our coders:

@Dependent
public class JsonEncoder implements Encoder.TextStream<Object> {
@Inject
private Jsonb jsonb;

@Override
public void encode(final Object o, final Writer writer) throws EncodeException, IOException {
jsonb.toJson(o, writer);
}

// other methods are no-op methods
}

The decoding side is now fast to develop, thanks to the JSON-B API, which fits this usage very well with its fromJson() API. We will just note that this side is specific to ValueRequest, since we need to specify the type to instantiate it (compared with the encoding side, which can determine it dynamically):

@Dependent
public class RequestDecoder implements Decoder.TextStream<ValueRequest> {
@Inject
private Jsonb jsonb;

@Override
public ValueRequest decode(final Reader reader) throws DecodeException, IOException {
return jsonb.fromJson(reader, ValueRequest.class);
}

// other methods are no-op methods
}

Now that we have a way to handle our messages, we need to bind our WebSocket endpoint and implement the @OnMessage method to find the price and send it back to the client relying on our business layer. In terms of implementation, we will react to a ValueRequest message, try to find the corresponding quote, fill the response payload, and send it back to the client:

@Dependent
@ServerEndpoint(
value = "/quote",
decoders = RequestDecoder.class,
encoders = JsonEncoder.class)
public class DirectQuoteSocket {
@Inject
private QuoteService quoteService;

@OnMessage
public void onMessage(final Session session, final ValueRequest request) {
final Optional<Quote> quote = quoteService.findByName(request.getName());
final ValueResponse response = new ValueResponse();
if (quote.isPresent()) {
response.setFound(true);
response.setValue(quote.get().getValue()); // false
}

if (session.isOpen()) {
try {
session.getBasicRemote().sendObject(response);
}
catch (final EncodeException | IOException e) {
throw new IllegalArgumentException(e);
}
}
}
}

Provision some data

At this point, we have our application. Now, we need to ensure that it has some data and, then, move on to evaluating its performance.

Without delving too much into the business details, we will implement the provisioning in two passes:

  • Find all the symbols to update
  • For each symbol found, update the price in the database

To do so, we will use two public webservices:

The first one is a plain CSV file, which we will parse without any library to keep things simple and because the format does not require special escaping/parsing. The second one will return a JSON payload, which we can read directly using the JAX-RS 2.1 client API.

Here is how we can retrieve our data:

private String[] getSymbols(final Client client) {
try (final BufferedReader stream = new BufferedReader(
new InputStreamReader(
client.target(symbolIndex)
.request(APPLICATION_OCTET_STREAM_TYPE)
.get(InputStream.class),
StandardCharsets.UTF_8))) {

return stream.lines().skip(2/*comment+header*/)
.map(line -> line.split(","))
.filter(columns -> columns.length > 2 && !columns[1].isEmpty())
.map(columns -> columns[1])
.toArray(String[]::new);
} catch (final IOException e) {
throw new IllegalArgumentException("Can't connect to find symbols", e);
}
}

Note that we directly read a buffered reader backed by the HTTP response stream. Once the symbols are extracted, we can simply iterate over them and request the price of each quote:

try {
final Data data = client.target(financialData)
.resolveTemplate("symbol", symbol)
.request(APPLICATION_JSON_TYPE)
.get(Data.class);

if (!data.hasPrice()) {
LOGGER.warning("Can't retrieve '" + symbol + "'");
return;
}

final double value = data.getQuoteSummary().getResult().get(0)
.getFinancialData().getCurrentPrice().getRaw();

final Quote quote = quoteService.mutate(symbol, quoteOrEmpty ->
quoteOrEmpty.map(q -> {
q.setValue(value);
return q;
}).orElseGet(() -> {
final Quote newQuote = new Quote();
newQuote.setName(symbol);
newQuote.setValue(value);
quoteService.create(newQuote);
return newQuote;
}));

LOGGER.info("Updated quote '" + quote.getName() + "'");
} catch (final WebApplicationException error) {
LOGGER.info("Error getting '" + symbol + "': " + error.getMessage()
+ " (HTTP " + (error.getResponse() == null ? "-" :
error.getResponse().getStatus()) + ")");
}

This piece of code sends an HTTP request, thanks to the JAX-RS client API and JSON-B, which unmarshalls a data model. Then, we use the obtained data to update our database quote if it already exists; otherwise, we use the data to create the database quote.

The code now needs to be wired to be executed. We have multiple options here:

  • Execute it at startup
  • Execute it regularly
  • Execute it when an endpoint is called

In the context of this book, we will use the first two options. The startup is common for us, even if it is not as realistic, because once started, we will get some data. The second option will use an EJB 3.2 @Schedule, which will run hourly.

The startup implementation requires a simple CDI bean with a method calling the previous logic when @ApplicationScoped is created (at startup):

@ApplicationScoped
public class InitialProvisioning {
@Inject
private ProvisioningService provisioningService;

public void onStart(@Observes @Initialized(ApplicationScoped.class) final ServletContext context) {
provisioningService.refresh();
}
}

The scheduling is done, thanks to the Enterprise Java Bean @Schedule API, which allows us, in one annotation, to request the container to regularly execute a method:

@Singleton
@Lock(WRITE)
public class DataRefresher {
@Inject
private ProvisioningService provisioningService;

@Schedule(hour = "*", persistent = false, info = "refresh-quotes")
public void refresh() {
provisioningService.refresh();
}
}
In a real application, you will probably want to configure the refresh frequency and use the TimerService API to trigger the execution based on the application configuration. In the same spirit, the startup execution could be ignored based on the configuration in order to have a faster startup.

Application summary

When working on the performance, it is always important to keep two things in mind:

  • The application business (what the application does)
  • The application technical stack (how the application was designed)

Even if the information you have about these two points is very high-level, ensure that you know them before working on the performance.

Let's do this exercise with our application and ensure that we know how to answer both the questions.

The application business

Our application is responsible for providing the quote prices to HTTP or WebSocket clients. With its model and customer/quote relationship, it can enable us to provide (or not provide) the price accessed by the customer if we add permissions or rules, for instance. What is important to see at this stage is that both the entities are in a relationship and that our application can visit this relationship for its business needs and trigger an implicit lazy loading of the relationship entities.

The data is injected into the system based on two external HTTP sources (CBOE and Yahoo). The first one provides a symbol dictionary of the quotes, and the second one, the prices.

The application design

Technically, the provisioning of the quote and prices is done asynchronously (not when a customer request is sent). It retrieves the data using a JAX-RS 2.1 client and inserts it as fast as possible into the database.

Access to the application is gained either through HTTP or WebSocket. In both cases, the application uses a JSON format for message exchange.

The application server

Java EE defines specifications and, therefore, you can find several different implementations. Each major vendor has its own server but, of course, for us and Java EE, a lot of servers are fully open source. As Java EE 8 is very recent, we will use GlassFish, which is the reference implementation and is therefore the first one to be compliant with the specification (it must be released with the specification). However, there are a lot of alternatives (such as Apache TomEE, Wildfly, Payara, Liberty Profile, and so on), which will probably follow in the coming months.

GlassFish can be downloaded from its website (https://javaee.github.io/glassfish/download). We need the 5.x version to target Java EE 8, but due to its early release, a major part of this book will work with the previous versions.

If you want to integrate it with your development environment (and Maven), you can add the GlassFish repository to pom.xml, as follows:

<pluginRepository>
<id>maven-java-net</id>
<url>https://maven.java.net/content/groups/promoted/</url>
</pluginRepository>

Add the GlassFish plugin without forgetting to specify the version of the server in order to override the default one, which is now quite old:

<plugin> <!-- glassfish.version = 5.0 -->
<groupId>org.glassfish.embedded</groupId>
<artifactId>maven-embedded-glassfish-plugin</artifactId>
<version>3.1.2.2</version>
<configuration>
<app>target/${project.build.finalName}</app>
<port>9090</port>
<contextRoot>${project.artifactId}</contextRoot>
</configuration>
<dependencies>
<dependency>
<groupId>org.glassfish.main.common</groupId>
<artifactId>simple-glassfish-api</artifactId>
<version>${glassfish.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.main.extras</groupId>
<artifactId>glassfish-embedded-all</artifactId>
<version>${glassfish.version}</version>
</dependency>
</dependencies>
</plugin>

With this setup, you can run the following command to package the application as war and deploy it in GlassFish:

$ mvn package embedded-glassfish:run

To shut down the server, type X and ENTER.

Testing the application

Before starting to work on our application from the performance window, let's get a bit familiar with it. We will not browse and test all the endpoints but just check how to get a price using the JAX-RS layer and WebSocket layer. In other words, we will define two customer use cases of our application.

The goal here is to ensure that we know how to use the application to be able to write test scenarios later. To do so, we will execute some requests manually on both fronts (HTTP and WebSocket).

Get a quote price the JAX-RS way

The endpoint we saw previously has been deployed on /<application_context>/api/quote/{quoteId} with the context of the web application, application_context. If you used the previous setup, it is, most likely, the artifact ID of the Maven project. Let's consider from now on that it is quote-manager.

Here is what it returns for one of the quotes:

$ curl -v http://localhost:9090/quote-manager/api/quote/8
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 9090 (#0)
> GET /quote-manager/api/quote/8 HTTP/1.1
> Host: localhost:9090
> User-Agent: curl/7.52.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: Undefined Product Name - define product and version info in config/branding 0.0.0
< X-Powered-By: Servlet/3.1 JSP/2.3 (Undefined Product Name - define product and version info in config/branding 0.0.0 Java/Oracle Corporation/1.8)
< Content-Type: application/json
< Content-Length: 54
<
* Curl_http_done: called premature == 0
* Connection #0 to host localhost left intact
{"id":8,"name":"JOBS","customer_count":0,"value":59.4}

This kind of application often needs a kind of index endpoint to be able to browse quotes (in a nice user interface or a command-line interface, for instance). In our case, it is our find all endpoint, which supports pagination through the query parameters. Here is how to use it and the kind of data it returns:

$ curl -v http://localhost:9090/quote-manager/api/quote?from=0&to=5
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 9090 (#0)
> GET /quote-manager/api/quote?from=0 HTTP/1.1
> Host: localhost:9090
> User-Agent: curl/7.52.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: Undefined Product Name - define product and version info in config/branding 0.0.0
< X-Powered-By: Servlet/3.1 JSP/2.3 (Undefined Product Name - define product and version info in config/branding 0.0.0 Java/Oracle Corporation/1.8)
< Content-Type: application/json
< Content-Length: 575
<
{"total":10,"items":[{"id":1,"name":"FLWS","customer_count":0,"value":9.0},{"id":2,"name":"VNET","customer_count":0,"value":5.19},{"id":3,"name":"XXII","customer_count":0,"value":2.2},{"id":4,"name":"TWOU","customer_count":0,"value":50.1},{"id":5,"name":"DDD","customer_count":0,"value":12.56},{"id":6,"name":"MMM","customer_count":0,"value":204.32},{"id":7,"name":"WBAI","customer_count":0,"value":10.34},{"id":8,"name":"JOBS","customer_count":0,"value":59.4},{"id":9,"name":"WUBA","customer_count":0,"value":62.63},{"id":10,"name":"CAFD","customer_count":0,"value":14.42}]}

Get the price, the WebSocket way

The WebSocket endpoint is deployed on /<application_context>/quote, and some exchanges can look like the following:

connect> ws://localhost:9090/quote-manager/quote
send> {"name":"VNET"}
received< {"found":true,"value":5.19}
send> {"name":"DDD"}
received< {"found":true,"value":12.56}
disconnect>
Connection closed: Close status 1000 (Normal Closure)

What is interesting to see in this communication dump is the fact that the connection lasts for more than one request, and it is based on the symbol more than the identifier (compared to the previous JAX-RS samples).

Setting up MySQL

All the previous parts will work transparently in Glassfish, as it can provide you with a default database if none is set since Java EE 7. This default database is an Apache Derby one for Glassfish. Considering that we will work on the performance soon, we want a recent production database. To ensure this, we will set up MySQL.

Assuming that you installed MySQL for your operating system and that it runs on localhost:3306 (the default), we need to create a new database. Let's call it quote_manager:

$ mysql -u root -p
Enter password: ******
...
mysql> create database quote_manager;
Query OK, 1 row affected (0.00 sec)

Now that we have a database, we can configure it in Glassfish and let JPA 2.2 create the tables for us based on our model. For this, we need to create glassfish-resources.xml in the WEB-INF folder of the war package (put it in src/main/webapp/WEB-INF in the Maven project):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resources PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN"
"http://glassfish.org/dtds/glassfish-resources_1_5.dtd">
<resources>
<jdbc-connection-pool allow-non-component-callers="false"
associate-with-thread="false"
connection-creation-retry-attempts="0"
connection-creation-retry-interval-in-seconds="10"
connection-leak-reclaim="false"
connection-leak-timeout-in-seconds="0"
connection-validation-method="auto-commit"
datasource-classname="com.mysql.jdbc.jdbc2.optional.MysqlDataSource"
fail-all-connections="false"
idle-timeout-in-seconds="300"
is-connection-validation-required="false"
is-isolation-level-guaranteed="true"
lazy-connection-association="false"
lazy-connection-enlistment="false"
match-connections="false"
max-connection-usage-count="0"
max-pool-size="10"
max-wait-time-in-millis="120000"
name="MySQLConnectinoPool"
non-transactional-connections="false"
pool-resize-quantity="2"
res-type="javax.sql.DataSource"
statement-timeout-in-seconds="-1"
steady-pool-size="8"
validate-atmost-once-period-in-seconds="0"
validation-table-name="DUAL" wrap-jdbc-objects="false">
<property name="URL" value="jdbc:mysql://localhost:3306/quote_manager"/>
<property name="User" value="root"/>
<property name="Password" value="password"/>
</jdbc-connection-pool>
<jdbc-resource jndi-name="java:app/jdbc/quote_manager" pool-name="MySQLConnectinoPool" enabled="true"/>
</resources>

Alternatively, you can also do it through code using the @DataSourceDefinition annotation, which is more portable than the specific descriptor of GlassFish (this is the solution we will rely on from now on):

@DataSourceDefinition(
name = "java:app/jdbc/quote_manager",
className = "com.mysql.jdbc.Driver",
url = "jdbc:mysql://localhost:3306/quote_manager",
user = "root",
password = "password"
)
public class DataSourceConfiguration {
}

If you recompile and restart the server, you will see that it has created the tables, thanks to our persistence.xml configuration:

mysql> show tables;
+-------------------------+
| Tables_in_quote_manager |
+-------------------------+
| CUSTOMER |
| QUOTE |
| QUOTE_CUSTOMER |
| SEQUENCE |
+-------------------------+

If you are waiting for the server to start and have kept the provisioning activated, you will also see some data in the QUOTE table:

mysql> select * from QUOTE limit 10;
+----+-------+-------+
| ID | NAME | VALUE |
+----+-------+-------+
| 1 | FLWS | 9 |
| 2 | VNET | 5.19 |
| 3 | XXII | 2.2 |
| 4 | TWOU | 50.1 |
| 5 | DDD | 12.56 |
| 6 | MMM | 204.32|
| 7 | WBAI | 10.34 |
| 8 | JOBS | 59.4 |
| 9 | WUBA | 62.63 |
| 10 | CAFD | 14.42 |
+----+-------+-------+

Conclusion

Now we have our functional Quote Manager application, and we can deploy it in a Java EE 8 server (GlassFish here) and store our data in a real database (MySQL).

Till now, we have mainly worked on making the application functional. Thanks to the high-level APIs of Java EE, this was not so hard, but it is important to understand what we used and what the performance implications of each element of our stack are, to be able to validate/invalidate the performance figures once you have them in your hands.

Summary

In this chapter, we created an application responsible for managing quote prices and enabling clients to access them through HTTP and WebSockets. The application uses plain Java EE code (no external dependencies). We also saw how to link the application to a database. We used MySQL as the database, which is a free and very common choice.

In the next chapter, we will go deeper into the Java EE stack, and understand its role and what it implies for the application in terms of the application's performance.

Left arrow icon Right arrow icon
Download code icon Download Code

Key benefits

  • Learn how to write a JavaEE application with performance constraints (Service Level Agreement—SLA) leveraging the platform
  • Learn how to identify bottlenecks and hotspots in your application to fix them
  • Ensure that you are able to continuously control your performance in production and during development

Description

The ease with which we write applications has been increasing, but with this comes the need to address their performance. A balancing act between easily implementing complex applications and keeping their performance optimal is a present-day need. In this book, we explore how to achieve this crucial balance while developing and deploying applications with Java EE 8. The book starts by analyzing various Java EE specifications to identify those potentially affecting performance adversely. Then, we move on to monitoring techniques that enable us to identify performance bottlenecks and optimize performance metrics. Next, we look at techniques that help us achieve high performance: memory optimization, concurrency, multi-threading, scaling, and caching. We also look at fault tolerance solutions and the importance of logging. Lastly, you will learn to benchmark your application and also implement solutions for continuous performance evaluation. By the end of the book, you will have gained insights into various techniques and solutions that will help create high-performance applications in the Java EE 8 environment.

Who is this book for?

If you're a Java developer looking to improve the performance of your code or simply wanting to take your skills up to the next level, then this book is perfect for you.

What you will learn

  • Identify performance bottlenecks in an application
  • Locate application hotspots using performance tools
  • Understand the work done under the hood by EE containers and its impact on performance
  • Identify common patterns to integrate with Java EE applications
  • Implement transparent caching on your applications
  • Extract more information from your applications using Java EE without modifying existing code
  • Ensure constant performance and eliminate regression

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Jan 30, 2018
Length: 350 pages
Edition : 1st
Language : English
ISBN-13 : 9781788473064
Vendor :
Oracle
Category :
Languages :
Tools :

What do you get with a Packt Subscription?

Free for first 7 days. $19.99 p/m after that. Cancel any time!
Product feature icon Unlimited ad-free access to the largest independent learning library in tech. Access this title and thousands more!
Product feature icon 50+ new titles added per month, including many first-to-market concepts and exclusive early access to books as they are being written.
Product feature icon Innovative learning tools, including AI book assistants, code context explainers, and text-to-speech.
Product feature icon Thousands of reference materials covering every tech concept you need to stay up to date.
Subscribe now
View plans & pricing

Product Details

Publication date : Jan 30, 2018
Length: 350 pages
Edition : 1st
Language : English
ISBN-13 : 9781788473064
Vendor :
Oracle
Category :
Languages :
Tools :

Packt Subscriptions

See our plans and pricing
Modal Close icon
$19.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
$199.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just €5 each
Feature tick icon Exclusive print discounts
$279.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just €5 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total 120.97
Java EE 8 and Angular
€36.99
Java EE 8 High Performance
€41.99
Architecting Modern Java EE Applications
€41.99
Total 120.97 Stars icon

Table of Contents

11 Chapters
Money – The Quote Manager Application Chevron down icon Chevron up icon
Looking Under the Cover – What is This EE Thing? Chevron down icon Chevron up icon
Monitor Your Application Chevron down icon Chevron up icon
Application Optimization – Memory Management and Server Configuration Chevron down icon Chevron up icon
Scale Up – Threading and Implications Chevron down icon Chevron up icon
Be Lazy; Cache Your Data Chevron down icon Chevron up icon
Be Fault-Tolerant Chevron down icon Chevron up icon
Loggers and Performances – A Trade-Off Chevron down icon Chevron up icon
Benchmarking Your Application Chevron down icon Chevron up icon
Continuous Performance Evaluation Chevron down icon Chevron up icon
Another Book You May Enjoy Chevron down icon Chevron up icon

Customer reviews

Top Reviews
Rating distribution
Full star icon Full star icon Full star icon Half star icon Empty star icon 3.9
(36 Ratings)
5 star 36.1%
4 star 41.7%
3 star 11.1%
2 star 2.8%
1 star 8.3%
Filter icon Filter
Top Reviews

Filter reviews by




Sergei Lvov Nov 21, 2022
Full star icon Full star icon Full star icon Full star icon Full star icon 5
Udemy Verified review Udemy
Shreeharsha GN Oct 18, 2022
Full star icon Full star icon Full star icon Full star icon Full star icon 5
Udemy Verified review Udemy
praween ranjan Sep 05, 2021
Full star icon Full star icon Full star icon Full star icon Full star icon 5
Udemy Verified review Udemy
Łukasz Warian May 06, 2021
Full star icon Full star icon Full star icon Full star icon Full star icon 5
Udemy Verified review Udemy
Hasan Yusuf Jan 05, 2021
Full star icon Full star icon Full star icon Full star icon Full star icon 5
Udemy Verified review Udemy
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

What is included in a Packt subscription? Chevron down icon Chevron up icon

A subscription provides you with full access to view all Packt and licnesed content online, this includes exclusive access to Early Access titles. Depending on the tier chosen you can also earn credits and discounts to use for owning content

How can I cancel my subscription? Chevron down icon Chevron up icon

To cancel your subscription with us simply go to the account page - found in the top right of the page or at https://subscription.packtpub.com/my-account/subscription - From here you will see the ‘cancel subscription’ button in the grey box with your subscription information in.

What are credits? Chevron down icon Chevron up icon

Credits can be earned from reading 40 section of any title within the payment cycle - a month starting from the day of subscription payment. You also earn a Credit every month if you subscribe to our annual or 18 month plans. Credits can be used to buy books DRM free, the same way that you would pay for a book. Your credits can be found in the subscription homepage - subscription.packtpub.com - clicking on ‘the my’ library dropdown and selecting ‘credits’.

What happens if an Early Access Course is cancelled? Chevron down icon Chevron up icon

Projects are rarely cancelled, but sometimes it's unavoidable. If an Early Access course is cancelled or excessively delayed, you can exchange your purchase for another course. For further details, please contact us here.

Where can I send feedback about an Early Access title? Chevron down icon Chevron up icon

If you have any feedback about the product you're reading, or Early Access in general, then please fill out a contact form here and we'll make sure the feedback gets to the right team. 

Can I download the code files for Early Access titles? Chevron down icon Chevron up icon

We try to ensure that all books in Early Access have code available to use, download, and fork on GitHub. This helps us be more agile in the development of the book, and helps keep the often changing code base of new versions and new technologies as up to date as possible. Unfortunately, however, there will be rare cases when it is not possible for us to have downloadable code samples available until publication.

When we publish the book, the code files will also be available to download from the Packt website.

How accurate is the publication date? Chevron down icon Chevron up icon

The publication date is as accurate as we can be at any point in the project. Unfortunately, delays can happen. Often those delays are out of our control, such as changes to the technology code base or delays in the tech release. We do our best to give you an accurate estimate of the publication date at any given time, and as more chapters are delivered, the more accurate the delivery date will become.

How will I know when new chapters are ready? Chevron down icon Chevron up icon

We'll let you know every time there has been an update to a course that you've bought in Early Access. You'll get an email to let you know there has been a new chapter, or a change to a previous chapter. The new chapters are automatically added to your account, so you can also check back there any time you're ready and download or read them online.

I am a Packt subscriber, do I get Early Access? Chevron down icon Chevron up icon

Yes, all Early Access content is fully available through your subscription. You will need to have a paid for or active trial subscription in order to access all titles.

How is Early Access delivered? Chevron down icon Chevron up icon

Early Access is currently only available as a PDF or through our online reader. As we make changes or add new chapters, the files in your Packt account will be updated so you can download them again or view them online immediately.

How do I buy Early Access content? Chevron down icon Chevron up icon

Early Access is a way of us getting our content to you quicker, but the method of buying the Early Access course is still the same. Just find the course you want to buy, go through the check-out steps, and you’ll get a confirmation email from us with information and a link to the relevant Early Access courses.

What is Early Access? Chevron down icon Chevron up icon

Keeping up to date with the latest technology is difficult; new versions, new frameworks, new techniques. This feature gives you a head-start to our content, as it's being created. With Early Access you'll receive each chapter as it's written, and get regular updates throughout the product's development, as well as the final course as soon as it's ready.We created Early Access as a means of giving you the information you need, as soon as it's available. As we go through the process of developing a course, 99% of it can be ready but we can't publish until that last 1% falls in to place. Early Access helps to unlock the potential of our content early, to help you start your learning when you need it most. You not only get access to every chapter as it's delivered, edited, and updated, but you'll also get the finalized, DRM-free product to download in any format you want when it's published. As a member of Packt, you'll also be eligible for our exclusive offers, including a free course every day, and discounts on new and popular titles.