Tapestry IoC: Modularization of web applications without OSGi

Posted on Dienstag, 19th Januar, 2010

In this article I’m going to describe the modularization features of Tapestry. You will learn how to create modular applications that can be customized without to change the code of the application. These customizable applications can be delivered in different editions to different customers with minimal effort. I intend to publish a series of articles on this topic. This post is the first article of the series and starts with a short introduction to OSGi and its modularity features.

Modularization with OSGi

In the last years there has been a hype around OSGi. Most of the attention that OSGi has been getting is related to its modularization features.  With OSGi you can cut your application in several bundles which can be installed, updated or removed at runtime. No shutdown of the whole system is needed. Furthermore the OSGi Service Platform allows you to specify the dependencies between bundles on the package level. A bundle can hide the private API by exporting only those packages that are meant to be visible to other bundles. Hiding internal packages allows bundle developers to change the implementation details without to fear any backward compatibility issues. One of the killer features of OSGi is that you can version not only your bundle but also the packages exported by your bundles (actually exporting packages without a version is a bad practice). This way you never run into the incompatibility problem between libraries in your application. In a traditional JEE container you have a problem if your application depends on two libraries that depend on two incompatible versions of a third library. In contrast the OSGi dependency resolution mechanism allows you to deploy several versions of the same bundle.

OSGi is a great technology but there is an impact of using it. For example you will find yourself at a lower level of productivity because you spend too much time debugging the class loader problems of your bundles. If you start developing OSGi-based applications, then ClassNotFoundException will be your best friend.

Another issue is the fact that the majority of java libraries out there are not currently shipped as OSGi bundles. Fortunately SpringSource launched the Enterprise Bundle Repository where you can find OSGi-ready versions of open source libraries but this repository is not up-to-date. Often you will need to transform the needed library into a bundle. There are also too much libraries that advertise to be OSGi-ready because their developers put a MANIFEST.MF file into the JAR. The most OSGi-based developers will concede that too much bundles are just bad. Some examples are the usage of  Require-Bundle manifest header or export of unversioned packages. Also unversioned imports or imports with fixed version make your life harder then it should be. Imagine you found a cool bundle and want to install it. Then you find out that the bundle has some dependencies. At first you think it is no problem: there is another bundle that exports the required packages. But then you realize that the new bundle imports the version 1.2.3 but 1.2.2 is exported. Damn, a version range would save your time.

Next annoying issue is that some cool libraries, that work in a JEE environment out of the box, are incompatible per se with OSGi because they load classes with Class.forName. Every OSGi-based developer, who had the pleasure to integrate Hibernate into OSGi, knows what I’m talking about.

Web applications in OSGi are problematic

If you ever built OSGi-based web application you surely came across HttpService. This service is described in the OSGi Compendium Specification and is intended to register Servlets and resources in the OSGi environment. The most annoying thing about HttpService is that it supports only the Servlet 2.1 specification. Filters and listeners are not available. This limitation is quite inconvenient because almost every Java web framework uses filters and listeners.

There exists several solutions to deal with the limitations of the HttpService. One of them is Pax Web. This project extends the HttpService with support of recent servlet APIs. Another solution is Spring DM that allows you to deploy a WAR file into an OSGi container. I’m not going to describe these two projects in this post. Instead I would like to describe how you can accomplish modularization of web applications without OSGi.

Do you really need OSGi?

Before you decide to build OSGi-based web applications you have to ask yourself the question: Do you have a requirement to add services to your applications at runtime without restarting the JVM? I guess the most web applications don’t have this requirement. Another question is: Do you want to build modular applications? In most cases the answer to this question is yes. You might have found a reason for using OSGi but wait. If your aim is to break your monolithic WAR files into smaller, more easily managed modules you don’t need OSGi at all. There exist much simple and probably more elegant solutions to accomplish it. Tapestry IoC is one of the them. As far as I know Tapestry is the only one Java web framework that provides this functionality out of the box.

Tapestry IoC vs. OSGi

