Geronimo Architecture: Part 1

Exclusive offer: get 50% off this eBook here
Apache Geronimo 2.1: Quick Reference

Apache Geronimo 2.1: Quick Reference — Save 50%

Develop Java EE 5 applications on Geronimo quickly and easily

$29.99    $15.00
by Vamsavardhana Reddy Chillakuru | November 2009 | Java Open Source

This article by Vamsavardhana Reddy Chillakuru expands on the Apache Geronimo architecture. We will first see the concept of Inversion of Control (IoC) and dependency injection, which are two of the core concepts around which the current architecture is developed. We will then give a high-level overview of the internal architecture of Apache Geronimo and go through each component that makes up the architecture. Therefore, we will be covering GBeans, configurations, the kernel interface, repository, attribute store, dependencies, class loaders, deployment, plugins, and the concept of custom server assemblies. We will be covering these topics in detail so that you are able to understand the big picture. It will also help you if you want to contribute to Apache Geronimo or develop new services to run on Apache Geronimo. We will also list the different modules by their configuration IDs and map them to their functionality.

In this article, you will learn about:

  • How Inversion of Control and dependency injection work
  • GBeans—the building blocks of Geronimo
  • Configuration—a collection of GBeans deployed together
  • High-level architecture of Geronimo
  • Class loader architecture
  • Geronimo server directory structure
  • Deployment architecture
  • Plugins

Inversion of Control and dependency injection

Inversion of Control (IoC) is a design pattern used in software engineering that facilitates the creation of loosely-coupled systems. In an IoC system, the flow of control is inverted, that is, the program is called by the framework—unlike in normal linear systems where the program calls the libraries. This allows us to circumvent the tight coupling that arises from the control being with the calling program. Dependency injection is a specific case of IoC where the framework provides an assembler or a configurator that provides the user program with the objects that it needs through injection. The user program declares dependencies on other services (provided by the framework or other user programs), and the assembler injects the dependencies into the user program wherever they are needed.

It is important that you clearly understand the concept of dependency injection before we proceed further into the Geronimo architecture, as that is the core concept behind the functioning of the Geronimo kernel and how services are loosely coupled in it. To help you understand the concept more clearly, we will provide a simple example.

Consider the following two classes:

package packtsamples;
public class RentCalculator{
private float rentRate;
private TaxCalculator tCalc;
public RentCalculator(float rate, float taxRate){
rentRate = rate;
tCalc = new ServiceTaxCalculator(taxRate);
}
public void calculateRent(int noOfDays){
float totalRent = noOfDays * rentRate;
float tax = tCalc.calculateTax(totalRent);
totalRent = totalRent + tax;
System.out.println("Rent is:"+totalRent);
}
}
package packtsamples;
public class ServiceTaxCalculator implements TaxCalculator{
private float taxRate;
public ServiceTaxCalculator(float rate){
taxRate = rate;
}
public float calculateTax(float amount){
return (amount * taxRate/100);
}
}
package packtsamples;
public interface TaxCalculator{
public float calculateTax(float amount);
}
package packtsamples;
public class Main {
/**
* @param args. args[0] = taxRate, args[1] = rentRate, args[2] =
noOfDays
*/
public static void main(String[] args) {
RentCalculator rc = new RentCalculator(Float.parseFloat(args[1]),
Float.parseFloat(args[0]));
rc.calculateRent(Integer.parseInt(args[2]));
}
}

The RentCalculator class calculates the room rent including tax, given the rent rate, and the number of days. The TaxCalculator class calculates the tax on a particular amount, given the tax rate. As you can see from the code snippet given, the RentCalculator class is dependent on the TaxCalculator interface for calculating the tax. In the given sample, the ServiceTaxCalculator class is instantiated inside the RentCalculator class. This makes the two classes tightly coupled, so that we cannot use the RentCalculator with another TaxCalculator implementation. This problem can be solved through dependency injection. If we apply this concept to the previous classes, then the architecture will be slightly different. This is shown in the following code block:>

package packtsamples.di;
public class RentCalculator{
private float rentRate;
private TaxCalculator tCalc;
public RentCalculator(float rate, TaxCalculator tCalc){
rentRate = rate;
this.tCalc = tCalc;
}
public void calculateRent(int noOfDays){
float totalRent = noOfDays * rentRate;
float tax = tCalc.calculateTax(totalRent);
totalRent = totalRent + tax;
System.out.println("Rent is:" +totalRent);
}
}
package packtsamples.di;
public class ServiceTaxCalculator implements TaxCalculator{
private float taxRate;
public ServiceTaxCalculator(float rate){
taxRate = rate;
}
public float calculateTax(float amount){
return (amount * taxRate/100);
}
}
package packtsamples.di;
public interface TaxCalculator{
public float calculateTax(float amount);
}

