Categories
Atbash Configuration

A MicroProfile Config implementation for plain Java SE

The ability to define configuration values for your application outside the deployment artifact is very important. It is one of the 12-factor items, the requirement that your application can be unaltered deployed on test, acceptance, production, and so on.

Many framework and runtimes have their proprietary solution and there were already several attempts to create a specification within the Java Enterprise world.
Currently, there is an effort going on to define Jakarta Config which is based on the MicroProfile Config specification.

Although MicroProfile Config specification is built on top of CDI concepts, the fundamentals can be used in plain Java SE. Also, other implementations, like SmallRye Config can be used in Java SE without the need for CDI to be present.

Extraction from Atbash Runtime

The goal of Atbash Runtime was to have a modular runtime that supports the specifications of the Jakarta EE 10 core profile. The development of this runtime started before the release of the Core profile so it was based on the Jakarta EE 9.1 specifications and used MicroProfile Config as the basis for the future to finish Jakarta Config specification.

Atbash Runtime version 0.3 already contained an implementation of the config specification and passed the MP Config TCK.

Recent experimentations with the Atbash JWT module on plain Java SE confirmed the need for an MP Config implementation that runs on pure Java SE. Since the implementation within the Atbash was already nicely separated into different packages, the new library was quickly ready.

Using Atbash MP Configuration SE

Before you can use the configuration values, you need to add the following artifact to your project.

    <dependency>
        <groupId>be.atbash</groupId>
        <artifactId>mp-config</artifactId>
        <version>1.0.1</version>
    </dependency>

This dependency brings in all required dependencies using the transitive functionality of Maven, including the MicroProfile Config 3.0 API.

Now you can retrieve a Config instance programmatically and retrieve the values just as described in the specification.

    Config config = ConfigProvider.getConfig();
    String value = config.getValue("value", String.class);

All functionality that doesn’t require CDI is supported, including

  • ConfigSources, the 3 default implementations with their default ordinal values and the possibility to define custom ones through the ServiceLoader mechanism.
  • Custom ConfigSourceProvider‘s can be loaded through the ServiceLoader mechanism.
  • Converter, the implicitly defined one as specified in the specification and the possibility to define custom converters using the ServiceLoader mechanism.
  • Support for optional values
  • Support for expressions where a value is a result of combining other configuration values and constant expressions.
  • Support for Config Profile defining the application phase (dev, test, …) on the property and ConfigSource level.
  • Support for ConfigBuilder and creating custom Config instances.

Since MicroProfile Config 3.0 is using the Jakarta namespace, you make use of the @Priority within the jakarta package to define the order in the converter list if you define a custom one.

 import jakarta.annotation.Priority;

Information about library

The code is compiled with JDK 11 source compatibility, and is thus useable in that or any higher version.

The library and all dependencies, including the MicroProfile MP Config API code take about 240 kB. Logging is performed through the SLF4J library, and thus a specific binding is required if you want to see the log.

The library can also be used in a GraalVM native image. No additional configuration is required to be able to include it as native compiled Java code.

Use case

There are several use cases where this new library can be useful.

  • A plain Java SE program where some configuration values are needed. By adding the dependency, you have the MicroProfile Config functionality available through that small compact library.
  • Use it in a Jakarta runtime that doesn’t support any configuration framework for your application. An example is Glassfish, including the upcoming version 7, where no configuration specification is available for your application.

Conclusion

A version of the MicroProfile Config API that runs on Java SE only can be useful in several cases. Not only for Java SE applications themselves but also for runtimes like Glassfish that still don’t support any configuration possibilities for the deployed applications. And config is essential for writing good enterprise applications.

The Atbash MP Config SE was extracted from the Atbash Runtime that has an implementation of this specification as part of the experimentations around the Jakarta EE Core profile.

Better name

I also need a better name for this new library So if you have any ideas, let me know on Twitter or use the feedback form on the Training page. From the suggestion, I will pick one at the end of October 2022.

Update november 2022: The chosen name is Atbash Delivery. It delivers the configuration from your environment to your application.

Atbash Training and Support

Do you need a specific training session on Jakarta or MicroProfile? Or do you need some help in getting up and running with your next project? Have a look at the training support that I provide on the page https://www.atbash.be/training/ and contact me for more information.

Enjoy

Categories
Atbash JAX-RS MicroProfile

MicroProfile Rest Client for Java SE

Introduction

One of the cool specifications produced by the MicroProfile group is the Rest Client for MicroProfile  available from MP release 1.3.

It builds on top of the Client API of JAX-RS and allows you to use type-safe access to your endpoints without the need to programmatic interact with the Client API.

MicroProfile compliant server implementations need to implement this specification, but nothing says we cannot expand the usage into other environments (with a proper implementation) like use in Java SE (JavaFX seems must useful here) and plain Java EE.

Atbash has created an implementation of the specification so that it can be used in these environments and will use it within Octopus framework to propagate authentication and authorization information automatically in calls to JAX-RS endpoints.

