The 2012 Devoxx Conference in Antwerp has begun. Here’s some sum-ups of the sessions I’ve been attending to. I’ll try to write one daily (unless I’m too lazy or tired, Devoxx has been known to have such consequences on geeks…).
--I followed no conference in the morning since I presented a hands-on lab on Vaadin 7--
Two current trends rule modern-day application: on one hand, applications tend to grow bigger, thus complex and agile development and refactoring become more common. Challenges that arise from these factors are manyfold, and include:
- Dependency management
- Long-term maintenance
When building applications for the cloud, there are a couple of non-functional requirements, such as 0-downtime and modular deployments. Once you got more customers, chances are you’ll end up having specific extensions for some, thus even more aggravating the previous challenges.
In university, we learned to promote high-cohesion and low-coupling systems for Object-Oriented systems. How can we lessen coupling in a system? The first step is to code by interface. Now, we need a mechanism to hide implementations, so as to prevent someone from accidentally using our implementtation classes. A module is a JAR extension component that provides such a feature (note that such feature is not available within current JVMs). Given a module, how can we instantiate a new hidden class? One possible answer can be dependency injection, another can be service registries.
Modularity is an architecture principle. You have to design with modularity in mind: it doesn’t come with a framework. You have to enforce separation of concerns in the code. At runtime, the module is the unit of modularity.
What we need is:
- An architectural focus on modularity
- High-level enterprise API
- A runtime dynamic module framework: right now, OSGi is the de facto standard since Jigsaw is not available at the time of this presentation.
--Now begins the demo--
In order to develop applications, you’ll probably have to use the BndTools plugin under Eclipse. A good OSGi practice is to separate a stable API (composed of interfaces) in a module and implementations (of concrete classes) in other ones.
OSGi metadata is included in the JAR’s
In order to make the API module usable by other modules, we need to export the desired package.
As for the implementation class, there’s no specific code, although we need a couple of steps:
- Configure the modules available to the module implementation (just like traditional classpath management)
- Create a binding between the interface and its implementation through an Activator. It can be done through Java code, through Java annotations or with XML.
- Configure implementation and activator classes to be private
Finally, we just have to develop client code for the previous modules, and not forget to tell which OSGi container will be used at runtime.
In case of exceptions, we need a way to interact with the container. In order to achieve this, a console would be in order: the gogo console can be hot-deployed to the container since it’s an OSGi module by itself. Once done, we can start and stop specific modules.
--Back to the slides--
Are JavaEE and OSGi fated to be enemies? While it could have been the case before, nowadays they’re not exclusive. In essence, we have 3 options:
- Use OSGi core architecture and use JavaEE APIs as published services.
It’s the approach taken by application servers just as GlassFish.
- In this case, web applications become Web Application Bundles (the extension plays no part).
Such modules are standard WAR files (JSF, JAX-RS, etc.) only for the Manifest.
Extra-entries include the
Web-Context-Pathdirective as well as the traditional OSGi `Import-Package`directive.
- The goal of EJB bundles is to use EJB and JPA code as now: unfortunately, it’s not a standard yet.
Manifest directive include
- For CDI, the target is to use CDI within bundles.
It’s currently prototyped in Weld (CDI RI).
All application servers use OSGi bundles under the cover, with supporting OSGi bundles as an objective in the near future. At this time, Glassfish and WebSphere have the highest level of support for that.
- In this case, web applications become Web Application Bundles (the extension plays no part). Such modules are standard WAR files (JSF, JAX-RS, etc.) only for the Manifest. Extra-entries include the
- When confronted with an existing JavaEE codebase but modularity is needed in a localized part of the application, it’s best to use an hybrid approach.
In this case, separate your application into parts: for exameple, one 'administrative' part based on Java and the other 'dynamic' using OSGi glued together by an injection bridge.
In the JavaEE part, the
BundleContextis injected through a standard
@Resourceannotation. --Note that your code is now coupled to the OSGi API, which defeats the low-coupling approach professed by OSGi--.
- Finally, you could need modularity early in the development cycle and use OSGi 'à la carte'. This is a viable option if you don’t use many JavaEE APIs, for example only JAX-RS.
Note that for debugging purposes, it’s a good idea to deploy the Felix Dependency Manager module.
What happens when you have more than one implementation module of the same API module? There’s no way to be deterministic about that. However, there are ways to use it:
- The first way is to use arbitrary properties on the API module, and only require such properties when querying the OSGi container for modules
- Otherwise, you can rank your services so as to get the highest rank available. It’s very interesting to have fallback services in case the highest ranking is not available.
- Finally, you can let you client code handle this so that it listens to service lifecycle events for available module implementations
It’s a good OSGi practice: keep modules pretty small in most cases, probably only a few classes. Thus, in a typical deployment, it’s not uncommon for the number of bundles to amount in hundreds.
Now comes the Cloud part (from the title): in order to deploy, we’ll use Apache ACE, a provisioning server. It defines features (modules), distributions (collections of modules) and targets (servers for distributions provisioning). By the way, ACE is not only built on top of OSGi but also uses Vaadin as its GUI (sorry, too good to miss). When a server registers on ACE (and is defined as a server), the latter will automatically deploy the desired distributions to it.
This method let us use auto-scaling: just use a script when a server is ready to register to the ACE server and it just works!
Weld-OSGI in action by Mathieu Ancelin and Matthieu Clochard
Key annotations of CDI (Context and Dependency Injection) are @Inject to request injection, @Qualifier to specify precise injection and @Observes to listen to CDI events.
OSGi is a modular and dynamic platform for Java: it’s stable and powerful but provides old API. In OSGi, bundles are the basis of the modularity, those are enhanced JARs. OSGi proposes three main features:
- bundles lifecycle management
- dependency management
- version management
Weld-OSGi is a CDI extension that tries to combine the best of both worlds. It’s a JBoss Weld project, and is developed by the SERLI company. What’s really interesting is that you don’t need to know about OSGi, it’s wrapped under CDI itself. Basically, each time a bundle is deployed in the OSGi container, a new CDI context is created. Also, CDI beans are exposed as OSGi services.
Weld-OSGI provides some annotations to achieve that, such as
@OSGIService to tell CDI you need an OSGi service.
Alternatively, you could require all services implementations through the
@Service<Plugin> annotation so as to use the desired implementation.
On both, you could refine the injected services through qualifier annotations, as in "true" CDI.
OSGi containers generate a lot of events, each time a bundle changes state (e.g. when a bundle starts or stops).
Those events can be observed through the use of the traditional
@Observes annotation, with the addition of some specific Weld-OSGI annotations.
A specific API is also available for events happening between bundles.
-- demo is very impressive, the UI being changed on the fly, synced with the OSGi container --