The modularization challenge

OSGi is a dynamic module system for Java™. So how does it help?

Effective software modules have the following characteristics:
  • Self-contained: Although a module is comprised of smaller parts, it is the whole module that can be moved around, installed, or uninstalled as a single unit, not the parts within it.
  • Highly cohesive: Each module has a coherent logical function.
  • Loosely-coupled: Modules have well-defined boundaries between them.
Modularized systems that have these characteristics are easier to maintain and extend.

Object-oriented languages such as Java support modularization. However, they focus on encapsulation of instance variables. This helps at the object and class level, but does not support higher forms of modularity. Java EE helps a little more by providing application-level isolation of application modules within an enterprise application.

Patterns such as SOA and Dependency Injection encourage modular design of large-scale enterprise applications. However, this modularity requires architectural governance rather than being encouraged or enforced by the runtime environment.

In the Java platform, data is encapsulated within a class, classes are scoped within a package, and packages are collected together in a Java archive (JAR) file. Java class visibility options are private, package, protected, and public. There is no access modifier that allows for a unit of deployment that is a JAR file rather than a package. Most JAR files consist of multiple packages, and if the JAR file represents a cohesive function, there is typically a need for classes in one package to access classes in another package in the same JAR file. This need requires public accessibility of that class, which also makes the class visible to classes in other JAR files. JAR files provide no visibility control. Even well-behaved applications that use only the classes a JAR file provider expects to be used externally are governed by the Java class path, because a required class might be available from multiple JAR files and the class that is loaded is the first available instance on the global class path.

JAR files cannot scope the visibility of what they contain, and also cannot declare their own dependencies. Many JAR files have implicit dependencies on other JAR files, which means these JAR files cannot be installed or moved around independently. If a JAR file is installed and its dependencies are missing, the problem is often not visible until run time.

Java class loading scans the class path to look inside each JAR file on the class path to locate the required class. This process has three main limitations:
  • Class path ordering determines which instance of a class is loaded, and therefore which JAR file it is loaded from.
  • Only one version of a class is available on the class path, again determined by the first instance that is found.
  • If the dependencies of a class are not resolved, the first indication of the problem is often a runtime ClassNotFoundException exception.
These class path and JAR file shortcomings are often referred to as JAR hell. Java EE partly mitigates these problems. Java EE introduces the enterprise archive (EAR) file, both as the method by which an enterprise application is delivered, and as a runtime isolation scope for the modules that are part of that application. Java EE applications have a class loader hierarchy that is partly shared between the enterprise applications, and partly isolated between the applications. For example, in an enterprise application that contains a web application archive (WAR) module, by default, the individual WAR modules are isolated from each other in the application, and isolated from anything in a different application.
While the JAR hell problems are reduced by managing different class paths with different enterprise applications, there are still limitations when you want to share libraries such as open source frameworks or utility libraries between applications. WebSphere® Application Server offers some advanced options for configuring enterprise applications to access libraries that are not delivered as part of the EAR file:
  • You can install an isolated library and administratively associate its classloader with one or more installed modules or applications, or associate the classloader with the server to make it visible to all application modules.
  • You can configure the classloader delegation pattern to help resolve versioning compatibility problems. For example, you can specify the class loader delegation mode as parent-last so that an application-supplied class is loaded in preference to a server-supplied class.
However, these approaches only partially address the modularity requirements of applications. The OSGi Framework offers a better solution.