The specification

A few words about the specification itself. JAX-RS 2.x contains a client API which allows you to access any ‘Rest’ endpoint in a uniform way.

Client client = ClientBuilder.newClient();
WebTarget employeeWebTarget = client.target("http://localhost:8080/demo/data").path("employees");
employeeWebTarget.request(MediaType.APPLICATION_JSON).get(new GenericType<List<Employee>>() {
});

This client API is great because we can use it to call any endpoint, not even limited to Java ones. As long as they behave in a standard way.

But things can be improved, by moving away from the programmatic way of performing these calls, into a more declarative way.

If we could define some kind of interface like this

@Path("/employees")
public interface EmployeeService {

@GET
@Produces(MediaType.APPLICATION_JSON)
List<Employee> getAll();
}

And we just could ask an implementation of this interface which performs the required steps of creating the Client, WebTarget and invoke it for us in the background. This would make it much easier for the developer and makes it much more type-safe.

Creating the implementation of that interface is what MicroProfile Rest Client is all about.

The interface defined above can then be injected in any other CDI bean (need to add the @RegisterRestClient on the interface and preferably a CDI scope like @ApplicationScoped) and by calling the method, we actually perform a call to the endpoint and retrieve the result.

@Inject
@RestClient
private EmployeeService employeeService;

public void doSomethingWithEmployees() {
....
... employeeService.getAll();
....
}

Atbash Rest Client

The specification also allows for a programmatic retrieval of the implementation, for those scenarios where no CDI is available.
However, remember that if we are running inside a CDI container, we can always retrieve some CDI bean by using

CDI.current().select();

from within any method.

The programmatic retrieval is thus an ideal candidate to use it in other environments or frameworks like JavaFX (basically every Java SE program), Spring, Kotlin, etc …

The programmatic retrieval starts from the RestClientBuilder with the newBuilder() method.

EmployeeService employeeService = RestClientBuilder.newBuilder()
    .baseUrl(new URL("https://localhost:8080/server/data"))
    .build(EmployeeService.class);

The above retrieves also an implementation for the Employee retrieval endpoint we used earlier on in this text.

For more information about the features like Exception handling, adding custom providers and more, look at the specification document.

The Atbash Rest Client is an implementation in Java 7 which can run on Java SE. It is created mainly for the Octopus Framework to propagate the user authentication (like username) and authorization information (like permissions) to JAX-RS endpoints in a transparent, automatically way.

A ClientRequestFilter is created in Octopus which creates a JWT token (compatible with MicroProfile JWT auth specification) containing username and permissions of the current user and this Filter can then be added as a provider to the MicroProfile Rest Client to have this security information available within the header of the call.

Since the current Octopus version is still based on Java SE 7, no other existing implementation could be used (MicroProfile is Java SE 8 based). The implementation is based on the DeltaSpike Proxy features and uses any Client API compatible implementation which is available at runtime.

Compliant, not certified.

Since all the MicroProfile specifications are Java 8 based, the API is also converted to Java SE 7. Except for a few small incompatibilities, the port is 100% interchangeable.

The most notable difference is creating the builder with the newBuilder() method. In the original specification, this is a static method of an interface which is not allowed in Java 7. For that purpose, an abstract class is created, AbstractRestClientBuilder which contains the method.

Other than that, class and method names should be identical, which makes the switch from Atbash Rest Client to any other implementation using Java 8 very smooth.

The Maven dependency has following coordinates (available on Maven Central):

<dependency>
   <groupId>be.atbash.mp.rest-client</groupId>
   <artifactId>atbash-rest-client-impl</artifactId>
   <version>0.5</version>
</dependency>

If you are running on Java 8, you can use the Apache CXF MicroProfile Rest client

<dependency>
   <groupId>org.apache.cxf</groupId>
   <artifactId>cxf-rt-rs-mp-client</artifactId>
   <version>3.2.4</version>
</dependency>

Which also can be used in a plain Java SE environment. Other implementations like the ones within Liberty and Payara Micro aren’t useable standalone in Java SE.

Remark

This first release of Atbash Rest Client is a pre-release, meaning that not all features of the specification are completely implemented. It is just a bare minimum for the a POC within Octopus.
For example, the handling of exceptions (because the endpoint returned a status in the range 4xx or 5xx) isn’t completely covered yet.

The missing parts will be implemented or improved in a future version.

Conclusion

With the MicroProfile Rest Client specification, it becomes easy to call some JAX-RS endpoints in a type-safe way. By using a declarative method, calling some endpoint becomes as easy as calling any other method within the JVM.

And since micro-services need to be called at some point from non-micro-service code, Java SE executable implementation is very important. It makes it possible to call it from plain Java EE, Java SE, any other framework or a JVM based language.

Have fun.

This website uses cookies. By continuing to use this site, you accept our use of cookies.  Learn more