Skip to content

rdebusscher/microstream-quarkus-patterns

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MicroStream Quarkus Usage Patterns

The v2 directory contains the examples with Quarkus 2.x. v3 is for Quarkus 3.x

When using Quarkus 3 extension, you need version 8.1, whereas version 8.0 of Microstream contains the extension for Quarkus 2.

Patterns in using MicroStream's Quarkus integration

This repository contains a few example projects that demonstrate how MicroStream and the MicroStream Quarkus integration can be used in a project.

It is not the idea to have all best practices around application development covered in these examples but only some patterns that can be used to work with the Object Graph that makes your database within the JVM heap (and persist data with MicroStream).
So aspects like security and observability are not covered but are also not affected by using MicroStream in your Quarkus application.

General concepts

The following are a few general concepts that are applied within the examples.

  • The Controller classes are responsible for defining the JAX-RS endpoint signatures (HTTP method, URLs, ...) and some validation on the received data (structures). So the Controller is not responsible for validating the business rules (does the user exists, can the customer place an order, ...) but merely some validation of the received values/structures (Are values in a certain range like non-negative for age, does the supplied JSON has a property email, ...)
  • The Service classes are responsible for validating the business rules of your application. They should not have any JAX-RS-specific relation so in case there is a problem with a request, a RuntimeException-based exception can be thrown.

Basic project is generated by Quarkus project generator with extensions JAX-RS, CDI/ARC and MicroProfile.

Example

The example supports (in a limited way) the management of a library. You have the concept books and users who can lend a book.

You can perform the following actions

  • Retrieve all known books.
  • Retrieve all known users.
  • Add a new User.
  • Update the email address of a User.
  • Retrieve the books assigned to a user.
  • Assign a book to the user.

Although the application is still limited in functionality, it is already a bit more elaborated than a hello-world style application. With a hello-world style example, we would have the danger of showing patterns that do not apply to the real world.

Plain

Without the integration code, see directory plain.

Without any integration code, you need to expose a (Quarkus) CDI bean for the StorageManager. This is performed by the DataConfiguration class. The class is injected with the configuration value one.microstream.config which will give us the location of the MicroStream configuration file. It also has a reference to the class that performs the initialisation of books and users when the storage is started for the very first time.

The CDI producer method performs the different steps in a similar way as when you use MicroStream in a Java SE program. It creates the EmbeddedStorageFoundation with the configuration file, it customizes the Foundation, creates the StorageManager, and initializes with data if needed.

The Quarkus beans are only created when requested. This means that the StorageManager is only created when the first request arrives and thus lazily initialised which is what is required for most applications.

Proposed changes

The following is the list of proposed changes to make the code (of your application) better structured and integration with MicroStream easier.

The examples require the code from microstream-one/microstream#422 to compile and work.

You can add the MicroStream extension to the Quarkus application using the following command

mvn quarkus:add-extension -Dextensions="one.microstream:microstream-quarkus-extension:08.00.00-MS-GA"

When using Quarkus 3, the extension is one.microstream:microstream-quarkus3-extension:09.00.00-MS-GA-SNAPSHOT

Foundation customizer

See directory foundation-customizer

The StorageManager configuration can be customized and storage initialized by using CDI beans based on some interface. These are the steps that are performed by the integration code:

  • Build EmbeddedStorageFoundation from the MicroProfile Configuration values
  • Allow customizations by the developer to EmbeddedStorageFoundation using EmbeddedStorageFoundationCustomizer beans.
  • Integration creates the StorageManager
  • Allow initialization of the StorageManager (like adding initial data when storage is created at the first run) through StorageManagerInitializer.

The code within the DataConfiguration of the plain example becomes now better structured and results in the classes FoundationCustomizer and RootPreparation.

@ApplicationScoped
public class FoundationCustomizer implements EmbeddedStorageFoundationCustomizer {

    @Override
    public void customize(EmbeddedStorageFoundation embeddedStorageFoundation) {
      // Do customization
    }
}
@ApplicationScoped
public class RootPreparation implements StorageManagerInitializer {

    private static final Logger LOGGER = LoggerFactory.getLogger(RootPreparation.class);

    @Override
    public void initialize(StorageManager storageManager) {
       // Check if Root is available (and assign if needed) and add initial data if needed.
    }
}    

The addition of these 2 interfaces and using them when the Bean for the StorageManager is created, makes the code better structured as each class has its own purpose. It also allows to make use of all the MicroProfile Config sources that your runtime supports to define the configuration of the MicroStream engine.

Root CDI Bean

See directory root-bean.

Within the Service beans, we accessed the Root object through the StorageManager bean. Although this works, it is a bit cumbersome to always retrieve the root in that way.

The integration has the option to turn the Root object into a CDI Bean by annotating it with @Storage.

@Storage
public class Root {

    @Inject
    transient StorageManager storageManager;

The storage annotation is a custom annotation that is recognised by the Quarkus annotation. The processor makes sure the instance of this class is turned into a bean from the StorageManager and even create a default instance of it when the storage does not have data yet.

Since it is a normal Bean, you can also inject other beans into it, like the StorageManager. Since the integration is responsible for creating the Root object instance if needed (through a special factory method) using standard Java constructs, only Field injection is allowed (and not constructor or setter injection)

About

Patterns in using MicroStream's Quarkus integration

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages