Web2.0 how-to Design Style Guide

February 26th, 2008

Summary of features covered

The list below is a summary of many of the common features of typical “Web 2.0″ sites.

Clearly, a site doesn’t need to exhibit all these features to work well, and displaying these features doesn’t make a design “2.0″ - or good!

I’ve already addressed some of these factors in my introductory Current Style article.

  1. Simplicity
  2. Central layout
  3. Fewer columns
  4. Separate top section
  5. Solid areas of screen real-estate
  6. Simple nav
  7. Bold logos
  8. Bigger text
  9. Bold text introductions
  10. Strong colours
  11. Rich surfaces
  12. Gradients
  13. Reflections
  14. Cute icons
  15. Star flashes

Disclaimer

Not all these design features are appropriate in all cases. There are always exceptions, and there are lots of bad examples of these features being used wrongly, over-used, or done without sensitivity to the “symphony” of a site’s design.

You can’t just take all these elements, throw them together and make a good web page, any more than you can take some eggs, sugar, flour and throw them together and get a cake.

Making a web page that works requires a lot of sensitivity to the various forces at work. A good design solution is one that balances those (often opposing) forces.

Web 2.0 ?!

I’m using the term “Web 2.0 design” to describe the prevailing style of web design I introduce in my current style article.

Many people use the term “Web 2.0″ to describe:

  • a resurgence in the web economy
  • a new level of technological interactivity between web sites and services
  • or social phenomena deriving from new types of online communities and social networks

Many others also use the term in reference to a recent school of web design. I’m comfortable with using it in that context here.

In sociological terms, movements impact people on many levels: economic, cultural, political, etc. Is skate-punk about entertainment and sport, music and the music industry, fashion, or the breakdown of society?

Shortcut to Web2.0 Style

If you don’t have the resources to create your own “2.0”-style site design, TemplateMonster have just (17 July 07) launched a new Web 2.0 Templates section.

Of course, a purchased template won’t always hit your goals perfectly, but a custom design doesn’t always guarantee that either!

Many sites will benefit loads from applying a fresh, current design, and purchasing a template for under $100 can be a great way to achieve that! And TemplateMonster have been doing this for years, so I’d certainly recommend taking a look.

Small screenshots of TemplateMonster template Small screenshots of TemplateMonster template Small screenshots of TemplateMonster template

Introduction

I’m going to take you through the features of the current wave of excellent web site designs, dissect the most significant features, explain why each one can be good, and show you how to use them in your own sites.

If I had to sum up “Web 2.0″ design in one word, it would have to be “simplicity”, so that’s where we’ll start.

I’m a great believer in simplicity. I think it’s the way forward for web design.

Today’s simple, bold, elegant page designs deliver more with less:

  • They enable designers to shoot straight for the site’s goals, by guiding the site visitor’s eye through the use of fewer, well-chosen visual elements.
  • They use fewer words but say more, and carefully selected imagery to create the desired feel.
  • They reject the idea that we can’t guess what people want from our sites

1Simplicity

“Use as few features as are necessary to achieve what you need to achieve”

Web design is simpler than ever, and that’s a good thing.

2.0 design means focused, clean and simple.

That doesn’t necessarily mean minimalist, as I’ll explain later.

I really believe in simplicity. That’s not to say that all web sites should be minimal, but that we should use as few features as are necessary to achieve what you need to achieve.

I’ve written elsewhere about Occam’s Razor, which is a principle I use all the time. One way of interpreting it is: Given any two possible solutions to a problem, the simpler one is better.

Here are some examples. Note how unnecessary elements have been stripped out from each. There could be a lot more on each page than there is… but would that make them stronger?

The result is that you have to look at the content. You find yourself interacting with exactly the screen features the designer intended. And you don’t mind - it’s easy, and you get just what you came for.

Mozilla store Medicon Media Etre Simplebits Artypapers Real Meat

Why simplicity is good

  • Web sites have goals and all web pages have purposes.
  • Users’ attention is a finite resource.
  • It’s the designer’s job to help users to find what they want (or to notice what the site wants them to notice)
  • Stuff on the screen attracts the eye. The more stuff there is, the more different things there are to notice, and the less likely a user is to notice the important stuff.
  • So we need to enable certain communication, and we also need to minimise noise. That means we need to find a solution that’s does its stuff with as little as possible. That’s economy, or simplicity.

When & how to make your designs simple

When?

Always!

How?

There are two important aspects to achieving success with simplicity:

  1. Remove unnecessary components, without sacrificing effectiveness.
  2. Try out alternative solutions that achieve the same result more simply.

“It seems that perfection is reached not when there is nothing left to add, but when there is nothing left to take away.”

Antoine de Saint-Exupéry,
Terre des hommes, 1939

Whenever you’re designing, take it as a discipline consciously to remove all unnecessary visual elements.

Concentrate particularly on areas of the layout that are less relevant to the purpose of a page, because visual activity in these areas will distract attention from the key content and navigation.

Use visual detail - whether lines, words, shapes, colour - to communicate the relevant information, not just to decorate.

Here’s an example of a design that suffers from not enough simplicity.

Yaxay’s interface uses a lot of pixels, but the vast majority of them are decorative, part of the page background. Relatively few pixels are used to user to find or understand information or interact with the site.

 

Yaxay is busy and ineffective Yaxay detail See how much “stuff” there is to look at, and notice how few of the pixels are used to clarify actual navigation, actual content, or actual interactive features.

Edward Tufte is the boss when it comes to the design of information. He uses the terms “data ink” (i.e. detail that enables information transfer) and “non-data ink” (i.e. detail that’s just detail) to describe this phenomenon.

One way Tufte specifically measures the effectiveness of information design (graphs, charts, presentations etc.) is using the ratio of data-ink to non-data-ink. The higher the proportion of data-ink used, the more likely it is that a design is effective.

Taking the Yaxay detail above, there’s a lot of what I call “busyness”, i.e. a lot of edges, tonal changes, colour variations, shapes, lines… a lot of stuff to look at. But, in this detail, the only useful features are:

  1. The site logo, and
  2. the label on the nav button (which reads “art gallery”)

All the rest of the “busyness”: the shapes in the background, the diagonal lines in the interface panel, the grid, the gradients… all this is noise, it’s all “non-data ink”, because it’s not enabling communication.

I’m not against richness, complexity or beauty in web design

Simplicity means:

Use as many pixels as you need, in whatever way you need, to facilitate the communication that needs to happen.

Of course, often what you’re communicating isn’t hard data, but soft information.

Hard data
means facts, like news, stock prices, train times, or how much money is in your bank account…
Soft information
covers the qualitative aspects of communication, like the first impression about the quality of a company, the sense of how approachable a service provider is, and whether you feel a product will be right for you. It can be just as important!

Whether what you’re communicating is hard or soft, your pixels count, so use them consciously and with care.

Take the example below:

Alex Dukal, illustrator

Alex Dukal’s site is rich, interesting and appealing. It uses a range of visual techniques to draw your attention, make you interested and to give you a warm feeling about the quality of Alex’s work.

But it’s also simple, because it uses its pixels/ink/busyness with care and sensitivity. It’s not gratuitous, it’s economical and rich.

Whatever you’re saying, choose wisely where you use your ink/pixels. Use it to communicate, first and foremost. Then, ask whether you can communicate just as effectively with less. If so, do it.

