Categories
Jakarta EE

Using Locks in Jakarta EE CDI

Jakarta EE applications are multi-threaded. The code to generate the response for the users’ requests runs in his own thread. This seems natural as we like to support multiple users at the same time.

For each user, data is retrieved and processed to return to the user. There are situations where data is coming from a single source and some synchronisation is required. Reading the data is no problem, but when we want to update them, we should have the guarantee that all data is updated in one go. So that threads that are reading the data see consistent data.

The Jakarta EE EJB Specification has the @Lock annotation to handle the synchronisation aspects of the method within an EJB Singleton bean. This blog describes what you can do if your application makes only use of CDI beans or when you want to synchronise the access to a data structure from within different beans.

JVM ReentrantReadWriteLock

The JVM class ReentrantReadWriteLock is created for the use case that is described in the introduction.

An instance maintains a pair of associated locks, one for read-only operations and one for writing. The read lock may be held simultaneously by multiple reader threads, so long as there are no writers. The write lock is exclusive.

Every piece of code that access our shared data for retrieving some information, not updating, must be protected by the read lock that is provided by the instance. The method, can be multiple ones if needed, or statements that update the data structure need to have the write lock before they can proceed.

This way, reading is possible by one or more threads simultaneously unless another part of your code has the write lock at the moment. And changing the data can only be done when no one is reading or they have to wait until the update is completed.

In a central location, a JVM singleton for example, we instantiate the object.

ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();

The pattern for reading from the data structure is

Lock lock = readWriteLock.readLock()
try {
   lock.lock();

    // All the read statements go here

} finally {
   lock.unlock();
}

A similar pattern for changing the data structure based on the write lock.

Lock lock = readWriteLock.writeLock()
try {
   lock.lock();

    // All the write statements go here

} finally {
   lock.unlock();
}

There exists also a variant that you do not wait indefinitely to obtain the lock, but an InterruptedException is thrown if the lock can’t be acquired within the time limit that is specified.

More info can be found on the readme page of the repository.

A CDI annotation

The above-described solution can be turned into a CDI interceptor that performs the tasks, similar to the @Lock annotation of Jakarta EE EJB specification.

You can create this yourself, or you can make use of the Atbash Named Lock library that is now available.

For Jakarta EE 8, add the following dependency to your project.

     <dependency>
         <groupId>be.atbash.cdi</groupId>
         <artifactId>locked</artifactId>
         <version>1.0-SNAPSHOT</version>
     </dependency>

The snapshot version is already available on Maven central. The final version will be Ade available in a couple of weeks. Together with the version based on the jakarta namespace so that you can use it with Jakarta EE 9.

You now have the be.atbash.cdi.lock.Locked annotation that you can use on any CDI method