Notice the difference here from the previous implementation. The RentCalculator class has a TaxCalculator argument in its constructor. The RentCalculator then uses this TaxCalculator instance to calculate tax by calling the calculateTax method. You can pass in any implementation, and its calculateTax method will be called. In the following section, we will see how to write the class that will assemble this sample into a working program.

package packtsamples.di;
import java.lang.reflect.InvocationTargetException;
public class Assembler {
private TaxCalculator createTaxCalculator(String
className, float taxRate){
TaxCalculator tc = null;
try {
Class cls = Class.forName(className);
tc = (TaxCalculator)cls.getConstructors()[0]
.newInstance(taxRate);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return tc;
}
private RentCalculator createRentCalculator(float rate,
TaxCalculator tCalc){
return new RentCalculator(rate,tCalc);
}
private void assembleAndExecute(String className,
float taxRate, float rentRate, int noOfDays){
TaxCalculator tc = createTaxCalculator(className, taxRate);
createRentCalculator(rentRate, tc).calculateRent(noOfDays);}
/**
*
* @param args args[0] = className, args[1] = taxRate args[2] =
rentRate args[3] = noOfDays
*/
public static void main(String[] args){
new Assembler().assembleAndExecute(args[0],
Float.parseFloat(args[1]),
Float.parseFloat(args[2]),
Integer.parseInt(args[3]));
}
}

In the given sample code, you can see that there is a new class called the Assembler. The Assembler, in its main method, invokes the implementation class of TaxCalculator that we want RentCalculator to use. The Assembler then instantiates an instance of RentCalculator, injects the TaxCalculator instance of the type we specify into it, and calls the calculateRent method. Thus the two classes are not tightly coupled and the program control lies with the assembler, unlike in the previous case. Thus there is Inversion of Control happening here, as the framework (Assembler in this case) is controlling the execution of the program. This is a very trivial sample. We can write an assembler class that is more generic and is not even coupled to the interface as in the previous case. This is an example of dependency injection. An injection of this type is called constructor injection, where the assembler injects values through the constructor. You can also have other types of dependency injection, namely setter injection and field injection. In the former, the values are injected into the object by invoking the setter methods that are provided by the class, and in the latter, the values are injected into fields through reflection or some other method. The Apache Geronimo kernel uses both setter injection and constructor injection for resolving dependencies between the different modules or configurations that are deployed in it.

The code for these examples is provided under di-sample in the samples. To build the sample, use the following command:

mvn clean install

To run the sample without dependency injection, use the following command:

java –cp di-sample-1.0.jar packtsamples.Main <taxRate> <rentRate>
<noOfDays>

To run the sample with dependency injection, use the following command:

java –cp di-sample-1.0.jar packtsamples.Assembler packtsamples.
di.ServiceTaxCalculator <taxRate> <rentRate> <noOfDays>

GBeans

A GBean is the basic unit in Apache Geronimo. It is a wrapper that is used to wrap or implement different services that are deployed in the kernel. GBeans are similar to MBeans from JMX. A GBean has attributes that store its state and references to other GBeans, and can also register dependencies on other GBeans. GBeans also have lifecycle callback methods and metadata. The Geronimo architects decided to invent the concept of GBeans instead of using MBeans in order to keep the Geronimo architecture independent from JMX. This ensured that they did not need to push in all of the functionality required for the IoC container (that forms Geronimo kernel) into the JMX implementation. Even though GBeans are built on top of MBeans, they can be moved to some other framework as well. A user who is writing a GBean has to follow certain conventions. A sample GBean is shown below:

import org.apache.geronimo.gbean.GBeanInfo;
import org.apache.geronimo.gbean.GBeanInfoBuilder;
import org.apache.geronimo.gbean.GBeanLifecycle;
public class TestGBean implements GBeanLifecycle{
private String name;
public TestGBean(String name){
this.name = name;
}
public void doFail() {
System.out.println("Failed.............");
}
public void doStart() throws Exception {
System.out.println("Started............"+name);
}
public void doStop() throws Exception {
System.out.println("Stopped............"+name);
}
public static final GBeanInfo GBEAN_INFO;
static {
GBeanInfoBuilder infoBuilder = GBeanInfoBuilder
.createStatic(TestGBean
.class, "TestGBean");
infoBuilder.setPriority(2);
infoBuilder.addAttribute("name", String.class, true);
infoBuilder.setConstructor(new String[]{"name"});
GBEAN_INFO = infoBuilder.getGBeanInfo();
}
public static GBeanInfo getGBeanInfo() {
return GBEAN_INFO;
}
}

You will notice certain characteristics that this GBean has from the previous section. We will list these characteristics as follows:

  • All GBeans should have a static getGBeanInfo method, which returns aGBeanInfo object that describes the attributes and references of GBean as well as the interfaces it can implement.
  • All GBeans will have a static block where a GBeanInfoBuilder object is created and linked to that GBean. All of the metadata that is associated with this GBean is then added to the GBeanInfoBuilder object. The metadata includes descriptions of the attributes, references, interfaces, and constructors of GBean.

We can add GBeans to configurations either programmatically, using methods exposed through the configuration manager and kernel, or by making an entry in the plan for the GBean, as follows:

<gbean name="TestGBean" class="TestGBean">
<attribute name="name">Nitya</attribute>
</gbean>

We need to specify the attribute values in the plan, and the kernel will inject those values into the GBean at runtime. There are three attributes for which we need not specify values. These are called the magic attributes, and the kernel will automatically inject these values when the GBeans are being started. These attributes are abstractName, kernel, and classLoader. As there is no way to specify the values of these attributes in the deployment plan (an XML file in which we provide Geronimo specific information while deploying a configuration), we need not specify them there. However, we should declare these attributes in the GBeanInfo and in the constructor. If the abstractName attribute is declared, then the Geronimo kernel will inject the abstractName of the GBean into it. If it is the kernel attribute, then a reference to the kernel that loaded this GBean is injected. If we declare classLoader, then the class loader for that configuration is injected.

Apache Geronimo 2.1: Quick Reference Develop Java EE 5 applications on Geronimo quickly and easily
Published: November 2009
eBook Price: $29.99
Book Price: $49.99
See more
Select your format and quantity:

Configurations

A group of GBeans that provide a certain service is called a configuration. A configuration has a name, can declare dependencies on other configurations, and is the basic deployable unit in Apache Geronimo. The GBeans that you write can only be deployed in Geronimo as part of a configuration. When you deploy a new service or an enterprise application in Apache Geronimo, the configuration details that you provide by means of a deployment plan are parsed and a configuration is created. Internally, a configuration is another GBean that actually groups a number of GBeans within it. A configuration contains the following persistable attributes:

  • Its configurationData

    The configurationData represents all of the information that is stored in this configuration. Among the information that it contains is the classpath of this configuration (a list of URLs to locations where the classes representing this configuration are located), its configurationId (a unique ID for identifying this configuration to the kernel), the namespace of this configuration, and a byte array representing the state of all of the GBeans in this configuration

  • The list of its parents

    This is the list of parent configurations for this configuration. A configuration can have multiple parents, and each parent can in turn have multiple parents, and so on.

  • A reference to a ManageableAttributeStore

    A manageable GBean attribute is one that can be changed at runtime by an administrator in order to change the behavior of the service that is wrapped by the GBean. For example, if we have a simple HttpServer service that is managed by a GBean, then one possible manageable attribute is the port on which the server will be listening. The ManageableAttributeStore is a repository where the manageable attributes are stored so that they are more easily accessible to the end user when compared to serialized configurations. Changes to the manageable attributes of the GBeans are made to the store and is persisted in the config.xml file present in the &ltGERONIMO_HOME>/var/config directory. There is also a config-substitutions.properties file for values of variables in the config.xml file. Each configuration is given a unique name. The name of a configuration as it is specified in the deployment plan of that module is, as follows:

<moduleId>
<groupId>org.apache.geronimo.configs</groupId>
<artifactId>openejb</artifactId>
<version>2.1.4</version>
<type>car</type>
</moduleId>

The name of the configuration is in the format <groupId>/<artifactId>/<version>/<type>