2Central layout

(More about this on the Current Style page). Basically, the vast majority of sites these days are positioned centrally within the browser window. Relatively few are full-screen (liquid) or left-aligned / fixed-size, compared to a few years ago.

Why a central layout is good

This “2.0″ style is simple, bold and honest. Sites that sit straight front & center feel more simple, bold and honest.

Also, because we’re being more economical with our pixels (and content), we’re not as pressurised to cram as much information as possible above the waterline/fold.

We’re using less to say more, so we can be a bit more free and easy with the amount of space used, and pad out our content with lots of lovely white space.

When & how to use a central layout

I’d say, position your site centrally unless there’s a really good reason not to.

You may be wanting to get more creative with the space, or get as much information on-screen as possible (for example with a web app).

3Fewer columns

A few years ago, 3-column sites were the norm, and 4-column sites weren’t uncommon. Today, 2 is more common, and 3 is the mainstream maximum.

Why using fewer columns is good

Less is more. Fewer columns feels simpler, bolder, and more honest. We’re communicating less information more clearly.

There’s also a by-product of the domination of centered layouts. Because we’re not filling the whole screen so much, and not trying to get as much on-screen at any one time, we simply don’t need as many columns of information.

37 Signals' home page 37Signals have always been at the front when it comes to questioning the status quo and coming up with simple answers.

Here, they use 2 columns. This a great case study in simplicity. It lets the message speak, and adds nothing that could get in the way.

 

Apple Expo Apple is the other leader in elegant simplicity.

This kind of layout works really, really well. Each time I experience Apple’s simple design, the more convinced I become that its zen approach is the holy grail of design.

This typical Apple layout shows that someone has honestly asked, “How many boxes/columns/lines do we really need?”. Then they’ve boldly edited out unnecessary elements, and the result is undeniably the cleanest, most effective communication.

 

How to choose your columns

I’d definitely recommend using no more than 3 columns, simply because you should use no more of anything than you need to.

There are always exceptions, so here are a few examples of more than 3 columns used effectively.

Derek Powazek's blog Derek Powazek’s blog site uses 3 columns for the main section of his blog, but 4 lower down.

The lower section is a kind of pick & mix, where the abundance of columns emphasises the “Take what you like” feel.

 

Amazon.co.uk Amazon (UK) has two side columns, and products arranged centrally in 3 additional columns.

It works beacuse the purpose of each column is clear from its design. The left col is definitely navigation; the right column is “other stuff”. The products in the middle are clearly tiled and separated by white space, so they don’t overwhelm.

 

Popurls.com screenshot Popurls.com contains loads of pick-n-mix information, collating the hot links from other sites like digg and del.icio.us, but it still keeps to 3 columns for the main blocks of text.

Further down, it shows thumbnails of popular images on the photo-sharing site Flickr (and there are Youtube vids later). These are tiled in several columns, which is fine, because it’s a sit-back, scan and pick your experience moment…

 

And here’s a site that gets it wrong…

All things web 2.0 has 2 much Here’s All Things Web2.0 using 4 columns: 2 side columns and 2 central columns.

The downside of this layout is that you don’t know where to start looking. Everything is somehow low-priority (partly because of the darkish background).

As we saw, Amazon differentiates the page to this extent, but the design helps you instantly identify what each area of screen real-estate is for, so it’s not confusing.

 

4Separate top sections

This means making the top of the screen (the main branding & nav area) distinct from the rest (the main content).

Of course, there’s nothing new about this approach. It’s a good idea, and has been used for ever. But it’s being used more than ever now, and the distinction is often stronger.

See how clear the “page-tops” are in these 6 samples, even at small scale:

Simplebits Mozilla store Medicon Media Curve2 Alsa Crétions Tony Yoo's Protolize

Why distinct top sections are good

The top section says “Here’s the top of the page”. Sounds obvious, but it feels good to know clearly where the page starts.

It also starts the site/page experience with a strong, bold statement. This is very “2.0″-spirited. We like strong, simple, bold attitude.

2 of these top-sections contain just branding (Protolize, Mediconmedia), 1 has just navigation (Cross Connector), and the remaining 3 have both.

The weakness of Cross Connector, in my view, is that the logo comes after the nav. I prefer the nav to be high-up, and clear (like e.g. Simple Bits).

When & how to use a distinct top section

On any site, both the main branding and main navigation should be obvious, bold and clear.

So it’s a good idea to create a clear space at the top of a web site design that positions the logo and nav boldly.

Always put your logo right up the top of the screen. I’d always recommend putting your main navigation right after it.

It’s definitely a good thing to mark the top of the page with a section that marks out the high-level screen features as separate from the main site content.

The top section should be visually distinct from the rest of the page content. The strongest way to differentiate is to use a bold, solid block of different colour or tone, but there are alternatives.

Here are 2 examples where the top section is separated with a solid line, rather than being solid colour itself.

London Pain Consultants Ex Blogs

And here, the top section contents simply sit boldly outside the main column area.

Aurum Newtech Steinruck Design

5Solid areas of screen real-estate

Leading on from the clearly differentiated top area, you’ll notice that lots of sites define the various areas of real-estate boldly and clearly.

Real estate comes in various forms, including:

  • Navigation
  • Background / canvas
  • Main content area
  • Other stuff
  • Callouts / cross-links

It’s possible to design a web page so that these areas are immediately distinct from their neighbours.

The strongest way to do this is using colour.

Medicon Media Jeremy Boles' blog Ex Blogs Curve2

 

But white space can be just as effective.

The risk with strong colour is that it draws the eye, so it can take attention away from other relevant screen elements.

I think that placing clean content on white space creates an easier experience, helping the viewer to feel more relaxed and free to browse.

Apple Expo Etre

 

6Simple nav

Permanent navigation - your global site nav that appears on every page as part of the page template - needs to be clearly identifiable as navigation, and should be easy to interpret, target and select.

  • 2.0 design makes global navigation large, bold, clean and obvious.
  • Inline hyperlinks (links within text) are typically clearly differentiated from normal text.

Navigation from TradingEye Navigation from Cross Connector Navigation from Mozilla Navigation from London Pain Consultants Navigation from Protolize

Why simple navigation is better

Users need to be able to identify navigation, which tells them various important information:

  • Where they are (in the scheme of things)
  • Where else they can go from here
  • And what options they have for doing stuff

Following the principle of simplicity, and general reduction of noise, the best ways to clarify navigation are:

  • Positioning permanent navigation links apart from content
  • Differentiating navigation using colour, tone and shape
  • Making navigation items large and bold
  • Using clear text to make the purpose of each link unambiguous

How to keep your nav simple

Simply remember the key: navigation should be clearly distinguishable from non-navigation.

Just follow the guidelines above, regarding differentiation through position, colour and clarity.

My article about navigation »

Inline hyperlinks should also stand out sufficiently from the text around them.

Check out these snippets. In each case, you’re in do doubt what’s a link. (Personally, I prefer using blue text (non-underlined) which turns to underlined red on hover…)

Save the Pixel book coverRead “Save the Pixel - the Art of Simple Web Design”

For the best professional insight into how to create super-simple, effective designs, get Ben Hunt’s new e-book.

It features 10 brand new chapters teaching pro pixel-saving skills, plus 22 worked example case studies. Buy it now, only £15

 