@Locked
public String getValues() {

To use the generic read lock. Or the method that updates the data structure and no other reading should be in progress

@Locked(operation = Locked.Operation.WRITE)
public void writeValue(String value) {

But as the name suggest, you can also specify the name of the lock that you want to use. And thus have more than one lock available within your application.

@Locked(name = "special")

This annotation will operate on another instance of the ReentrantReadWriteLock class and thus work with locks that are indecent of the generic named ones.

Side effect

The write lock, without using the read lock from the pair, can be used to synchronise a method.

@Locked(operation = Locked.Operation.WRITE)
public void writeValue(String value) {

This declaration means that only one thread at a time can execute the method writeValue, which has the same effect as the synchronized keyword from the java language. When the annotation is used on multiple CDI methods, you have the same effect as using a synchronized block that make use of a singleton object so that at any given time, only one annotated method within the entire JVM can be executed at the same time.

Conclusion

The Named locks for CDI is a small library that brings the capabilities of the @Lock from the EJB specification and the ReentrantReadWriteLock JVM class as an annotation to any Jakarta runtime.
It allows you to use the same philosophy of Jakarta EE, concentrate on the user logic, and infrastructure-related aspects are handled automatically or by annotation, for the synchronisation requirements to protect the access to a shared data structure within your application.

Categories
Atbash Jakarta EE

Testing the Jakarta EE Core Profile with Atbash Runtime.

What is the Core Profile?

The Jakarta EE specifications have already two profiles, the Full profile, and the Web profile. The Web Profile contains a set of specifications that are geared toward the typical Web Applications. It groups the typical Web Application specifications like Servlet, REST, JSON, JPA, Faces, Security, etc …

The Full profile contains all the Java Enterprise specifications and adds to the above list specifications like WebServices, Messaging, the full EJB specification, connectors, etc …

But the trend in the last years is, mainly due to the move to the cloud, to have smaller runtimes that only need a limited set of specifications.

The MicroProfile specifications are built on top of a limited set of Jakarta specifications, JAX-RS, CDI, JSON-P, and JSON-B.
MicroProfile, although many specifications are useful in all architectural cases, has a focus on microservices and smaller runtime. This has led to the idea to have a specific profile within Jakarta EE that groups a, specific adapted set of specifications in a Core Profile.

The goal of the profile is defined as (see here https://jakarta.ee/specifications/coreprofile/10/)

To provide a profile that contains a set of Jakarta EE Specifications targeting smaller runtimes suitable for microservices and ahead-of-time compilation.

Which specifications?

The idea, since the Core profile is not yet available, is to combine the following specifications

  • Jakarta Servlet
  • Jakarta REST (JAX-RS)
  • Jakarta CDI lite
  • Jakarta JSON-P
  • Jakarta JSON-B
  • Jakarta Configuration

The CDI lite specification focuses around using build-time Compatible Extensions so that the runtime can be used in Ahead-of-time compilation scenarios like GraalVM. When there are no runtime discovery features and everything is known at compile-time, it makes the native compilation much easier.

The Jakarta Configuration specification will be based on the current MicroProfile Configuration specification and is hopefully, after several attempts to standardise this within Java Enterprise, finally available.

What is Atbash Runtime?

The Core Profile is not yet available and will not be available in May 2022, the expected release date of Jakarta EE 10. Mainly because the Jakarta Configuration specification is not ready yet, and the work related to Jakarta EE 10 took more time so there was not enough time available to perform some work around this new Profile.

The idea of Jakarta specifications is also that it is based on some experience and not only on some theoretical assumptions. That was the basis of my idea to create a runtime that contains the specifications of the Core Profile.

The work started some 6 months ago in my spare time and the goal was to create a runtime that combines the mentioned specifications. At that time, only Jakarta EE 9.1 was available. So the current version of Atbash Runtime, version 0.3, is based on

  • Jakarta Servlet 5.0
  • Jakarta CDI 3.0
  • Jakarta REST 3.0
  • Jakarta JSON-P 2.0
  • Jakarta JSON-B 2.0
  • MicroProfile Config 3.0

And it combines the following frameworks

  • Jetty 11.0.8
  • Jersey 3.0.4
  • Weld 4.0.3
  • Jackson Databind 2.13.1
  • Custom implementation of MicroProfile Config based on SmallRye Config.

How can I try it out?

First of all, you can download the zip file to install the runtime from this download URL. It is only 13.3 Mb in size.

Unzip this into a directory of your choice. It will create several JAR files in a directory structure.

Start your application with

java -jar atbash-runtime.jar path-to/application.war

And the application is available on port 8080 (default, can be changed by command line parameter). The runtime is built with JDK 11 and tested on JDK 11, 17, and 18.

Besides this instance mode, there is also a domain mode so that you can remotely access the runtime to, for example, deploy applications on a running process.

It has a modular structure that will be explored more in future versions and has typical extras like an embedded mode, Arquillian adaptor, Docker image, and integration testing framework based on TestContainers.

You can read more about them in the user guide.

What is next?

The following ideas are on my table to experiment more with this runtime and the idea of a Core Profile Runtime

  • Upgrade to the Jakarta EE 10 versions of the specifications now that they become available.
  • Add security like the MicroProfile JWT specification.
  • Add some data access including the fast Java-native object graph persistence provided by MicroStream.

And of course, your ideas and feedback are valuable for the realisation of the Core profile with Jakarta EE.

Enjoy.