The SpringSource dm Server
The SpringSource dm Server
Join the DZone community and get the full member experience.Join For Free
How do you break a Monolith into Microservices at Scale? This ebook shows strategies and techniques for building scalable and resilient microservices.
We are excited to tell you about a new book we are working on: SpringSource dm Server in Action. In this article, we are going to tell you about the central component of the Platform, the dm Server. We know that we should be starting with a positive outlook – you know, there are no problems, there are only solutions and so on, but let’s be honest for a moment and explore the issues we face in our Java EE application development and delivery.
When we implement our Java EE applications, we usually take extra care not to introduce too many dependencies. We layer the applications and we use the development environments and build scripts to enforce the layering rules. We use circular dependency and complexity analysis tools to ensure our code is as clean as possible. Then we take our well-designed and cleanly structured code and build a deployment archive. The archive and the deployed application do not maintain the structure we have worked so hard to create.
This article is based on SpringSource dm Server in Action, to be published June 2009. It is being reproduced here by permission from Manning Publications. Manning early access books and ebooks are sold exclusively through Manning. Visit the book's page for more information[img_assist|nid=6648|title=|desc=|link=url|url=http://manning.com/machacek/|align=right|width=147|height=182]
We also try to keep the libraries in our applications consistent. When we start building our application, we make sure that we satisfy the dependencies of all components in our application exactly. When we use Hibernate 3.3.0 SP1, we need to include Commons Collections 3.1. All is well until some other component needs Commons Collections 3.2.1. We cannot keep both the 3.1 and the 3.2.1 Commons Collections jars, so we only keep the latest version and hope for the best. Problems that are even more serious arise when we need to make changes to our application. In the current Java EE application servers, it is difficult to update components of running applications without restarting them. As a result, even a simple change means downtime and even if we exhaustively test the application in a preproduction environment, the deployment may still fail.
Finally, when our deployed application is running, it becomes a black box. To alleviate this problem, we include management and logging code in our application. Unfortunately, each application uses slightly different logging infrastructure. Moreover, the logging that the management and monitoring infrastructure does not always contain the information the developers need.
To summarize, the list of issues we face the traditional Java EE application deployment includes:
- Monolithic deployment archives. When we build our carefully designed application, all its structure is lost in the blob of the deployment archive.
- Complex re-use of services. If we want to use a service from another part of our application, we have to explicitly expose it. This forces us to spend a lot of time considering the technical aspects of the solution rather than spending the time writing the application’s business logic.
- Complex change control. Whenever we want to deploy a new version of even a small component in a monolithic application, we have to deploy the entire application.
- Lack of versioning. It is impossible to control the versions of the libraries in our applications and – more worryingly – across different applications. We sometimes find ourselves in a deploy & pray situation, where we deploy the application and hope that it would work.
- Complex management and monitoring of running applications. Over time, we have perfected the logging and monitoring of our Java EE applications. Still, time and time again, we find ourselves complaining that the logs do not contain enough information to identify an error.
We got used to living with these problems: we automatically package our applications into a monolithic archives; we hope that the different library versions will be compatible enough not to cause any problems in our application. We accept that to design a flexible service-oriented application, we have to jump through technological hoops. We have resigned to the fact that the logs will not contain the crucial bit of information we need to find the error.
The SpringSouce dm Server promises to not only tackle all these problems. You can finally keep the structure of your applications at runtime. You can swap your application’s modules at runtime without having to restart the application. You can at last implement service-oriented applications with versioned services without jumping through technological hoops. Read on to find out more about the dm Server.
Enter SpringSource dm Server
The dm Server is the central component of the SpringSource Application Platform and it is the only OSGi R4.1based application server available, but it does not impose the strict limitations of the OSGi execution environment. This allows you to deploy legacy Java EE applications without any major modifications to their code. However, in your new applications you can take full advantage of the dm Server’s extended OSGi environment. The benefits of the OSGi environment include the ability to keep the modularization of your applications even when deployed, versioning of the modules and the ability to specify dependencies between the modules.
OSGi in dm Server
Let’s now focus on the main difference between the dm Server and other Java EE application servers: the OSGi execution environment. Because the OSGi execution environment is a completely new approach to packaging and deploying applications, we need to take a look at its principles before we can delve into the depths of the dm Server.
When you want to deploy Java EE application in non-OSGi Java EE application server, you have to prepare a deployment archive. The deployment archive obliterates the structure of your application’s source code. Let’s take application whose architecture is shown in Figure A.
You can see that the web module uses the services module, which uses the dataaccess module. All three modules use the domain module. We can enforce this structure in our IDE and in the build process, but when we create the deployment archive, the structure is lost. We end up with one archive that contains all classes from all packages. Further, if we cannot easily re-deploy a single module, we always have to re-deploy the entire application.
The library versioning problem is just as bad – in the introduction, we showed that if we find that we need two different versions of the same class, we usually take the later version and hope for the best. This is not an ideal situation, but at least we have made a conscious decision to use the later version. Sometimes, we accidentally include more than one version of some class; for example, when we add two jars that happen to include different versions of a class with the same name. Our code can still run in our unit tests, but may fail in the production environment, because the test environment’s ClassLoader behaves differently than the production’s ClassLoader. Tracking these errors (typically NoSuchMethod or ClassCastExceptions) is very difficult.
Finagle’s law of dynamic negatives describes this situation perfectly: Anything that can go wrong, will—at the worst possible moment. We can directly apply this to our enterprise application. It will fail when it is running the most critical process (on Sunday evening).
Enter OSGi. In OSGi, there are no complex Java EE applications in large deployment archives. There aren’t even any applications, there are only bundles. Each bundle can export and import packages, register and reference services in the OSGi execution environment’s registry. If we wanted to deploy the application from Figure X in an OSGi execution environment, we would deploy it as four bundles: dataaccess, services, web and domain. The web bundle would import packages and reference services from the from the services bundle, the services bundle would import packages and reference services from the dataaccess bundle, the web, services and dataaccess bundles would import packages from the domain bundle.
It is important to remember that deploying a bundle is not the same as including a jar on an application’s classpath. The OSGi execution environment uniquely identifies each bundle using its symbolic name and version; you will never end up in the “jar hell” of today’s enterprise applications.
The OSGi execution environment allows you to deploy, start, stop and undeploy bundles dynamically. This means that we can update the services bundle without stopping the web bundle.
It would seem that OSGi alone is the ideal solution. Unfortunately, it brings strict restrictions to the structure of the applications. As we said earlier, there are no applications or jars in OSGi; there are only bundles. You can no longer “just include the hibernate-3.2.2-ga.jar on the classpath”; you have to turn it into an OSGi bundle. While turning a jar into a bundle is not a complicated process, it is enough to put most developers off the idea of using OSGi. Finally, the OSGi execution environment can deploy and run bundles, but it does not deal with typical Java
JEE application requirements. For example, Equinox, an OSGi execution environment implementation is not aware of servlets. Another limitation of OSGi is that there is no concept of applications: there are only bundles and all bundles share the same space – the OSGi registry. There are two scenarios where a single OSGi registry causes a problem and two more reasons to use the dm Server, which extends the OSGi execution environment’s features to overcome these limitations.
The first scenario is when you want to deploy two instances of the same set of bundles. Figure B shows this situation.
We show Application A to emphasize that the two bundles logically belong into the application unit, but the OSGi execution environment is not aware of this. Therefore, the first deployment of services_1 and web_1 bundles will succeed. However, we cannot deploy a second instance of the services_1 and web_1 bundles, because bundles with the same name are already registered in the OSGi registry.
The second scenario where a single OSGi registry causes problems is a situation where bundles with different names export the same service (see Figure C).
In this scenario, the OSGi registry allowed bundles services_1, services_2, web_1 and web_2 to register, because their names did not conflict. However, you can see that services_1 and services_2 both export the BookSearchService. In single-registry OSGi execution environments, there is no guarantee that web_1 will receive the BookSearchService from services_1 and not from services_2 – something we would expect, given the structure of the applications.
The last limitation (or perhaps just annoyance) of OSGi is that you can only import packages. For example, if we wanted to import all packages from the Spring Framework OSGi bundles, we would need to write 249 Import-Package directives.
The SpringSource dm Server addresses all standard OSGi execution environment issues. It is an OSGi R4.1 execution environment, but it allows you to deploy legacy applications with minimal impact, which will allow you to gradually migrate existing Java EE applications to dm Server. To help you write new OSGi-based applications, its distribution includes a comprehensive list of bundles for typical Java EE libraries. If you cannot find a particular bundle in the dm Server’s distribution, you can use SpringSource’s bundle repository, which contains hundreds of Java libraries converted into OSGi bundles. Figure D shows a fragment of the repository’s content.
Apart from the vast collection of OSGi bundles representing common Java EE libraries, the dm Server includes support for applications as set of bundles. It also allows you to specify the type of code the bundle contains. For example, you can mark a bundle as web bundle. The dm Server will direct HTTP requests to the web bundles and you will be able to easily create OSGi web applications. Finally, the dm Server allows you to import all packages from a bundle: all 249 Import-Package lines can now be replaced by only 15 Import-Bundle lines
Core components of the dm Server
Now that we have covered the reasons why the OSGi extensions in dm Server make application development easier, we need to take a under the dm Server’s hood. The dm Server makes the most of existing Java frameworks and tools. The core libraries the dm Server uses are the Spring Framework, Apache Tomcat, OSGi R4.1, Equinox and Spring Dynamic Modules for OSGi. Because these are the core components of the dm Server, we are going to take a look at every one of them in more detail.
At its core, the Spring Framework is a lightweight inversion of control container. Applications that follow the IoC principle use configuration that describes the dependencies between its components. It is then up to the IoC framework to satisfy the configured dependencies. The “inversion” means that the application does not control its structure; it is up to the IoC framework to do that. Consider an example where an instance of class Foo depends on an instance of class Bar to perform some kind of processing. Traditionally, Foo creates an instance of Bar using the new operator or obtains one from some kind of factory class. Using the IoC technique, an instance of Bar (or a subclass) is provided to Foo at runtime by some external process. This injection of dependencies at runtime has sometimes led to IoC being given the much more descriptive name dependency injection (DI).
Spring’s DI implementation puts focus on loose coupling: the components of your application should assume as little as possible about other components. The easiest way to achieve loose coupling in Java is to code to interfaces. Imagine your application’s code as a system of components: in a web application, you will have components that handle the HTTP requests and then use the components that contain the business logic of the application. The business logic components, in turn, use the data access objects (DAOs) to persist the data to a database. The important concept is that each component does not know what concrete implementation it is using; it only sees an interface. Because each component of the application is aware only of the interfaces of the other components, we can switch the implementation of the components (or entire groups or layers of components) without affecting the components that use the changed components. Spring’s DI core uses the information from your application’s configuration files to satisfy the dependencies between its components.
Apart from the dependency injection core, the Spring Framework brings extensive support for aspect-oriented programming as well as support for major components of Java EE applications. The enterprise component support includes data access, remoting, scheduling, Enterprise Java Beans, JMS, JMX. A large component of today’s Java EE applications use web interface. You can take advantage of Spring’s own Model-View-Controller implementation as well as Spring WebFlow in the implementation of your web applications.
Tomcat implements the Java Servlet and JavaServer Pages specifications. It is widely used throughout the Java world; Tomcat contributors claim that it runs in at least 100,000 production environments. Because of its reliability and performance, the dm Server uses Tomcat to deploy the web applications.
The dm Server uses Tomcat to deploy web bundles. As you can imagine, a web bundle is a bundle that contains web application code (controllers, JSP files) and it processes HTTP requests and produces HTTP responses.
There were many efforts to keep the modularization from the source code to deployment and runtime. The most notable one in the Java world is the OSGi framework (which used to stand for Open Services Gateway initiative, but became just OSGi). The dm Server uses the latest specification of the OSGi release.
We are not going to cover the details of OSGi specification in this book; however, if you are interested in reading about OSGi in detail, take a look at OSGi Service Platform by OSGi Alliance, which covers OSGi Release 3, but will give you good background knowledge of the specification.
There are several implementations of the OSGi execution environment: JOnAS 5, GlassFish v3 and Equinox. The dm Server does not re-invent the wheel; instead, it uses the Equinox 3.4. Equinox is not only an implementation of the OSGi R4.1 core specification, its aim is to provide additional bundles that make Equinox an excellent candidate for usage in other projects. Interestingly, the entire Eclipse platform uses Equinox internally. The dm Server takes the same route as Eclipse. The dm Server uses the Config Admin service to instruct Equinox to control the Equinox instance.
Spring Dynamic Modules for OSGI
The Spring Dynamic Modules for OSGi simplifies development of applications written using the Spring Framework in an OSGi runtime. The combination of OSGi execution environment and SDM allows us to:
- Keep the logical structure of our application at runtime,
- Use and control the versioning of the bundles that make up our applications,
- Discover services exposed from other bundles and to use these services,
- Make the services available as regular Spring beans in Spring applications.
In short, Spring Dynamic Modules for OSGi allows you to export a Spring bean as OSGi service and to import an OSGi service and expose it as Spring bean. Let’s take the web and services bundles in Figure E.
As you can see, both bundles use Spring Dynamic Modules for OSGi. The services bundle’s Spring application context contains the bookSearchService bean. The SDM exposes the bookSearchService bean in the OSGi registry. The SDM in the web bundle discovers a service that implements the BookSearchService interface in the OSGi registry and exposes it as the bookSearchService Spring bean.
You can fine-tune the SDM’s behaviour. We will mention just one to wet your appetite: we can set a timeout in which the referenced service must become available. If the referenced service is unavailable (or becomes unavailable), then the SDM will wait the specified time before failing. This allows us to dynamically remove, update and start dependent services at runtime, without the need to restart all bundles that make up the application. The application that uses the dependent bundle will simply wait until the dependent bundle becomes available again or the timeout expires.
This is the magic you saw in many presentations of the Spring Dynamic Modules for OSGi: the web bundle was using a services bundle. The administrators then stopped the services bundle and replaced it with another implementation. While they were doing that, the web bundle was still running, but the calls to the service referenced from the services bundle were being queued. As soon as the new services bundle became available and the referenced service appeared in the OSGi registry, the web bundle started using the updated service.
The combination of Spring Dynamic Modules for OSGi and the dm Server gives you the ability to create flexible and manageable applications.
In this article, we looked at the features of the dm Server, a central component of the SpringSource Application Platform. We hope that we have given you enough of a taster to try out the dm Server or the entire SpringSource Application Platform.
We will follow up this article by a series of shorter articles explaining specific aspects of the dm Server and the entire Application Platform. We will start with the obligatory Hello, World application, followed quickly by more complicated dm Server applications. Now, stop browsing and reading about other Java EE application servers; download the SpringSource dm Server instead and enter the brave new world.
Opinions expressed by DZone contributors are their own.