Howie Jacobson, author of “Adwords for Dummies”, says…

“Save the Pixel is the best book on web design and usability I’ve ever read, and one of the best books on internet marketing in general. If you’re sending traffic to your web site via Google AdWords and you haven’t discovered the strategies and tactics in Save the Pixel, I guarantee you’re throwing away money.

“It’s not just information, but a systematic way of designing a site for your customers rather than your web designer’s online portfolio. Save the Pixel is the one book I insist my clients read before I’ll roll out an AdWords campaign for them.”

7Bold logos

A clear, bold, strong brand - incorporating attitude, tone of voice, and first impression - is helped by a bold logo.

Here are some (100% scale). Notice that logos are tending to be quite large, in line with the general 2.0 principles.

Collection of strong logos

Why?

Strong, bold logos say “This is who we are.” in a way that we can believe.

When & how?

See my articles on logos and text-based logos.

It’s very hard to say how to create a good logo, but in brief…

Your logo should:

  • work visually in its main context, and any other uses in which it may be used (like flyers or t-shirts?)
  • be recognisable and distinctive
  • represent your brand’s personality and qualities on first viewing

8Bigger text

Lots of “2.0″ web sites have big text, compared to older-style sites.

If you fill the same amount of space with less “stuff”, you have more room.

When you’ve made more room, you can choose to make more important elements bigger than less important elements (if they’re still there).

Making things bigger makes them more noticeable than lesser elements. This effect has been used throughout the history of print design, on headings, title pages and headlines.

Not only does big text stand out, but it’s also more accessible to more people. That’s not just people with visual impairments, but also people looking on LCD screens in sunlight, people sitting a little further from the screen, and people just skimming the page. If you think about it, that could be quite a lot of people!

Browse Happy 37 Signals' home page Mozilla store Aurum Newtech

 

When & how to use big text

Big text makes most pages more usable for more people, so it’s a good thing.

Of course, size is relative. You can’t take a normal, busy site, make ALL the text bigger, and make it more usable. That might not work, that might be worse.

In order to use big text, you have to make room by simplifying, removing unnecessary elements.

You also need to haave a reason to make some text bigger than other text. And the text must be meaningful and useful. There’s no point adding some big text just because it’s oh-so 2.0!

If you need to have a lot of information on a page, and it’s all relatively equal in importance, then maybe you can keep it all small.

9Bold text introductions

Leading on from the big text theme, many sites lead with strong all-text headline descriptions.

These normally set out the site’s USP, elevator pitch or main message.

They tend to be graphical, rather than regular text. The reason for this is that designers want a lot of control over the page’s visual impact, especially early on in a browsing experience.

Apple.com 37 Signals' home page Ex Blogs Cross Connector

 

When & how to use a bold text intro

Only use one if you’ve got something bold to say. v (If you haven’t got something bold to say, maybe it’s worth having a think about the purpose of your page/site and coming up with somethign worth saying boldly!)

If you have a simple message that you want to be seen first, go ahead and headline it. Make it clear by putting it against a relatively plain background.

10Strong colours

Bright, strong colours draw the eye. Use them to divide the page into clear sections, and to highlight important elements.

When you have a simple, stripped-out design, you can use a bit of intense colour to help differentiate areas of real-estate and to draw attention to items you want the visitor to notice.

Treo mobile The Treo Mobile site uses 3 areas of strong colour to mark out and advertise 3 main areas of the site.

The background colour makes it clear that this isn’t main content, and large, bold title text helps you see quickly what’s in each one, so you can decide whether it interests you.

 

Colorschemer Colorschemer sections the page with bands of intense, bright, cheerful colour, set against a more neutral background.

 

Apple.com home Apple’s design has always used a great balanced combination of tone (darks), rich effects and colour to draw the eye.

It may be the most perfectly designed web site there is, in my opinion.

In this image, the intense dark areas and strong colour are used sparingly to pick out important content.

 

Colour is also a great medium for communicating brand values

Real Meat Here, the colour isn’t bright, but it is strong, partly because of the amount of green used.

This design uses green to communicate the values of “quality” and “health”.

Note: site design doesn’t match this image!

 

Gear for girls This site sells outdoor clothes exclusively for females, and the soft colours reinforce the chosen brand personality.

 

Be careful to use intense colour on or around high-value features

Giddy Kippa A nice, effective page design is compromised by the use of large areas of intense colour outside the main page area.

The result is that the eye is drawn away from the real content.

 

Aurum Newtech The Aurum Newtech site risks the same effect, but the colour is just pale enough to keep the content noticeable.

Also, the big, bold and well-spaced content elements help draw attention away from the “attractive” background.

 

Remember to use sparingly

If you’re using strong colours to attract the eye, it only works if there’s lots of area that isn’t strongly coloured.

If everything is trying to attract the eye, then the eye just gets confused, and the site will feel confusing and chaotic.

11Rich surfaces

Most 2.0-style sites use subtle 3D effects, sparingly, to enhance the qualitative feel of the design.

We all know that these little touches just feel nice, but we may not know why.

Realistic surface effects (like drop-shadows, gradients and reflections) help make a visual interface feel more real, solid and “finished”.

They may also remind us of certain tactile or aesthetic qualities of real-world objects, such as water droplets, shiny plastic buttons, and marble floors. Making stuff look solid and real can make it look “touchable”, which is likely to appeal.

 

When & how to use rich surfaces

The golden rule here is to use with care, and not to overdo it.

As I explain in the tutorial on 3D Effects, these effects should not be applied to everything.

Like any of these techniques, a rich surface may add value to your design when used sensitively and appropriately.

If your navigation/icon/logo/layout sucks fundamentally, you can’t polish your way out. Get the fundamentals right first.

It can also be important to maintain a consistent light-source. Although this can get more complex with the illusion of back-lit diffusion in buttons etc., you still know whether an overall design feels consistent.

3D effects can also make elements seem to stand out from the page, but only if the rest of the page is relatively flat.

Avoid trying to make your entire design 3D-realistic because:

  • It’s more work
  • It will increase the overall size of the page assets
  • And you don’t need to. 3D effects use lots of different pixels, and different pixels should be used deliberately to draw the visitor’s attention to key content elements, or to enhance “soft” informational aspects. A little goes a long way.

12Gradients

Web 2.0 design has more gradients than the Alps.

Why gradients are so useful

Gradients soften areas that would otherwise be flat colour/tone.

Artypapers They can create the illusion of a non-flat surface, used to good effect on Alex Dukal’s portfolio.

 

Aurum homepage Gradients can be used to fade a colour into a lighter or darker tone, which can help create mood.

 

Artypapers In page backgrounds, they may also create an illusion of distance.

A common gradient combo is blue-to-white, which evokes the effect of aerial perspective, creating the sense that the background fades away towards the horizon.

 

They are commonly used at the very top of page backgrounds, where they help denote the boundary of the viewable area.

Colorschemer Alex Dukal, illustrator

 

They’re also an integral part of drop-shadows, and the inner-glows and specular highlights you see on glass- or plastic-style buttons.

Note that gradients usually work best when juxtaposed with areas of flat colour or tone.

Curve2 On the Curve2 homepage, the gradients are more effective because each one is positioned adjacent to a flat white or grey section.