Tapestry IoC and OSGi have a lot in common. Similar to OSGi bundles Tapestry IoC Modules are packaged into JAR files. The MANIFEST.MF file acts as deployment descriptor for OSGi bundles and for Tapestry IoC Modules. When setting up the IoC registry, Tapestry automatically locates modules packaged into JARs. The framework scans through all JARs in the classpath and searches for a manifest entry Tapestry-Module-Classes inside MANIFEST.MF of every single JAR. The value of the entry is a comma-separated list of fully qualified class names of module classes. This means that a single JAR can contain multiple modules.

Manifest-Version: 1.0
Tapestry-Module-Classes: org.example.lib.LibraryModule, org.example.internal.AnotherModule

The OSGi bundles are identified in the same way. Every OSGi bundle has a MANIFEST.MF containing Bundle Manifest Headers. The headers BundleSymbolicName and Bundle-Version are required. The combination of these two headers is the unique identifier of the bundle inside OSGi. A BundleActivator is used to perform the bundle-specific activities necessary to start or stop a bundle. This is the place where services are registered or unregistered. In Tapestry services are registered in IoC Modules.

Both OSGi and Tapestry IoC provide support for service-oriented architectures. OSGi Service Platform provides a lightweight publish, find, and bind service model for services inside the JVM with the OSGi Framework service registry. Tapestry IoC also provides a Registry which is used to access the available services. While in OSGi you need to perform a service lookup, Tapestry provides a powerful Inversion of Control container. This container allows you to assemble your application from many small, easily testable pieces. Using Tapestry IoC you don’t need to lookup the dependencies of your services. Tapestry will instantiate your classes and resolve all the dependencies of your services. More details about Tapestry IoC can be found here.

Inverting the purpose of Component Libraries

Tapestry is a component-oriented web framework and allows you to create components with ease. The components are reusable by their nature and can be packaged into component libraries. What is exciting about Tapestry is that component libraries can also be used to create modular web applications. For this purpose you can invert the purpose of a component library: Instead of creating reusable libraries that are used in several applications you can create small libraries that are used only in a single application of your customer.

For example if you deliver the same application to several customers, you often have a problem that a special requirement of a customer conflicts with a special requirement of another customer. If you include these special wishes into the application, it will become bloated sooner or later. What you need is a feature that allows you to extend your application without to change it. In Tapestry this can be accomplished by component libraries. If one of your customer wishes a special page in the delivered application, you can create a small library that contains only this special page. This library is delivered to the customer as an additional JAR fie.  You don’t have to integrate this special page into your application.

A component library consists not only of components but also pages, mixins and services. This means that you can break your monolithic WAR file into several JARs, each containing a subset of pages. This way you can assemble your application from different pieces and deliver it to different customers. Your WAR file doesn’t have to contain any pages. When you deliver your application to a customer, you just include several libraries (JARs) depending on the needs of the customer.

Another use case is an application that is available in different editions. Just imagine that the Community Edition contains pages that are located inside the WAR file. The Professional Edition contains some further modules with additional pages and services. The upgrade from the Community Edition to the Professional Edition is just the matter of dropping a new JAR file onto the classpath and restarting the application. Nice, isn’t?

Creating component libraries is very simple. Pleas read this guide for more details.

Modularization example

Now let’s have a look at the modularization features of Tapestry. Imagine you need to create a Menu component which creates a navigation menu dynamically. Depending on the edition of the installed application Menu component renders a different set of menu items. For example when your customer upgrades to the Professional edition, the menu component doesn’t have to be changed. It just renders more items provided by the additional JAR.

Creating dynamic menus

The template of the Menu component might look like the following one. The Loop component iterates over a collection of page names and creates a link to the page of current iteration.

<div class="menu" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd">
      <li t:type="loop" source="pageNames"
         <a t:type="pagelink" page="${var:currentPage}">

Next we create the Java class of the component. The component retrieves the names of the available pages from the service ComponentClassResolver. This service is responsible for resolving page names and component types to fully qualified class names and can be injected into a page or component via the @Inject annotation. Just as with Tapestry applications, Tapestry component libraries have a unique base package. That’s why the service ComponentClassResolver is aware of all the pages available in all the modules of a Tapestry application.