  • groupId: The groupId identifies a group of related modules. If no group ID is specified for a module or an application, then its groupId is taken as default. If no group ID is specified for a dependency entry, then it is taken as a wildcard and instances of groupId are not used in the search.
  • artifactId: The artifactId identifies the artifact within the group. It should be unique within the group. If the artifactId is not specified, then it will be defaulted to the name of the module file.
  • version: The version is the version of that artifact. It can take the form 1.x.x. If it is not specified, then the version is taken as the timestamp at the time of deploying the configuration
  • type: This represents the type of the artifact. It can be car for system services and jar,, ear, war, and so on for other modules.

Dependencies

A module or configuration can have dependencies on other modules. You can specify the dependencies on other modules through the dependency tag, as shown below:

<dependencies>
<dependency>
<groupId>org.apache.geronimo.configs</groupId>
<artifactId>j2ee-server</artifactId>
<version>2.1.4</version>
<type>car</type>
</dependency>
<dependency>
<groupId>org.apache.geronimo.framework</groupId>
<artifactId>geronimo-kernel</artifactId>
<version>2.1.4</version>
<type>jar</type>
</dependency>
</dependencies>

Most commonly, users will need to give dependencies on other configurations, services, or libraries. There is a difference in the way in which these dependencies are handled by the Geronimo kernel. In the case of a dependency on a configuration, all of the services of that configuration as well as the classes, are available to the current configuration. A configuration, specified as a dependency becomes a parent of the current configuration. Its class loader becomes the parent of the current configuration's class loader. If the dependency is on a jar type artifact, which is not a configuration, the classes of that jar type artifact are added to the classpath of the current configuration.

High-level architecture

Apache Geronimo consists of a lightweight kernel that provides services such as Lifecycle Management, Dependency Management, Repository, and Configuration Management to the other services that are deployed on it. As we already know, the basic manageable unit in Apache Geronimo is the GBean. GBean is a manageable wrapper object with attributes, references, and lifecycle callback methods. It also has a static GBEAN_INFO attribute, which is, a description used by the kernel to instantiate, manage, and modify the GBean state.

The following diagram shows the Apache Geronimo kernel and all of the services that it provides, as well as the other services that are layered on top of the basic kernel services:

Apache Geronimo 2.1: Quick Reference

This architecture is the key for Geronimo's extensibility. It adds new services or plugins as services deployed on the server, which are in the form of GBeans whose state, dependencies, and lifecycle are managed by the kernel. A GBean may have a reference to another GBean, and the kernel makes sure that the GBean has access to a properly initialized and started instance of that GBean. The Configuration Manager is a component in the Apache Geronimo kernel that takes care of starting the configurations in the requisite order and also of providing the plumbing required to connect related and dependent configurations together so that they can consume the services of other configurations

The Apache Geronimo kernel also provides the Repository and configuration store that contains configurations of the existing modules as well as the required libraries. Any new module that you add will also be added to the Repository. If it is a configuration archive, then it will be added to the configuration store as well.

By the Geronimo kernel, we mean the core of Geronimo that providesthe services shown in the previous diagram. We will also be referring to the org.apache.geronimo.kernel.Kernel interface. This is the core interface whose implementations will actually manage GBeans. Whenever we refer to the Kernel implementation, we mean implementations of this interface. We will be referring to both of these, and you should keep in mind the subtle difference between them.

We will now see each of the services that the kernel provides, in detail:

  • Repository

    The repository is the place where Apache Geronimo stores the majority of the artifacts that it contains. The repository consists of two types of artifacts:

    • Libraries: The libraries are utilized by Apache Geronimo as well as the applications that are deployed on it. The libraries are usually JAR files that contain a number of classes. The libraries may be standalone or be included in a configuration. An example of a commonly-used library is log4j for logging. The log4j library will be present in the repository in the directory &ltGERONIMO_HOME>/repository/log4j/log4j/1.2.14/log4j-1.2.14.jar.
    • Configurations: These are the configurations that are deployed in Apache Geronimo. A configuration represents a set of services that can be loaded and brought online by the Geronimo kernel. Once you deploy a module, the configuration information is serialized to the disk in a subdirectory of &ltGERONIMO_HOME>/repository, along with the libraries that provide the functionality of that module. The serialized configuration information generally consists of the information in the deployment plan as well as the values for different GBean attributes, and queries for different GBean references. It is stored in the META-INF directory directly inside the root directory of the configuration. The path of the root directory of the configuration will consist of the group ID of the configuration, with dots replaced by slashes. A configuration will always have a directory name ending with .car. For example, the openEJB configuration will be present in the repository in the <GERONIMO_HOME>/repository/org/apache/geronimo/configs/openejb/2.1.4/openejb-2.1.4.car directory as its artifactId is org.apache.geronimo.configs/openejb/2.1.4/car.
  • Configuration Management