It’s common to find gradients enhancing the base colour (using mix effects like color-burn or overlay in Photoshop), which create subtly different hues.

Here, the highlighted green colour is warmer and friendlier than the darker base colour. The overall effect is both softer and richer.

 

13Reflections

The illusion of reflection is one of the most common applications on gradients.

These commonly come in 2 kinds:

  • Highlights caused by light reflecting on shiny surfaces
  • That shiny table effect!

Specular highlights

Realistic effects of water droplets, glass beads, shiny plastic buttons etc. have been very popular over the past couple of years.

I don’t know where the trends started, but Apple’s web site must have been one of the most influential, preceding their Aqua interface look & feel.

Here are some examples:

The classic Apple.com shiny plastic tabs, still in use today.

These use highlights caused by a light source above the tabs, combined with an inner, diffuse glow that creates the plastic effect.

 

These tabs, from one of my recent redesigns, have a polished (from the strong white highlight) carbon-fibre appearance. The carbon effect comes from the warm diagonal-stroke pattern from the icon’s glow.

 

More nice shiny plastic. Notice how the reflections fall off at the edge of the shape, which create the illusion of rounded edges.

 

Similar effect on a square shape looks like a badge.

The non-horizontal angle creates a sense of dynamism.

 

This shiny button from cafepress.com uses a rounded reflection that suggests a wide light source coming off a rounded surface.

 

This button from web hosts Mediatemple has a more diffuse reflection, suggesting a matt glass finish.

 

That shiny table effect!

Pioneered by Apple again (I’m sure). This is a really nice effect which is so prevalent now, it’s in danger of being overused, now starting to look tired and is falling out of favour with designers.

Remember, of course, that web designers are usually more sensitive to these things, so even if we’re getting turned off by it, the general public may still think it’s cool for some time to come.

The standard Apple look. Greyed-out and fading on a white base.

On a coloured background

Fading out to either side (my one this, not published yet)

More extreme angle, and a rich layered effect reflecting the colour of the solid object

 

Here’s how to do it (from photoshoplab.com) »

14Cute icons

Icons play an important role in Web 2.0 design. Today we use fewer, better icons that carry more meaning.

Icons can be useful when they’re easily recognisable and carry a clear meaning. In lots of other cases, a simple word is more effective.

In the old days, icons were sometimes overused. It seemed that everyone wanted an icon for every navigation link or tab. Now, we use clear text more extensively, and are less ready to litter a page with icons.

Where 2.0 designers do employ icons, they are reserved for higher-value spots, where .

Simpler, more spacious designs demand less attention and allow for a richer icons.

Some examples, demonstrating various attributes.

Simple and clean

 

Cute and quirky

Do not necessarily have to feature tiny hills!

37 Signals Overture

 

Richly detailed

Creatively inspired by Mac OSX. See Enhanced Labs for a great showcase.

 

15Star flashes

These are the star-shaped labels that you see stuck on web pages, alerting you to something important.

They work by evoking price stickers in low-cost stores. For this reason, they suit the start-up ethic of many 2.0 sites, but for the same reason may cheapen other sites.

They can really work well, but of course should only be used to draw attention to something important.

I’d recommend only using one on a page (at most!).

Another style that’s seeming over-used, and will probably run its course over the next year.

Using ActiveMQ JMS from C#

February 25th, 2008

Wishing to have a publish/subscribe message queue available in .NET, I have looking for ways to allow .NET to talk to a JMS implementation. After reading the article An Introduction to IKVM by Avik Sengupta, I took the latest release of ActiveMQ and IKVM, complied the jar files (as described in the article), and modified one of the examples from the ActiveMQ distribution and created a C# version (see below). Everything seems to work. The example submits items to the queue, and them retrieves them.

using System;
using System.Threading;
using ikvm.lang;
using org.codehaus.activemq;
using org.codehaus.activemq.util;
using org.codehaus.activemq.message;
using javax.jms;
using java.util;

namespace DefaultNamespace
{
    class MainClass : MessageListener
    {
        protected int messageCount = 100;
        protected String[] data;
        protected ActiveMQConnectionFactory connectionFactory;
        protected Session session;
        protected MessageConsumer consumer;
        protected MessageProducer producer;
        protected Destination destination;
        protected Connection connection;

        protected Connection receiveConnection;
        protected Session receiveSession;

        protected List messages = Collections.synchronizedList(new ArrayList());
        protected bool topic = true;

        protected ActiveMQMessage createMessage()
        {
            return new ActiveMQMessage();
        }

        protected Destination createDestination(String subject)
        {
            return new ActiveMQTopic(subject);
        }

        public void testSendReceive()
        {
            messages.clear();

            for (int i = 0; i < data.Length; i++)
            {
                Message message = session.createTextMessage(data[i]);

                Console.WriteLine(“About to send a message: “ + message + ” with text: “ + data[i]);

                producer.send(destination, message);
            }

            // lets wait a little while
            Thread.Sleep(4000);

            Console.WriteLine(“should have received a message: {0} {1} {2}”, messages, data.Length, messages.size());

            for (int i = 0; i < data.Length; i++)
            {
                TextMessage received = (TextMessage) messages.get(i);
                String text = received.getText();

                Console.WriteLine(“Received Text: “ + text);

            }
        }

        public MainClass()
        {
            topic = true;

            data = new String[messageCount];
            for (int i = 0; i < messageCount; i++)
            {
                data[i] = “Text for message: “ + i + ” at “ + DateTime.Now.ToLongTimeString();
            }

            connectionFactory = new ActiveMQConnectionFactory();
            connectionFactory.setBrokerURL(“vm://localhost”);
            connectionFactory.setUseEmbeddedBroker(true);

            connection = connectionFactory.createConnection();
            receiveConnection = connectionFactory.createConnection();

            Console.WriteLine(“Created connection: “ + connection);

            session = connection.createSession(false, 1);
            receiveSession = receiveConnection.createSession(false, 1);

            Console.WriteLine(“Created session: “ + session);
            producer = session.createProducer(null);

            Console.WriteLine(“Created producer: “ + producer);

            if (topic)
            {
                destination = receiveSession.createTopic(“FOO.BAR”);
            }
            else
            {
                destination = session.createQueue(“FOO.QUEUE”);
            }

            consumer = receiveSession.createConsumer(destination);
            consumer.setMessageListener(this);
            receiveConnection.start();
                connection.start();

            Console.WriteLine(“Created connection: “ + connection);

            testSendReceive();

            Console.WriteLine(“Dumping stats…”);
            connectionFactory.getFactoryStats().dump(new IndentPrinter());

            Console.WriteLine(“Closing down connection”);

            session.close();
            receiveSession.close();

            connection.close();
            receiveConnection.close();

            connectionFactory.stop();
            connection.close();

        }

        public void onMessage(Message message)
        {
            Console.WriteLine(“Received message: “ + message);

            messages.add(message);
        }

        public static void Main(string[] args)
        {
            MainClass mc = new MainClass();
        }
    }
}

Magic with JMS, MDBs, and ActiveMQ in Geronimo

February 25th, 2008
Apache Geronimo is the workhorse open source Java™ 2 Platform, Enterprise Edition (J2EE) 1.4 server container with an open framework that’s ready to host a variety of existing servers and services. ActiveMQ is a proven best-of-breed, open source Java Messaging Service (JMS) engine with a Swiss-army-knife arsenal of features and connectivity options. When you marry the two, magic happens! Sing Li takes you on a grand tour of this symbiotic relationship, providing example code to help you get started writing JMS applications and creating message-driven beans (MDBs) with Geronimo immediately.

The JMS API is an integral part of the J2EE platform, enabling message-based communications between loosely coupled components. Messages can be sent and received throughout the J2EE stack between clients, Web-tier components, business-tier Enterprise JavaBeans (EJBs), and Enterprise Information System (EIS)-tier services. These messages are sent asynchronously, where the sender continues with other application logic once the message is sent, and a message broker is responsible for delivering the message on behalf of the sender. Messages can be sent and received between specific endpoints (sender and recipients), or passed anonymously between producer(s) and consumer(s) using a publish/subscribe interaction model. Within the J2EE framework, components communicating through JMS can leverage the security and transaction capabilities provided by the container. Geronimo supports this vital API by integrating an open source project called ActiveMQ.

This article explores the ActiveMQ integration within Geronimo. You’ll see how Geronimo benefits from the integration and how ActiveMQ’s capabilities are enhanced when hosted inside Geronimo. A hands-on example, which you can download from this article, reveals how to code clients and Geronimo components that communicate through JMS. Another example shows you how to create versatile MDBs within Geronimo.

ActiveMQ: a best-of-breed, open source JMS implementation

ActiveMQ is a mature and feature-rich JMS server, or message broker in JMS terminology. Housed at Codehaus (see Resources), ActiveMQ supports a large variety of transports (such as TCP, SSL, UDP, multicast, intra-JVM, and NIO) and client interactions (such as push, pull, and publish/subscribe). With a sizable existing user base, the ActiveMQ server can work in a completely stand-alone state, independent of any container (J2EE or otherwise), or in conjunction with a J2EE server host, such as Geronimo.

When operated within Geronimo, ActiveMQ provides support for MDBs, which are EJBs that consume JMS messages. The asynchronous nature of JMS enables MDBs to be activated on demand by the container to perform work within the J2EE server on behalf of clients. Geronimo benefits greatly from ActiveMQ’s rich client support. Unlike session or entity EJBs, MDBs are not called through rigid EJB interfaces. Instead, a client can invoke MDB services by simply sending a JMS message to a destination. This significantly simplifies the coding of clients that consume EJB-based services. In fact, Geronimo inherits the ability to provide services to non-J2EE clients — those supported by the stand-alone ActiveMQ server.

Back to top

Wrapping the ActiveMQ message broker in a GBean

The ActiveMQ message broker is designed to be embeddable. Geronimo takes advantage of this capability. By providing a GBean container that wraps an embedded message broker, the ActiveMQContainerGBean is created. Other components of the ActiveMQ message broker are also wrapped as GBeans, as you will see shortly. Figure 1 illustrates how the ActiveMQContainerGBean embeds the ActiveMQ message broker.
Figure 1. The ActiveMQContainerGBean
The ActiveMQContainerGBean
By wrapping the ActiveMQ message broker in a GBean, the broker’s life cycle can now be managed through Geronimo. Specifically, you can deploy, start, and manage instances of ActiveMQ message brokers using Geronimo deployer and management tools. The configurable properties of the message broker are exposed as GBean properties. In Figure 1, the ActiveMQContainerGBean wraps the ActiveMQ message broker and provides life cycle management and configuration services. In addition to life cycle and configuration support, Geronimo provides the persistence support for durable messages. The current ActiveMQ server configuration uses the default Derby RDBMS instance to handle persistence.

The default J2EE server assembly supplied by Geronimo has an instance of the ActiveMQ message broker integrated. This assembly starts the message broker when the server is started, typically using the command line:

java -jar binserver.jar

To see how this instance is configured, examine the system-activemq-plan.xml deployment plan in the plan directory of the Geronimo source code distribution. You’ll see how the ActiveMQContainerGBean and other related ActiveMQ components are configured. Listing 1 shows the relevant segment in this deployment plan.
Listing 1. Configuring the ActiveMQContainerGBean in the system-activemq-plan.xml deployment plan

<?xml version="1.0" encoding="UTF-8"?>
<configuration
    xmlns="http://geronimo.apache.org/xml/ns/deployment"
    configId="org/apache/geronimo/ActiveMQServer"
    parentId="org/apache/geronimo/SystemDatabase">
...
<gbean name="ActiveMQ"
  class="org.activemq.gbean.ActiveMQContainerGBean">
  <attribute name="brokerName">possibly-unique-broker</attribute>
  <reference name="persistenceAdapter">
  <gbean-name>geronimo.server:j2eeType=JMSPersistence,name=ActiveMQ.cache,*</gbean-name>
  </reference>
 </gbean>

<gbean name="ActiveMQ.cache"
class="org.activemq.store.cache.SimpleCachePersistenceAdapterGBean">
<attribute name="cacheSize">10000</attribute>
<reference name="longTermPersistence">
<gbean-name>geronimo.server:j2eeType=JMSPersistence,name=ActiveMQ.journal,*</gbean-name>
</reference>
</gbean>

<gbean name="ActiveMQ.jdbc"
class="org.activemq.store.jdbc.JDBCPersistenceAdapterGBean">
  <reference name="dataSource">
<gbean-name>geronimo.server:J2EEApplication=null,J2EEServer=geronimo,
JCAResource=org/apache/geronimo/SystemDatabase,j2eeType=JCAManagedConnectionFactory,
name=SystemDatasource</gbean-name>
</reference>
</gbean>

<gbean name="ActiveMQ.tcp.${PlanServerHostname}.${PlanActiveMQPort}"
  class="org.activemq.gbean.ActiveMQConnectorGBean">
  <attribute name="url">tcp://${PlanServerHostname}:${PlanActiveMQPort}</attribute>
   <reference
    name="activeMQContainer">
<gbean-name>geronimo.server:j2eeType=JMSServer,name=ActiveMQ,*</gbean-name>
</reference>
  </gbean>

<gbean name="ActiveMQ.vm.localhost" class="org.activemq.gbean.ActiveMQConnectorGBean">
  <attribute name="url">vm://localhost</attribute>
  <reference name="activeMQContainer">
  <gbean-name>geronimo.server:j2eeType=JMSServer,name=ActiveMQ,*</gbean-name>
  </reference>
</gbean>

In Listing 1, the first GBean sets up the ActiveMQ message broker. The GBean has an attribute with a reference to a persistence adapter, and points to the second GBean. The second GBean wraps an instance of the ActiveMQ in-memory cache. This second GBean references ActiveMQ’s persistence component for long-term persistence. The third GBean wires a JDBC datasource for the persistence, pointing to the SystemDatasource — a Derby RDBMS instance. The last two GBeans set up the following two transports for accessing the message broker:

  • A TCP transport, by default at the localhost and port 61616
  • An in-VM transport, by default mapped to vm://localhost

If you ever need to change the configuration of this instance, you can modify this system-activemq-plan.xml file and then redeploy the org/apache/geronimo/ActiveMQServer configuration.

Back to top

Accessing the message broker through JCA 1.5 resource adapter

An application component (such as a servlet, JSP, or EJB) utilizing JMS must access the message broker through a library that implements the JMS API. This API is provided by Geronimo. To implement this API in a way that will work with any JMS provider (such as a message broker), Geronimo supports the J2EE Connector (JCA) 1.5 specification. The JCA 1.5 specification details the contracts required between the application server (Geronimo) and the resource adapter (RA) — a driver supplied by ActiveMQ. (See Resources for an article on JCA 1.5.) Managed application components hosted in Geronimo access the ActiveMQ message broker only through this RA. This is another major benefit that ActiveMQ brings to the table — it has a ready-for-integration JCA 1.5-compliant RA implementation. Figure 2 shows the ActiveMQ JCA 1.5-compliant RA.
Figure 2. The ActiveMQ JCA 1.5-compliant RA
The ActiveMQ JCA 1.5 compliant RA
In Figure 2, you can see that the ActiveMQ RA interacts with Geronimo’s security and transaction system through well-defined JCA 1.5 system contracts. The ActiveMQ RA supports both outbound connections (JMS calls out to the message broker), and inbound connections (ActiveMQ-originated calls call into MDBs). For outbound connections, the message-sending application can enroll the JMS provider (ActiveMQ in this case) as a part of a distributed transaction, perhaps involving another resource manager (such as an RDBMS). For inbound connections, typically activating MDBs, the transaction is started by Geronimo. In the current JCA 1.5 specification, and in the Geronimo implementation, inbound connections do not interact with the container’s security subsystem.

The WorkManager contract is part of JCA 1.5. It allows an RA to submit work to the application server for execution. This allows the server — Geronimo — to have control over the thread management and work distribution for a compliant RA. In the case of ActiveMQ, this feature is used to manage threads for the inbound connections. For more information on this feature, read “JCA 1.5, Part 3: Message inflow” (developerWorks, June 2005).

Listing 2 shows a fragment of the system-jms-plan.xml deployment plan. This plan configures the components for an RA instance, as detailed for a deployment descriptor in the JCA 1.5 specification. In the ActiveMQ RA case, these components include an RA implementation class, an outbound connection factory, topics, and queues (administered objects).

The deployment plan in Listing 2 configures the following:

  • An instance of the ActiveMQ RA, to access the ActiveMQ message broker configured in Listing 2, using the TCP protocol for transport
  • A JCA 1.5 WorkManager implementation, supplied by Geronimo, for the ActiveMQ RA instance
  • A JMS connection factory that can be used to create queue connections (through the QueueConnectionFactory interface), or topic connections (through the TopicConnectionFactory interface)
  • An admin object that contains a JMS queue named MDBTransferBeanOutQueue
  • An admin object that contains a JMS queue named SendReceiveQueue

If you need to modify this default configuration of the JMS RA (for example, to add another queue), you’ll need to make the appropriate changes in the system-jms-plan.xml deployment plan. To make any change effective, first undeploy the org/apache/geronimo/SystemJMS configuration, and then redeploy it. For other deployment plans where you can configure instances of ActiveMQ RAs, see the sidebar Deploying ActiveMQ RAs.

Back to top

Application client JMS access

A J2EE application client, supported by Geronimo’s Client Application Container, can have access to the ActiveMQ message broker. Figure 3 shows some client access configurations.

Deploying ActiveMQ RAs
Other than server-start deployment in the system-jms-plan.xml, you can also deploy ActiveMQ RA instances in one of the following ways:

  • Stand-alone, using an ra.xml deployment plan
  • With your Enterprise Application aRchive (EAR), inside a <module> element within the geronimo-application.xml deployment plan
  • With a Web Application aRchive (WAR), inside a <resource> element within the geronimo-web.xml deployment plan

Figure 3. J2EE and non-J2EE client access to message broker
J2EE and non-J2EE client access to message broker
The top configuration in Figure 3 shows a J2EE client application accessing an RA deployed in the client scope. This RA instance is configured to access the message broker located at the server. The second configuration in Figure 3 shows another J2EE client with an RA deployed in the client scope, but accessing a message broker instance deployed also at the client. (This can be useful in disconnected operations — notebook computers that occasionally connect to the enterprise network.) In the third configuration, a non-J2EE client’s access to the ActiveMQ message broker can be direct through any configured transport. The hands-on example demonstrates how to create such a stand-alone, non-J2EE ActiveMQ application client.

Back to top

Creating a JMS application: a servlet producer with native ActiveMQ consumer

This first example shows how a servlet can communicate with an external non-J2EE application through JMS. The example uses the global server-scoped queue called SendReceiveQueue (see Listing 2). It consists of a JMS message sender (producer), and a JMS message receiver (consumer). The producer is a servlet, called SenderServlet, that runs inside Geronimo. The consumer is a stand-alone ActiveMQ client that does not use Geronimo for JMS support. Figure 4 shows the interactions in this example.
Figure 4. SenderServlet with ActiveMQ receiver application
SenderServlet with ActiveMQ receiver application
In Figure 4, the application flow is as follows:

  1. The user accesses the SenderServlet using a Web browser.
  2. The SenderServlet, hosted by Geronimo, presents a data-entry form to the user.
  3. The user enters a text message and clicks Send.
  4. The SenderServlet processes the form submission and uses JMS to send the text message to the SendReceiveQueue.
  5. The stand-alone, non-J2EE ActiveMQ client reads the SendReceiveQueue and displays the received message.

The Web application source code for this example is in the war_only directory of the code download (see the Download section below Resources). The client code is in the mqclient subdirectory.

If you just want to try out the example, you can find the sender.war archive in the war_only/dist subdirectory. Just deploy the following application archive on your Geronimo server:

java -jar bin/deployer.jar sender.war

Use system for the user name and manager for the password when prompted. Follow the instructions in the readme.txt file to build the client. Next, go into the mqclient directory and run the client application using the run.bat file. This will start the client waiting for incoming messages.

Access the data entry servlet through a browser using the URL http://localhost:8080/sender/sendform.cgi.

Enter a text message into the field, and click Send. Notice that the ActiveMQ client receives and prints out the message immediately.

View Listing 3 to see some of the code for SendServlet.java. You can find the complete source in the war_only/src directory.

In Listing 3, the servlet generates the input form on an HTTP GET request and handles form submission on an HTTP POST request. The actual doPost() method extracts the entered message, creates a queue connection, starts a session, and sends the message to the queue.

The servlet init() method looks up the connection factory and queue using Java Naming and Directory Interface (JNDI). Geronimo provides the JNDI mapping service. You can see that the queue is looked up using java:comp/env/dwSendReceiveQueue. This name is mapped in the web.xml deployment descriptor for the Web application. The relevant segment of web.xml is reproduced in Listing 4.
Listing 4. JNDI mapping and resource reference in web.xml

<resource-ref>
  <res-ref-name>DefaultActiveMQConnectionFactory</res-ref-name>
  <res-type>javax.jms.QueueConnectionFactory</res-type>
  <res-auth>Container</res-auth>
</resource-ref>

<message-destination-ref>
  <message-destination-ref-name>dwSendReceiveQueue</message-destination-ref-name>
  <message-destination-type>javax.jms.Queue</message-destination-type>
  <message-destination-usage>Produces</message-destination-usage>
  <message-destination-link>SendReceiveQueue</message-destination-link>
</message-destination-ref>

In Listing 4, the <message-destination-ref> maps the name dwSendReceiveQueue to the system scoped queue through a <message-destination-link> subelement. Unfortunately, the J2EE 1.4 specification does not support a <resource-link> subelement inside a <resource-ref> element in web.xml. As a result, you must use the actual resource name for the connection factory (DefaultActiveMQConnectionFactory), or you will have to create a custom deployment plan (such as geronimo-web.xml) to map the reference.

Coding the ActiveMQ message receiver client

The receiver is a native ActiveMQ client; it does not use any Geronimo client support. It accesses the ActiveMQ message broker hosted in Geronimo using the TCP transport and the URL tcp://localhost:61616. Partial source code to this client, JMSReceiver, is shown in Listing 5. You can see the complete source code in the war_only/clientsrc directory.
Listing 5. JMSReceiver.java — a non-J2EE JMS messages receiver client

package com.ibm.dw.geronimo.jms;

import javax.jms.*;
import org.activemq.ActiveMQConnectionFactory;

public class JMSReceiver {
	protected Queue queue;
	protected String queueName = "SendReceiveQueue";
	protected String url = "tcp://localhost:61616";
	protected int ackMode = Session.AUTO_ACKNOWLEDGE;

	public static void main(String[] args) {
		JMSReceiver msgReceiver = new JMSReceiver();
		msgReceiver.run();
	}

	public void run() {
		try {
			ActiveMQConnectionFactory connectionFactory =
				new ActiveMQConnectionFactory(url);
			QueueConnection connection =
				(QueueConnection)
				connectionFactory.createConnection();
			connection.start();
			MessageConsumer consumer = null;
			Session session = connection.createQueueSession(
					false,
					Session.AUTO_ACKNOWLEDGE);
			queue = session.createQueue(queueName);
			consumer = session.createConsumer(queue);
			System.out.println("Waiting for message (max 5)");
			for (int i = 0; i < 5; i++) {
				Message message = consumer.receive();
				processMessage(message);
			}
			System.out.println("Closing connection");
			consumer.close();
			session.close();
			connection.close();

		} catch (Exception e) {
        ...
		}
	}

	public void processMessage(Message message) {
		try {
			TextMessage txtMsg = (TextMessage) message;
			System.out.println("Received a message: " + txtMsg.getText());
		} catch (Exception e) {
        ...
        }
	}

}

In Listing 5, the JMSReceiver is completely free of J2EE code. There is no need to perform JNDI lookup or destination mapping, because the ActiveMQ native library performs the equivalent actions automatically.

Coding this non-J2EE message consumer is straightforward, using a mix of JMS API and ActiveMQ support library. Coding of a J2EE message consumer, with Geronimo’s support, is also simple. The next example shows the construction of a useful J2EE message consumer: an MDB that adds product categories to the Really Big Pet Store example.

Back to top

Creating an MDB for data update

The second hands-on example shows the construction of an MDB. This example uses the same SendServlet code as in the first example, but the message consumer is now an MDB inside the same enterprise application (bundled in the same EAR). Figure 5 illustrates the operation of this example.
Figure 5. Operation of the MDB example
Operation of the MDB example
The example uses code from the article, “Geronimo! Part 2: Tame this J2EE 1.4 bronco” (developerWorks, May 2005). The article includes more information on the operation of the Really Big Pet Store.

In Figure 5, the operation of the original Web application is left intact. Shoppers use a browser to access the store’s JSP-based user interface. The StoreController servlet fetches the product categories information using the getCats() method of a stateless session EJB called CategoriesBean.

CategoriesBean has been modified to use a new helper class, called CategoryData, to obtain the list of categories.

The MDB is called CategoriesMDB. This EJB is activated when a message is placed into the SendReceiveQueue. CategoriesMDB extracts the message content and uses it to add a product category to CategoryData. Because the session EJB, CategoriesBean, uses CategoryData for every screen update, the new category is visible to the shopper immediately.

In a production environment, the CategoryData helper class can be replaced by an entity bean representing the categories. The use of an entity bean is purposely avoided here to simplify the configuration and setup for this example.

Coding CategoriesMDB

The code for SenderServlet is almost identical to the version in the first example. See ear_ejb/src/SenderServlet.java for complete source.

The code for CategoriesMDB is shown in Listing 6. You can find complete source at ejb/CategoriesMDB.java.
Listing 6. CategoriesMDB — consuming JMS messages and add category

import javax.ejb.*;
import javax.jms.*;
import com.ibm.dw.reallybigpet.ejb.CategoryData;

public class CategoriesMDB
  implements MessageDrivenBean,MessageListener {

private transient MessageDrivenContext mdc = null;
public CategoriesMDB() {
}

public void setMessageDrivenContext(MessageDrivenContext mdc) {
   this.mdc = mdc;
}

public void ejbCreate() {
}

public void onMessage(Message inMessage) {
    TextMessage msg = null;

    try {

        if (inMessage instanceof TextMessage) {
            msg = (TextMessage) inMessage;
         CategoryData.getInstance().addCat(msg.getText());

        }
     } catch (Exception e) {
        e.printStackTrace();
    }
} 

public void ejbRemove() {
}

}
Parent configuration and class loading
Make sure to set the parentId attribute of the application element in geronimo-application.xml to org/apache/geronimo/SystemJMS. This will ensure that you are using the class loader of the JMS RA. If you set your parentId to org/apache/geronimo/System instead, you will encounter class-loading problem similar to java.lang.ClassNotFoundException: org.activemq.ra.ActiveMQActivationSpec. This is the most common mistake you are likely to make when deploying MDB with Geronimo.

The MDB code is simple. The highlighted lines in Listing 7 are where the work is performed. When a JMS message is received at the queue, Geronimo will:

  1. Pick up the message.
  2. Activate an instance of this MDB.
  3. Call the MDB’s onMessage() method, passing the received message as an argument of the method.

You need to configure the MDB with the associated JMS destination (or queue) in the deployment descriptor, ejb-jar.xml. See an example of this in Listing 7.

In Listing 8, the SendReceiveQueue is associated with MDB through an <activation-config> subelement in the <message-driven> element. To select the JMS RA that will be used, create a custom openejb=jar.xml similar to Listing 8.
Listing 8. Custom deployment plan, openejb-jar.xml, to select JMS RA

<?xml version="1.0"?>
<openejb-jar xmlns="http://www.openejb.org/xml/ns/openejb-jar"
configId="catmdb"
parentId="org/apache/geronimo/SystemJMS"
>
<enterprise-beans>
  <message-driven>
        <ejb-name>CatMDB</ejb-name>
        <resource-adapter>
           <resource-link>ActiveMQ RA</resource-link>
         </resource-adapter>
   </message-driven>
</enterprise-beans>
</openejb-jar>

In Listing 8, the default system-scoped RA is selected by name using the <resource-link> element. See the sidebar Parent configuration and class loading for information on the need for a geronimo-application.xml deployment plan.

To try out this example, deploy the reallybigpet.ear application, located in the ear_ejb/dist directory. To access the store, point your browser to http://localhost:8080/ReallyBigPetStore/store.cgi. To access the category add form, point your browser to http://localhost:8080/ReallyBigPetStore/sendform.cgi.

Back to top

Conclusion

ActiveMQ provides quintessential JMS service for Geronimo, while Geronimo provides ActiveMQ with JDBC-based persistence, life cycle management (through JCA 1.5 compliance), security, transaction, and work management. This symbiotic relationship allows Geronimo users to enjoy the best of both worlds: access to standardized J2EE 1.4 JMS and MDB facilities enhanced by ActiveMQ’s rich transports and client support.

Asynchronous calls and remote callbacks using Lingo Spring Remoting

February 25th, 2008

Lingo is the only Spring Remoting implementation that supports asynchronous calls and remote callbacks. Today I’ll cover all the nitty gritty details of the async/callback related functionality along with the limitations and gotchas.Asynchronous method invocation and callback support by Lingo is an awesome feature and there are several usecases where these are an absolute must. Lets consider a simple and rather common use case : You have a server side application (say an optimizer) for which you want you write a remote client API. The API has methods like solve() which are long running and methods like cancel() which stops the optimizer solve.

A synchronous API under such circumstances is not really suitable since the solve() method could take a really long time to complete. It could be implemented by having the client code spawn their own thread and do its own exception management but this becomes really kludgy. Plus you have to worry out network timeout issues. You might be thinking “I’ll just use JMS if I need an asynchronous programming model”. You could use JMS but think about the API you’re exposing. Its going to be a generic JMS API where the client is registering JMS listeners, and sending messages to JMS destinations using the JMS API. Compare this to a remote API where the client is actually working with the Service interface itself.

Lingo combines the elegance of Spring Remoting with the ability to make asynchronous calls. Lets continue with our Optimizer example and implement a solution using Lingo and Spring. OptimizerService interface

public interface OptimizerService {
    void registerCallback(OptimizerCallback callback) throws OptimizerException;

