Skip to content

Modularity Patterns with JPMS: Published Interface and External Configuration

In this post, we look at two usability patterns: Published Interface and External Configuration. Usability patterns help to integrate modules with each other and generally simplify development with modules.

When working with a module, the developer needs to know how he is supposed to use it. The published interface pattern acknowledges this and focuses on a clearly defined API for modules. Another problem that we may face when using modules and especially re-using them is that we may need to change some configuration values. To allow this without recompilation of the module configuration can be located outside of the module as the external configuration pattern proposes.

Published Interface

The published interface pattern [Kno12] states that one should make the API of a module well known. What is part of the public API of the module and equally (or even more) important what is not? It is important to make this obvious for anyone using your modules. If we don’t, users (like ourselves next month) will certainly access elements of the module that we did not intend to. Afterward, we cannot change such elements easily without breaking code that uses the module.

Before the java module system, it was impossible to enforce usage of the public API. With the module system, we can publish it and prevent usage of elements by only exporting the required packages and providing services.

The Sample

Continuing the webshop sample let’s have a look at the customer component before refactoring it to modules. It contains implementations for consumers and business customers. They both implement a shared interface and users should use the factory to create them. The files are organized as follows:

com\opus\customer\
  Customer.java
  CustomerFactory.java

com\opus\customer\types\
  BusinessCustomer.java
  ConsumerCustomer.java

Without the module system, it was possible for users to create the implementation types directly without using the factory. They could access the implementation types directly. Therefore, any change to these classes could have a big impact on users of the component.

Now we refactor to a module by adding the following module descriptor:

module opus.customers {
    exports com.opus.customer;
}

It is now impossible for users of our module to use the implementation classes directly. We have not only published the interface by explicitly stating exported packages but also prevent access to the others.

External Configuration

Another usability pattern introduced by [Kno12] is external configuration. It states that we should make modules externally configurable. When we create modules that are configurable the chances that they can be reused are increased.

Sample

In many projects, there are multiple stages or environments involved when deploying an application. Maybe there should be at least two, one for testing and the production. To deploy a module to multiple environments it needs to be configurable. For example, the sales module from the webshop application posts an event to a REST endpoint when a sale was completed. It, therefore, needs to know the URI of the endpoint which is different for each environment. We configure the URI externally through a properties file which we deploy next to the module JAR file.

Webshop\modules\sales\
    sales.jar
    config.properties

With this setup, we can provide a different settings file for each environment. It probably would be easier to store the properties files inside the module, but then we would need to rebuild it for each environment.

Wrap Up / Final Thoughts

In this post, we saw two usability patterns that simplify usage and maintainability of modules. With the published interface we can ensure that our modules are used as intended. The external configuration allows for reusable modules that can be configured for different environments or even use cases.

[Kno12] K. Knoernschield: Java Application Architecture – Modularity Patterns with Examples Using OSGi (homepage)

An den Anfang scrollen