public class Menu {
   private ComponentClassResolver componentClassResolver;

   public List<String> getPageNames() {
      return this.componentClassResolver.getPageNames();

Now create a simple Index page containing the Menu component.

<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd">

Start the server and call the URL of your application. The result should look like in the following picture.

If you would add a new page to your application, then the Menu component would show a new entry in the navigation menu. The same applies for component libraries. If you just drop a new JAR onto the classpath and restart your application, Tapestry will find all the pages, components, mixins and services inside the JAR. There is no need to change the code of the application if you want to add a new entry into the Menu. For example if you include the Tapestry/Hibernate integration library into you application the built-in page Statistics will be automatically added into the menu. The result looks like:

Because Tapestry contains some built-in pages the code above has to be changed slightly. You probably want to exclude the built-in pages from your menu. For this purpose we need an annotation to mark the pages to be included in the menu.

Defining the Annotation

We will place the following annotation in page classes to mark a page as an element of the menu.

@Target( { ElementType.TYPE })
public @interface PluginPage {

For example we want the Index page to be included into the menu.

public class Index {

Excluding Pages

Now let’s have a look at the modified Menu component. We iterate over the names of the available pages and convert every page name into a fully qualified class name. The class name is used to check if the @PluginPage annotation is present. If the annotation is not present, we filter out the page name.

public class Menu {
   private ComponentClassResolver componentClassResolver;

   public List<String> getPageNames() {
      List<String> result = new ArrayList<String>();

      List<String> pages =

      for (final String pageName : pages) {
         String className = this.componentClassResolver

         Class clazz = loadClass(className);

         if (clazz.isAnnotationPresent(PluginPage.class)) {

      return result;

   private Class loadClass(final String className) {
      try {
         return Thread.currentThread()
      } catch (final ClassNotFoundException e) {
         throw new RuntimeException(e);

The result looks like:

Creating customer libraries

Now let’s assume one of your customer wishes a special page to be included into the application you delivered. Because we don’t want to change the application at all we create a simple component library that contains the new page. The structure of the library should look like in the following picture:

The class LibraryModule is the IoC Modul that is used to configure the application. Inside this module we tell Tapestry where to search for our page and component classes. This is accomplished by making a contribution to the ComponentClassResolver configuration. As you remember, we used this service in the Menu component to find the available pages. In the following example we map the prefix mylib to the root package of our library, namely org.example.lib.

public class LibraryModule {
    public static void contributeComponentClassResolver(
             Configuration<LibraryMapping> configuration){
        configuration.add(new LibraryMapping(
                    "mylib", "org.example.lib"));

As you remember, Tapestry scans the classpath to find all IoC Modules. That’s why we need to put the following manifest entry into the MANIFEST.MF file.

Manifest-Version: 1.0
Tapestry-Module-Classes: org.example.lib.LibraryModule

Now build the JAR file, drop it onto the classpath and restart the application. You will see the the following result.


In this article you learned how to create modular applications without OSGi. If you don’t have the requirement to add services to your applications at runtime without restarting the JVM then the described solution is sufficient for your application. You don’t need to migrate to OSGi. Of course OSGi solves some other problems that can’t be handled inside an IoC Container. An example is the version incompatibility of included libraries: OSGi is the only one technology that allows you to install the same library in different versions. At the end of the day you have to decide which technology is more suitable for your needs. Tapestry IoC is a simple, lightweight (and maybe limited) solution for modularization of web applications.

In the next article I’m going to describe some more Tapestry features that allow you to create modular web applications.  Stay tuned.


  1. Borut
  2. igor
  3. André L. Aro
  4. Igor Drobiazko
  5. Igor Drobiazko
  6. Igor Drobiazko
  7. Soddino
  8. Igor Drobiazko
  9. Soddino
  10. Soddino
  11. Alexander
  12. Igor Drobiazko
  13. Michael



Your name

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>


Tapestry 5 Blog - Copyright © 2009 - Eclectic Theme by Your Inspiration Web - Powered by WordPress