Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
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.

eBook
€22.99 €32.99
Paperback
€41.99
Subscription
Free Trial
Renews at €18.99p/m

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
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
Estimated delivery fee Deliver to Slovakia

Premium delivery 7 - 10 business days

€25.95
(Includes tracking information)

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

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Estimated delivery fee Deliver to Slovakia

Premium delivery 7 - 10 business days

€25.95
(Includes tracking information)

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
€18.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
€189.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
€264.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
Architecting Modern Java EE Applications
€41.99
Java EE 8 High Performance
€41.99
Java EE 8 and Angular
€36.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 the delivery time and cost of print book? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela
What is custom duty/charge? Chevron down icon Chevron up icon

Customs duty are charges levied on goods when they cross international borders. It is a tax that is imposed on imported goods. These duties are charged by special authorities and bodies created by local governments and are meant to protect local industries, economies, and businesses.

Do I have to pay customs charges for the print book order? Chevron down icon Chevron up icon

The orders shipped to the countries that are listed under EU27 will not bear custom charges. They are paid by Packt as part of the order.

List of EU27 countries: www.gov.uk/eu-eea:

A custom duty or localized taxes may be applicable on the shipment and would be charged by the recipient country outside of the EU27 which should be paid by the customer and these duties are not included in the shipping charges been charged on the order.

How do I know my custom duty charges? Chevron down icon Chevron up icon

The amount of duty payable varies greatly depending on the imported goods, the country of origin and several other factors like the total invoice amount or dimensions like weight, and other such criteria applicable in your country.

For example:

  • If you live in Mexico, and the declared value of your ordered items is over $ 50, for you to receive a package, you will have to pay additional import tax of 19% which will be $ 9.50 to the courier service.
  • Whereas if you live in Turkey, and the declared value of your ordered items is over € 22, for you to receive a package, you will have to pay additional import tax of 18% which will be € 3.96 to the courier service.
How can I cancel my order? Chevron down icon Chevron up icon

Cancellation Policy for Published Printed Books:

You can cancel any order within 1 hour of placing the order. Simply contact customercare@packt.com with your order details or payment transaction id. If your order has already started the shipment process, we will do our best to stop it. However, if it is already on the way to you then when you receive it, you can contact us at customercare@packt.com using the returns and refund process.

Please understand that Packt Publishing cannot provide refunds or cancel any order except for the cases described in our Return Policy (i.e. Packt Publishing agrees to replace your printed book because it arrives damaged or material defect in book), Packt Publishing will not accept returns.

What is your returns and refunds policy? Chevron down icon Chevron up icon

Return Policy:

We want you to be happy with your purchase from Packtpub.com. We will not hassle you with returning print books to us. If the print book you receive from us is incorrect, damaged, doesn't work or is unacceptably late, please contact Customer Relations Team on customercare@packt.com with the order number and issue details as explained below:

  1. If you ordered (eBook, Video or Print Book) incorrectly or accidentally, please contact Customer Relations Team on customercare@packt.com within one hour of placing the order and we will replace/refund you the item cost.
  2. Sadly, if your eBook or Video file is faulty or a fault occurs during the eBook or Video being made available to you, i.e. during download then you should contact Customer Relations Team within 14 days of purchase on customercare@packt.com who will be able to resolve this issue for you.
  3. You will have a choice of replacement or refund of the problem items.(damaged, defective or incorrect)
  4. Once Customer Care Team confirms that you will be refunded, you should receive the refund within 10 to 12 working days.
  5. If you are only requesting a refund of one book from a multiple order, then we will refund you the appropriate single item.
  6. Where the items were shipped under a free shipping offer, there will be no shipping costs to refund.

On the off chance your printed book arrives damaged, with book material defect, contact our Customer Relation Team on customercare@packt.com within 14 days of receipt of the book with appropriate evidence of damage and we will work with you to secure a replacement copy, if necessary. Please note that each printed book you order from us is individually made by Packt's professional book-printing partner which is on a print-on-demand basis.

What tax is charged? Chevron down icon Chevron up icon

Currently, no tax is charged on the purchase of any print book (subject to change based on the laws and regulations). A localized VAT fee is charged only to our European and UK customers on eBooks, Video and subscriptions that they buy. GST is charged to Indian customers for eBooks and video purchases.

What payment methods can I use? Chevron down icon Chevron up icon

You can pay with the following card types:

  1. Visa Debit
  2. Visa Credit
  3. MasterCard
  4. PayPal
What is the delivery time and cost of print books? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela