Service-oriented architecture (SOA) and service-oriented programming are terms that refer to a style of software engineering that encapsulates business logic as modular services. These services target dynamic runtime environments in which associations between service providers and service consumers are loosely coupled. Services that are loosely coupled typically have no compile-time associations, so you can link them dynamically at run time, allowing deployment personnel the flexibility to make deployment decisions as needs arise. In addition to loose couplings, the following concepts are common in a service-oriented environment:
- Coarse granularity: Granularity with services refers to the extent of functionality that a service presents publicly. Fine-grained services present public interfaces defining a specialized degree of functionality. Coarse-grained services present a more general degree of functionality, typically to suit a given business domain.
- Location transparency: Location transparency refers to the idea that clients can access services without regard to location on a network.
- Protocol independence: Protocol independence refers to the idea that clients can access services without regard to the communication/network protocol.
Building services with these concepts in mind can be a daunting task. POJO programming seeks to simplify this task.
POJOs are Java classes that are not required to adhere to specific external interfaces or third-party APIs. This ability in itself essentially decouples code from external associations. One of the primary benefits of this decoupling is the freedom it gives software developers from ancillary tasks, such as persistence, transaction support, and remoting. Many techniques eliminate component/class decoupling and facilitate POJO programming, including:
- Annotations are metadata that development tools consume and use to generate code that "decorates" a class or a portion of a class to support a given type of functionality or feature, such as remoting, persistence, and framework support.
- Dependency injection is a technique for building pluggable components whereby object creation and association is removed from the components and carried out by containers or assembler components.
- Reflection is the runtime discovery of information, such as methods, fields, and constructors, about a given class or interface.
Each decoupling technique has its advantages and disadvantages. This article proposes a simple SOA framework through POJO programming that uses reflection and Geronimo's GBean dependency injection to enable component decoupling.
Geronimo is built on a general-purpose kernel that uses Java Management Extensions (JMX) and a dependency injection framework of managed components called GBeans. Virtually everything in Geronimo (adapters, applications, containers, and so on) is either a GBean or is based on a GBean. GBeans share many similarities and underlying infrastructure with JMX and JMX Managed Beans (MBeans).
The JMX specification has emerged as the Java standard for systems management, applications management, and resource management. JMX defines a standard for dynamically augmenting Java classes, interfaces, and runtime objects with attributes and operations to be used for management purposes. This augmentation technique is known as instrumentation.
JMX can manage any resource (such as an application, device, or service) that you can abstract using the Java programming language. Each managed resource is referred to as an MBean. JMX defines four types of MBeans:
- Standard MBeans use Java interfaces to define their management attributes and operations.
- Dynamic MBeans use runtime discovery to define their management attributes and operations.
- Model MBeans act as proxies for objects wanting to expose manageable operations and attributes.
- Open MBeans use a predefined metadata vocabulary to expose the manageable attributes and operations of classes and objects.
The primary interface to interacting with MBeans is the javax.management.MBeanServer. The
MBeanServer acts as a central repository of MBeans and facilitates communication with the
MBeans from MBean clients.
MBeans are uniquely identified by an ObjectName object. An ObjectName
instance consists of:
- A domain, which is an arbitrary name for a given domain; conventions recommend using reverse domain name system (DNS) naming for domains in the same manner as Java package naming.
- A key property list, which is an arbitrary, unordered set of keys and associated values.
The following code demonstrates constructing a typical ObjectName object:
String domain = "com.jeffhanson.test"; |
ObjectName objects are used as parameters to many of the
MBeanServer methods to retrieve attributes and invoke operations on an MBean.
GBeans are managed components in Geronimo that share many similarities and relationships with JMX MBeans, such as
exposing attributes and operations according to a class named GBeanInfo, which is
strikingly similar to the JMX equivalent MBeanInfo class. Geronimo uses the
MX4J library (see Resources at the end of this article for a link) as its implementation of JMX.
GBeans maintain states and association dependencies, and they handle life cycle events. A GBean can register as an interested party in the status of other GBeans. After the GBean of interest is started, the interested GBean will receive a reference to the GBean of interest through dependency injection. A GBean can be in one of these seven life cycle states at any given time:
- Loaded
- Unloaded
- Starting
- Running
- Stopping
- Stopped
- Failed
Listing 1 illustrates a simple GBean containing one attribute (message).
Listing 1. A typical GBean
public class TestGBean
implements GBeanLifecycle
{
private static GBeanInfo GBEAN_INFO = null;
static
{
GBeanInfoBuilder infoFactory =
GBeanInfoBuilder.createStatic(TestGBean.class);
infoFactory.addAttribute("message", String.class, true);
infoFactory.addOperation("getMessage");
GBEAN_INFO = infoFactory.getBeanInfo();
}
private String message;
public String getMessage()
{
return message;
}
...
}
|
You can start (activate) and stop the GBean with the code illustrated in Listing 2.
Listing 2. Starting a typical GBean
ObjectName testGBeanOName =
ObjectName.newInstance("jeffhanson.test:ID=test");
GBeanData gBeanData =
new GBeanData(testGBeanOName, TestBean.GBEAN_INFO);
gBeanData.setAttribute("message", "Hello world");
geronimoKernel.loadGBean(gBeanData,
Thread.currentThread().
getContextClassLoader());
geronimoKernel.startGBean(testGBeanOName);
...
geronimoKernel.stopGBean(testGBeanOName);
geronimoKernel.unloadGBean(testGBeanOName);
|
You can use GBeans extensively throughout the Geronimo kernel.
A Geronimo kernel is a framework of GBeans. Using this framework, you can model and build most any sophisticated system as a set of GBean containers and GBean components to manage state, relationships, and event handling.
Creating a Geronimo kernel programmatically is a simple process using the KernelFactory classes.
Listing 3 demonstrates how to create a new Geronimo kernel named TestGeronimo,
booting the kernel, logging the boot time, and loading and starting a servlet GBean.
Listing 3. Creating a simple Geronimo kernel
try
{
Kernel geronimoKernel =
BasicKernelFactory.newInstance().
createKernel("TestGeronimo");
geronimoKernel.boot();
log.debug("Geronimo BootTime: "
+ geronimoKernel.getBootTime());
// add the servlet GBean
ObjectName servletObjName =
new ObjectName("jeffhanson.test:ID=MyGBean");
GBeanData servletGBeanData = new GBeanData(servletObjName,
GBEAN_INFO);
ClassLoader classLoader = getClass().getClassLoader();
geronimoKernel.loadGBean(servletGBeanData, classLoader);
geronimoKernel.startGBean(servletObjName);
}
catch (Exception e)
{
log.error(e);
}
|
After you create and run the kernel, invoking a method on a POJO service simply becomes an exercise in using the Geronimo kernel server and its reflection capabilities, as shown in Listing 4.
Listing 4. Invoking a call on a service registered with the kernel
private static
Object invokePOJOService(ObjectName serviceObjName,
String operationName,
String[] params)
throws Exception
{
String[] paramTypes = null;
if (params != null && params.length > 0)
{
paramTypes = new String[params.length];
for (int i = 0; i < params.length; i++)
{
paramTypes[i] = params[i].getClass().getName();
}
}
Kernel geronimoKernel =
KernelManager.getInstance().getGeronimoKernel();
Object retVal =
geronimoKernel.invoke(serviceObjName,
operationName,
(Object[])params,
paramTypes);
return retVal;
}
|
An adaptable framework of service-oriented POJOs in Geronimo
The POJO-for-SOA framework referred to in this article uses an instance of the Geronimo kernel to register POJOs as GBeans whereby interested clients can query and invoke them without the need for additional interfaces or APIs. The framework resides in the business tier of a multi-tiered enterprise application environment. A service-locator class is responsible for interacting with the kernel to find and, if needed, register POJOs to be used as services. The service-locator class then returns the POJOs to a business-delegate component where it invokes them. Figure 1 illustrates the relationships of components in the framework.
Figure 1. The POJO-for-SOA framework
The framework is designed to receive HTTP requests from a client, and then pass the request(s) through to a dispatcher component that massages and dispatches the request(s) to the business-delegate component. The business-delegate component then makes use of the service locator to find the service for a particular request. The business delegate component invokes the service and wraps any return value as a model object. The appropriate view component processes the model object and returns it as a formatted response to the client. The sequence diagram in Figure 2 illustrates these steps.
Figure 2. Round-trip sequences of a typical HTTP request and service invocation
The class diagram in Figure 3 illustrates the relationships between the framework's classes.
Figure 3. Relationships between framework classes
Deploying and running the framework
The framework resides in the business tier of an enterprise application system. The framework exposes one servlet that receives HTTP requests and dispatches the content to the framework for processing. The next section explains the simple deployment process.
You can package the classes for the framework and the enterprise application in a .war file and place it within the geronimo_home/deploy directory. If this directory doesn't already exist, create it.
Geronimo deploys the .war file automatically on startup. Applications placed in the deploy directory are hot-loaded, enabling Geronimo to reload the application at run time when you make changes. This makes it convenient for debugging the applications.
You start the Geronimo application server using the startup script (startup.bat or startup.sh) found in the geronimo_home/bin directory. When you invoke the Geronimo startup script, the Geronimo console window becomes visible. After you deploy the framework and the application, Geronimo's console window on startup contains lines similar to those shown in Listing 5, confirming that the Web application has started successfully.
Listing 5. Confirmation the Web application has started successfully
0 [main] DEBUG org.apache.geronimo.kernel.basic.BasicKernel - Starting boot 422 [main] DEBUG org.apache.geronimo.gbean.runtime.GBeanInstanceState - GBeanInstanceState for: :role=Kernel State changed from stopped to starting 422 [main] DEBUG org.apache.geronimo.gbean.runtime.GBeanInstanceState - GBeanInstanceState for: :role=Kernel State changed from starting to running 422 [main] DEBUG org.apache.geronimo.kernel.basic.BasicKernel - Booted 640 [main] DEBUG com.jeffhanson.apptier.FrontController - Geronimo BootTime: Sat May 20 18:51:08 MDT 2006 656 [main] DEBUG org.apache.geronimo.gbean.runtime.GBeanInstanceState - GBeanInstanceState for: jeffhanson.test:ID=FrontController State changed from stopped to starting 656 [main] DEBUG org.apache.geronimo.gbean.runtime.GBeanInstanceState - GBeanInstanceState for: jeffhanson.test:ID=FrontController State changed from starting to running |
Now type the following URL into a Web browser window to instigate the setMessage
operation on the HelloWorld service:
http://<host>:<port>/<context>?Action=
HelloWorld&Operation=setMessage&Params=Hello+everybody!
When the framework processes the request, your console output should be similar to that shown in Listing 6.
Listing 6. Output of
setMessage operation processing719 [main] DEBUG com.jeffhanson.businesstier.ServiceLocator - Adding service [HelloWorld] to kernel... 719 [main] DEBUG com.jeffhanson.businesstier.ServiceLocator - Loading GBean: jeffhanson.test:Name=HelloWorld,Type=GenericService 734 [main] DEBUG org.apache.geronimo.gbean.runtime.GBeanInstanceState - GBeanInstanceState for: jeffhanson.test:Name=HelloWorld,Type=GenericService State changed from stopped to starting 734 [main] DEBUG org.apache.geronimo.gbean.runtime.GBeanInstanceState - GBeanInstanceState for: jeffhanson.test:Name=HelloWorld,Type=GenericService State changed from starting to running |
Type the following URL into a Web browser window to instigate the sayHello operation
on the HelloWorld service:
http://<host>:<port>/<context>?
Action=HelloWorld&Operation=sayHello
When the framework processes the request, your console output should be similar to that shown in Listing 7.
Listing 7. Output of
sayHello operation processing750 [main] DEBUG com.jeffhanson.businesstier.ServiceLocator - serviceObjName: jeffhanson.test:Name=HelloWorld,Type=GenericService 750 [main] DEBUG com.jeffhanson.businesstier.ServiceLocator - Service [HelloWorld] already in kernel 1156 [main] DEBUG com.jeffhanson.businesstier.ServiceLocator - serviceObjName: jeffhanson.test:Name=HelloWorld,Type=GenericService 1156 [main] INFO com.jeffhanson.businesstier.services.HelloWorld - Hello everybody! |
When the servlet engine shuts down the servlet and calls the destroy method on the
servlet, the servlet shuts down the Geronimo kernel. When the servlet engine shuts down the servlet, your
console output should be similar to that shown in Listing 8.
Listing 8. Output following servlet shutdown
1156 [main] DEBUG org.apache.geronimo.kernel.basic.BasicKernel - Starting kernel shutdown 1156 [main] DEBUG org.apache.geronimo.kernel.basic.BasicKernel - Kernel shutdown complete |
The HelloWorld class is a simple POJO with a setMessage method,
a getMessage method, and a sayHelloWorld message. After you
register an instance of this class with the Geronimo kernel, you can invoke the instance dynamically and associate
it with other services and components at run time using dependency injection. The code in Listing 9 illustrates the simple HelloWorld POJO class.
Listing 9. A simple HelloWorld service
package com.jeffhanson.businesstier.services;
import org.apache.log4j.Logger;
public class HelloWorld
{
private static Logger log = Logger.getLogger(HelloWorld.class);
private String message = "Hello world";
public void setMessage(String message)
{
if (message == null || message.length() <= 0)
{
throw new RuntimeException("HelloWorld.setMessage "
+ "param is not set");
}
this.message = message;
}
public String getMessage()
{
return message;
}
public void sayHello()
{
log.info(message);
}
}
|
Designing a nimble and effective SOA that can respond to business domain changes and events in a timely manner is a complex task. However, an SOA built around a properly designed POJO layer can help simplify this task. The Geronimo platform provides frameworks and tools that you can use to build a flexible, scalable, and maintainable SOA using POJOs.
| Description | Name | Size | Download method |
|---|---|---|---|
| SOA with POJOs framework | GeronimoSOAwithPOJOs.zip | 14KB | HTTP |
Information about download methods
Learn
- Get clear definitions and explanations of the fundamentals of POJO programming.
- Use these resources for
SOA and dependency injection.
- Find information about MX4J.
- Get more insight into JMX.
- Get resources for Java Reflection.
- Check out the developerWorks Apache Geronimo project area for articles, tutorials, and other resources to help you get started developing with Geronimo today.
- Find helpful resources for beginners and experienced users at the Get started now with Apache Geronimo section of developerWorks.
- Check out the IBM® Support for Apache Geronimo offering, which lets you develop Geronimo applications backed by world-class IBM support.
- Visit the developerWorks Open source zone for extensive how-to information, tools, and project updates to help you develop with open source technologies and use them with IBM's products.
- Browse all the Apache articles and free Apache tutorials available in the developerWorks Open source zone.
- Browse for books on these and other technical topics at the Safari bookstore.
Get products and technologies
- Download Apache Geronimo, Version 1.0.
- Innovate your next open source development project with IBM trial software, available for download or on DVD.
- Download your free copy of IBM WebSphere® Application Server Community Edition V1.0 -- a lightweight J2EE application server built on Apache Geronimo open source technology that is designed to help you accelerate your development and deployment efforts.
Discuss
- Participate in the discussion forum.
- Get involved in the developerWorks community by participating in developerWorks blogs.

Jeff Hanson has more than 20 years of experience in the software industry, including work as senior engineer for the Windows OpenDoc project and lead architect for the Route 66 framework at Novell. Jeff is currently the chief architect for eReinsure.com, Inc. and builds Web service frameworks and platforms for Java EE-based reinsurance systems. Jeff is the author of numerous articles and books, including .NET versus J2EE Web Services: A Comparison of Approaches, Pro JMX: Java Management Extensions, and Web Services Business Strategies and Architectures.
Comments (Undergoing maintenance)





