We are living in a new era of information technology. All people like me, who started work at the beginning of the 2000s, have gone through a constant but gradual evolution of languages, frameworks, and architectures. The last year has marked a great change in the way we approach a software release.
The great competition that drives the global market has changed the cultural approach of companies, which now have a milestone target—the reduction of time to market. The need to release a new business service as soon as possible is the main target of a company, regardless of their business area.
From an information technology point of view, this need has been translated into a complete review of development platforms and their updating and evolution processes.
From an enterprise point of view, this change, defined as digital disruption, is leading to the need to review company structures with regard to the organization of roles and skills, as well as to the policies of continuously updating to keep up with market needs. The community side of developers has led to a conceptualization of ideas as has not been seen for some time.
The best way to comprehend all the ideas that are being born around these concepts is through the open source model.
In this chapter, we will cover the following topics:
- Open source
- The Java programming language
- OpenJDK 9 and 10
- Java EE – MicroProfile.io – Jakarta EE
First of all, we start with a definition of open source—it is a way of thinking about the development of software that encourages the sharing of ideas and code. All sections of a product—documentation, source code, and so on—should be made publicly available. Using this model, you can build a product that will be able to benefit from the continuous improvement boosts given by the community in terms of standards, security, and technology evolution.
Sometimes, people confuse open source with the concept of no cost, which means we can use the technology for free. Using a technology only on the basis of its cost (cheap versus expensive) can expose your project to very high risks, including the failure of the objectives set. This way of perceiving open source is extremely reductive and dangerous.
Open source is much more. It is a model, like a philosophy, that encourages open collaboration and the sharing of ideas. An idea becomes stronger and more useful if more people collaborate to identify the weaknesses in order to improve them and find the right solutions. The intent is to promote these ideas in order to create an ecosystem based on solid rules for building the architecture of the future and to make all ideas freely available.
In this way, a community is created that cannot only develop the ideas that have emerged, but also continues the work of improvement, evolution, and dissemination. We can therefore state that, as in all other sectors, even in information technology, unity is strength.
Once the standards on which the technologies are based have been identified, it is possible to move on to their realization. In this stage as well, open source represents the best approach.
All stacks of software can grow in a better way if implemented under the open source model. Imagine having a community spread around the world that could test, evaluate, update, and fix your code in many different scenarios; a team composed of people, of different cultures and different skills, linked by a common goal—to create and consolidate a development framework. What company has such a special team?
- Software foundations:
- Operating systems:
This is only a fraction of the great number of open source communities involved in just a few critical areas. Do you still continue to think that open source means only free of cost?
One of the key points of the open source model is participation. Collaboration between people in the community is fundamental and solves one big question that companies often have—should they build a solution from scratch, or buy a solution that implements their requirements?
It's difficult to have all the skills needed to build an entire development framework. Buying a product from a vendor may solve the problem and reduce the effort of implementation, but leaves you unable to know the limit of your solution and the margins for improvement.
Using an open source-based solution gives you the opportunity to know exactly what you're using, letting you know whether your solution will be able to adapt to the future evolutions of information technology.
You should choose your open source community and project based on your needs.
- Share your knowledge through blogs, social networks, and all free channels that give you the opportunity to disseminate knowledge and encourage the exchange of ideas.
- Create your source code and donate it to the community, using one of the open source licenses and standards (https://opensource.org/licenses).
- Fork, star, watch, and create issues on open source repositories, such as GitHub, in order to promote good principles and ideas.
- Take part in the source life cycle of the open source project, and submit code that is able to solve issues that you may encounter during your experience.
- Help with documentation, in order to allow an increasingly clear and simple use of open source code.
- Help to test features; this could help the community to increase the strength of code, and gives an easy-to-understand example of usage of code.
In other words, you can become part of the community and make your contribution according to your skills, and the time you can dedicate.
From the application development perspective, open sourcing has provided a great contribution over the years. One of the most popular programming languages that has grown (thanks to the help of open source communities—this is one that will be the leading actor in our microservice journey) is Java.
Java is a full-featured and general-purpose programming language that was initiated in 1991 by a team led by James Gosling and Patrick Naughton at Sun Microsystems. Let's take a look at the evolution of Java in the hands of its developers.
Sun Microsystems released the first Java public implementation, version 1.0, in 1996. The concept of write once run anywhere, with the promise of great portability of software and ease of learning and use from the developers (in particular for automatic memory management and object-oriented paradigms) have all facilitated the rapid spread of Java in the information technology ecosystem.
The evolution and spread of the language was fast and continuous. After the two releases JDK 1.1 (February, 1997) and Java Standard Edition (JSE) 1.2 (December, 1998), Sun Microsystems released Java Platform, Enterprise Edition (Java EE (which was formerly known as Java 2 Platform, Enterprise Edition (J2EE)).
This was intended as a set of specifications, based on Java Platform, Standard Edition (Java SE), dedicated to enterprise applications that were rapidly moving from a desktop's local environment to a web browser environment.
At the end of 2006, Sun decided to donate the major part of the core code of the Java Virtual Machine (JVM), Standard and Enterprise Edition, as open source software under the terms of the General Public License (GPL). At the beginning of 2007, Sun completed the process, making all of its JVM's code available under free software and open source distribution terms. The final result of this process is the creation of OpenJDK, which became the open source implementation of the Java SE.
The work Sun did during these 10 years, from the first public release of 1996 to the birth of OpenJDK and the open source release of the JVM core and JSE platform in 2007, ideally made its role with regard to Java seem like that of an evangelist.
After this great period, Oracle Corporation acquired Sun Microsystems in 2009-2010.
At the beginning of this new era, Oracle declared that it will continue supporting and investing in Java for customers. You can take a look at the declaration on the following site: https://web.archive.org/web/20100131091008/http://www.oracle.com/us/technologies/java/index.html
Despite this declaration; the resignation from Oracle of James Gosling, the father of Java, in 2010; and the lawsuit against Google in 2012 related to the use of Java in the Android SDK; changed the perception of the community about the future of the Java language.
Oracle tried to give new impulse to Java and, after almost five years, released a new Java SE version (JDK 7 - July, 2011) and a new Java Enterprise Release (Java EE 7 - June, 2013). Furthermore, OpenJDK became a reference implementation of Java SE since version 7.
The rapid evolution of business requirements and the slowdown of the Java source life cycle convinced Oracle to change the strategy about the Java platform with a clear bet on the open source model.
OpenJDK binaries are the reference implementation of the JSE platform. OpenJDK is an incubator of the latest new features and has defined time-based releases that will be delivered every year in March and September. The version numbers follow the schema of year-month (YY.M). Unlike the previous release approach, this one will not be delayed to await a major feature to be completed and stabilized—an example was the delay of JDK 8 due to Jigsaw project issues, which was then retargeted into JDK 9.
With the new model, the new features will not be merged all together into a release source control repository until they are complete. If they are not ready to be included in a new release, they will be retargeted for the next release or later. The intention of this model is to avoid problems with a feature that, if not ready, could delay an entire release that could contain other features useful for developers.
Those enterprises and organizations that don't necessarily want or need to upgrade at a rapid pace will be free to choose a vendor to have support for a specific Java version, depending on market reaction. The same choice was also made for Java EE.
During the years, the platform became very big. The need to maintain backward compatibility and the delay of new Java SE releases, on which it depends, have made the platform very difficult to manage, delaying its evolution and making it unattractive for environments, such as cloud and microservices, in continuous evolution.
At the end of 2017, Oracle announced the donation of Java EE to the Eclipse Foundation. Initially, the project was named Eclipse Enterprise for Java (EE4J). After a survey taken by the community, the name of Java EE was changed, in order to avoid legal problems due to the fact that Oracle owns the trademark for the name Java, to Jakarta Enterprise Edition (Jakarta EE)—the entry point for the new platform is Java EE 8.
Under the umbrella of the Eclipse Foundation community, and with the commitment of the major vendors, the Enterprise Edition platform could start a new life in order to accelerate the adoption for the implementation of business applications for a cloud-native world.
The migration of all source code to Jakarta EE is proceeding quickly but, in the meantime, the evolution of the cloud environment and microservices require immediate answers in terms of standards and implementation models.
For this reason, Eclipse MicroProfile was created, as it's meant to optimize Enterprise Java for a microservice architecture. MicroProfile is aimed at spurring innovation that may result in future as a standard, but at the moment requires a faster rate of change than the intentionally measured pace of a standard process.
The expectation is that the existing Eclipse MicroProfile community and other open source communities should continue leading the way. Jakarta EE will incorporate Java innovations from these projects and communities into new versions in order to have complete and strong standards.
The following screenshot shows the history of Java EE releases, in terms of versions and the time duration between each of them, in months:
As you can see, the intervals between releases keep getting longer, and the last release version, which is Java EE 8, came out after 52 months!
In the next section, we will analyze the details of the latest OpenJDK versions, 9 and 10, and the Java EE 8 platform. These represent the base on which Eclipse MicroProfile is found, which is the Java Enterprise proposal for the realization of microservice architectures in cloud environments.
Java SE 9 and 10 introduce some important new features and improvements.
A detailed analysis of the new features is out of the scope of this book. We will look at the main innovations that have brought added value to the use of Java within cloud platforms and microservices.
Let's start with Java SE 9, the revolutionary element entailing the modularization of the JDK reached through the Jigsaw project (http://openjdk.java.net/projects/jigsaw/).
The main goals of this new feature are as follows:
- Make Java SE more flexible and scalable
- Improve security and maintainability
- Make it easier to construct, maintain, deploy, and upgrade large applications
- Enable improved performance
Two of the main criticisms made by the community toward the Java SE platform were the slowness in the release of the newer versions, as described previously, and the size of the JDK both in terms of space occupation and class size (approximately 4,240 classes in JDK 8).
But, it was not easy to find a solution that would allow overcoming these limits without abandoning one of the cornerstones of Java SE—the backward compatibility between versions.
It was, therefore, difficult to eliminate obsolete classes or remove classes designed for internal use but used intensively, especially by the framework, via Java reflection. The most famous example is the one put up by Sun Microsystems, which is related to the
com.sun.misc.Unsafe class. It specified that:
sun.* packages are not part of the supported, public Java interface. If you want to see the actual release, you can visit this link: https://www.oracle.com/technetwork/java/faq-sun-packages-142232.html
Through the Jigsaw project, it was not only possible to modularize the JDK in its core code but also to provide a tool for the realization of applications able to significantly decouple the interfaces of exposure of its services with respect to the actual implementation.
For JDK core code, it is possible to encapsulate JDK APIs, as described in JEP 260 (http://openjdk.java.net/jeps/260), using the following approach:
- Encapsulate, by default, all internal APIs that are considered non-critical.
- Encapsulate all internal APIs, that are considered critical, for which exist, in JDK 8, supported replacements.
- Do not encapsulate critical internal APIs, but implement the following steps:
- Deprecate them in JDK 9
- Define a plan to remove these APIs in JDK 10
- Implement a workaround solution via a command-line parameter
- Remove, from the JDK distribution, a limited number of supported Java Community Process (JCP) standard APIs
- Remove the extension mechanisms and the endorsed standards override
- Java EE modules, due to the Jigsaw project, are not resolved by default.
In this way, you can easily obtain a small bootable Java runtime that contains only the features, in terms of classes and interfaces that you really need, avoiding the presence of useless code and that can have only negative side effects in terms of footprint and space allocation.
You could easily analyze this using the following command:
$ java -listmods
As mentioned before, both the JDK and the application can benefit from modular development. Decoupling the components present in the applications is essential in microservice architectures, which need a very agile software life cycle to reduce time to market.
Using a modularity approach, you could easily achieve the following:
- Loose coupling between components
- Clear contracts and dependencies between components
- Hidden implementation using strong encapsulation
The main element in your implementation is the module.
Developers can organize their code into a modular structure, within which are declared dependencies inside their respective module definition files.
The properties of a module are defined into a file named
module-info.java that contains the following attributes:
- The module name
- The module's packages that you want to make available publicly
- The dependencies, direct or transitive, that the module depends on
- The list of the services that the module consumes
- All possible implementation of the service that the module provides
The following are the main keywords used to set the main features of a module through the
module: The module definition file starts with this keyword followed by its name and definition.
provides ... with ...: The
provideskeyword is used to indicate that the module provides implementations for a defined service interface. The service interface is expressed using the
requires: This keyword is used to indicate the dependencies of the modules. A module name has to be specified after this keyword and the list of dependencies are set through multiple required directives.
transitive: This keyword is set after the
requireskeyword; with this feature, you are declaring that any module that depends on the module defining
requires transitive <modulename>gets an implicit dependence on the
uses: This keyword is used to indicate the service interface that this module is using; a type name, complete with fully qualified class or interface name, has to be specified after this keyword.
opens: This keyword is used to indicate the packages that are accessible only at runtime; you can also use them for introspection, using Reflection APIs. This is quite important for libraries and frameworks that use reflection APIs in order to be as abstract as possible; the
opensdirective can also be set at module level—in this case, all packages of the module are accessible at runtime.
exports: This keyword is used to indicate the packages of the module that are publicly available; a package name has to be specified after this keyword.
But the two approaches, Java Jigsaw module and Open Service Gateway Initiative (OSGi), have some differences.
OSGi's adoption is largely due to its support for dynamic component control. In this case, plugins or components are loaded dynamically and then activated, deactivated, and even updated or removed as needed. Presently, this dynamic module life cycle is not available with Java modules.
Additionally, compared with Java modules, OSGi supports improved versioning. Other OSGi advantages are related to isolation; for example, bundle changes require only the direct dependencies to be recompiled, whereas a Java module's entire layer, along with all child layers, need to be recompiled if just one module changes.
The downside is that OSGi bundles still suffer from class path issues, such as runtime exceptions for missing dependencies, or arbitrary class loading for packages with the same name.
Additionally, OSGi requires a class loader per module, which can affect some libraries that expect only a single class loader. Java modules don't allow split packages which is considered a big improvement in Java overall, and don't have similar class loader requirements or restrictions. One big advantage Java modules have over OSGi is compiler support.
I think we can get the most out of the modularization of the application components in a microservice architecture, combining the best of both technologies. The overall strategy is to use Java modules to modularize libraries (either imported or exported) and the JVM itself, and use OSGi on top to handle application modularity and dynamic life cycle control.
JDK 10 introduced some new features. As mentioned earlier, we will concentrate on the most important features related to cloud environments and microservice architecture.
The first one is Docker awareness, which is supported for Linux only. With this feature, you can extract container-specific information about the number of CPUs (automatically) and allocated memory (automatically).
The following new JVM configuration parameters have been introduced:
-XX:UseContainerSupport: The JVM has been updated in order to be aware that it is running in a Docker container. In this way it will extract container specific configuration information and it will not query the operating system. The more important information that it will be extract is the total memory that have been allocated to the container and the amount of CPUs. The value of CPUs available to the Java process is calculated from any specified CPU shares, CPU quotas or CPU sets.
-XX:ActiveProcessorCount: This value overrides any other logic of CPU detection implemented automatically by the JVM.
-XX:MinRAMPercentage: This parameters allows users that run the JVM into Docker containers to have more control over the amount of system memory that will be used for the Java Heap allocation.
A great performance improvement is achieved with the Parallel Full GC for G1, as described in JEP 307 (http://openjdk.java.net/jeps/307). With this feature, full GC occurs on parallel threads with great benefits, such as the following:
- Low latency
- High throughput
- No/fewer stop-of-world (STW) pauses
- Improved G1 worst-case latencies
In order to obtain better performance, it has also introduced the application class-data sharing (CDS) with JEP 310 (http://openjdk.java.net/jeps/310). This feature reduces resource footprint when multiple JVMs are running on the same physical machine, and improves the startup time of applications.
Furthermore, processes and applications can share common class metadata (class data), from a shared archive (the CDS archive); prior to Java SE 10, the use of CDS had been restricted to the bootstrap class loader only.
Another important element in an environment such as the cloud that must be as responsive as possible is the Thread-Local Handshakes feature, defined in JEP 312 (http://openjdk.java.net/jeps/312). It's a new way to execute a
callback on threads that reduces the impact of acquiring a stack trace sample, for example, for profiling operations. It makes it possible to cheap-stop individual threads, reduce stops of STW pauses, and give better GC performance. With the Thread-Local Handshakes feature, it is possible to stop single threads and not just all threads or none—in this way, you don't need to make a global JVM safe point, giving a great performance improvement.
Last but not least, JDK 10 makes it possible to perform heap allocation on alternative devices, as described in JEP 316 (http://openjdk.java.net/jeps/316).
This great feature, realized with the contribution of Intel, allows the JVM to allocate the heap needed to store Java objects on a different memory device specified by the user, for example, a Non-Volatile Dual In-line Memory Module (NVDIMM).
This aspect could be extremely important in a multi-JVM environment, where you will instruct the processes with lower priority to use the NVDIMM memory while instructing the higher priority processes to use dynamic random access memory (DRAM).
I have described only a small set of the new features released in JDK 9 and 10 that demonstrate the great effort done to improve the Java language and make it a good choice for microservice implementation in cloud environments.
In September 2018, JDK 11 was released with some new great features, such as Epsilon—a no-op garbage collector.
Do you still have doubts about the use of Java for new microservice architectures?
The Java EE platform is one of the main tools for creating enterprise applications, thanks to a series of standards and specifications whose implementations have allowed us to manage crucial aspects such as transactions, security, scalability, concurrency, and management of the components it is deploying.
Together with Spring and Pivotal technology, Java EE represents the implementation model for modern Java-based enterprise applications on any kind of deployment platform.
As previously stated, the delay in the evolution of the platform and, consequently, in the release of new versions able to meet the new requirements related to the implementation of microservices in cloud environments have generated in the community a sense of distrust in its use.
I don't want to start some sort of religion war on which technology among Java EE, Spring, or others is regarded as the best to implement modern applications. Java EE 7, the latest stable and supported version, was released in 2013, and it received very positive feedback from the community.
Java EE 7's relevance in the ecosystem of enterprise applications has been very
important, as evidenced by the following survey—Developers Affirm Strong Support for Java EE 7 in DZone Survey
Spring's influence on Java EE was clear and helped to improve the platform by making it significantly less complex for example, through the following:
- The arrival of Spring and Hibernate has provided new ideas and approaches to development, which has given birth to EJB 3 and JPA 1, which represent the two major innovations introduced in Java EE 5.
- Spring Dependency Injection was the base on which Context and Dependency Injection (CDI) was built.
- Spring Batch has merged into JBatch specification (JSR 352 https://www.jcp.org/en/jsr/detail?id=352).
Since its creation, Spring has become popular among developers, thanks to the ease-of-use approach and a speedy time to market that allow us to quickly adopt technological innovations, such as microservices and cloud native applications.
Java EE, instead, and in particular after version 5, has a slower time to market; the reasons are related to the length of time needed to write specifications, and the implementation and certification time. Usually, several months are needed for a specification release to be supported and certified by the application servers.
Recently, this gap has widened:
- Spring Boot has increased its ease of use through the convention-over-configuration principle.
- Spring Cloud is becoming the major platform used in cloud-native developments by leveraging open source components from Netflix, which creates modules that implement important cloud concepts such as service registry, service discovery, load balancing, monitoring, and so on.
Now the question could be—is Java EE still a good choice to make microservices and cloud-native applications?
In my opinion, the answer is yes.
First of all, Java EE, in particular version 8, introduced or has consolidated a great number of specifications that are extremely useful for microservices implementation, such as the following:
- CDI 2.0
- Java API for JSON Processing (JSONP) 1.1
- Java API for JSON Binding (JSON-B) 1.0
- Java API for RESTful Web Services (JAX-RS) 2.1
- Java Servlet 4.0
CDI 2.0 defines the behavior of CDI outside of a Java EE container, allowing the use of patterns such as inversion of control even in contexts such as third-party utility libraries.
The specification is split in three parts—core CDI, CDI for Java SE, and CDI for Java EE. This split makes CDI more modular in order to help other Java EE specifications better integrate with it.
The de facto standard for API communications in microservices environments is the JSON format. Java EE has two great specifications, JSON-B and JSONP that can help developers to easily produce and process a JSON payload.
JSONP has great support, with utilities such as JSON Pointer, JSON Patch, JSON Merge Patch, and so on, for meeting the Internet Engineering Task Force (IETF) standards (https://www.ietf.org/standards/). It has also added editing operations to
JSONArray, and introduced helper classes and methods to better utilize Java SE 8 Stream operations.
JSON-B set a JAXB-like API to easily marshal or unmarshal Java objects to/from JSON. It created a default mapping between classes and JSON, and a standard support to handle the
application/JSON media type for JAX-RS. It's a natural follow-on to JSONP specifications, and closes the JSON support gap.
JAX-RS 2.1 standardized some features most used in microservices development, as follows:
In this way, it has facilitated integration with other JSRs and frameworks.
Servlet 4.0 introduced support for HTTP/2 protocol and the use of request/response multiplexing, server push notifications, and so on. It's also aligned with the latest HTTP 1.1 RFCs.
All the specifications and features described previously are certainly useful, but not sufficient to make Java EE suitable to meet the needs of cloud-native applications and microservices.
Now, the main targets are as follows:
- Deploy the applications onto the cloud
- Build microservices in an easy manner
- Enable more rapid evolution of applications
The community, through the Java EE guardians (https://javaee-guardians.io/) and the Java User Groups (JUG), pushed for modernizing Java EE for cloud and microservices environments. The target is to extend the Java EE platform in order to make it able to build microservice architecture, while still maintaining backwards compatibility with previous Java EE versions. Furthermore, the community wanted a migration path to evolve the consolidated applications into cloud-ready applications that could take advantage of new cloud development and deployment models.
In detail, the request was to obtain functionalities as follows:
- Client-side circuit breakers in order to make remote REST invocations fault-tolerant
- A standard way of health checking Java apps
- A secret vault to shadow sensitive data
- Multitenancy support to accommodate the needs of complex applications
- OAuth and OpenID support technologies have rapidly emerged as a de facto standard in security context implementation
- An externalized configuration store to make it an easy process to promote applications across environments
The answers to these requests were essentially two, as follows:
- The creation of the MicroProfile.io project, in the middle of 2016
- The new life on Java EE with the Jakarta EE community project at the end of April 2018
The delay in the release of the new version of Java EE, and the rapid change of the technological scenario (which is increasingly oriented toward cloud platforms and microservice architectures), have pushed a community of individuals, organizations, and vendors collaborating within an open source (Eclipse) project to bring microservice features to the Enterprise Java community.
Some of the major players in the history of the Java EE platform are involved in this project, such as Payara, Fujitsu, Tomitribe, IBM, Red Hat, Hammock, SmartBear, Hazelcast, and Oracle to name a few.
The project is based on the idea of extending the main features of the Java EE with new specifications essential to meeting the requirements of the new technological context.
At the time of writing this book, the project is at version 1.3, and is composed of the specifications shown below:
Fault tolerance 1.0
JWT propagation 1.0
REST client 1.0
Health check 1.0
As mentioned previously, in addition to the specifications relating to CDI, JSONP, and JAX-RS used to expose the API via RESTful web services in JSON format, there are a number of new specifications such as configuration, fault tolerance, JSON Web Tokens (JWTs), metrics, health checks, JWT propagation, OpenTracing, OpenAPI, and the REST client that are able to allow the realization of microservices in cloud environments.
In the following chapters, we will analyze in detail these specifications, with examples of code that will allow us to understand their purposes well. For now, let's have a quick introduction to the objectives of each of these new specifications, based on the descriptions that are given in their GitHub repositories:
- Config: A common feature, not strictly related to cloud or microservice architecture, is the ability of the applications to be configured based on the running environment. Usually they use properties files in different formats, but the request is to have the opportunity to update the configuration properties without the need to rebuild and repackage the application. Also, the changed values should be retrieved by the client without the need to redeploy and restart the application. This requirement is extremely important for microservices running in a cloud environment. The MicroProfile Config specification defines the way to implement this concept.
- REST client: This specification defines how to invoke RESTful services over the HTTP protocol. The REST client implementation outlines a continuity with Java EE/Jakarta EE, suggesting the use of JAX-RS 2.0 specifications in order to give the ability to reuse code written in tradition Java EE applications.
- Fault tolerance: One of the most important features required in cloud and microservice environments is resiliency to failure. This specification defines a way to provide different strategies to drive the execution and the result of computation implemented by the code; for example, providing fall backs and an alternative result when code execution fails due to unexpected exceptions. Retry strategies, bulkheads, and circuit breakers are enterprise integration patterns that you should implement to adhere to this specification.
- Metrics: In a distributed environment such as a Platform as a Service (PaaS), it is essential to retrieve metrics related to the execution environment. Usually, companies use agents that shadow the complexity to retrieve this information. In the past, the Java Management Extension (JMX) was implemented for this purpose. This specification extends JMX and defines another two main aspects, as follows:
- A standard way for MicroProfile servers to expose monitoring data to management agents
- A standard Java API that applications should use to expose their telemetry data to operations teams
- OpenAPI: The main goal of this specification is to define a standard Java API that implements the OpenAPI version 3 specification defined here: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md. The applications should adhere to this specification to expose their API documentation.
- JWT propagation: The most used technology in microservice architecture is the RESTful web service as compared to the HTTP protocol, and so the security of the APIs exposed must be guaranteed. The RESTful architecture services should be stateless—this means that any security state associated with a client is sent to the requested service every time a new request is performed. The security context is always recreated and the systems must perform both authentication and authorization validation on every request. The principal security protocols are based on security tokens—OAuth2, WS-Federation, OpenID Connect, WS-Trust, and Security Assertion Markup Language (SAML) are the main ones. The target technologies of JWT propagation specification are based on standards defined by OAuth2, JWT, and OpenID Connect.
- OpenTracing: The microservice usually runs in distributed system environments, so it's extremely important to trace requests in order to rebuild the execution flow of the code. This specification defines APIs that describe how incoming and outgoing requests should be traced by an OpenTracing-compliant Tracer Object. They also set the way to access a configured Tracer Object.
- Health check: The monitoring of the production infrastructure is a key point of the operation teams—it's important to always know the state of a node in order to react quickly if there are issues. These APIs describe the rules for determining the state of a node. In a PaaS health check specifications could be used to determine whether a node needs to be discarded and replaced by another instance using automatic mechanisms, reducing the out-of-service time.
One of the main goals of these specifications is the compatibility with the well-known cloud platforms, such as, Kubernetes.
It is expected that MicroProfile 2.0 will align all APIs to Java EE 8 in order to obtain a set of features, as shown below:
REST client 1.0
Fault tolerance 1.0
JWT propgation 1.0
Health check 1.0
At this moment, there are some products that have already passed the Technology Compatibility Kit (TCK) tests of the JSRs described before, or that are in the in progress state.
- Open Liberty (https://openliberty.io/)
- WebSphere Liberty (https://developer.ibm.com/wasdev/websphere-liberty/)
- Thorntail (https://thorntail.io/)
- Payara (https://www.payara.fish/upstream_builds)
You can find the updated list of the MicroProfile implementation at the Eclipse MicroProfile Wiki (https://wiki.eclipse.org/MicroProfile/Implementation).
So, now we have a great community, that of MicroProfile.io that is building a Java EE on steroids. But, how will Java EE evolve, and how will the new features made available by MicroProfile be included in it?
The evolution of Java EE is Jakarta EE.
Last September, Oracle announced, with the support of IBM and Red Hat that Java EE was going to move to the Eclipse Foundation. Since then, some other important companies have joined the initiative with strategic or participating-level commitments.
Following are the members involved in the Jakarta EE project:
- Strategic members:
- Red Hat
- Participating members:
- IncQuery Labs
- RCP Vision
The community requires that the Jakarta EE platform evolve faster than Java EE—to continue to be a reference platform for cloud architectures and microservices, which evolve rapidly, it is necessary to quickly incorporate into new versions of the platform the new features coming from open source communities, such as Eclipse MicroProfile.
Jakarta EE should make developers able to build cloud-native and mission-critical applications using the decades of developer experience built that Java EE was built upon.
The migration process from Java EE to Jakarta EE is complex, but, despite everything, it is proceeding relatively quickly.
After dealing with all the legal aspects related to the use of the name Java and javax within the specifications, it started the phase of migration of projects, specifications, and reference implementations to the Eclipse Foundation repositories.
This process requires a lot of effort because there are approximately 110 repositories to transfer. You can find the complete list with the project statuses here https://dmitrykornilov.net/2018/05/09/jakarta-ee-projects-summary/.
The community is performing the following activities:
- Internal license checking in order to make sure licenses are correct.
- Internal third-party analysis in order to identify what dependencies should be replaced with their latest versions to fix major bugs and security issues.
- Renaming the original projects with the following scheme:
- Eclipse Project for XXX for API projects
- Eclipse XXX for implementation projects
- Issuing transfers in order to preserve issue numbers and history without losing the previous job.
- Building environments in order to create the infrastructure needed to compile and run, in an agile continuous-integration way, the projects that make up the Jakarta EE platform.
- Aligning the previous projects' repositories in order to set a message that communicates that the project has been transferred to the Eclipse Foundation.
The base version for the final first release of Jakarta EE is Java EE 8.
At the end of the process, we will have a platform that will make all actors (vendors, Java communities, individuals, and so on) able to interact as peers with no one vendor holding, as in the spirit of the open source model.
In my opinion, the answer is yes, and throughout the rest of the book, we will see together how to maximize the potential of Java and of the PaaS to create microservices in distributed environments.
In this chapter, we covered the fundamentals of the open source model and the origins of Java. We walked through the evolution of the Java SE and Java EE platforms in order to understand the causes of the birth of Jakarta EE and MicroProfile entities.
In the next chapter, we will speak about the new architecture approaches that have revolutionized enterprise applications—microservices and reactive architectures.