    void solve();

    void cancel() throws OptimizerException;
}

The solve() method is asynchronous while the cancel() and registerCallback(..) methods are not. Asynchronous methods by convention must not have a return value and also must not throw exceptions. The registerCallback(..) method registers a client callback with the Optimizer. In order to make an argument be a remote callback, the argument must implement java.util.EventListener or java.rmi.Remote. In this example the OptimizerCallback interface extends java.util.EventListener. If the argument does not implement either of these interfaces, it must implement java.io.Serializable and it will then be passed by value.

OptimizerCallback interface

public interface OptimizerCallback extends EventListener {

    void setPercentageComplete(int pct);

    void error(OptimizerException ex);

    void solveComplete(float solution);
}

The callback API has a method for the Optimizer to set the percentage complete, report an error during the solve() process (remember that the solve() method is asynchronous so it cannot throw an exception directly) and finally the solveComplete(..) callback to inform the client that the solve is complete along with the solution.

OptimizerService implementation

public class OptimizerServiceImpl implements OptimizerService {

    private OptimizerCallback callback;
    private volatile boolean cancelled = false;

    private static Log LOG = LogFactory.getLog(OptimizerServiceImpl.class);

    public void registerCallback(OptimizerCallback callback) {
        LOG.info(“registerCallback() called …”);
        this.callback = callback;
    }

    public void solve() {
        LOG.info(“solve() called …”);
        float currentSolution = 0;

        //simulate long running solve process
        for (int i = 1; i <= 100; i++) {
            try {
                currentSolution += i;
                Thread.sleep(1000);
                if (callback != null) {
                    callback.setPercentageComplete(i);
                }
                if (cancelled) {
                    break;
                }
            } catch (InterruptedException e) {
                System.err.println(e.getMessage());
            }
        }
        callback.solveComplete(currentSolution);

    }

    public void cancel() throws OptimizerException {
        LOG.info(“cancel() called …”);
        cancelled = true;
    }
}

The solve() method sleeps for a while and makes the call setPercentageComplete(..) on the callback registered by the client. The code is pretty self explanatory here.

Optimizer Application context - optimizerContext.xmlWe now need to export this service using Lingo Spring Remoting. The typical Lingo Spring configuration as described in the Lingo docs and samples is :

<?xml version=“1.0″ encoding=“UTF-8″?>
<!DOCTYPE beans PUBLIC “-//SPRING//DTD BEAN//EN” “http://www.springframework.org/dtd/spring-beans.dtd”>

<beans>
    <bean id=“optimizerServiceImpl” class=“org.sanjiv.lingo.server.OptimizerServiceImpl” singleton=“true”/>

    <bean id=“optimizerServer” class=“org.logicblaze.lingo.jms.JmsServiceExporter” singleton=“true”>
        <property name=“destination” ref=“optimizerDestination”/>
        <property name=“service” ref=“optimizerServiceImpl”/>
        <property name=“serviceInterface” value=“org.sanjiv.lingo.common.OptimizerService”/>
        <property name=“connectionFactory” ref=“jmsFactory”/>
    </bean>

    <!– JMS ConnectionFactory to use –>
    <bean id=“jmsFactory” class=“org.activemq.ActiveMQConnectionFactory”>
        <property name=“brokerURL” value=“tcp://localhost:61616″/>
        <property name=“useEmbeddedBroker”>
            <value>true</value>
        </property>
    </bean>

    <bean id=“optimizerDestination” class=“org.activemq.message.ActiveMQQueue”>
        <constructor-arg index=“0″ value=“optimizerDestinationQ”/>
    </bean>
</beans>

In this example, I’m embedding a JMS broker in the Optimizer process. However you are free to use an external JMS broker and change the JMS Connection Factory configuration appropriately.

Note : The above optimizerContext.xml it the typical configuration in the Lingo docs/examples
but is not the ideal configuration. It has some serious limitations which I'll cover in a bit
along with the preferred  "server" configuration.

OptimizerServer The “main” class that exports the OptimizerService simply needs to instantiate the “optimizerServer” bean in the optimizerContent.xml file.

public class OptimizerServer {

    public static void main(String[] args) {
        if (args.length == 0) {
            System.err.println(“Usage : java org.sanjiv.lingo.server.OptimizerServer <config file>”);
            System.exit(-1);
        }
        String applicationContext = args[0];

        System.out.println(“Starting Optimizer …”);
        FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext(applicationContext);

        ctx.getBean(“optimizerServer”);

        System.out.println(“Optimizer Started.”);

        ctx.registerShutdownHook();
    }
}

The ClientIn order for the client to lookup the remote OptimizerService, we need to configure the client side Spring application context as follows : Client Application Context - clientContext.xml

<?xml version=“1.0″ encoding=“UTF-8″?>
<!DOCTYPE beans PUBLIC “-//SPRING//DTD BEAN//EN” “http://www.springframework.org/dtd/spring-beans.dtd”>

<beans>
    <bean id=“optimizerService” class=“org.logicblaze.lingo.jms.JmsProxyFactoryBean”>
        <property name=“serviceInterface” value=“org.sanjiv.lingo.common.OptimizerService”/>
        <property name=“connectionFactory” ref=“jmsFactory”/>
        <property name=“destination” ref=“optimizerDestination”/>

        <!– enable async one ways on the client –>
        <property name=“remoteInvocationFactory” ref=“invocationFactory”/>
    </bean>

    <!– JMS ConnectionFactory to use –>
    <bean id=“jmsFactory” class=“org.activemq.ActiveMQConnectionFactory”>
        <property name=“brokerURL” value=“tcp://localhost:61616″/>
    </bean>

    <bean id=“optimizerDestination” class=“org.activemq.message.ActiveMQQueue”>