    The kernel manages all of these tasks, from creating new configurations to linking them to their parents and children, serializing them to disk, reading them back, as well as managing the attributes of the GBeans. There is a configuration manager GBean which manages these tasks. An additional task that the kernel performs is to make MBean wrappers for the GBeans so that they can be managed remotely over JMX.

  • Lifecycle Management

    This is another service that is provided by the kernel. This actually includes providing lifecycle management to all of the services that are deployed in Apache Geronimo. The Kernel implementation provides Lifecycle Management through GBeans. The Kernel implementation is actually aware of GBeans only, and it can Start, Stop, Load, and Unload GBeans. GBeans thatimplement the org.apache.geronimo.gbean.GBeanLifecycle interface will provide implementations of callback methods that will be called by the Kernel after starting (doStart), before stopping (doStop), and in case of failure (doFail). The kernel internally has a LifecycleMonitor that will be sent notifications whenever a GBean is loaded, starting, running, stopping, stopped, failed, or unloaded. The notifications are sent by a LifecycleBroadcaster. The LifecycleMonitor will have a number of instances of LifecycleListener that are registered with it, and they are configured to perform tasks corresponding to the state notifications that they receive.

  • Dependency Management

    Finally, the Apache Geronimo Kernel provides Dependency Management—that is, the management of dependencies for the services deployed in the server. The dependencies for a configuration or module are specified in the deployment plan for that module. So the kernel provides the plumbing that will link a configuration together with all of its dependencies. Dependency Management also includes making sure that all of the services that a configuration depends on are started before the configuration is started. Again at the Kernel implementation level the dependencies are between GBeans, and the Kernel manages starting all of the dependencies of a GBean before it is started, as well as making them available to the GBean at runtime.

>> Continue Reading Geronimo Architecture: Part 2

 

[ 1 | 2 ]
If you have read this article you may be interested to view :
Apache Geronimo 2.1: Quick Reference Develop Java EE 5 applications on Geronimo quickly and easily
Published: November 2009
eBook Price: $29.99
Book Price: $49.99
See more
Select your format and quantity:

About the Author :


Vamsavardhana Reddy Chillakuru

Vamsavardhana Reddy Chillakuru, a.k.a., Vamsi is an Advisory Software Engineer working with IBM India Private Limited since 1996 and is part of the IBM worldwide Level 3 support team for Apache Geronimo and IBM Application Server Community Edition. He is proficient in Java and Java EE technologies with more than 10 years experience with Java EE application development. His interests include application security in general and cryptographic security in particular. He has presented sessions on Apache Geronimo at Apache conferences on various topics ranging from security to server administration. He has authored many articles in IBM developerWorks and also co-authored an IBM Redbook on Migration to WebSphere Application Server. Considered as a security expert in the Geronimo community, he is actively involved in adding new security features to Geronimo. He is responsible for adding a Certification Authority portlet to Geronimo Admin Console. Associated with Apache Geronimo project since July 2005, he is a committer on Apache Geronimo and Apache Tuscany projects and a member of the Apache Geronimo PMC. He is involved in the standards development for Service Component Architecture (SCA) and is a member of OASIS (Organization for the Advancement of Structured Information Standards) SCA-Assembly, SCA-Java and SCA-Policy Technical Committees and SCA-J Java EE Subcommittee. He received his B.Stat. (Hons.) and M.Stat. degrees from the Indian Statistical Institute, Kolkata, India in the years 1994 and 1996 respectively.

Books From Packt


jQuery UI 1.7: The User Interface Library for jQuery
jQuery UI 1.7: The User Interface Library for jQuery

Matplotlib for Python Developers
Matplotlib for Python Developers

Linux Email
Linux Email

Moodle 1.9 Math
Moodle 1.9 Math

ICEfaces 1.8: Next Generation Enterprise Web Development
ICEfaces 1.8: Next Generation Enterprise Web Development

Pentaho Reporting 3.5 for Java Developers
Pentaho Reporting 3.5 for Java Developers

Tomcat 6 Developer's Guide
    Tomcat 6 Developer's Guide

RESTful Java Web Services
RESTful Java Web Services


No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
N
8
A
c
w
Z
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software