ONJava.com    
 Published on ONJava.com (http://www.onjava.com/)
 See this if you're having trouble printing code examples


Nukes: the Open Source Java CMS

by Marc Fleury and Julien Viet
06/04/2003

Why Nukes?

In early 2003 we at JBoss Group were facing an interesting problem on our jboss.org web site. We needed to simplify the management of the web site for our administrators and we needed to expand the capacities of our web site to better serve our developer community.

We started using the PHP solution "PostNuke." It looked good on the surface, as it is heavily developed and has a wealth of applications and modules. However, when we put it in production, it just didn't withstand the load. We went from 30 percent CPU utilization (with forums running and all) to a box crawling on its knees with 100 percent utilization, and response times in the minute range. It was unusable.

We tried tweaking. We read about optimizations. We even read some of PostNuke's source. What we found was shocking for Java system developers. For example, it appeared that for the security components (highly developed in PostNuke), the engine went back to the database every time. We don't know about other PHP applications, but clearly this was a scalability mistake, as it means that every web request goes to the database and does a query. We understand what the PHP LAMP crowd means when they say "database-driven applications".

Another factor we were a bit ambivalent about was the fact that we were using non-Java technology for our web site. Here was the most popular open source Java application server using PHP for its own web site. Many people didn't understand the move and the armchair quarterbacks started armchair quaterbacking. Our answer has always been, "if you don't like it, write it" and the move was mainly a pragmatic one: from the "give me something that works now before you give me religion" school of thought.

In defense of the PHP coders, we want to acknowledge the amazing feat they've pulled off. PostNuke, while non-performant in our installation and under our load, benefits from a simple and evolved user/programmer model (which we have blindly copied in Nukes); a vibrant community (no simple feat); and an amazing collection of modules and applications we are now striving to port and emulate. Much respect to those who get stuff done. Java folk can be snobbish when it comes to modern infrastructure--God knows our JBoss crowd is --but at the end of the day there was no open source Java CMS engine source when we looked.

Ultimately, it didn't work with PHP, so we decided to pull the plug on the PHP web site and put all we had learned about system design for scalability in four years of J2EE in JBoss (including EJB) to the test. Could we port the Nukes engine to J2EE? We did just that. We put Nukes in production in April 2003 and haven't moved since then. It is stable and performant and simple, as it follows PostNuke's "critical mass" tested paradigm. Our CPU utilization is back to normal levels and our module development has kicked off. We encourage you to come and help if you can. Our sales guys update the web site themselves through the web interfaces and we have one of the most interesting study cases of J2EE versus PHP technology. Marrying J2EE and PostNuke gave us a best of both worlds approach.

Nukes on JBoss is therefore the first comprehensive open source Java CMS engine on the market. Let's look at some of its features.

Components at a Glance

Because we mostly steal concepts from PostNuke, skip this section if you are already familiar with that PHP framework. PostNuke is based on a lightweight component model. In JBoss, we leverage the JMX packaging and microkernel approach to provide a truly dynamic environment for Nukes. Like PostNuke, we have three different components: modules, blocks, and themes.

A module is responsible for generating the main content of a page by responding to web invocations. When you click on a link on the page, that call is redirected to the appropriate module in a simple manner. Modules provide the CMS functions.

A block presents information and actions. Blocks are the numerous squares and tiles that compose a page. For example, we have a login block on every web page. We construct the banners and navigation from a collection of blocks. Usually blocks are the little brothers of a module. Blocks are tied to a module—either they display information coming from a module, or they display links that will be handled by a module.

A theme is the glue that puts blocks and modules together when a page is displayed. A theme is a collection and layout of modules and blocks. Themes output a customized HTML layout providing the web site look and feel. Several themes can coexist at the same time. They are customizable. There is a default theme chosen by the administrator for all visitors, and each registered user may choose a theme among the installed.

Nukes
Figure 1. A typical Nukes page

As a real CMS engine, Nukes stores and manages the files you upload in a database. There is no file system with HTML files per se. This is a bit of a departure from the classical web site and a bit disturbing at first, but it turns out to be valuable as we build all kinds of fancy features on top of it. Your web site is stored in a database that makes it robust and easily versioned.

Installing and Using Nukes

Nukes is bundled in several flavors. The easiest way to get it running is to use the preinstalled version. This download contains the JBoss application server, Hsqldb (an embedded lightweight relational dabatase all written in Java), and Nukes itself. Hsqldb already contains a basic configuration that enables you to run Nukes immediately. Download the file, unzip it, click on the launch script, and voila, you have your first web site running on Nukes.

After the boot sequence, you are ready to use Nukes. Point your browser to the address http://localhost:8080 and look at the welcome page.

If you don't want to be tied to the Hsqldb engine, you can download an alternate version that runs on other databases. So far Nukes supports MySQL (which we use for jboss.org) and we are working on a PostgreSQL version. These versions come with database installers, a simple servlet wizard that will help you to insert step by step statements in the database of your choice.

The last way to install Nukes is to download the current development version from our CVS. You must not be afraid to work directly from CVS and the bowels of our systems. We have a step-by-step tutorial on our web site that will help you with this.

Customize and use it!

Using the JMX administration console to change component properties

One of the nice byproducts of using the JMX (Java Management eXtensions) engine from JBoss is that you can interact with the components directly as an administrator. JMX defines a standard component model. The engines that host these components (such as JBossMX) enable you to call and modify all declared attributes. JBoss ships with a web based console that can display all the components hosted by JBoss in a easy to read web page. It takes care of all programmatic interaction with the JMX engine. Since Nukes components are all JMX components, you can manage your Nukes installation through these simple web pages.

Now that Nukes is running, let's manage it. You will see the default site name and slogan, "Your Site Name :: Your Slogan Name", in Nukes. This is the natural first step of customization. Simply use the JMX console to change these properties. Point your browser to the address http://localhost:8080/jmx-console to see the JMX agent view. This page enables you to customize Nukes components. All the JBoss components are listed here, from the bare servlet to the the advanced invalidation cache.

Nukes.modules JMX domain
Figure 2 — the Nukes.modules JMX domain

To help you navigate the JMX components, their names come neatly prefixed with the domain name they pertain to. Look for the domain called Nukes.modules. Under that domain you will find all the installed web site modules. The core engine is called "core" and can be found on the line that says name=core. Click on it. The core module is the main Nukes module and contains the properties we will customize. Edit the core module properties by clicking on the link and you will see a list of MBean attributes that reflects your current Nukes installation. The ones that interest us are the SiteName and Slogan attributes. Change their values and apply the changes. When you update the Nukes main page, notice that the site name and the slogan have changed.

core properties
Figure 3 — simplified view of core properties

We just looked at how to manage the components attributes directly through the JMX engine. This is still "underbelly" management for hardcore system administrators of Nukes web sites. Next we will look at how non-techies can manage the content of the web site.

Log in as administrator and edit the web site content

If you want to manage the web site content itself you can do so directly through the web site. That is the beauty of it. You don't need to go back to a file; you can work directly off of the web site, toggling production versions on and off through a series of webpages. Let's change the content of the main webpage (index).

Nukes login block
Figure 4 — the login block will log you in

On the left of the main webpage of your site, you will find a block called login. Log in to Nukes with admin as the user name and password. Once you are logged in, you will see the management menu on the left navigation banner. In the management block itself you will see a manage HTML link, a function only offered to administrators. Click on this link. Now you are in the HTML module administration. You can see the list of all the pages the module manages, though there is only one entry, index. There are two dropdown lists associated with the index entry. One is version, showing the different versions of a page. So far there is only one version for index. The other is the action you can do on the page. You have a choice of five actions:

Nukes HTML module
Figure 5 — the HTML module in action

Now select the Edit action and click Submit. You are editing the main page and can completely replace the actual content with your own. Make sure the checkboxes Make new version and Make prod are selected, as they are by default, then submit your changes by clicking on the Update HTML page button. If you visit the homepage again you will see your new content. If you go in the module html management page you will notice that now there are two versions of the same file. You can rollback the page to the previous content if you desire.

Nukes' HTML module editor
Figure 6 — add your index content

Versioning

As you can see, the Nukes engine has a notion of versioning. This feature is not present in the original PostNuke engine. The persistence engine of JBoss uses a feature that increments the version and it keeps old versions as long as you want them. This way you can rollback in case you missed something. This is very useful as you work on a live web site. Also, the makeProd toggle enables you to select which version will be publicly displayed to your visitors.

The different modules

We have already ported many PostNuke modules. Nukes on JBoss comes bundled with several modules that will provide you facilities to publish content, administer your community and much more.

Nukes' Architecture Unveiled

Use each technology for what it does the best

We chose JMX to manage Nukes components to provide hot deployment and component decoupling. This means a component can be removed from the system while it is running with little or no consequence. A webpage is made of several tiles, and each "tile" is a component/block/module package. We also wanted to support completely dynamic web sites, so you can add new modules to a running instance without service disruption. The jboss-system module built on top of core JMX brings us more features than plain vanilla JMX, like service dependencies. Therefore, each component is an MBean service hooked in JBoss. The original PostNuke components have a lifecycle, but they do not handle dependencies at all. Nukes does, leveraging a typical J2EE specification with some JBoss flavor.

In our port we split data and made a clean separation between management model and the business model. Usually business data need to be scalable and highly configurable, so they are often made of entity EJB components. Our infrastructure leverages the local interfaces introduced since EJB 2.0 because we stay in the same VM all the time. We colocate the web server and the component containers in the same space, avoiding excessive serialization. We do not use data patterns such as DAO or DTO, preferring to use JBoss in its default local mode.

Because of the JMX architecture decision, the hardcore management data is exposed as MBeans attributes. We saw how to change the site name and the site slogan, but you can configure Nukes further this way. Each MBean attribute is persisted in the relational database as well, avoiding the loss of configuration when you restart the server.

Nukes Component Development

It is easy to create a Nukes component from scratch. We are going to create a small module.

Module invocation

Since a module is more or less a set of operations, we need a standard way to invoke them. We chose to keep the original way that PostNuke authors decided to specify invocations in URL syntax. It looks deceptively standard. Each action on a module is triggered when you call a URL that looks like this:

http://localhost:8080/index.html?module=module_name&op=operation_name&...

That URL triggers the operation operation_name on the module module_name. The two parameters, module and op, tell Nukes which operation to invoke on what module. The other parameters can be fetched by the module by introspection when it is invoked. Since a module is a JMX MBean, each managed operation that follows the right pattern may be invoked in this manner. This spells out an invocation that the JMX server can apply on a target MBean. Behind the scenes, we translate a URL invocation in a JMX invocation in memory. It is fast and follows the same naming patterns.

public void operation(org.jboss.Nukes.html.Page page)

If you type the URL with the value of the op parameter as operation, Nukes will call that method on your module object.

Module Creation

PostNuke's module model is almost identical to the servlet model. You code your page behavior in pure Java. We prefer this to the JSP Model 2 architecture. Let's start with the TemplateModule class declaration:

// a module extends the class org.jboss.Nukes.module.ModuleSupport
public class TemplateModule extends ModuleSupport
{
   // ...
}

In order to have the Nukes support, your module must extend the ModuleSupport class. This has multiple effects:

The Nukes API

The major object which you will have to deal with is the Page object. Let's see how to use it:

/**
 * This method is called with the following url:
 * http://localhost:8080/Nukes/index.html?module=template
 */
public void main(Page page)
{
    page.print(&quot;<div align=\"center\">&quot;);
    page.print("Welcome to the template module");
    page.print(&quot;</div>&quot;);

    // print a form that ask for a name
    page.print(&quot;<table align=\"center\">&quot;);

    // call Nukes main entry point
    page.print(&quot;<form action=\"index.html\" method=\"GET\">&quot;);

    // with module = template
    page.print(&quot;<input type=\"hidden\" name=\"module\" 
        value=\"template\"/>&quot;);

    // and op = action
    page.print(&quot;<input type=\"hidden\" name=\"op\" 
        value=\"action\"/>&quot;);

    // name = XXX
    page.print(&quot;<tr><td>Type your name: 
        </td><td><input type=\"text\" 
               name=\"name\" value=\"\"/></td></tr>&quot;);
    page.print(&quot;<tr><td colspan=\"2\"><input 
        type=\"submit\"/></td></tr>&quot;);
    page.print(&quot;</form>&quot;);
    page.print(&quot;</table>&quot;);
    page.print(&quot;</div>&quot;);
}

As you can see the method main is called with the following url:

http://localhost:8080/Nukes/index.html?module=template&op=main

The Page object is provided as a parameter by the core and is used by this method to render the HTML content. In this Nukes operation, the HTML rendered form carries an URL that will activate the method action of the module Template.

Let's see the action method declared by the Template module:

/** 
 * This method is called with the following url: 
 * http://localhost:8080/Nukes/index.html?module=template&op=action 
 */ 
public void action(Page page) 
{ 
    // get the parameter 
    String name = page.getParameter("name"); 

    // if no name has been provided, just render the main page again 
    if (name == null || name.length() == 0) 
    { 
       main(page); 
       return; 
    } 

    page.print(&quot;<div align=\"center\">&quot;); 
    page.print("Welcome to the template module " + name); 
    if ( getApi().userLoggedIn() ) 
    { 
       page.print("you are logged in"); 
    } 
    page.print(&quot;</div>&quot;); 
}

This method uses Page as a context object because it stores the HTTP parameters like the HttpRequest object in the servlet API. You can use the Page API as you do in the servlet API. Another object that is used by this method is the Api object returned by the getApi() method. It provides services a component may need. In this case it is used to know whether a user is logged in or not and to display a message.

Module packaging

The final step in our module creation is deployment. We have to tell JBoss that the class we just wrote is a Nukes module. The jboss-service.xml file declares a Nukes module using the class we just examined.

<?xml version="1.0" encoding="UTF-8"?>
<server>
   <mbean
      code="org.jboss.Nukes.core.modules.user.blocks.LoginBlock"
      name="Nukes.blocks:name=login">
      <depends>Nukes.modules:name=core</depends>
      <attribute name="DisplayName">Template module</attribute>
      <attribute name="Description">The Template module</attribute>
   </mbean>
</server>

Then we package the class in a jar archive and we add a file jboss-service.xml in the META-INF directory of that archive. Packaging the file is done with the command jar -cvf Nukes-template.sar *. The special extension .sar tells JBoss that the packaged file is a service archive.

Template module package
Figure 7 — the module packaged for deployment

Finally we copy that file into the JBoss deploy directory, where it is automatically deployed. The module can be used without restarting Nukes. Deployment is totally dynamic and is done at runtime.

Template module deployment
Figure 8 — the template module is deployed

Final words

What did we learn from our experience? Software that exists is a good place to start even if it is in another language and we are Java snobs. The second lesson was that PHP/PostNuke isn't really designed to handle very high loads. We decided to port to J2EE and leverage many of the existing APIs (JMX and EJB) to provide a straight port of PHP technology that became "enterprise level" almost immediately. That was the real lesson for us, a proof that all the work we do on system level Java pays off in spades at the application level.

Today, the product is maturing. We've ported the majority of the original PostNuke modules and enhanced some of them along the way. Nukes is production ready — it's in production. It has powered the JBoss.org web site for three months without major problems. Its advanced architecture makes it very scalable and easy to work with. We welcome you to come and help us with the porting of modules so we can finally have a decent CMS/Portal base in Open Source Java.

Marc Fleury , Ph.D., is CEO of JBossGroup, LLC. and founder of the JBoss open-source project.


Return to ONJava.com

Copyright © 2009 O'Reilly Media, Inc.