JavaBeat

  • Home
  • Java
    • Java 7
    • Java 8
    • Java EE
    • Servlets
  • Spring Framework
    • Spring Tutorials
    • Spring 4 Tutorials
    • Spring Boot
  • JSF Tutorials
  • Most Popular
    • Binary Search Tree Traversal
    • Spring Batch Tutorial
    • AngularJS + Spring MVC
    • Spring Data JPA Tutorial
    • Packaging and Deploying Node.js
  • About Us
    • Join Us (JBC)
  • Privacy
  • Contact Us

How To Add Environment Entries (JNDI) to Tomcat Web Server

March 2, 2016 by Krishna Srinivasan Leave a Comment

Have you tried configuring the JNDI variables with Tomcat server?. This tutorial is going to explain you step-by-step procedure on how to configure JNDI variables in your tomcat server. It is very simple configuration in the Tomcat server’s configuration XML file.

Tomcat JNDI Configuration
Tomcat JNDI Configuration
  1. Open the Tomcat server’s context.xml file. The same change can be done using the server.xml file by adding the configurations inside context element.
  2. The root element for the context.xml file will be context. You have to add all the environment entries inside this root element. If you want to add a new JNDI environment entry, please add the new element as below.

[code lang=”xml”]
<Environment name="envEntryName" value="envEntryValue" type="java.lang.String" override="false" description="Describe about this variable"/>
[/code]

Here is the explanation for the attributes used for the Environment element:

  • description: It is a human readable description for this variable. This is an optional parameter.
  • name : This is the name of the environment entry. This entry is relative to the java:comp/env context.
  • value : This is the value of the parameter returned to the application when accessed from the JNDI context. This value must be convertible to the Java type defined by the type attribute.
  • type : It is fully qualified Java class name expected by the Java web application from this environment entry. This must be a legal value for the in the web.xml.
  • override : Set this value as false if you don’t want to add env-entry for this entry in the web application deployment descriptor. By default, overrides are allowed.

The above sample example snippet is equivalent of writing the following entries in your web deployment descriptor web.xml:

[code lang=”xml”]
<env-entry>
<env-entry-name>envEntryName</env-entry-name>
<env-entry-value>envEntryValue</env-entry-value>
<env-entry-type>java.lang.String</env-entry-type>
</env-entry>
[/code]

The above entries can be accessed in your Java program as below:

[code lang=”java”]
InitialContext initialContext = new javax.naming.InitialContext();
String debug = (String) initialContext.lookup("java:comp/env/envEntryName");
[/code]

If the JNDI entry is not found, then the above code would throw the javax.naming.NameNotFoundException.

Filed Under: Servers Tagged With: Apache Tomcat

WildFly 8 Final is released!

March 13, 2014 by Krishna Srinivasan Leave a Comment

WildFly 8 Application server (formerly known as JBoss Application Server) is available for the general use. JBoss blog has announced this new on Feb 11, 2014. Jason Greene, who is the lead for this project updates the features on this new release and providing the road map for the future releases. One of the key feature in the WildFly is the support for Java EE 7 specification which is the latest Java EE release. Here I summarize the list of features added as part of this release.

wildflynewimproved

  • Java EE 7 Support: With this latest support, all the great technologies supported by Java EE 7 is now available with the WildFly 8. Some of the notable features in the Java EE 7 is batch processing, web socket as part of servlet 3.0 , Concurrency, JMS and improvements in the Dependency Injection (DI). And lot many other infrastructure improvements.
  • Default Web Server Undertow: With this release, WildFly replaces the default web server Tomcat and comes up with its own web server Undertow which is scheduled to release it’s 1.0 version. Currently its in 1.0.0 beta. As noted by them, this web server improves the performance and have great features like the asynchronous procession which is supported in the latest web technologies specification.
  • Reduction in Port Usage: With the help of HTTP upgrade, WildFly could effectively reduce the port to two. It has only management port (9990) and application port (8080). This could be more effective for the cloud providers like OpenShift.
  • Java 8 Support: This release has improved the compatibility with the Java 8 features. If any one wants to use the Java 8 with their project, WildFly 8 will work without any problem. Further releases are planned to update the latest features on Java 8 technology.
  • Other Features: There are many other notable features are added as part of this release. Here I am listing summary of the list.
    • Improvement on Web Services for Apache CXF bus instances, WS-Policy code-first improvements, etc.
    • WildFly 8 includes RESTEasy 3 which supports the standard Java EE REST APIs (JAX-RS 2.0).
    • Hibernate Search is now offered out of the box in WildFly
    • Technologies which are removed from the Java EE 7 also discarded in the release are : CMP, JAX-RPC and JSR 88
    • CDI integration and performance improvements

Here we will update the latest news on WildFly 8 server!. You can download the server here.

Filed Under: Servers Tagged With: WildFly, WildFly 8

Apache Tomcat 8 Features

January 22, 2014 by Krishna Srinivasan Leave a Comment

If you are a Java web developer, it is most likely that you are aware of the popularity of Tomcat web server. Tomcat is the Reference Implementation (RI) for the JSP and Servlets specification from the beginning. Not only that, many of the application servers internally using the Tomcat as their web server since it already provides the best implementation. The last stable release is Tomcat 7.0. At present Tomcat 8.0 is in the development release and it is expected to be made available for the production use anytime soon. This new version supports many of the new Java EE specifications out of the box. This tutorial highlights the main features in this release.

Tomcat 8.0 release aligns with the Java EE 7 Specification

  • It supports Java Servlet 3.1
  • Java Server Pages (JSP) 2.3
  • Java Unified Expression Language (EL) 3.0
  • Java WebSocket 1.0

Also look at the previous releases and what it supports:

  • Tomcat 7: Servlet 3.0, JSP 2.2, and EL 2.2.
  • Tomcat 6: Servlet 2.5, JSP 2.1, and EL 2.1.

The below table summarizes the over all detail and support for each release.

Servlet Spec JSP Spec EL Spec WebSocket Spec Apache Tomcat version Actual release revision Minimum Java Version
3.1 2.3 3.0 1.0 8.0.x 8.0.0-RC10 (alpha) 1.7
3.0 2.2 2.2 1.0 7.0.x 7.0.50 1.6 (WebSocket 1.0 requires 1.7)
2.5 2.1 2.1 N/A 6.0.x 6.0.37 1.5
2.4 2.0 N/A N/A 5.5.x (archived) 5.5.36 (archived) 1.4
2.3 1.2 N/A N/A 4.1.x (archived) 4.1.40 (archived) 1.3
2.2 1.1 N/A N/A 3.3.x (archived) 3.3.2 (archived) 1.1

Filed Under: Servers Tagged With: Apache Tomcat, Tomcat 8.0

How to Install Tomcat in Ubuntu?

August 3, 2013 by Krishna Srinivasan Leave a Comment

Linux is good environment for running the Java applications. Most of the developers not trying the Linux environment only because of the complicated installation procedures needed for at the time of beginning. Once if you are familiar with the installation then it is cake walk for developing the Java applications. But, I can not say that it is always better than Windows environment, it depends on the developers knowledge level to adopt the Linux environment. Generally advanced technical users would like to work on these environment.

This article provides very basic information on installing Tomcat server in Ubuntu environment. I have tried this example in Ubuntu 12.0 environment. If you face any problems during the installation, please write it in the comments section. If you are interested in receiving the future articles, please subscribe here. follow us on @twitter and @facebook

ubuntu

Tomcat Installation in Ubuntu

This steps explains how to manually install the tomcat in your Ubuntu. As a first step download Tomcat from http://tomcat.apache.org/. Unzip the tar file using the command

[java]
tar -zxvf apache-tomcat-6.0.16.tar.gz
[/java]

apache-1
apache-2Once unzip is completed, it is very simple to run the tomcat server. There is no other configurations are required.
[java]
apache-tomcat-6.0.16/bin$ sh startup.sh
apache-tomcat-6.0.16/bin$ sh shutdown.sh
[/java]

apache-3
I have uploaded the screen-shots of each stem in detail, that would help you. If you have better suggestion for installing it, please post it in the comments section.

If you are interested in receiving the future articles, please subscribe here. follow us on @twitter and @facebook

Filed Under: Servers Tagged With: Tomcat, Ubuntu

Oracle Weblogic 10.3.2 Campaign

April 17, 2011 by Krishna Srinivasan Leave a Comment

Introduction

This post is to present the steps for creating a Campaign in Weblogic Portal that illustrates some vague points about it.

The campaign target is to show an advertisement in a placeholder, within some interval (start & end dates), with some goals to be reached before the end date of the campaign.

also read:

  • WebLogic Interview Questions
  • JBoss Portal Server Development
  • Tomcat Interview Questions

Campaign Goals

Campaign goals are set against content clicks or impressions (views) count. This count can be calculated based on the clicks/views of the specific content that is displayed in the campaign, or if the content is viewed/clicked outside the campaign. Also, the count is checked for each content count or the summation of the contents’ count in the goal.

Example Scenario

For example, a campaign is to show some advertisements on the ads area of the portal, on IPhone should display 5 different contents. Each content is displayed in its place based on the queries defined in the placeholders in the portal, content selectors or Content Presenter Portlet. The goal of the campaign is to reach 1,000,000 clicks on the 5 contents/ads. So, the goal is to check on the summation of the 5 content paths added to the campaign goal.

Campaign Target

The campaign should target females only. So in the data sync project, we create a gender property in the default profile, GroupSpace profile, and make it restricted multi-value property, with two values (male or female). Then, define a user segment that filters the users based on the gender profile property to equal “female”.

Campaign Content Action

We can now add a new scenario to the campaign, and drag the segment condition on it, then assign it to be the “females” segment. Now, we need to define the action. Here we create two actions to be performed. First, we need to place a specific content on a placeholder (suppose that the place holder by default shows the logo of the company). We drag the “place content” action, and assign a query to this action that retrieve the content to be placed and then select the place holder, that to be replaced its content with the content retrieved.

Campaign Calling Method Action

Second, we need to call a static method in a Class. When I tried this, I created a class in the Web project and I was getting an exception that the class is not found. I didn’t read carefully that I need to make this class “application-scoped” class by creating a Library Project (JAR) and add it to the EAR project, to expose all the classes in this library to the portal project. Then, we drag the “call static method” action on the campaign, then enter both the method name & the type of the class.

The campaign works fine, but there is something bothered me. When I made the campaign has a goal of X clicks on a content, I didn’t notice that the count is not resting when I redeploy, the count persisted in the database. But I needed someway to monitor how many clicks so far on the content and debug if the campaign goal is reached successfully or not.

Database Tables

I used PointBase console and looked around the tables in the “weblogic” scheme, till I found the table named “AD_COUNT”. It contains the column “AD_ID” which represents the path of the ad, a column that represents the Portal Application, a column for the view count, and another for the clicks count. Also, I found that the whole content in the WLP Repository goes in the table CM_NODE & CM_PROPERTY. The funny thing about PointBase console that it interprets the binary column and display the content image inside it. Check figure 1

Figure 1 Shows the image appears in the PointBase database console as it interpreted its binary content

Conclusion

Weblogic Portal Campaigns is a powerful feature that lets you provide personalized content on the portal, with predefined goals, targeting specific segment(s) of users. It enables the portal to be dynamic to adapt with market changes by changing the parameters of the campaigns in run-time, choosing which content to be displayed to which segment till the campaign goal is reached or the campaign due date comes. It integrates with Weblogic Virtual Content repository.

A feature it lacks is enabling the campaign to end based on goals other than content views/clicks only, like checking against an inventory of the limited product items(which may require calling some back-end method or web service) to flag the campaign as ended. Also the documentation lacks many details about features found in the development IDE (Eclipse packed with OEPE) which make it hard to exploit all the features of Weblogic Portal Campaigns.

Filed Under: Servers Tagged With: WebLogic

JBoss AS 5 Performance Tuning

January 29, 2011 by itadmin Leave a Comment

JBoss AS 5 Performance TuningJBoss AS 5 Performance Tuning will teach you how to deliver fast applications on the JBoss Application Server and Apache Tomcat, giving you a decisive competitive advantage over your competitors. You will learn how to optimize hardware resources, meeting your application requirements with less expenditure.

also read:

  • WebLogic Interview Questions
  • JBoss Portal Server Development
  • Tomcat Interview Questions

The performance of Java Enterprise applications is the sum of a set of components including the Java Virtual Machine configuration, the application server configuration (in our case,JBoss AS), the application code itself, and ultimately the operating system. This book will show you how to apply the correct tuning methodology and use the tuning tools that will help you to monitor and address any performance issues.

By looking more closely at the Java Virtual Machine, you will get a deeper understanding of what the available options are for your applications, and how their performance will be affected. Learn about thread pool tuning, EJB tuning, and JMS tuning, which are crucial parts of enterprise applications.

The persistence layer and the JBoss Clustering service are two of the most crucial elements which need to be configured correctly in order to run a fast application. These aspects are covered in detail with a chapter dedicated to each of them.

Finally, Web server tuning is the last (but not least) topic covered, which shows how to configure and develop web applications that get the most out of the embedded Tomcat web server.

What This Book Covers

Chapter 1, Performance Tuning Concepts, discusses correct tuning methodology and how it fits in the overall software development cycle.

Chapter 2, Installing the Tools for Tuning, shows how to install and configure the instruments for tuning, including VisualVM, JMeter, Eclipse TPTP Platform, and basic OS tools.

Chapter 3, Tuning the Java Virtual Machine, provides an in-depth analysis of the JVM heap and garbage collector parameters, which are used to start up the application server.

Chapter 4, Tuning the JBoss AS, discusses the application server’s core services including the JBoss System Thread Pool, the Connection Pool, and the Logging Service.

Chapter 5, Tuning the Middleware Services, covers the tuning of middleware services including the EJB and JMS services.

Chapter 6, Tuning the Persistence Layer, introduces the principles of good database design and the core concepts of Java Persistence API with special focus on JBoss‘s implementation (Hibernate).

Chapter 7, JBoss AS Cluster Tuning, covers JBoss Clustering service covering the lowlevel details of server communication and how to use JBoss Cache for optimal data replication and caching.

Chapter 8, Tomcat Web Server Tuning, covers the JBoss Web server performance tuning including mod_jk, mod_proxy, and mod_cluster modules.

Chapter 9, Tuning Web Applications on JBoss AS, discusses developing fast web applications using JSF API and JBoss richfaces libraries.

JBoss AS Cluster Tuning

6th Circle of Hell: Heresy. This circle houses administrators who accurately set up
a cluster to use Buddy Replication. Without caring about steady sessions.

Clustering allows us to run applications on several parallel instances (also known as cluster nodes). The load is distributed across different servers, and even if any of the servers fails, the application is still accessible via other cluster nodes. Clustering is crucial for scalable Enterprise applications, as you can improve performance by simply adding more nodes to the cluster.
In this chapter, we will cover the basic building blocks of JBoss Clustering with the following schedule:

  • A short introduction to JBoss Clustering platform
  • In the next section we will cover the low level details of the JGroups library, which is used for all clustering-related communications between nodes
  • In the third section we will discuss JBoss Cache, which provides distributed cache and state replication services for the JBoss cluster on top of the JGroups library

Introduction to JBoss clustering

Clustering plays an important role in Enterprise applications as it lets you split the load of your application across several nodes, granting robustness to your applications. As we discussed earlier, for optimal results it’s better to limit the size of your JVM to a maximum of 2-2.5GB, otherwise the dynamics of the garbage collector will decrease your application’s performance.

Combining relatively smaller Java heaps with a solid clustering configuration can lead to a better, scalable configuration plus significant hardware savings.

The only drawback to scaling out your applications is an increased complexity in the programming model, which needs to be correctly understood by aspiring architects.

JBoss AS comes out of the box with clustering support. There is no all-in-one library that deals with clustering but rather a set of libraries, which cover different kinds of aspects. The following picture shows how these libraries are arranged:

The backbone of JBoss Clustering is the JGroups library, which provides the communication between members of the cluster. Built upon JGroups we meet two building blocks, the JBoss Cache framework and the HAPartition service. JBoss Cache handles the consistency of your application across the cluster by means of a replicated and transactional cache.

On the other hand, HAPartition is an abstraction built on top of a JGroups Channel that provides support for making and receiving RPC invocations from one or more cluster members. For example HA-JNDI (High Availability JNDI) or HA Singleton (High Availability Singleton) both use HAPartition to share a single Channel and multiplex RPC invocations over it, eliminating the configuration complexity and runtime overhead of having each service create its own Channel. (If you need more information about the HAPartition service you can consult the JBoss AS documentation http://community.jboss.org/wiki/jBossAS5ClusteringGuide.). In the next section we will learn more about the JGroups library and how to configure it to reach the best performance for clustering communication.

Configuring JGroups transport

Clustering requires communication between nodes to synchronize the state of running applications or to notify changes in the cluster definition. JGroups (http://jgroups.org/manual/html/index.html) is a reliable group communication toolkit written entirely in Java. It is based on IP multicast, but extends by providing reliability and group membership.

Member processes of a group can be located on the same host, within the same Local Area Network (LAN), or across a Wide Area Network (WAN). A member can be in turn part of multiple groups. The following picture illustrates a detailed view of JGroups architecture:

A JGroups process consists basically of three parts, namely the Channel, Building blocks, and the Protocol stack. The Channel is a simple socket-like interface used by application programmers to build reliable group communication applications. Building blocks are an abstraction interface layered on top of Channels, which can be used instead of Channels whenever a higher-level interface is required. Finally we have the Protocol stack, which implements the properties specified for a given channel.

In theory, you could configure every service to bind to a
different Channel. However this would require a complex thread
infrastructure with too many thread context switches. For this
reason, JBoss AS is configured by default to use a single Channel
to multiplex all the traffic across the cluster.

The Protocol stack contains a number of layers in a bi-directional list. All messages sent and received over the channel have to pass through all protocols. Every layer may modify, reorder, pass or drop a message, or add a header to a message. A fragmentation layer might break up a message into several smaller messages, adding a header with an ID to each fragment, and re-assemble the fragments on the receiver’s side.

The composition of the Protocol stack (that is, its layers) is determined by the creator of the channel: an XML file defines the layers to be used (and the parameters for each layer).

Knowledge about the Protocol stack is not necessary when
just using Channels in an application. However, when an
application wishes to ignore the default properties for a Protocol
stack, and configure their own stack, then knowledge about what
the individual layers are supposed to do is needed.

In JBoss AS, the configuration of the Protocol stack is located in the file, \deploy\cluster\jgroups-channelfactory.sar\META-INF\jgroupschannelfactory-stacks.xml.

The file is quite large to fit here, however, in a nutshell, it contains the following basic elements:

The first part of the file includes the UDP transport configuration. UDP is thedefault protocol for JGroups and uses multicast (or, if not available, multiple unicast messages) to send and receive messages.

A multicast UDP socket can send and receive datagrams from multiple
clients. The interesting and useful feature of multicast is that a client
can contact multiple servers with a single packet, without knowing the
specific IP address of any of the hosts.

Next to the UDP transport configuration, three protocol stacks are defined:

  • udp: The default IP multicast based stack, with flow control
  • udp-async: The protocol stack optimized for high-volume asynchronous RPCs
  • udp-sync: The stack optimized for low-volume synchronous RPCs

Thereafter, the TCP transport configuration is defined . TCP stacks are typically used when IP multicasting cannot be used in a network (for example, because it is disabled) or because you want to create a network over a WAN (that’s conceivably possible but sharing data across remote geographical sites is a scary option from the performance point of view).

You can opt for two TCP protocol stacks:

  • tcp: Addresses the default TCP Protocol stack which is best suited to high-volume asynchronous calls.
  • tcp-async: Addresses the TCP Protocol stack which can be used for low-volume synchronous calls.

If you need to switch to TCP stack, you can simply include the following
in your command line args that you pass to JBoss:
-Djboss.default.jgroups.stack=tcp
Since you are not using multicast in your TCP communication, this
requires configuring the addresses/ports of all the possible nodes in the
cluster. You can do this by using the property -Djgroups.tcpping.
initial_hosts. For example:
-Djgroups.tcpping.initial_hosts=host1[7600],host2[7600]

Ultimately, the configuration file contains two stacks which can be used for optimising JBoss Messaging Control Channel (jbm-control) and Data Channel (jbm-data).

How to optimize the UDP transport configuration

The default UDP transport configuration ships with a list of attributes, which can be tweaked once you know what they are for. A complete reference to the UDP transport configuration can be found on the JBoss clustering guide (http://docs. jboss.org/jbossclustering/cluster_guide/5.1/html/jgroups.chapt. html); for the purpose of our book we will point out which are the most interesting ones for fine-tuning your transport. Here’s the core section of the UDP transport configuration:

The biggest performance hit can be achieved by properly tuning the attributes concerning buffer size (ucast_recv_buf_size, ucast_send_buf_size, mcast_recv_buf_size, and mcast_send_buf_size ).
[code lang=”java”] <UDP
singleton_name="shared-udp"
mcast_port="${jboss.jgroups.udp.mcast_port:45688}"
mcast_addr="${jboss.partition.udpGroup:228.11.11.11}"
tos="8"
ucast_recv_buf_size="20000000"
ucast_send_buf_size="640000"
mcast_recv_buf_size="25000000"
mcast_send_buf_size="640000"
loopback="true"
discard_incompatible_packets="true"
enable_bundling="false"
max_bundle_size="64000"
max_bundle_timeout="30"
. . . .
/>
[/code]
As a matter of fact, in order to guarantee optimal performance and adequate reliability of UDP multicast, it is essential to size network buffers correctly. Using inappropriate network buffers the chances are that you will experience a high frequency of UDP packets being dropped in the network layers, which therefore need to be retransmitted.

The default values for JGroups’ UDP transmission are 20MB and 64KB for unicast transmission and respectively 25MB and 64KB for multicast transmission. While these values sound appropriate for most cases, they can be insufficient for applications sending lots of cluster messages. Think about an application sending a thousand 1KB messages: with the default receive size, we will not be able to buffer all packets, thus increasing the chance of packet loss and costly retransmission.

Monitoring the intra-clustering traffic can be done through the jboss.jgroups domain Mbeans. For example, in order to monitor the amount of bytes sent and received with the UDP transmission protocol, just open your jmx-console and point at the jboss.jgroups domain. Then select your cluster partition. (Default the partition if you are running with default cluster settings). In the following snapshot (we are including only the relevant properties) we can see the amount of Messages sent/received along with their size (in bytes).

Besides increasing the JGroups’ buffer size, another important aspect to consider is that most operating systems allow a maximum UDP buffer size, which is generally ower than JGroups’ defaults. For completeness, we include here a list of default maximum UDP buffer size:

So, as a rule of thumb, you should always configure your operating system to take advantage of the JGroups’ transport configuration. The following table shows the command required to increase the maximum buffer to 25 megabytes. You will need root privileges in order to modify these kernel parameters:

Another option that is worth trying is enable_bundling, which specifies whether to enable message bundling. If true, the transport protocol would queue outgoing messages until max_bundle_size bytes have accumulated, or max_bundle_time milliseconds have elapsed, whichever occurs first.

The advantage of using this approach is that the transport protocol would send bundled queued messages in one single larger message. Message bundling can have significant performance benefits for channels using asynchronous high volume messages (for example, JBoss Cache components configured for REPL_ASYNC. JBoss Cache will be covered in the next section named Tuning JBoss Cache).

On the other hand, for applications based on a synchronous exchange of RCPs, the introduction of message bundling would introduce a considerable latency so it is not recommended in this case. (That’s the case with JBoss Cache components configured as REPL_SYNC).

How to optimize the JGroups’ Protocol stack

The Protocol stack contains a list of layers protocols, which need to be crossed by the message. A layer does not necessarily correspond to a transport protocol: for example a layer might take care to fragment the message or to assemble it. What’s important to understand is that when a message is sent, it travels down in the stack, while when it’s received it walks just the way back.

For example, in the next picture, the FLUSH protocol would be executed first, then the STATE, the GMS, and so on. Vice versa, when the message is received, it would meet the PING protocol first, them MERGE2, up to FLUSH.

Following here, is the list of protocols triggered by the default UDP’s Protocol stack.
[code lang=”xml”]<stack name="udp"
description="Default: IP multicast based stack, with flow
control.">
<config>
<PING timeout="2000" num_initial_members="3"/>
<MERGE2 max_interval="100000" min_interval="20000"/>
<FD_SOCK/>
<FD timeout="6000" max_tries="5" shun="true"/>
<VERIFY_SUSPECT timeout="1500"/>
<pbcast.NAKACK use_mcast_xmit="false" gc_lag="0"
retransmit_timeout="300,600,1200,2400,4800"
discard_delivered_msgs="true"/>
<UNICAST timeout="300,600,1200,2400,3600"/>
<pbcast.STABLE stability_delay="1000"
desired_avg_gossip="50000"
max_bytes="400000"/>
<pbcast.GMS print_local_addr="true" join_timeout="3000"
shun="true"
view_bundling="true"
view_ack_collection_timeout="5000"/>
<FC max_credits="2000000" min_threshold="0.10"
ignore_synchronous_response="true"/>
<FRAG2 frag_size="60000"/>
<pbcast.STATE_TRANSFER/>
<pbcast.FLUSH timeout="0"/>
</config>
</stack>[/code]
The following table will shed some light on the above cryptic configuration:

While all the above protocols play a role in message exchanging, it’s not necessary that you know the inner details of all of them for tuning your applications. So we will focus just on a few interesting ones.

The FC protocol, for example can be used to adapt the rate of messages sent with the rate of messages received. This has the advantage of creating an homogeneous rate of exchange, where no sender member overwhelms receiver nodes, thus preventing potential problems like filling up buffers causing packet loss. Here’s an example of FC configuration:
[code lang=”xml”] <FC max_credits="2000000"
min_threshold="0.10"
ignore_synchronous_response="true"/>[/code]
The message rate adaptation is done with a simple credit system in which each time a sender sends a message a credit is subtracted (equal to the amount of bytes sent). Conversely, when a receiver collects a message, a credit is added.

  • max_credits specifies the maximum number of credits (in bytes) and should obviously be smaller than the JVM heap size
  • min_threshold specifies the value of min_credits as a percentage of the max_credits element
  • ignore_synchronous_response specifies whether threads that have carried messages up to the application should be allowed to carry outgoing messages back down through FC without blocking for credits

The following image depicts a simple scenario where HostA is sending messages (and thus its max_credits is reduced) to HostB and HostC, which increase their max_credits accordingly.

The FC protocol, while providing a control over the flow of messages, can be a bad choice for applications that are issuing synchronous group RPC calls. In this kind of applications, if you have fast senders issuing messages, but some slow receivers across the cluster, the overall rate of calls will be slowed down. For this reason, remove FD from your protocol list if you are sending synchronous messages or just switch to the udpsync protocol stack.

Besides JGroups, some network interface cards (NICs) and switches
perform ethernet flow control (IEEE 802.3x), which causes overhead
to senders when packet loss occurs. In order to avoid a redundant flow
control, you are advised to remove ethernet flow control. For managed
switches, you can usually achieve this via a web or Telnet/SSH interface.
For unmanaged switches, unfortunately the only chance is to hope that
ethernet flow control is disabled, or to replace the switch.
If you are using NICs, you can disable ethernet flow control by means of
a simple shell command, for example, on Linux with the ethtool:
/sbin/ethtool -A eth0 autoneg off tx on rx on
If you want simply to verify if ethernet flow control is off:
/sbin/ethtool -a eth0

One more thing you must be aware of is that, by using JGroups, cluster nodes must store all messages received for potential retransmission in case of a failure. However, if we store all messages forever, we will run out of memory. The distributed garbage collection service in JGroups periodically removes messages that have been seen by all nodes from the memory in each node. The distributed garbage collection service is configured in the pbcast.STABLE sub-element like so:
[code lang=”xml”] <pbcast.STABLE stability_delay="1000"
desired_avg_gossip="5000"
max_bytes="400000"/>
[/code]
The configurable attributes are as follows:

  • desired_avg_gossip: Specifies the interval (in milliseconds) between garbage collection runs. Setting this parameter to 0 disables this service.
  • max_bytes: Specifies the maximum number of bytes to receive before triggering a garbage collection run. Setting this parameter to 0 disables this service.

You are advised to set a max_bytes value if you have a high-traffic cluster.

Tuning JBoss Cache

JBoss Cache provides the foundation for many clustered services, which need to synchronize application state information across the set of nodes.

The cache is organized as a tree, with a single root. Each node in the tree essentially contains a map, which acts as a store for key/value pairs. The only requirement placed on objects that are cached is that they implement java.io.Serializable.

 Actually EJB 3 Stateful Session Beans, HttpSessions, and Entity/Hibernate rely on JBoss Cache to replicate information across the cluster. We have discussed thoroughly data persistence in Chapter 6, Tuning the Persistence Layer, so we will focus in the next sections on SFSB and HttpSession cluster tuning.

The core configuration of JBoss Cache is contained in the JBoss Cache Service. In JBoss AS 5, the scattered cache deployments have been replaced with a new CacheManager service, deployed via the /deploy/cluster/jbosscache-manager.sar/META-INF/jboss-cache-manager-jboss-beans.xml.

The CacheManager acts as a factory for creating caches and as a registry for JBoss Cache instances. It is configured with a set of named JBoss Cache configurations. Here’s a fragment of the standard SFSB cache configuration:
[code lang=”xml”] <b><entry><key>sfsb-cache</key></b>
<value>
<bean name="StandardSFSBCacheConfig"
class="org.jboss.cache.config.Configuration">
<property
name="clusterName">${jboss.partition.name:DefaultPartition}-
SFSBCache</property>
<property
name="multiplexerStack">${jboss.default.jgroups.stack:udp}</property>
<property name="fetchInMemoryState">true</property>
<property name="nodeLockingScheme">PESSIMISTIC</property>
<property name="isolationLevel">REPEATABLE_READ</property>
<property name="useLockStriping">false</property>
<property name="cacheMode">REPL_SYNC</property>
. . . . .
</bean>
</value>
</entry>
[/code]
Services that need a cache ask the CacheManager for the cache by name, which is specified by the key element; the cache manager creates the cache (if not already created) and returns it.

The simplest way to reference a custom cache is by means of the org.jboss.ejb3. annotation.CacheConfig annotation. For example, supposing you were to use a newly created Stateful Session Bean cache named custom_sfsb_cache:
[code lang=”java”] @Stateful
@Clustered
@CacheConfig(name="custom_sfsb_cache")
public Class SFSBExample {
}
[/code]
The CacheManager keeps a reference to each cache it has created, so all services that request the same cache configuration name will share the same cache. When a service is done with the cache, it releases it to the CacheManager. The CacheManager keeps track of how many services are using each cache, and will stop and destroy the cache when all services have released it.

Understanding JBoss Cache configuration

In order to tune your JBoss Cache, it’s essential to learn some key properties. In particular we need to understand

    • How data can be transmitted between its members. This is controlled by the cacheMode property.
  • How the cache handles concurrency on data between cluster nodes. This is handled by nodeLockingScheme and isolationLevel configuration attributes.

Configuring cacheMode

The cacheMode property determines how JBoss Cache keeps in sync data across all nodes. Actually it can be split in two important aspects: how to notify changes across the cluster and how other nodes accommodate these changes on the local data.

As far data notification is concerned, there are the following choices:

    • Synchronous means the cache instance sends a notification message to other nodes and before returning waits for them to acknowledge that they have applied the same changes. Waiting for acknowledgement from all nodes adds delay. However, if a synchronous replication returns successfully, the caller knows for sure that all modifications have been applied to all cache instances.

    • Asynchronous means the cache instance sends a notification message andthen immediately returns, without any acknowledgement that changes have been applied. The Asynchronous mode is most useful for cases like session replication (for example, Stateful Session Beans), where the cache sending data expects to be the only one that accesses the data. Asynchronous messaging adds a small potential risk that a fail over to another node may generate stale data, however, for many session-type applications this risk is acceptable given the major performance benefits gained.

    • Local means the cache instance doesn’t send a message at all. You should use this mode when you are running JBoss Cache as a single instance, so that it won’t attempt to replicate anything. For example, JPA/Hibernate Query Cache uses a local cache to invalidate stale query result sets from the second level cache, so that JBoss Cache doesn’t need to send messages around the cluster for a query result set cache.

As far as the second aspect is concerned (what should the other caches in the cluster do to refl ect the change) you can distinguish between:

Replication: means that the cache replicates cached data across all cluster nodes. This means the sending node needs to include the changed state, increasing the cost of the message. Replication is necessary if the other nodes have no other way to obtain the state.

 Invalidation means that you do not wish to replicate cached data but simply inform other caches in a cluster that data under specific addresses are now stale and should be evicted from memory. Invalidation reduces the cost of the cluster update messages, since only the cache key of the changed state needs to be transmitted, not the state itself.

By combining these two aspects we have a combination of five valid values for the cacheMode configuration attribute:

Should I use invalidation for session data?
No, you shouldn’t. As a matter of fact, data invalidation it is an
excellent option for a clustered JPA/Hibernate Entity cache,
since the cached state can be re-read from the database in case
of failure. If you use the invalidation option, with SFSBs or
HttpSession, then you lose failover capabilities. If this matches
with your project requirements, you could achieve better
performance by simply turning off the cache.

Configuring cache concurrency

JBoss Cache is a thread-safe caching API, and uses its own efficient mechanisms of controlling concurrent access. Concurrency is configured via the nodeLockingScheme and isolationLevel configuration attributes.

There are three choices for nodeLockingScheme:

    • Pessimistic locking involves threads/transactions acquiring locks on nodes before reading or writing. Which is acquired depends on the isolationLevel but in most cases a non-exclusive lock is acquired for a read and an exclusive lock is acquired for a write. Pessimistic locking requires a considerable overhead and allows lesser concurrency, since reader
      threads must block until a write has completed
      and released its exclusive lock (potentially a long time if the write is part of a transaction). The drawbacks include the potential for deadlocks, which are ultimately solved by a TimeoutException.
    • Optimistic locking seeks to improve upon the concurrency available with Pessimistic by creating a workspace for each request/transaction that accesses the cache. All data is versioned; on completion of non-transactional requests or commits of transactions the version of data in the workspace is compared to the main cache, and an exception is raised if there are inconsistencies. This eliminates the cost of reader locks but, because of the cost associated with the parallel workspace, it carries a high memory overhead and low scalability.
    • MVCC is the new locking schema that has been introduced in JBoss Cache 3.x (and packed with JBoss AS 5.x). In a nutshell, MVCC reduces the cost of slow, and synchronization-heavy schemas with a multi-versioned concurrency control, which is a locking scheme commonly used by modern database implementations to control concurrent access to shared data.

    The most important features of MVCC are:

    1. Readers don’t acquire any locks.
    2. Only one additional version is maintained for shared state, for a single writer.
    3. All writes happen sequentially, to provide fail-fast semantics.

    How does MVCC can achieve this?

    For each reader thread, the MVCC’s interceptors wraps state in a lightweight container object, which is placed in the thread’s InvocationContext (or TransactionContext if running in a transaction). All subsequent operations on the state are carried out on the container object using Java references, which allow repeatable read semantics even if the actual state changes simultaneously.

    Writer threads, on the other hand, need to acquire a lock before any writing can start. Currently, lock striping is used to improve the memory performance of the cache, and the size of the shared lock pool can be tuned using the concurrencyLevel attribute of the locking element.

    After acquiring an exclusive lock on a cache Full Qualified Name, the writer thread then wraps the state to be modified in a container as well, just like with reader threads, and then copies this state for writing. When copying, a reference to the original version is still maintained in the container (for rollbacks). Changes are then made to the copy and the copy is finally written to the data structure
    when the write completes.

    Should I use MVCC with session data too?
    While MVCC is the default and recommended choice for JPA/Hibernate
    Entity caching, as far as Session caching is concerned, Pessimistic is still the
    default concurrency control. Why? As a matter of fact, accessing the same
    cached data by concurrent threads it’s not the case with a user’s session. This is
    strictly enforced in the case of SFSB, whose instances are not accessible
    concurrently. So don’t bother trying to change this property for session data.

    Configuring the isolationLevel

    The isolationLevel attribute has two possible values, READ_COMMITTED and REPEATABLE_READ which correspond in semantics to database-style isolation levels. Previous versions of JBoss Cache supported all database isolation levels, and if an unsupported isolation level is configured, it is either upgraded or downgraded to the closest supported level.

    REPEATABLE_READ is the default isolation level, to maintain compatibility with previous versions of JBoss Cache. READ_COMMITTED, while providing a slightly weaker isolation, has a significant performance benefit over REPEATABLE_READ.

    Tuning session replication

    As we have learnt, the user session needs replication in order to achieve a consistent state of your applications across the cluster. Replication can be a costly affair, especially if the amount of data held in session is significant. There are however some available strategies, which can mitigate a lot the cost of data replication and thus improve the performance of your cluster:

    • Override isModified method: By including an isModified method in your SFSBs, you can achieve fine-grained control over data replication. Applicable to SFSBs only.
    • Use buddy replication. By using buddy replication you are not replicating the session data to all nodes but to a limited set of nodes. Can be applicable both to SFSBs and HttpSession.
    • Configure replication granularity and replication trigger. You can apply custom session policies to your HttpSession to define when data needs to be replicated and which elements need to be replicated as well. Applicable to HttpSession.

    Override SFSB’s isModified method

    One of the simplest ways to reduce the cost of SFSBs data replication is implementing in your EJB a method with the following signature: public boolean isModified ();

    Before replicating your bean, the container will detect if your bean implements this method. If your bean does, the container calls the isModified method and it only replicates the bean when the method returns true. If the bean has not been modified (or not enough to require replication, depending on your own preferences), you can return false and the replication will not occur.

    If your session does not hold critical data (such as financial information), using the isModified method is a good option to achieve a substantial benefit in terms of performance. A good example could be a reporting application, which needs session management to generate aggregate reports through a set of wizards. Here’s a graphical view of this process:

    The following benchmark is built on exactly the use case of an OLAP application, which uses SFSBs to drive some session data across a four step wizard. The benchmark compares the performance of the wizard without including isModified and by returning true to isModified at the end of the wizard.

    Ultimately, by using the isModified method to propagate the session data at wider intervals you can improve the performance of your application with an acceptable risk to re-generate your reports in case of node failures.

    Use buddy replication

    By using buddy replication, sessions are replicated to a configurable number of backup servers in the cluster (also called buddies), rather than to all servers in the cluster. If a user fails over from the server that is hosting his or her session, the session data is transferred to the new server from one of the backup buddies. Buddy replication provides the following benefits:

    • Reduced memory usage
    • Reduced CPU utilization
    • Reduced network transmission

    The reason behind this large set of advantages is that each server only needs to store in its memory the sessions it is hosting as well as those of the servers for which it is acting as a backup. Thus, less memory required to store data, less CPU to elaborate bits to Java translations, and less data to transmit.

    For example, in an 8-node cluster with each server configured to have one buddy, a server would just need to store 2 sessions instead of 8. That’s just one fourth of the memory required with total replication.

    In the following picture, you can see an example of a cluster configured for buddy replication:

    Here, each node contains a cache of its session data and a backup of another node. For example, node A contains its session data and a backup of node E. Its data is in turn replicated to node B and so on.

    In case of failure of node A, its data moves to node B which becomes the owner of both A and B data, plus the backup of node E. Node B in turn replicates (A + B) data to node C.

    In order to configure your SFSB sessions or HttpSessions to use buddy replication you have just to set to the property enabled of the bean BuddyReplicationConfig inside the /deploy/cluster/jboss-cache-manager.sar/META-INF/jboss-cache-manager-jboss-beans.xml configuration file, as shown in the next code fragment:
    [code lang=”xml”]
    <property name="buddyReplicationConfig">
    <bean
    class="org.jboss.cache.config.BuddyReplicationConfig">
    <b><property name="enabled">true</property></b>
    . . .
    </bean>
    </property>
    [/code]
    In the following test, we are comparing the throughput of a 5-node clustered web application which uses buddy replication against one which replicates data across all members of the cluster.

    In this benchmark, switching on buddy replication improved the application throughput of about 30%. No doubt that by using buddy replication there’s a high potential for scaling because memory/CPU/network usage per node does not increase linearly as new nodes are added.

    Advanced buddy replication

    With the minimal configuration we have just described, each server will look for one buddy across the network where data needs to be replicated. If you need to backup your session to a larger set of buddies you can modify the numBuddies property of the BuddyReplicationConfig bean. Consider, however, that replicating the session to a large set of nodes would conversely reduce the benefits of buddy replication.

    Still using the default configuration, each node will try to select its buddy on a different physical host: this helps to reduce chances of introducing a single point of failure in your cluster. Just in case the cluster node is not able to find buddies on different physical hosts, it will not honour the property ignoreColocatedBuddies and fall back to co-located nodes.

    The default policy is often what you might need in your applications, however if you need a fine-grained control over the composition of your buddies you can use a feature named buddy pool. A buddy pool is an optional construct where each
    instance in a cluster may be configured to be part of a group- just like an “exclusive club membership”.

    This allows system administrators a degree of fl exibility and control over how buddies are selected. For example, you might put two instances on separate physical servers that may be on two separate physical racks in the same buddy pool. So rather than picking an instance on a different host on the same rack, the BuddyLocators would rather pick the instance in the same buddy pool, on a separate rack which may add a degree of redundancy.

    Here’s a complete configuration which includes buddy pools:
    [code lang=”xml”] <property name="buddyReplicationConfig">
    <bean class="org.jboss.cache.config.BuddyReplicationConfig">
    <b><property name="enabled">true</property>
    <property name="buddyPoolName">rack1</property></b>
    <property name="buddyCommunicationTimeout">17500</property>
    <property name="autoDataGravitation">false</property>
    <property name="dataGravitationRemoveOnFind">true</property>
    <property name="dataGravitationSearchBackupTrees">true</property>
    <property name="buddyLocatorConfig">
    <bean
    class="org.jboss.cache.buddyreplication.NextMemberBuddyLocatorConfig">
    <b><property name="numBuddies">1</property>
    <property name="ignoreColocatedBuddies">true</property></b>
    </bean>
    </property>
    </bean>
    </property>
    [/code]
    In this configuration fragment, the buddyPoolName element, if specified, creates a logical subgroup and only picks buddies who share the same buddy pool name. If not specified, this defaults to an internal constant name, which then treats the entire cluster as a single buddy pool.

    If the cache on another node needs data that it doesn’t have locally, it can ask the other nodes in the cluster to provide it; nodes that have a copy will provide it as part of a process called data gravitation. The new node will become the owner of the data, placing a backup copy of the data on its buddies.

    The ability to gravitate data means there is no need for all requests for data to occur on a node that has a copy of it; that is, any node can handle a request for any data. However, data gravitation is expensive and should not be a frequent occurrence; ideally it should only occur if the node that is using some data fails or is shut down, forcing interested clients to fail over to a different node.

    The following optional properties pertain to data gravitation:

    • autoDataGravitation: Whether data gravitation occurs for every cache miss. By default this is set to false to prevent unnecessary network calls.
    • DataGravitationRemoveOnFind: Forces all remote caches that own the data or hold backups for the data to remove that data, thereby making the requesting cache the new data owner. If set to false, an evict is broadcast instead of a remove, so any state persisted in cache loaders will remain. This is useful if you have a shared cache loader configured. (See next section about Cache loader). Defaults to true.
    • dataGravitationSearchBackupTrees: Asks remote instances to search through their backups as well as main data trees. Defaults to true. The resulting effect is that if this is true then backup nodes can respond to data gravitation requests in addition to data owners.

    Buddy replication and session affinity

    One of the pre-requisites to buddy replication working well and being a real benefit is the use of session affinity, also known as sticky sessions in HttpSession replication speak. What this means is that if certain data is frequently accessed, it is desirable that this is always accessed on one instance rather than in a “round-robin” fashion as this helps the cache cluster optimise how it chooses buddies, where it stores data, and minimises replication traffic.

    If you are replicating SFSBs session, there is no need to configure anything since SFSBs, once created, are pinned to the server that created them.

    When using HttpSession, you need to make sure your software or hardware load balancer maintain the session on the same host where it was created.

    By using Apache’s mod_jk, you have to configure the workers file (workers. properties) specifying where the different node and how calls should be load-balanced across them. For example, on a 5-node cluster:
    [code lang=”java”] worker.loadbalancer.balance_workers=node1,node2,node3,node4,node5
    worker.loadbalancer.sticky_session=1[/code]
    Basically, the above snippet configures mod_jk to perform round-robin load balancing with sticky sessions (sticky_session=1) across 5 nodes of a cluster.

    Configure replication granularity and replication trigger

    Applications that want to store data in the HttpSession need to use the methods setAttribute to store the attributes and getAttribute to retrieve them. You can define two kind of properties related to HttpSessions:

    • The replication-trigger configures when data needs to be replicated.
    • The replication-granularity defines which part of the session needs
      to be replicated.

    Let’s dissect both aspects in the following sections:

    How to configure the replication-trigger

    The replication-trigger element determines what triggers a session replication and can be configured by means of the jboss-web.xml element (packed in the WEB-INF folder of your web application). Here’s an example:
    [code lang=”xml”] <jboss-web>
    <replication-config>
    <b><replication-trigger>SET</replication-trigger></b>
    </replication-config>
    </jboss-web>
    [/code]
    The following is a list of possible alternative options:

      • SET_AND_GET is conservative but not performance-wise; it will always replicate session data even if its content has not been modified but simply accessed. This setting made (a little) sense in AS 4 since using it was a way to ensure that every request triggered replication of the session’s timestamp. Setting max_unreplicated_interval to 0 accomplishes the same thing at much lower cost.
      • SET_AND_NON_PRIMITIVE_GET is conservative but will only replicate if an object of a non-primitive type has been accessed (that is, the object is not of a well-known immutable JDK type such as Integer, Long, String, and so on.)This is the default value.
      • SET assumes that the developer will explicitly call setAttribute on the session if the data needs to be replicated. This setting prevents unnecessary replication and can have a major beneficial impact on performance.

      In all cases, calling setAttribute marks the session as dirty and thus triggers replication.

      For the purpose of evaluating the available alternatives in performance terms, we have compared a benchmark of a web application using different replication-triggers:

      In the first benchmark, we are using the default rule (SET_AND_NON_PRIMITIVE_GET). In the second we have switched to SET policy, issuing a setAttribute on 50% of the requests. In the last benchmark, we have formerly populated the session with the required attributes and then issued only queries on the session via the getAttribute method.

      As you can see the benefit of using the SET replication trigger is obvious, especially if you follow a read-mostly approach on non-primitive types. On the other hand, this requires very good coding practices to ensure setAttribute is always called whenever a mutable object stored in the session is modified.

      How to configure the replication-granularity

      As far as what data needs to be replicated is concerned, you can opt for the following choices:

      • SESSION indicates that the entire session attribute map should be replicated when any attribute is considered modified. Replication occurs at request end. This option replicates the most data and thus incurs the highest replication cost, but since all attributes values are always replicated together it ensures that any references between attribute values will not be broken when the session is deserialized. For this reason it is the default setting.
      • ATTRIBUTE indicates that only attributes that the session considers to be potentially modified are replicated. Replication occurs at request end. For sessions carrying large amounts of data, parts of which are infrequently updated, this option can significantly increase replication performance.
      • FIELD level replication only replicates modified data fields inside objects stored in the session. Its use could potentially drastically reduce the data traffic between clustered nodes, and hence improve the performance of the whole cluster. To use FIELD-level replication, you have to first prepare (that is bytecode enhance) your Java class to allow the session cache to detect when fields in cached objects have been changed and need to be replicated. 

      In order to change the default replication granularity, you have to configure the desired attribute in your jboss-web.xml configuration file:
      [code lang=”xml”] <jboss-web>
      <replication-config>
      <b><replication-granularity>FIELD</replication-granularity></b>
      <replication-field-batch-mode>true</replication-field-batchmode>
      </replication-config>
      </jboss-web>
      [/code]
      In the above example, the replication-field-batch-mode element indicates whether you want all replication messages associated with a request to be batched into one message.

      Additionally, if you want to use FIELD level replication you need to perform a bit of extra work. At first you need to add the @org.jboss.cache.pojo.annotation. Replicable annotation at class level:
      [code lang=”java”] @Replicable
      public class Person { … }[/code]

      If you annotate a class with @Replicable, then all of its subclasses will
      be automatically annotated as well.

      Once you have annotated your classes, you will need to perform a post-compiler processing step to bytecode enhance your classes for use by your cache. Please check the JBoss AOP documentation (http://www.jboss.org/jbossaop) for the usage of the aoc post-compiler. The JBoss AOP project also provides easy to use ANT tasks to help integrate those steps into your application build process.

      As proof of concept, let’s build a use case to compare the performance of ATTRIBUTE and FIELD granularity policies. Supposing you are storing in your HttpSession an object of Person type. The object contains references to an Address, ContactInfo, and PersonalInfo objects. It contains also an ArrayList of WorkExperience.

      A prerequisite to this benchmark is that there are no references between
      the field values stored in the Person class (for example between the
      contactInfo and personalInfo fields), otherwise the references will
      be broken by ATTRIBUTE or FIELD policies.

      By using the SESSION or ATTRIBUTE replication-granularity policy, even if just one of these fields is modified, the whole Person object need to be retransmitted. Let’s compare the throughput of two applications using respectively the ATTRIBUTE and FIELD replication-granularity.

      In this example, based on the assumption that we have a single dirty field of Person’ class per request, by using FIELD Replication generate a substantial 10% gain.

      Tuning cache storage

      Cache loading allows JBoss Cache to store cached data in a persistent store and is used mainly for HttpSession and SFSB sessions. Hibernate and JPA on the other hand, have already their persistence storage in the database so it doesn’t make sense to add another storage.

      This data can either be an overflow, where the data in the persistent store has been evicted from memory. Or it can be a replication of what is in memory, where everything in memory is also refl ected in the persistent store, along with items that have been evicted from memory.

      The cache storage used for web session and EJB3 SFSB caching comes into play in two circumstances:

      • Whenever a cache element is accessed, and that element is not in the cache (for example, due to eviction or due to server restart), then the cache loader transparently loads the element into the cache if found in the backend store.
      • Whenever an element is modified, added or removed, then that modification is persisted in the backend store via the cache loader (except if the ignoreModifications property has been set to true for a specific cache loader). If transactions are used, all modifications created within a transaction are persisted as well.

      Cache loaders are configured by means of the property cacheLoaderConfig of session caches. For example, in the case of SFSB cache:
      [code lang=”xml”]
      <b><entry><key>sfsb-cache</key></b>
      <value>
      <bean name="StandardSFSBCacheConfig"
      class="org.jboss.cache.config.Configuration">
      . . . . .
      <b><property name="cacheLoaderConfig"></b>
      <bean class="org.jboss.cache.config.CacheLoaderConfig">
      <b><property name="passivation">true</property>
      <property name="shared">false</property></b>
      <property name="individualCacheLoaderConfigs">
      <list>
      <bean
      class="org.jboss.cache.loader.FileCacheLoaderConfig">
      <property
      name="location">${jboss.server.data.dir}${/}sfsb</property>
      <property name="async">false</property>
      <property name="fetchPersistentState">true</property>
      <property name="purgeOnStartup">true</property>
      <property name="ignoreModifications">false</property>
      <property
      name="checkCharacterPortability">false</property>
      </bean>
      </list>
      </property>
      </bean>
      . . . ..
      </entry>
      [/code]
      The passivation property , when set to true, means the persistent store acts as an overflow area written to when data is evicted from the in-memory cache.

      The shared attribute indicates that the cache loader is shared among different cache instances, for example where all instances in a cluster use the same JDBC settings to talk to the same remote, shared database. Setting this to true prevents repeated and  unnecessary writes of the same data to the cache loader by different cache instances. The default value is false.

      Where does cache data get stored?

      By default, the Cache loader uses a filesystem implementation based on the class org.jboss.cache.loader.FileCacheLoaderConfig, which requires the location property to define the root directory to be used.

      If set to true, the async attribute read operations are done synchronously, while write (CRUD – Create, Remove, Update, and Delete) operations are done asynchronously. If set to false (default), both read and writes are performed synchronously.

      Should I use an async channel for my Cache Loader?
      When using an async channel, an instance of org.jboss.cache.
      loader.AsyncCacheLoader is constructed which will act as an
      asynchronous channel to the actual cache loader to be used. Be aware
      that, using the AsyncCacheLoader, there is always the possibility of
      dirty reads since all writes are performed asynchronously, and it is thus
      impossible to guarantee when (and even if) a write succeeds. On the
      other hand the AsyncCacheLoader allows massive writes to be written
      asynchronously, possibly in batches, with large performance benefits.
      Checkout the JBoss Cache docs for further information http://docs.
      jboss.org/jbosscache/3.2.1.GA/apidocs/index.html.

      fetchPersistentState determines whether or not to fetch the persistent state of a cache when a node joins a cluster and conversely the purgeOnStartup property evicts data from the storage on startup, if set to true.

      Finally, checkCharacterPortability should be false for a minor performance improvement.

      The FileCacheLoader is a good choice in terms of performance, however it has some limitations, which you should be aware of before rolling your application in a production environment. In particular:

      1. Due to the way the FileCacheLoader represents a tree structure on disk (directories and files) traversal is “inefficient” for deep trees.
      2. Usage on shared filesystems such as NFS, Windows shares, and others should be avoided as these do not implement proper file locking and can cause data corruption.
      3. Filesystems are inherently not “transactional”, so when attempting to use your cache in a transactional context, failures when writing to the file (which happens during the commit phase) cannot be recovered.

      As a rule of thumb, it is recommended that the FileCacheLoader not
      be used in a highly concurrent, transactional. or stressful environment,
      and, in this kind of scenario consider using it just in the testing
      environment.

      As an alternative, consider that JBoss Cache is distributed with a set of different Cache loaders which can be used as alternative. For example:

      • The JDBC-based cache loader implementation that stores/loads nodes’ state into a relational database. The implementing class is org.jboss.cache. loader.JDBCCacheLoader.
      • The BdbjeCacheLoader, which is a cache loader implementation based on the Oracle/Sleepycat’s BerkeleyDB Java Edition (note that the BerkeleyDB implementation is much more efficient than the filesystem-based implementation, and provides transactional guarantees, but requires a commercial license if distributed with an application (see http://www.oracle.com/database/berkeley-db/index.html for details).
      • The JdbmCacheLoader, which is a cache loader implementation based on the JDBM engine, a fast and free alternative to BerkeleyDB.
      • Finally, S3CacheLoader, which uses the Amazon S3 solution (Simple Storage Solution http://aws.amazon.com/) for storing cache data. Since Amazon S3 is remote network storage and has fairly high latency, it is really best for
        caches that store large pieces of data, such as media or files.

      When it comes to measuring the performance of different Cache Loaders, here’s a benchmark executed to compare the File CacheLoader, the JDBC CacheLoader (based on Oracle Database) and Jdbm CacheLoader.

      In the above benchmark we are testing cache insertion and cache gets of batches of 1000 Fqn each one bearing 10 attributes. The File CacheLoader accomplished the overall best performance, while the JBDM CacheLoader is almost as fast for Cache gets.

      The JDBC CacheLoader is the most robust solution but it adds more overhead to the Cache storage of your session data.

      Summary

      Clustering is a key element in building scalable Enterprise applications. The infrastructure used by JBoss AS for clustered applications is based on JGroups framework for the nodes inter-communication and JBoss Cache for keeping the cluster data synchronized across nodes.

      • JGroups can use both UDP and TCP as communication protocol. Unless you have network restriction, you should stay with the default UDP that uses multicast to send and receive messages.
      • You can tune the transmission protocol by setting an appropriate buffer size with the properties mcast_recv_buf_size, mcast_send_buf_size, ucast_recv_buf_size, and ucast_send_buf_size. You should as well increase your O/S buffer size, which need to be adequate to accept JGroups’ settings.
      • JBoss Cache provides the foundation for robust clustered services.
      • By configuring the cacheMode you can choose if your cluster messages will be synchronous (that is will wait for message acknowledgement) or asynchronous. Unless you need to handle cache message exceptions, stay with the asynchronous pattern, which provides the best performance.
      • Cache messages can trigger as well cluster replication or cluster invalidation. A cluster replication is needed for transferring the session state across the cluster while invalidation is the default for Entity/Hibernate, where state
        can be recovered from the database.
      • The cache concurrency can be configured by means of the nodeLockingScheme property. The most efficient locking schema is the MVCC, which reduces the cost of slow, or synchronization-heavy schemas of Pessimistic and Optimistic schemas.
      • Cache replication of sessions can be optimised mostly in three ways:
      • By overriding the isModified method of your SFSBs you can achieve a fine-grained control over data replication. It’s an optimal quick-tuning option for OLAP applications using SFSBs.
      • Buddy replication is the most important performance addition to your session replication. It helps to increase the performance by reducing memory and CPU usage as well as network traffic. Use buddy replication pools to achieve a higher level of redundancy for mission critical applications.
      • Clustered web applications can configure replication-granularity and replication-trigger:
      • As far as the replication trigger is concerned, if you mostly read immutable data from your session, the SET attribute provides a substantial benefit over the default SET_AND_PRIMITIVE_GET.
      • As far as replication granularity is concerned, if your sessions are generally small, you can stay with the default policy (SESSION). If your session is larger and some parts are infrequently accessed, ATTRIBUTE replication will be more effective. If your application has very big data objects in session attributes and only fields in those objects are frequently modified, the FIELD policy would be the best.

Filed Under: Servers Tagged With: WildFly

Tomcat 6.0 Servlet Container Overview

June 20, 2010 by itadmin Leave a Comment

Tomcat 6.0 Developer’s Guide

Current books on Tomcat are primarily focused on the application deployer or administrator. As a result, they invariably focus on the issues related to managing a Tomcat installation, configuring the runtime environment, and on deploying web applications.

also read:

  • WebLogic Interview Questions
  • JBoss Portal Server Development
  • Tomcat Interview Questions

On the other hand, while books on servlet programming are targeted at Java web developers, they often provide a container-agnostic view of the servlet specification. Tomcat is often a bit player in these books and has very few speaking lines.

This book fills the void between these two approaches.
It will take you on a guided tour of a living implementation of an industrial-strength servlet container.
Along the way, you will learn how various elements of the Servlet 2.5 specification as well as how the HTTP RFCs are implemented.

By the end of your journey, you will have acquired specialist grade skills in a range of technologies that contribute to the arena of Java server-side development.

This book intended to provide Tomcat administrators, deployers, and developers an introduction into the internal workings of the Tomcat servlet container.

At the same time, it provides Java web programmers with a deep appreciation of the Servlet APiby exploring its reference implementation—the Tomcat container.

While this book provides you with the conceptual background of all that is necessary to take your skills to the next level, it assumes that the reader has a general understanding of the Java programming language and Java web programming.

What This Book Covers

Chapter 1—Introduction to Tomcat introduces you to the Tomcat container and provides you with the tools necessary to begin to take it apart. The key objective of this chapter is to allow you to make a current source distribution of Tomcat active in a development environment (Eclipse Galileo) so that you can trace the path that a request takes through the container’s code.

Chapter 2—Servlet APiOverview provides the prerequisite information necessary to navigate the remainder of the book. It describes the Java Enterprise Edition Platform, the HTTP protocol, and the Servlet API, and serves as a refresher for those who are already familiar with Java EE web development.

Chapter 3—Servlet Container Overview introduces the reader to the Tomcat container.
This is the 10,000 foot overview of the container that provides a backdrop to the chapters that follow. All the components of Tomcat are described with just enough detail, so as not to overwhelm the reader with too much information, too early in the process.

Chapter 4—Starting up Tomcat takes a closer look at the startup process for Tomcat. This
is also where you will be first introduced to the Apache Digester project—a key component that we will revisit in later chapters. The chapter ends with an example that demonstrates how a web application can be deployed to a dissected Tomcat container living within an Integrated Development Environment.

Chapter 5—The Server and Service Components discusses the Server component and investigates one of its key services—an implementation of the Java Naming and Directory Interface (JNDI) API. We are also introduced to the Lifecycle interface that almost every component within Tomcat implements in order to participate in a standardized event based listener mechanism. To show JNDiin action, our example considers connecting to a MySQL database to retrieve data.

Chapter 6—The Connector Component introduces our first Tomcat luminary, the Coyote Connector. We take a closer look at the standard Java I/O implementation of an HTTP connector. In this chapter, we get a closer look at socket programming, advanced elements of the HTTP protocol, and the internals of the request processing mechanism.

Chapter 7—The Engine Component describes the first request processing ‘Container’ within Tomcat and gives us an inkling of things to come. We are also introduced to the Pipeline and its Valves, which are the standard request processing mechanism for Tomcat components.

Chapter 8—The Host Component discusses the Tomcat implementation of a Virtual Host. This is the key component responsible for the deployment of web application contexts, as well as for the error page mechanism.

Chapter 9—The Context Component is at the central core of this book. You get an upclose-
and-personal look at how a Context is configured, how it accesses its resources, and how it implements its class loading magic.

Chapter 10—The Wrapper Component takes us to the workhorse of the Tomcat component hierarchy. This component wraps an actual servlet, and as a result is close to a web developer’s heart. In addition to reviewing the mapping rules dictated by the Servlet API, we also look at the implementation of servlet filters and the request dispatcher mechanism.

Chapter 11—The Session Component discusses how sessions are implemented in Tomcat to enable stateful behavior over the stateless HTTP protocol. In addition to looking at some core concepts, such as Java serialization and entropy gathering for random number generation, we look at the standard memory based session implementation, as well as an implementation that uses files to persist sessions.

Servlet Container Overview

In the last chapter, we noted that the Java Enterprise Edition can be considered to be nothing more than a set of specifications, or interfaces, for which service providers are required to provide implementations.

While it is the actual implementation that does all the work, these specifications ensure that each implementation can assume that all its other collaborating pieces work as described by their interfaces. In theory, this allows complex software platforms (such as application servers) to be assembled from constituent implementations, each of which is sourced from a different vendor.

In practice, it is highly unlikely that you will interface an EJB container from WebSphere and a JMS implementation from WebLogic, with the Tomcat servlet container from the Apache foundation, but it is at least theoretically possible.

Note that the term ‘interface’, as it is used here, also encompasses abstract classes. The specification’s APimight provide a template implementation whose operations are defined in terms of some basic set of primitives that are kept abstract for the service provider to implement. For instance, in Chapter 2, we noted that the servlet hierarchy is made up of the Servlet interface, and the GenericServlet and HttpServlet abstract classes within the javax.servlet package.

A service provider is required to make available concrete implementations of these interfaces and abstract classes. For example, the HttpSession interface is implemented by Tomcat in the form of org.apache.catalina.session.StandardSession.

Let’s return to the image of the Tomcat container that we saw in Chapter 1.

As was stated in Chapter 1, the objective of this book is to cover the primary request processing components that are present in this image. Advanced topics, such as clustering and security, are shown as shaded in this image and are not covered.

In this image, the ‘+’ symbol after the Service, Host, Context, and Wrapper instances indicate that there can be one or more of these elements. For instance, a Service may have a single Engine, but an Engine can contain one or more Hosts.
In addition, the whirling circle represents a pool of request processor threads.

In this chapter, we will fl y over the architecture of Tomcat from a 10,000-foot perspective taking in the sights as we go.

Component taxonomy

Tomcat’s architecture follows the construction of a Matrushka doll from Russia. In other words, it is all about containment where one entity contains another, and that entity in turn contains yet another.

In Tomcat, a ‘container’ is a generic term that refers to any component that can contain another, such as a Server, Service, Engine, Host, or Context.

Of these, the Server and Service components are special containers, designated as Top Level Elements as they represent aspects of the running Tomcat instance. All the other Tomcat components are subordinate to these top level elements.

The Engine, Host, and Context components are officially termed Containers, and refer to components that process incoming requests and generate an appropriate outgoing response.

Nested Components can be thought of as sub-elements that can be nested inside either Top Level Elements or other Containers to configure how they function. Examples of n ested components include the Valve, which represents a reusable unit of work; the Pipeline, which represents a chain of Valves strung together; and a Realm which helps set up container-managed security for a particular container.

Other nested components include the Loader which is used to enforce the specification’s guidelines for servlet class loading; th e Manager that supports session management for each web application; the R esources component that represents the web application’s static resources and a mechanism to access these resources; and the Listener th at allows you to insert custom processing at important points in a container’s life cycle, such as when a component is being started or stopped.
[code]
Not all nested components can be nested within every container.
[/code]

A final major component, which falls into its own category, is the Connector. It represents the connection end point that an external client (such as a web browser) can use to connect to the Tomcat container.

Before we go on to examine these components, let’s take a quick look at how they are organized structurally.

Note that this diagram only shows the key properties of each container.

When Tomcat is started, the Java Virtual Machine (JVM) instance in which it runs will contain a singleton Server top level element, which represents the entire Tomcat server. A Server will usually containjust one Service object, which is a structural element that combines one or more Connectors (for example, an HTTP and an HTTPS connector) that funnel incoming requests through to a single Catalina servlet Engine.

The Engine represents the core request processing code within Tomcat and supports the definition of multiple Virtual Hosts within it. A virtual host allows a single running Tomcat engine to make it seem to the outside world that there are multiple separate domains (for example, www.my-site.com and www.your-site.com) being hosted on a single machine.

Each virtual host can, in turn, support multiple web applications known as Contexts that are deployed to it. A context is represented using the web application format specified by the servlet specification, either as a single compressed WAR (Web Application Archive) file or as an uncompressed directory. In addition, a context is configured using a web.xml file, as defined by the servlet specification.

A context can, in turn, contain multiple servlets that are deployed into it, each of which is wrapped in a Wrapper component.

The Server, Service, Connector, Engine, Host, and Context elements that will be present in a particular running Tomcat instance are configured using the server.xml configuration file.
[code]
Things are a bit more complicated than this. However, we’ll defer the
complexity until later chapters when we deal with each component in a
lot more detail.
[/code]

Architectural benefits

This architecture has a couple of useful features. It not only makes it easy to manage component life cycles (each component manages the life cycle notifications for its children), but also to dynamically assemble a running Tomcat server instance that is based on the information that has been read from configuration files at startup.In particular, the server.xml file is parsed at startup, and its contents are used to instantiate and configure the defined elements, which are then assembled into a running Tomcat instance.
[code]
The server.xml file is read only once, and edits to it will not be picked
up until Tomcat is restarted.
[/code]

This architecture also eases the configuration burden by allowing child containers to inherit the configuration of their parent containers. For instance, a Realm defines a data store that can be used for authentication and authorization of users who are attempting to access protected resources within a web application. For ease of configuration, a realm that is defined for an engine applies to all its children hosts and contexts. At the same time, a particular child, such as a given context, may override its inherited realm by specifying its own realm to be used in place of its
parent’s realm.

Top Level Components

The Server and Service container components exist largely as structural conveniences. A Server represents the running instance of Tomcat and contains one or more Service children, each of which represents a collection of request processing components.

Server


A Server represents the entire Tomcat instance and is a singleton within a Java Virtual Machine, and is responsible for managing the life cycle of its contained services.

The following image depicts the key aspects of the Server component. As shown, a Server instance is configured using the server.xml configuration file. The root element of this file is and represents the Tomcat instance. Its default implementation is provided using org.apache.catalina.core.StandardServer, but you can specify your own custom implementation through the className attribute of the element.

A key aspect of the Server is that it opens a server socket on port 8005 (the default) to listen a shutdown command (by default, this command is the text string SHUTDOWN). When this shutdown command is received, the server gracefully shuts itself down. For security reasons, the connection requesting the shutdown must be initiated from the same machine that is running this instance of Tomcat.

A Server also provides an implementation of the Java Naming and Directory Interface (JNDI) service, allowing you to register arbitrary objects (such as data sources) or environment variables, by name.

At runtime, individual components (such as servlets) can retrieve this information by looking up the desired object name in the server’s JNDibindings.

While a JNDiimplementation is not integral to the functioning of a servlet container, it is part of the Java EE specification and is a service that servlets have a right to expect from their application servers or servlet containers. Implementing this service makes for easy portability of web applications across containers.

While there is always just one server instance within a JVM, it is entirely possible to have multiple server instances running on a single physical machine, each encased in its ownjVM. Doing so insulates web applications that are running on one VM from errors in applications that are running on others, and simplifies maintenance by allowing a JVM to be restarted independently of the others. This is one of the mechanisms used in a shared hosting environment (the other is virtual hosting,
which we will see shortly) where you need isolation from other web applications that are running on the same physical server.

Service


While the Server represents the Tomcat instance itself, a Service represents the set of request processing components within Tomcat.

A Server can contain more than one Service, where each service associates a group of Connector components with a single Engine.

Requests from clients are received on a connector, which in turn funnels them through into the engine, which is the key request processing component within Tomcat. The image shows connectors for HTTP, HTTPS, and the Apache JServ Protocol (AJP).

There is very little reason to modify this element, and the default Service instance is usually sufficient.

A hint as to when you might need more than one Service instance can be found in the above image. As shown, a service aggregates connectors, each of which monitors a given IP address and port, and responds in a given protocol. An example use case for having multiple services, therefore, is when you want to partition your services (and their contained engines, hosts, and web applications) by IP address and/or port number.

For instance, you might configure your firewall to expose the connectors for one service to an external audience, while restricting your other service to hosting intranet applications that are visible only to internal users. This would ensure that an external user could never access your Intranet application, as that access would be blocked by the firewall.

The Service, therefore, is nothing more than a grouping construct. It does not
currently add any other value to the proceedings.
[code]
The server and service components are covered in more detail in
Chapter 5, The Server and Service Components.
[/code]

Connectors

A Connector is a service endpoint on which a client connects to the Tomcat container. It serves to insulate the engine from the various communication protocols that are used by clients, such as HTTP, HTTPS, or the Apache JServ Protocol (AJP).

Tomcat can be configured to work in two modes—Standalone or in Conjunction with a separate web server.

In standalone mode, Tomcat is configured with HTTP and HTTPS connectors, which make it act like a full-fl edged web server by serving up static content when requested, as well as by delegating to the Catalina engine for dynamic content.

Out of the box, Tomcat provides three possible implementations of the HTTP/1.1 and HTTPS connectors for this mode of operation.

The most common are the standard connectors, known as Coyo te which are implemented using standard Java I/O mechanisms.

You may also make use of a couple of newer implementations, one which uses the non-blocking NIO features of Java 1.4, and the other which takes advantage of native code that is optimized for a particular operating system through the Apache Portable Runtime (APR).

Note that both the Connector and the Engine run in the same JVM. In fact, they run within the same Server instance.

In conjunction mode, Tomcat plays a supporting role to a web server, such as Apache httpd or Microsoft’s IIS. The client here is the web server, communicating with Tomcat either through an Apache module or an ISAPiDLL. When this module determines that a request must be routed to Tomcat for processing, it will communicate this request to Tomcat using AJP, a binary protocol that is designed to be more efficient than the text based HTTP when communicating between a web server and Tomcat.

On the Tomcat side, an AJP connector accepts this communication and translates it into a form that the Catalina engine can process.

In this mode, Tomcat is running in its ownjVM as a separate process from the web server.

In either mode, the primary attributes of a Connector are the IP address and port on which it will listen for incoming requests, and the protocol that it supports. Another key attribute is the maximum number of request processing threads that can be created to concurrently handle incoming requests. Once all these threads are busy, any incoming request will be ignored until a thread becomes available.

By default, a connector listens on all the IP addresses for the given physical machine (its address attribute defaults to 0.0.0.0). However, a connector can be configured to listen onjust one of the IP addresses for a machine. This will constrain it to accept connections from only that specified IP address.

Any request that is received by any one of a service’s connectors is passed on to the service’s single engine. This engine, known as Catalina, is responsible for the processing of the request, and the generation of the response.

The engine returns the response to the connector, which then transmits it back to the client using the appropriate communication protocol.
[code]
This component is covered in more detail in Chapter 6,
The Connector Component.
[/code]

Container components

In this section, we’ll take a look at the key request processing components within Tomcat; the engine, virtual host, and context components.

Engine


An Engine represents a running instance of the Catalina servlet engine and comprises the heart of a servlet container’s function. There can only be one engine within a given service. Being a true container, an Engine may contain one or more virtual hosts as children.

Being the primary request processing component, it receives objects that represent the incoming request and the outgoing response. Its main function is to delegate the processing of the incoming request to the appropriate virtual host. If the engine has no virtual host with a name matching the one to which the request should be directed, it consults its defaultHost attribute to determine the host that should be used.

Virtual host


A virtual host in Tomcat is represented by the Host component, which is a container for web applications, or, in Tomcat parlance, contexts.

Two key concepts come into play when working with virtual hosts—the host’s domain name and its application base folder.


  • Domain name: Each virtual host is identified by the domain name that you registered for use with this host. This is the value that you expect the client browser to send in the Host: request header. A host’s name is required to be unique within its containing engine.

  • Application base folder: This fo lder is the location that contains the contexts that will be deployed to this host. This folder location can either be specified as an absolute path or as a path relative to CATALINA_BASE.


[code]
CATALINA_HOME is an environment variable that references the location
of the Tomcat binaries. The CATALINA_BASE environment variable
makes it possible to use a single binary installation of Tomcat to run
multiple Tomcat instances with different configurations (which are
primarily determined by the contents of the conf folder).
In addition, the use of a CATALINA_BASE location that is separate
from CATALINA_HOME keeps the standard binary distribution separate
from your installation. This has the beneficial effect of making it easy
to upgrade to a newer Tomcat version, without having to worry about
clobbering your existing web applications and related configuration files.
This component is covered in more detail in Chapter 7,
The Engine Component.
[/code]

Basic concepts


When it comes to mapping host names to Internet Protocol addresses, the simplest scenario is one in which a given Fully Qualified Host Name (FQHN), such as www.swengsol.com, is associated with the IP address that maps to a particular physical host.

The downside with this approach is that connecting a host to the Internet is fairly expensive. This is especially true when you consider the costs related to bandwidth, infrastructure (such as database/mail servers, firewalls, uninterruptible power supplies, fault tolerance, and so on), and maintenance (including staffing, administration, and backups), not to mention having to obtain an IP address in the first place.

As a result, many small businesses find it preferable to lease space and infrastructure from hosting service providers. The hosting service may have a single physical server that is connected to the Internet and is identified with a specific IP address. This physical server could host several domains on behalf of the provider’s customers.

For example, consider the case where Acme Widgets Inc. and Vertico LLC have their domains, www.acme-widgets.com and www.vertico.com, hosted on a single physical machine at a hosting service. The applications that are deployed to both these domains must be able to function without any interference from the other.

In this case, both these domains are termed ‘virtual’ hosts, in the sense that they appear to be represented by separate physical hosts. However, in reality, they exist simply as a logical partitioning of the address space on a single physical host.

Virtual host techniques


There are two common ways to set up virtual hosting:

  • IP-based virtual hosting

  • Name-based virtual hosting

IP-based virtual hosting


With this technique, each FQHN resolves to a separate IP address. However, each of these IP addresses resolves to the same physical machine.

You can achieve this by using either of the following mechanisms:

  • A multi-homed server, that is, a machine that has multiple physical Network Interface Cards (NICs) installed, each of which has an assigned IP address.

  • Using operating system facilities to set up virtual network interfaces by dynamically assigning multiple IP addresses to a single physical NIC.


In either case, the downside is that we need to acquire multiple IP addresses, and these addresses (at least for IPv4) are a limited resource.

The web server is configured to listen on ports that are assigned to each of these IPaddresses, and when it detects an incoming request on a particular IP address, it generates the response appropriate for that address.

For example, you can have a web server that is running on a particular physical host that is monitoring port 80 on both 11.156.33.345 and 11.156.33.346. It is configured to respond to requests that are coming in on the former IP address with content that is associated with a particular host name, say www.host1.com, whereas it is www.host2.com for the latter.

When a request comes in on 11.156.33.346, the server knows that it should serve content from the www.host2.com, and does so. To the user, this is indistinguishable from an entirely separate physical server.

Name-based virtual hosting



This is a newer technique that lets you map different domain names to the same IP address. The domain names are registered as normal, and multiple DNS entries exist to map these domain names to the same IP address.

The HTTP/1.1 protocol requires that every request must contain a Host: header that carries the fully qualified host name, as well as the port number (if specified) to which the user wishes to connect. The web server that runs on the host at the IP address will receive this request and will read this header to determine the specific virtual host that should handle this request.

Name-based virtual hosting is preferred for its simplicity and for the fact that it does not use up IP addresses needlessly.

However, you may have to use IP-based virtual hosting when you are using virtual hosts together with SSL. The reason is that the negotiation protocol commits to a certificate before it pays heed to the specific virtual host for which the request is being made. This is because the SSL protocol layer works at a lower level than the HTTP protocol, and the module negotiating this handshake with the client cannot read the HTTP request header until the handshake is complete.
[code]
You may be able to use name-based virtual hosting with SSL if
your web server and client supports the Server Name Indication
extension as specified in RFC 3546—Transport Layer Security
Extensions (http://www.ietf.org/rfc/rfc3546.txt).
Using this extension, during the SSL negotiation, the client also
transmits the host name to which it is trying to connect, thereby
allowing the web server to handle the handshake appropriately
by returning the certificate for the correct host name.
[/code]

Virtual host aliasing


Aliasing works by informing the web server that if it sees the aliased domain name in the Host: header, it should be treated in exactly the same manner as the virtual host’s domain name.

For example, if you set up swengsol.com as an alias for the www.swengsol.com virtual host, then typing either domain name in the URL will result in the same virtual host being used to process the request.

This works well when a particular host may be known by more than one domain name, and you don’t want to clutter your configuration file by creating one set of entries per alias that a user may use to connect to that host.
[code]
This component is covered in more detail in Chapter 8,
The Host Component.
[/code]

Context


A Context, or web application, is where your application specific code (servlets and JSPs) live. It provides a neat way to organize the resources that comprise a given web application.

A context maps to a ServletContext instance within the servlet specification. In many ways, the servlet specification is primarily concerned with this context component. For instance, it mandates the format for deploying a context, and dictates the contents of the deployment descriptor.

Important attributes for a context include:


  • Document base: This is the path name, either absolute or relative to its containing host’s application base, to where its WAR file or exploded folder (its content root) are located.

  • Context path: It represents the portion of the URL that uniquely identifies a web application within a given host. It helps the host container to determine which of its deployed contexts should be responsible for handling an incoming request.

    One of your contexts may be identified as the default context. This context is then the application that will be invoked when no context path is specified on the URL. This default context is identified by specifying an empty string as its context path, and as such, can be referenced by using a URL that only specifies a hostname. The default application is identified in Tomcat by a
    folder named ROOT in the application base folder for a given host.


  • Automatic reload: A c ontext’s resources can be monitored for changes, and the context reloaded automatically when any changes are detected. While this is remarkably useful during development, this is an expensive operation and should be turned off in production.


Context configuration


A Context is unique because it has multiple options when it comes to its configuration. We have already noted the presence of the conf/server.xml file that is used to set up the overall structure of the Tomcat instance. While this file’s element can be used to configure a context, this is no longer recommended.

Instead, Tomcat lets you configure a Context by letting you extract the element from the server.xml file and move it into a separate file called a context fragment file. Context fragments are monitored and reloaded by Tomcat at runtime.
[code]
Note that the server.xml file is only ever loaded once at startup.
[/code]

To ensure a clear separation of contexts by host and engine, Tomcat expects to find context fragments using a specific directory path CATALINA_HOME/conf/ //. The context fragments for contexts deployed into this host are found within this folder and are named .xml.

For the default case, that is, an engine named Catalina and a host named localhost, this works out to be the folder CATALINA_HOME/conf/Catalina/ localhost. However, the name of the host could be any valid domain name, for example, www.swengsol.com, resulting in a folder named CATALINA_HOME/conf/
Catalina/www.swengsol.com.

In addition, context fragments may also be found embedded within the META-INF folder of a web application’s WAR file or exploded directory. In such cases, the fragment must be named context.xml.

Contexts can also be configured using the web application deployment descriptor, web.xml. While the fragment file is proprietary to Tomcat, the deployment descriptor is described by the servlet specification, and therefore is portable across Java EE compliant servlet containers. We will consider both of these in much greater detail in later chapters.
[code]
This component is covered in more detail in Chapter 9,
The Context Component.
[/code]

Wrapper

A Wrapper object is a child of the context container and represents an individual servlet (or a JSP file converted to a servlet). It is called a Wrapper because it wraps an instance of a javax.servlet.Servlet.

This is the lowest level of the Container hierarchy, and any attempt to add a child to it will result in an exception being thrown.

A wrapper is responsible for the servlet that it represents, including loading it, instantiating it, and invoking its lifecycle methods such as init(), service(), and destroy().

It is also responsible, through its basic valve, for the invocation of the filters that are
associated with the wrapped servlet.
[code lang=”java”]
This component is covered in more detail in Chapter 10,
The Wrapper Component.
[/code]

Nested components

These components are specific to the Tomcat implementation, and their primary purpose is to enable the various Tomcat containers to perform their tasks.

Valve

A valve is a processing element that can be placed within the processing path of each of Tomcat’s containers—engine, host, context, or a servlet wrapper. A Valve is added to a container using the element in server.xml. They are executed in the order in which they are encountered within the server.xml file.

The Tomcat distribution comes with a number of pre-rolled valves. These include:


  • A valve that logs specific elements of a request (such as the remote client’s IPaddress) to a log file or database

  • A valve that lets you control access to a particular web application based on the remote client’s IP address or host name

  • A valve that lets you log every request and response header

  • A valve that lets you configure single sign-on access across multiple web applications on a specific virtual host

If these don’t meet your needs, you can write your own implementations of
org.apache.catalina.Valve and place them into service.

A container does not hold references to individual valves. Instead, it holds a reference to a single entity known as the Pipeline, which represents a chain of valves associated with that container.

When a container is invoked to process a request, it delegates the processing to its associated pipeline.

The valves in a pipeline are arranged as a sequence, based on how they are defined within the server.xml file. The final valve in this sequence is known as the pipeline’s basic valve. This valve performs the task that embodies the core purpose of a given container.

Unlike individual valves, the pipeline is not an explicit element in server.xml, but instead is implicitly defined in terms of the sequence of valves that are associated with a given container.

Each Valve is aware of the next valve in the pipeline. After it performs its pre processing, it invokes the next Valve in the chain, and when the call returns, it performs its own post processing before returning.

This is very similar to what happens in filter chains within the servlet specification.

In this image, the engine’s configured valve(s) fire when an incoming request is received. An engine’s basic valve determines the destination host and delegates processing to that host. The destination host’s (www.host1.com) valves now fire in sequence. The host’s basic valve then determines the destination context (here, Context1) and delegates processing to it. The valves configured for Context1 now fire and processing is then delegated by the context’s basic valve to the appropriate wrapper, whose basic valve hands off processing to its wrapped servlet.
The response then returns over the same path in reverse.
[code]
A Valve becomes part of the Tomcat server’s implementation and
provides a way for developers to inject custom code into the servlet
container’s processing of a request. As a result, the class files for custom
valves must be deployed to CATALINA_HOME/lib, rather than to the
WEB-INF/classes of a deployed application.
[/code]
As they are not part of the servlet specification, valves are non-portable elements of your enterprise application. Therefore, if you rely on a particular valve, you will need to find equivalent alternatives in a different application server.

It is important to note that valves are required to be very efficient in order not to introduce inordinate delays into the processing of a request.
[code]
The valve and pipeline components are covered in more detail in
Chapter7, The Engine Component.
[/code]

Realm

Container managed security works by having the container handle the authentication and authorization aspects of an application.
Authentication is defined as the task of ensuring that the user is who she says she is, and authorization is the task of determining whether the user may perform some specific action within an application.

The advantage of container managed security is that security can be configured declaratively by the application’s deployer. That is, the assignment of passwords to users and the mapping of users to roles can all be done through configuration, which can then be applied across multiple web applications without any coding changes being required to those web applications.
[code]
Application Managed Security
The alternative is having the application manage security. In this case,
your web application code is the sole arbiter of whether a user may access
some specific functionality or resource within your application.
[/code]

For Container managed security to work, you need to assemble the following components:


  • Security constraints: Within your web application’s deployment descriptor, web.xml, you must identify the URL patterns for restricted resources, as well as the user roles that would be permitted to access these resources.

  • Credential input mechanism: In th e web.xml deployment descriptor, you specify how the container should prompt the user for authentication credentials. This is usually accomplished by showing the user a dialog that prompts the user for a user name and password, but can also be configured to use other mechanisms such as a custom login form.

  • Realm: This is a dat a store that holds user names, passwords, and roles, against which the user-supplied credentials are checked. It can be a simple XML file, a table in a relational database that is accessed using the JDBC API, or a Lightweight Directory Access Protocol (LDAP) server that can be accessed through the JNDiAPI. A realm provides Tomcat with a consistent
    mechanism of accessing these disparate data sources.

All three of the above components are technically independent of each other. The power of container based security is that you can assemble your own security solution by mixing and matching selections from each of these groups.

Now, when a user requests a resource, Tomcat will check to see whether a security constraint exists for this resource. For a restricted resource, Tomcat will then automatically request the user for her credentials and will then check these credentials against the configured realm. Access to the resource will be allowed only if the user’s credentials are valid and if the user is a member of the role that is configured to access that resource.

Executor

This is a new element, available only since 6.0.11. It allows you to configure a shared thread pool that is available to all your connectors. This places an upper limit on the number of concurrent threads that may be started by your connectors.
Note that this limit applies even if a particular connector has not used up all the
threads configured for it.

Listener

Every major Tomcat component implements the org.apache.catalina.Lifecycle interface. This interface lets interested listeners to register with a component, to be notified of lifecycle events, such as the starting or stopping of that component.

A listener implements the org.apache.catalina.LifecycleListener interface and implements its lifecycleEvent() method, which takes a LifecycleEvent that represents the event that has occurred.

This gives you an opportunity to inject your own custom processing into Tomcat’s lifecycle.

Manager

Sessions allows ‘applications’ to be made possible over the stateless HTTP protocol. A session represents a conversation between a client and a server and is implemented by a javax.servlet.http.HttpSession instance that is stored on the server and is associated with a unique identifier that is passed back by the client on each interaction.

A new session is created on request and remains alive on the server either until it times out after a period of inactivity by its associated client, or until it is explicitly invalidated, for instance, by the client choosing to log out.

The above image shows a very simplistic view of the session mechanism within Tomcat.

An org.apache.catalina.Manager component is used by the Catalina engine to create, find, or invalidate sessions. This component is responsible for the sessions that are created for a context and their life cycles.

The default Manager implementation simply retains sessions in memory, but supports session survival across server restarts. It writes out all active sessions to disk when the server is stopped and will reload them into memory when the server is started up again.

A must be a child of a element and is responsible for managing the sessions associated with that web application context.

The default Manager takes attributes such as the algorithm that is used to generate its session identifiers, the frequency in seconds with which the manager should check for expired sessions, the maximum number of active sessions supported, and the file in which the sessions should be stored.

Other implementations of Manager are provided that let you persist sessions to a durable data store such as a file or a JDBC database.
[code]
This component is covered in more detail in Chapter 11,
The Manager Component.

[/code]

Class Loader

This element represents the class loader for a given web application. A class loader is
a very sacred entity injava. In its most basic form, it is responsible for locating the bytecode that represents a compiled Java class and interpreting it.

The bytecode for a given class may be found in a variety of locations, the most common being either on the local file system or over the network. A class loader’s primary goal is to abstract away the process of how the bytes are obtained and reconstituted into a class in memory.

Delegation model


Since Java 2, the class loading mechanism has used a delegating model, where the class loaders within a JVM are organized in a parent-child hierarchy. It is recommended that each class loader first delegate the task of finding and loading a class to its parent before it may attempt to do so itself.

This delegation mechanism ensures that no application can load in a malicious version of a system class (such as java.lang.Object) that may then compromise the integrity of the applications that are running in the JVM.

At the top of this class loader hierarchy is the Bootstrap class loader, called the primordial class loader, which is written in native code and is part of the JVM itself. Being part of the JVM ensures that there is at least one class loader that can be relied upon to load the core Java classes, such as java.lang.Object. This class loader is responsible for loading classes from the core Java packages (such as java.lang or java.util). In the SunjVM implementation, these classes are found injAVA_HOME/jre/lib/rt.jar. The Bootstrap class loader is unique in that, it is at the top of the tree, and so has no parent class loader.

Next down the hierarchy is the Extension class loader which, in the SunjVM, is a java.net.URLClassLoader that monitors the JAVA_HOME/jre/lib/ext folder for extensionjARs. Any JARs placed in this folder are automatically loaded without needing to be on the class path.

Finally, there is the System class loader (or Application class loader), which is also a
URLClassLoader in the SunjVM implementation. It monitors the folders and JARs that are described in the CLASSPATH. This class loader is responsible for loading the
application’s main class.

If a normal application needs to load a class (such as java.lang.String), it will first ask the System class loader for it. The System class loader delegates to the Extension class loader, which in turn delegates to the Bootstrap class loader, which locates the String.class file in rt.jar, loads the class and makes it available as an instance of java.lang.Class.

If an application-specific class file, such as com.swengsol.UserModel.class, is requested, the delegation process works just as before. However, this time the Bootstrap class loader is unable to locate this class in rt.jar. Next, it is the turn of the Extension class loader, and it too is unsuccessful. Finally, the System class loader has a go, and locates the class on its CLASSPATH. This class is then loaded and made
available for the JVM to use.

Caching occurs within each class loader, so each must first check its own cache to see if the class was loaded earlier. If a hit is found, then the class is returned right away.
In our previous example, if the application needed to use another String, then the
Bootstrap class loader would return its cached instance of the String class.
[code]
Endorsed Standards Override Mechanism
Both J2SE 1.4 and 1.5 include a Java APifor XML Processing Parser. The
classes for this parser are loaded by the Bootstrap class loader, and so
take precedence over any parser that you might have installed on your
classpath, even if you have a newer version of the parser classes installed.
The Endorsed Standards Override Mechanism lets you place overrides
to certain classes (CORBA and JAXP classes) in the JAVA_HOME/lib/
endorsed folder. The Bootstrap loader will then load these preferentially
over any classes that it might otherwise find. For details on this
mechanism, see http://java.sun.com/j2se/1.5.0/docs/guide/
standards/.
[/code]
Some interesting points to note about class loading are as follows:


  • A class is considered fully qualified only when it is described in terms of its package name, its class name, and the class loader instance that was used to load that class. In other words, the same class loaded by two different class loaders is treated as two distinct classes. This has implications for the assignment of instances of this class and treatment of static fields or
    singletons, even within a single JVM.

  • Each class loader can only see the class locations that are above it in the hierarchy. For example, a JAR in the Extension folder cannot use a class file on the application’s CLASSPATH. This is because the classes in the Extension folder can only see classes that are served up by either the Extension class loader or the Bootstrap class loader.

  • When code in a class references another class, the referenced class is loaded using the same class loader that loaded the referencing class, called its defining class loader. The defining class loader for a class can be obtained using Class.getClassLoader().

  • Every thread has a context class loader that can be accessed using Thread. currentThread().getContextClassLoader(). Every time a thread is created, its context class loader is set to that of its creating thread. The class loader for the main() thread is the System class loader, which is automatically propagated down to each worker thread, unless you intervene
    by invoking Thread.currentThread().setContextClassLoader().


Java EE class loading


The Java EE world throws in a bit of a twist into this model.

A servlet container is required to provide a restricted environment for its web applications.

If a servlet were to directly use the System class loader, then it would be able to see every class that was on the class path for the JVM command that was used to start Tomcat. This is potentially a security risk, as a malicious web application (as in a hosting vendor’s deployment) may be able to load classes of its sibling web applications.

As a result, each web application must be given its very own class loader, which is placed at the bottom of the tree and preferentially loads classes that are found in the WEB-INF/classes and WEB-INF/lib folders of the web application directory.

This custom class loader will only delegate to its parent class loader when the class that is being requested is one of the standard Java classes.

When a web application needs any other class, instead of delegating to its parent, this custom class loader will first check within the WEB-INF\classes and WEB-INF\lib folders.
Only if it is not found there will it delegate to its parent class loader, which will then follow the standard delegating pattern.

Tomcat’s additional class loaders Endorsed Standards



During startup, Tomcat first neutralizes the System class loader by clearing out the CLASSPATH and resetting it to point to CATALINA_HOME/bin/bootstrap.jar (for the classes required for Tomcat to start up), tomcat-juli.jar (for logging), and tools.jar (for the JSP compiler). This leaves the System class loader useful only for loading a minimal set of Tomcat-specific classes.

Tomcat also changes the endorsed directory to point to CATALINA_HOME/endorsed.

Below it, Tomcat establishes its own hierarchy of class loaders by appending the Server class loader, the Shared class loader, the Co mmon class loader, and one web application class loader per deployed application.

When a web application needs to load a class, the request first comes to the web application class loader, which is responsible (as described above) for loading the classes in the web application’s WEB-INF/classes and WEB-INF/lib folders.

This class loader first delegates to the System class loader to allow the delegation hierarchy to locate any core Java classes. If the requested class cannot be found, then the web application class loader attempts to locate the class within its own repositories. If the class is still not found, it will delegate to the Common class loader, or to the Shared class loader if it is installed.

The Shared class loader and the Server class loader are not instantiated by default. You can enable them by editing the CATALINA_HOME/conf/catalina.properties file and adding the shared.loader and server.loader entries.

The Common class loader monitors the contents of the CATALINA_HOME/lib folder, which contains commonly used JARs such as servlet-api.jar, jasper.jar, coyote.jar, and jsp-api.jar.

Classes that are placed in the Shared loader directory will be available to all web applications, but not to Tomcat’s internal classes, whereas classes that are placed in the Server loader directory will be available only to Tomcat’s internal classes.

Class reloading in web applications


Having a web application-specific class loader enables Tomcat to support class reloading.

When a context needs to be redeployed or when a class needs to be reloaded (such as when a recompiled class file is copied into WEB-INF\classes), the entire web application class loader is discarded, and a brand new instance is created to load all the classes for this web application.

This new class loader is now used to service all future requests.
[code]
This component is covered in more detail in Chapter 9,
The Context Component.
[/code]

Logger

The Logger element in server.xml has been deprecated since Tomcat 5.5. Instead, logging in Tomcat 6 is based on the Java Logging APithat was introduced injava 1.4.

Java Logging could only be configured at the entire JVM level and not at the per class loader level. To allow a different configuration file per web application, Tomcat implemented its own Java Logging implementation, known as JULI and implemented in CATALINA_HOME/bin/tomcat-juli.jar.

The global CATALINA_HOME/conf/logging.properties file controls the debug log settings. In addition, each web application can have its own logging configuration file, WEB-INF/classes/logging.properties.

As shown in the image above, logging is comprised of the following components:


  • Logger: All logging requests are made to Logger objects. These objects are arranged in a hierarchy, rooted at a root logger. This hierarchy mirrors the package hierarchy of classes. Properties can be tied to any level within this hierarchy, and a child Logger inherits properties from its parent.

  • Handler: It specifies the location where log messages should be sent. Options include a ConsoleHandler (which writes to the console), a FileHandler (which writes to a file), and a SocketHandler (which writes to a TCP socket).

  • Level: This is one of seven levels, SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST, OFF (disabled), and ALL (all messages logged), that define which message types are logged.

  • Formatter: This element determines how the information is formatted for display. Tomcat provides both a SimpleFormatter and an XMLFormatter for this purpose.

Resources

The resources associated with a web application context include static resources such as classes, HTML, JSP, and CSS files. These resources may exist in a variety of storage formats. By default, Tomcat supports retrieval of resources from either a compressed WAR file, or from an exploded folder laid out in the WAR format.

It is conceivable that a context’s resources may also be accessed from alternative storage mechanisms, such as a JDBC database. The Resources component makes this possible.

Tomcat provides a directory service implementation of the JNDiAPI, that supports access of resources in a storage-agnostic manner.
[code]
This mechanism is covered in more detail in Chapter 9,
The Context Component.
[/code]

Summary

That was a lot to take in, but now that you are done, rest assured that you understand the overall architecture of Tomcat. We looked at some of the core building blocks of Tomcat and saw how a running Tomcat instance was composed of the various Top Level Components, Connectors, and Nested Components. In the next few chapters, we will take the request processing components that were identified in this chapter and examine them in a lot more detail. But before we get there, we have one more stop to make. In the next chapter, we will explore the bootstrapping process for Tomcat.

Filed Under: Servers Tagged With: Tomcat, Tomcat 6.0

JBoss Tools 3 Developer’s Guide

October 10, 2009 by Krishna Srinivasan Leave a Comment

JBoss Tools 3 Developer’s GuideThis book will show you how to develop a set of Java projects using a variety of technologies and scenarios. Everything is described through the “eyes” of JBoss Tools.

After we settle on the project (or scenario) that will be developed, we will configure the proper environment for the current tool (those projects selected will cover between them the main components of a web application in terms of the backstage technology). We
continue by exploring the tool for accomplishing our tasks and developing the project’s components. A cocktail of images, theoretical aspects, source codes, and step-by-step examples will offer you a thoroughgoing for every tool. At the end, the project will be
deployed and tested. In addition, every chapter is “lard” with pure notions about the underlying technology, which will initiate you into, or remind you of, the basic aspects of it.

also read:

  • WebLogic Interview Questions
  • JBoss Portal Server Development
  • Tomcat Interview Questions

This book will show you complete and functional applications, and will familiarize you with the main aspects of every tool. By the end you will have been provided with sufficient information to successfully handle your own projects through JBoss Tools.

What This Book Covers

Chapter 1 is a compressive chapter that will help you discover the features brought by the new JBoss Tools 3.0. The main goal of this chapter is to make an introduction to what will follow in the next chapters and to “wake up” your curiosity. In addition, the reader
can see different possibilities of installing JBoss Tools on different platforms and for different goals.

Chapter 2 teaches you how to use Eclipse and JBoss AS in a symbiotic manner. In this chapter you will see how to use the JBoss AS Tools to configure, start, stop and monitor the JBoss AS directly from Eclipse IDE. Also, you can see how to create and deploy
new projects.

Chapter 3 is a collection of tag-components from different technologies as Ajax, JSF, RichFaces, Seam, and so on. Because the components are built on the drag-and-drop technique, this tool is very easy to use, especially when you need a fast method for
generating tags into JSP pages. This chapter will cover—with description and examples—the most important tags that can be generated through JBoss Palette. Also, the chapter will contain a section about the Palette Options.

Chapter 4 will talk about punctual framework’s tools and I will start with JBoss Tools for Java Server Faces. After I present the Faces Config Editor, which is the main visual component for JSF support, I will follow the framework mains characteristics and I will
discuss—from the JSF Tools perspective—about managed beans, validators, converters, navigation rules, and so on.

Chapter 5 will give you a complete cover of the graphical Struts editors that are used for generating/managing XML documents (configuration, tiles, validators). Also, you will see how to work with code generation and debug support for Struts projects. Everything will be sustained by images (captures) and examples.

Chapter 6 will show you how to accomplish the most important modules of a Seam project, like Action, Form, Entity, and so on through the Seam Tools filter in the first part. Later, in the second part of the chapter, you will work with the visual editors
dedicated to increasing the speed of developing/controlling Seam components.

Chapter 7 will show some advanced skills, like Hibernate and Ant, generation of POJOs, debugging goals and reverse engineering control after a detailed presentation of how to use Hibernate Tools to speed up the configuration and mapping tasks.

Chapter 8 will discuss about the jBPM Tools. You will see how to develop and test a complete jBPM project.

Chapter 9 will detail the main concepts of JBossESB Services, and you will see how to use ESB Tools to develop such a Service.

Chapter 10 will help you create from scratch a WSDL document using WSDL Editor. You will generate a complete web service from a WSDL document and from a Java bean using WS Tools wizards, and you will publish a web service using jUDDI and Web Services Explorer. In addition, you will see how to generate a web service’s client, how to test a web service through Web Services Explorer, how to convert WSDL documents to WSIL documents and how to inspect WSDL web services through WSIL and WSE.

Chapter 11 will work with the Portal Tools. You will see how to use the wizards for creating projects with Portlet Facets, creating the Java Portlet wizard and creating the JSF/Seam Portlet wizard.

JBoss Tools Palette

In this chapter, we will discuss the JBoss Tools Palette, which is a very useful tool designed especially for speeding up the development of JSP, JSF, HTML, XHTML or any other text file that contains tags. In principle, JBoss Tools Palette is a collection of
common tags, exposed through a flexible and easy-to-use interface.

By default, JBoss Tools Palette is available in the Web Development perspective that can be displayed from the Window menu by selecting the Open Perspective | Other option. In the following screenshot, you can see the default look of this palette:

Let’s dissect this palette to see how it makes our life easier!

JBoss Tools Palette Toolbar

Note that on the top right corner of the palette, we have a toolbar made of three buttons (as shown in the following screenshot). They are (from left to right):

  • Palette Editor
  • Show/Hide
  • Import

Each of these buttons accomplishes different tasks for offering a high level of flexibility and customizability. Next, we will focus our attention on each one of these buttons.

Palette Editor

Clicking on the Palette Editor icon will display the Palette Editor window (as shown in the following screenshot), which contains groups and subgroups of tags that are currently supported. Also, from this window you can create new groups, subgroups,
icons, and of course, tags—as you will see in a few moments.

As you can see, this window contains two panels: one for listing groups of tag libraries (left side) and another that displays details about the selected tag and allows us to modify the default values (extreme right). Modifying a tag is a very simple operation that can be done like this:

  1. Select from the left panel the tag that you want to modify (for example, the <div> tag from the HTML | Block subgroup, as shown in the previous screenshot).
  2. In the right panel, click on the row from the value column that corresponds to the property that you want to modify (the name column).
  3. Make the desirable modification(s) and click the OK button for confirming it (them).

Creating a set of icons

The Icons node from the left panel allows you to create sets of icons and import new icons for your tags. To start, you have to right-click on this node and select the Create | Create Set option from the contextual menu (as shown in the following screenshot).

This action will open the Add Icon Set window where you have to specify a name for this new set. Once you’re done with the naming, click on the Finish button (as shown in the following screenshot). For example, we have created a set named eHTMLi:

Importing an icon

You can import a new icon in any set of icons by right-clicking on the corresponding set and selecting the Create | Import Icon option from the contextual menu (as shown in the following screenshot):

This action will open the Add Icon window, where you have to specify a name and a path for your icon, and then click on the Finish button (as shown in the following screenshot). Note that the image of the icon should be in GIF format.

Creating a group of tag libraries

As you can see, the JBoss Tools Palette has a consistent default set of groups of tag libraries, like HTML, JSF, JSTL, Struts, XHTML, etc. If these groups are insufficient, then you can create new ones by right-clicking on the Palette node and selecting the Create | Create Group option from the contextual menu (as shown in the following screenshot).

This action will open the Create Group window, where you have to specify a name for the new group, and then click on Finish. For example, we have created a group named mygroup:

Note that you can delete (only groups created by the user) or edit groups (any group) by selecting the Delete or Edit options from the contextual menu that appears when you right-click on the chosen group.

Creating a tag library

Now that we have created a group, it’s time to create a library (or a subgroup). To do this, you have to right-click on the new group and select the Create Group option from the contextual menu (as shown in the following screenshot).

This action will open the Add Palette Group window, where you have to specify a name and an icon for this library, and then click on the Finish button (as shown in the following screenshot). As an example, we have created a library named eHTML with an icon that we had imported in the Importing an icon section discussed earlier in this chapter:

Note that you can delete a tag library (only tag libraries created by the user) by selecting the Delete option from the contextual menu that appears when you right-click on the chosen library.

Creating a new tag

After you have created a tag library, it is time to place your first tag in it. To do this, you have to right-click on the tag library and select the Create | Create Macro option from the contextual menu (as shown in the following screenshot).

This action will open the Add Palette Macro window, where you can configure the new tag. In this window, you have to specify:

  • The tag Name (mandatory)—it is displayed in Tools Palette
  • An Icon (optional)
  • Start Text of the tag (optional)
  • End Text of the tag (optional)
  • Automatically Reformat Tag Body (mandatory).

For example, let’s create a tag for representing the following HTML code, which is a scrollable HTML table with a single column. We have named the tag <mytable>:

[code lang=”html”]
<div style="overflow: auto; width: 270px; height: 375px; padding: 0px; margin: 0px;">
<table cellspacing="0" cellpadding="2"><colgroup><col width="270" /></colgroup>
<tbody>
<tr>
<td valign="top" nowrap="nowrap" width="270"></td>
</tr>
</tbody>
</table>
</div>

[/code]

For this, we fill up the Add Palette Macro as seen in the previous screenshot.

Note that you can delete a tag (only tags created by the user) by selecting the Delete option from the contextual menu that appears when you right-click on the chosen tag.

As you can see in the previous screenshot, there is no section for describing your tag definition, syntax, attributes, etc. For that you can click on the tag name and modify the description row from the right panel of the Palette Editor or you can right-click on the tag name and select the Edit option from the contextual menu. This will open the Edit window that contains a Description section as you can see in the following screenshot:


In this section, we can write a tag description in HTML format. For example, for the <mytable> tag, we have created the following description:

[code lang=”html”]

<table width="300">
<tbody>
<tr>
<td><span style="color: olive;">
<strong>Name:</strong> </span>
Scrollable table

<span style="color: olive;"> <strong>Syntax:</strong> </span>

</td>
</tr>
</tbody>
</table>
<span style="color: olive;"><strong>Atributes:</strong></span>
CSS and table specific attributes

[/code]

Now, closing t he Palette Editor by clicking the OK button will automatically add the new group, the tag library, and the tag into the JBoss Tools Palette as shown in the following figure (note the description that appears on mouse over).

Show/Hide

As the name sug gests, this feature allows us to customize the number of groups displayed in the palette. By default, the palette shows only five groups, but we can add or remove groups by clicking on this button, which displays the window as shown in the following screenshot.

In this window, select the groups and/or tag libraries that you want to see in the palette and deselect the on es that you want to remove from the palette.

Importing third-party tag libraries

A great facility of JBoss Tools Palette is the ability to import third party tag libraries. This can be done using the Import button, which opens the Import Tags from TLD file window as shown in the following screenshot.

Now, it is mandatory to set the TLD file, and a name for the new tag library. Optionally, we can specify a default prefix, a library URI, and a group that will host the tag library (this can be an existing group or a new one). For example, in the following screenshot you can see how we have imported the sql.tld library into a JSF project (for now, all you can do is imagine this case, but keeping this in mind
will help you in the following chapters, where we will create real projects):

Using tags in text files

In this section, w e will discuss inserting tags from the Palette into our text files. This is a very simple task that consists of the following steps:

  1. Navigate through the Palette until you see the tag that will be inserted.
  2. Click on this tag as you click on any button.
  3. If the tag has attributes, then you will see the Insert Tag window that allows you to customize the values of these attributes (the following screenshot represents the Insert Tag window for the <table> tag that can be found in HTML group, Table tag library). Note that if the selected tag doesn’t have any attributes to be set, then this step will be skipped and the tag will be
    inserted into your page.
  4. After you have set the values of the attributes, simply click the Finish button. This action will automatically insert the chosen tag into your page. For example, in the following screenshot you can see the effect of inserting the <mytable> tag, created in the Create a new tag section, into an empty HTML page.
  5.  If you followed Chap ter 2, then now you should have an empty project named test. Expand the test | WebContent node, right-click on it, and select New | Other option. In the New window, expand Web node and select HTML leaf. Type example
    (without the .html extension) in the File name field and click on the Finish button. Now, you have the shown example.html page and you can try to add our tag to it. Also, you can play with other tags to get used to them! In the following chapters
    this will be no more a task, it will simply be routine.

Summary

In this chapter, you have learnt how to use and customize the JBoss Tools Palette for speeding up the development process of different kinds of pages, like JSP, HTML, XHTML, etc. This will be an important skill to possess in the following chapters when we will develop projects that contain many such pages.

Filed Under: Servers Tagged With: JBoss Tools, WildFly

WebSphere Messaging

October 3, 2009 by itadmin Leave a Comment

WebSphere Application Server 7.0 Administration Guide

As a J2EE (Enterprise Edition) administrator, you require a secure, scalable, and resilient infrastructure to support and manage your J2EE applications and service-oriented architecture services.

The WebSphere suite of products from IBM provides many different industry solutions and WebSphere Application Server is the core of the WebSphere product range from IBM.

WebSphere is optimized to ease administration and improve runtime performance. It runs your applications and services in a reliable, secure, and high-performance environment to ensure that your core business opportunities are not lost due to application or infrastructure downtime.

Whether you are experienced or new to WebSphere, this book will provide you with a cross-section of WebSphere Application Server features and how to configure these features for optimal use. This book will provide you with the knowledge to build and manage performance-based J2EE applications and service-oriented architecture (SOA) services, offering the highest level of reliability, security, and scalability.

Taking you through by examples, you will be shown the different methods for installing
WebSphere Application Server and will be shown how to configure and prepare WebSphere resources for your application deployments. The facets of data-aware and message-aware applications are explained and demonstrated, giving the reader real-world examples of manual and automated deployments.

WebSphere security is covered in detail showing the various methods of implementing federated user and group repositories. Key administration features and tools are introduced, which will help WebSphere administrators manage and tune their WebSphere implementation and applications. You will also be shown how to administer your WebSphere server standalone or use the new administrative agent, which provides the ability to administer multiple installations of WebSphere Application Server using one single administration console.

also read:

  • WebLogic Interview Questions
  • JBoss Portal Server Development
  • Tomcat Interview Questions

What This Book Covers

Chapter 1, Installing WebSphere Application Server covers how to plan and prepare your WebSphere installation and shows how to manually install WebSphere using the graphical installer and how to use a response file for automated silent installation. The fundamentals of application server profiles are described and the administrative console is introduced.
Chapter 2, Deploying your Applications explains the make-up of Enterprise Archive (EAR) files, how to manually deploy applications, and how Java Naming and Directory Interface (JNDI) is used in the configuration of resources. Connecting to databases is explained via the configuration of Java database connectivity (JDBC) drivers and data sources used in the deployment of a data-aware application.
Chapter 3, Security demonstrates the implementation of global security and how to federate lightweight directory access protocol (LDAP) and file-based registries for managing WebSphere security. Roles are explained where users and groups can be assigned different administrative capabilities.
Chapter 4, Administrative Scripting introduces ws_ant, a utility for using apache Ant
build scripts to deploy and configure applications. Advanced administrative scripting is demonstrated by using the wsadmin tool with Jython scripts, covering how WebSphere deployment and configuration can be automated using the extensive WebSphere Jython scripting objects.
Chapter 5, WebSphere Configuration explains the WebSphere installation structure and key XML files, which make up the underlying WebSphere configuration repository. WebSphere logging is covered showing the types of log and log settings that are vital for administration. Application Server JVM settings and class loading are explained.
Chapter 6, WebSphere Messaging explains basic Java message service (JMS) messaging concepts and demonstrates both JMS messaging using the default messaging provider and WebSphere Message Queuing (MQ) along with explanations of message types. Use of Queue Connection Factories, Queues, and Queue Destinations are demonstrated via a sample application.
Chapter 7, Monitoring and Tuning shows how to use TivoliPerformance Monitor, request metrics, and JVM tuning settings to help you improve WebSphere performance and monitor the running state of your deployed applications.
Chapter 8, Administrative Features covers how to enable the administrative agent for
administering multiple application servers with a central administrative console. IBM HTTP Server and the WebSphere plug-in are explained.
Chapter 9, Administration Tools demonstrates some of the shell-script-based utilities vital to the WebSphere administrator for debugging and problem resolution.
Chapter 10, Product Maintenance shows how to maintain your WebSphere Application Server by keeping it up-to-date with the latest fix packs and feature packs.

WebSphere Messaging

Messaging in a large enterprise is common and a WebSphere administrator needs to understand what WebSphere Application Server can do for Java Messaging and/or WebSphere Message Queuing (WMQ) based messaging. Here, we will learn how to create Queue Connection Factories (QCF) and Queue Destinations (QD) which we will use in a demonstration application where we will demonstrate the Java Message Service (JMS) and also show how WMQ can be used as part of a
messaging implementation.

In this chapter, we will cover the following topics:

  • Java messaging
  • Java Messaging Service (JMS)
  • WebSphere messaging
  • Service integration bus (SIB)
  • WebSphere MQ
  • Message providers
  • Queue connection factories
  • Queue destinations

Java messaging

Messaging is a method of communication between software components or applications. A messaging system is often peer-to-peer, meaning that a messaging client can send messages to, and receive messages from, any other client. Each client connects to a messaging service that provides a system for creating, sending, receiving, and reading messages. So why do we have Java messaging? Messaging
enables distributed communication that is loosely-coupled. What this means is that a client sends a message to a destination, and the recipient can retrieve the message from the destination. A key point of Java messaging is that the sender and the receiver do not have to be available at the same time in order to communicate.
The term communication can be understood as an exchange of messages between software components. In fact, the sender does not need to know anything about the receiver; nor does the receiver need to know anything about the sender. The sender and the receiver need to know only what message format and what destination to use. Messaging also differs from electronic mail (email), which is a method of communication between people or between software applications and people.
Messaging is used for communication between software applications or software components. Java messaging attempts to relax tightly-coupled communication (such as, TCP network sockets, CORBA, or RMI), allowing software components to communicate indirectly with each other.

Java Message Service

Java Message Service (JMS) is an application program interface (API) from Sun. JMS provides a common interface to standard messaging protocols and also to special messaging services in support of Java programs. Messages can involve the exchange of crucial data between systems and contain information such as event notification and service requests. Messaging is often used to coordinate programs in dissimilar systems or written in different programming languages. By using the JMS interface, a programmer can invoke the messaging services like IBM’s WebSphere MQ (WMQ) formerly known as MQSeries, and other popular messaging products. In addition, JMS supports messages that contain serialized Java objects and messages that contain XML-based data.

A JMS application is made up of the following parts, as shown in the following diagram:

  • A JMS provider is a messaging system that implements the JMS interfaces and provides administrative and control features.
  • JMS clients are the programs or components, written in the Java programming language, that produce and consume messages.
  • Messages are the objects that communicate information between JMS clients.
  • Administered objects are preconfigured JMS objects created by an administrator for the use of clients. The two kinds of objects are destinations and Connection Factories (CF).


As shown in the diagram above, administrative tools allow you to create destinations and connection factories resources and bind them into a Java Naming and Directory Interface (JNDI) API namespace. A JMS client can then look up the administered objects in the namespace and establish a logical connection to the same objects through the JMS provider.

JMS features

Application clients, Enterprise Java Beans (EJB), and Web components can send or synchronously receive JMS messages. Application clients can, in addition, receive JMS messages asynchronously. A special kind of enterprise bean, the message-driven bean, enables the asynchronous consumption of messages. A JMS message can also participate in distributed transactions.

JMS concepts

The JMS API supports two models:

Point-to-point or queuing model

As shown below, in the point-to-point or queueing model, the sender posts messages to a particular queue and a receiver reads messages from the queue. Here, the sender knows the destination of the message and posts the message directly to the receiver’s queue. Only one consumer gets the message. The producer does not have to be running at the time the consumer consumes the message, nor does the consumer need to be running at the time the message is sent. Every message successfully processed is acknowledged by the consumer. Multiple queue senders and queue receivers can be associated with a single queue, but an individual message can be delivered to only one queue receiver. If multiple queue receivers are listening for messages on a queue, Java Message Service determines which one will receive the next message on a first-come-first-serve basis. If no queue receivers are listening on the queue, messages remain in the queue until a queue receiver attaches to the queue.

Publish and subscribe model

As shown by the above diagram, the publish/subscribe model supports publishing messages to a particular message topic. Unlike the point-to-point messaging model, the publish/subscribe messaging model allows multiple topic subscribers to receive the same message. JMS retains the message until all topic subscribers have received it. The Publish & Subscribe messaging model supports durable subscribers, allowing you to assign a name to a topic subscriber and associate it with a user or application. Subscribers may register interest in receiving messages on a particular message topic.
In this model, neither the publisher nor the subscriber knows about each other.

By using Java, JMS provides a way of separating the application from the transport layer of providing data. The same Java classes can be used to communicate with different JMS providers by using the JNDI information for the desired provider. The classes first use a connection factory to connect to the queue or topic, and then populate and send or publish the messages. On the receiving side, the clients then receive or subscribe to the messages.

JMS API

The JMS API is provided in the Java package javax.jms. Below are the main interfaces provided in the javax.jms package:

Messaging applications use the above listed interfaces in the Java code to implement JMS. The demo JMS Test Tool application contains code which you can look into to see how the above interfaces are used. We will cover the JMS Test Tool later in the chapter when we demonstrate how to deploy an application which uses messaging.

WebSphere messaging

WebSphere Application Server implements two main messaging sub-systems. The default-messaging-provider is internal to WebSphere and the WebSphere MQ messaging provider which uses WebSphere MQ. First, we will cover the default messaging provider which is implemented by using a SIB. Then, we will move onto the WebSphere MQ messaging provider. To demonstrate use of the SIB and the default Messaging provider, we will deploy an application which will use JMS via the SIB. Before we deploy the application, we will need to set up the JMS resources required for the application to implement Java messaging using the Java Message Service (JMS).

Default JMS provider

WebSphere Application Server comes with a default JMS provider as part of its installation and supports messaging through the use of the JMS. The default JMS provider allows applications deployed to WAS to perform asynchronous messaging without the need to install a third-party JMS provider. This is a very useful feature which runs as part of the WebSphere Application Server. The default JMS provider is utilized via the SIB and you can use the Administrative console to configure the SIB and JMS resources.

Enterprise applications use JMS CF to connect to a service integration bus. Applications use queues within the SIB to send and receive messages. An application sends messages to a specific queue and those messages are retrieved and processed by another application listening to that queue. In WebSphere, JMS queues are assigned to queue destinations on a given SIB. A queue destination is where messages can be persisted over time within the SIB. Applications can also use topics for messages. Applications publish messages to the topics. To receive messages, applications subscribe to topics. JMS topics are assigned to topic spaces on the bus. The JMS topics are persisted in the SIB and accessed via appropriate connection factories which applications use to gain access to the bus.

The following table gives a quick overview of the types of resource available for configuring JMS resources for the Default JMS provider running in the SIB.

WebSphere SIB

Before our applications can be installed and set up to use the default messaging provider, we must create a service integration bus. In a way, the SIB provides the backbone for JMS messaging when you are using the default provider. The default provider is internal to WebSphere Application Server and no third-party software is required utilize it.

A service integration bus supports applications using message-based and service-oriented architectures. A bus is a group of interconnected servers and clusters that have been added as members of the bus. Applications connect to a bus at one of the messaging engines associated with its bus members.

Creating a SIB

To create a Service Integration Bus (SIB), log into the admin console and navigate to the Service integration section within the lefthand side panel and click on Buses,
as shown in the following screenshot:

Click New to enter the Create a new Service Integration Bus page where we will begin our SIB creation. Type InternalJMS in the Enter the name of your new bus field and uncheck the Bus security checkbox as shown below and then click Next.

On the next screen, you will be prompted to confirm your SIB settings. Click Finish to complete the creation of the SIB. Once the wizard has completed, click Save to retain your configuration change. You will be returned to a screen which lists the available SIBs installed in your WebSphere configuration. Now that the SIB has been created, you can click on the SIB name to configure settings and operation of the SIB. We will not be covering managing a SIB in this book as it is beyond our scope. All we need to do is create a SIB so we can demonstrate an application using the default JMS provider which requires a SIB to operate.

To complete the configuration, we must add an existing server as a member to the SIB so that we have a facility for message persistence. The SIB is just a service integration bus, almost like a connecting conduit, however we need and actual members, which in our case will be our application server called server1, which contain the actual implementation for the message store.

To add a server as a bus member, click on the bus name called InternalJMS in the SIB list and then navigate to the Topology section and click Bus members as shown below.

You will now be presented with a screen where you can add bus members. Click Add and you will be able to select the server you wish to add as a member to the bus. You will notice that the server is already pre-selected as shown below.

Click Next to the final screen, where you will select the File store option from the option group field labeled Choose type of message store for the persistence of message state. Click Next to view the next configuration page where we will use the page defaults. Click Next to enter the Tune performance parameters page where we will also use the defaults. Clicking Next again will take you to the final summary page where you will click Finish to finalize adding the application server as a bus member. Click Save to retain the changes. You will now see the application server called server1 listed as a bus member. Now we can move on to configure the JMS resources.

Configuring JMS

Once we have created a SIB, we can configure JMS resources. The types of resources we need to create depend entirely upon the application you are deploying. In our demo JMS application, we are going to demonstrate putting a message on a queue using a sending Servlet which places messages on a queue, known as the sender, and then demonstrate receiving a message on the receiving Servlet, known as the receiver. This exercise will give you a detailed enough overview of a simple implementation of JMS. To continue, we will need to set up a queue connection factory which the application will use to connect to a message queue and an actual queue which the application will send messages to and receive messages from.

Creating queue connection factories

To create a queue connection factory, navigate to the Resources section of the left-hand-side panel in the Administrative console and click Queue connection factories from the JMS category as shown below.

Select a scope of cell from the cell-scope pick-list and then click New to create a new
QCF. In the Select JMS resource provider screen as shown below, select Default messaging provider from the available provider options and click OK.

On the next page, you will be asked to fill in configuration settings for the QCF. We will only need to fill in a few fields. As shown below, type QCF.Test in the Name field, jms/QCF.Test in the JNDI name field and select the bus called InternalJMS
from the Bus name field.

Click Apply and then Save when prompted to do so in order to retain the changes.
You will now see the QCF listed in the list of configured QCF.

Creating queue destinations

To create a queue, we will follow a similar process to creating a QCF. Select Queues from the JMS category located in the Resources section found in the left-hand-side panel of the Admin console.

Select Default messaging provider from the list of messaging providers and then click on OK to enter the queue configuration page.

On the queue configuration page, enter Q.Test in the Name field and jms/Q.Test in the JNDI name field.

Select InternalJMS from the Bus name field found in the Connection section and select Create Service Bus destination from the Queue name field and click Apply. You will then be prompted to create a queue destination.

In the Create a new queue for point-to-point messaging screen, type QD.Test in the identifier field and click Next.

In the following screen of the wizard labelled Assign the queue to a bus member, you will see that server1 sis already pre-selected in the field called Bus member. The bus mentioned in the Bus member field is where the actual queue destination will be created Clicking Next will present you with the final step, a summary screen where you can click Finish and then Save to retain your queue configuration.

To view your queue destination, you need to select the bus called InternalJMS from the list of buses found by navigating to the Service integration section of the left-hand-side panel from the Admin console and then click Buses. You will recognize this screen as the main bus configuration page we used when we created the SIB. Click the Destinations link located in the Destination resources section shown in the Destinations page as shown in the screenshot below.

You will then be presented with a list of queue destinations in the SIB.

To create Topics Connection Factories (TCF) and Topic Destinations (TD) for publish/subscribe messaging, you can follow a similar process. Publish/subscribe messaging will not be demonstrated in this book; however, you can use the process defined for creating QCF and QD as an example of how to create TCF and TD.

Installing the JMS demo application

To demonstrate the use of QCF and QD in the SIB, we will manually deploy an EAR file which contains two servlets that can be used to test JMS configurations.

The JMS Test Tool application is a web application which provides a controller Servlet, which will process requests from an input page, which allows a user to put a simple message on a queue then get the message. The application is not industrial strength; however, it goes a long way to demonstrating the basics of JMS. The application can be downloaded from www.packtpub.com and it also contains all the source code, so you can look into the mechanics of simple JMS programming. We will not explain the code in this chapter as it detracts from administration; however, feel free to change the code and experiment in your learning of JMS.

After you have downloaded the JMSTester.ear file to your local machine, use the Admin console to deploy it using the instructions in Chapter 2 as a guide. We will take you through some screens to ensure you correctly configure the appropriate resources as part of the installation.

When you start the installation (deployment) of the EAR file, ensure you select the option called Detailed from the How do you want to install the application? section on the Preparing for the application installation screen as shown below to expose the configuration steps required by the EAR file, otherwise you will be given the default JMS configuration and you might not understand how JMS has been configured in the application. Another good reason for selecting the Detailed option is that the wizard will present extra screens which will allow you to optionally override the JNDI mappings for resource references.

On the Install New Application screen, change the application name to JMS Test Tool, and then keep clicking Next until you come to Step 6, the Bind message destination references to administered objects page. When you get to this page, type jms/Q.Test in the Target Resource JNDI Name field, which means you want to bind the application’s internal resource reference called jms/Queue to the WebSphere configured JMS queue destination called jms/Q.Test (which we created earlier) as shown below.

Using this level of JNDI abstraction means that the application does not need to know the actual JMS implementation technology, which in this case happens to be the internal WebSphere Default JMS provider. Click Next to proceed to the next step of the wizard. The next screen of the wizard will be the Map resource references to resources screen where you will be given the option of binding the applications JNDI resource declarations to the actual JNDI implementation as configured in WebSphere. In the image below you can see that the application has been configured to point to a QCF called jms/QCF, however in our configuration of WebSphere we have called our connection factory jms/QCF.Test. Type jms/QCF.Test into the Target Resource JNDI Name field.

This concept of abstraction which WebSphere offers to J2EE applications which utilize indirect JNDI naming is a very powerful and very important part of configuring enterprise applications. Using indirect JNDI allows for the decoupling of the application from the application server actual implementation of JMS. The application is then pointed to the JNDI which it will use to look up the actual resource reference that has been configured in WebSphere. So, in simple words, the administrator decides what messaging sub-system the application will be using and is transparent to the application.

We have now completed the configuration elements that require user intervention, so we can keep clicking Next until the application wizard is complete. If you get any warning as shown below, you can ignore it; the warnings come up due to WebSphere telling you that you have configured the QCF and queue destinations at cell level, and that other applications could be referencing them as well. Just click Continue to move on to the next steps.

When you come to the Context root page, take note that the EAR file has been configured to use JMSTester as the web applications context root. We will leave this as defaulted for our demonstration; however, you could override it by typing in another context root. When you get to the Summary page of the wizard, click on Finish and Save to retain the applications deployment.

JMS Test Tool application

The JMS Test Tool application provides a simple test harness to send and receive messages to and from queues. The application can be downloaded from http://www.packtpub.com. To launch the deployed application, you can use the following URL:
[code]
http://<host_name>:9080/JMSTester/.
[/code]

If the application is deployed and has started error-free, you will be presented with the JMS Test Tool interface, which is a set of three HTML frames, as shown below.

The main frame is the top-most frame where you enter a test message as shown below. The left-hand-side bottom frame provides help on how to use the tool, and the right-hand-side frame will show the results of a send or get message action.

If you click Put Message, you will see that the left-hand-side bottom frame displays the status of the message being sent as shown below. Each time you click Put Message, a new message will be put on the queue.

If you click Get Message, you will see that the left-hand-side bottom frame displays the contents of a given message retrieved from the queue as shown below.

Each time you click Get Message, the next message will be read from the queue until there are no more messages.

You can use this application to test both JMS and local MQ queue managers. This concludes our overview of using JMS and the default messaging provider.

WebSphere MQ overview

WebSphere MQ formerly known as MQ Series is IBM’s enterprise messaging solution. In a nutshell, MQ provides the mechanisms for messaging both in point-to-point and publish-subscribe. However, it guarantees to deliver a message only once. This is important for critical business applications which implement messaging. An example of a critical system could be a banking payments system where messages contain messages pertaining to money transfer between banking systems, so guaranteeing delivery of a debit/credit is paramount in this context. Aside from guaranteed delivery, WMQ is often used for messaging between dissimilar systems and the WMQ software provides programming interfaces in most of the common languages, such as Java, C, C++, and so on. If you are using WebSphere, then it is common to find that WMQ is often used with WebSphere when WebSphere is hosting message-enabled applications. It is important that the WebSphere administrator understands how to configure WebSphere resources so that application can be coupled to the MQ queues.

Overview of WebSphere MQ example

To demonstrate messaging using WebSphere MQ, we are going to re-configure the previously deployed JMS Tester application so that it will use a connection factory which communicates with a queue on a WMQ queue manager as opposed to using the default provider which we demonstrated earlier.

Installing WebSphere MQ

Before we can install our demo messaging application, we will need to download and install WebSphere MQ 7.0. A free 90-day trial can be found at the following URL:
[code]
http://www.ibm.com/developerworks/downloads/ws/wmq/.
[/code]

Click the download link as shown below.

Similar to Chapter 1, you will be prompted to register as an IBM website user before you can download the WebSphere MQ Trial. Once you have registered and logged in, the download link above will take you to a page which lists download for different operating systems.
Select WebSphere MQ 7.0 90-day trial from the list of available options as
shown below.

Click continue to go to the download page. You may be asked to fill out a questionnaire detailing why you are evaluating WebSphere MQ (WMQ). Fill out the question as you see fit and submit to move to the download page.

As shown above, make sure you use the IBM HTTP Download director as it will
ensure that your download will resume, even if your Internet loses a connection.
[code]
If you do not have a high-speed Internet connection, you can try
downloading a free 90-day trial of WebSphere MQ 7.0 overnight
while you are asleep.
[/code]

Download the trial to a temp folder, for example c:\temp, on your local machine. The screenshot above shows how the IBM HTTP Downloader will prompt for a location where you want to download it to. Once the WMQ install file has been downloaded, you can then upload the file using an appropriate secure copy utility like Winscp to an appropriate folder like /apps/wmq_install on your Linux machine. Once you have the file uploaded to Linux, you can then decompress the file and run the installer to install WebSphere MQ.

Running the WMQ installer

Now that you have uploaded the WMQv700Trial-x86_linux.tar file on your Linux machine, and follow these steps:

  1. You can decompress the file using the following command:
    gunzip ./WMQv700Trial-x86_linux.tar.gz
  2. Then run the un-tar command:
    tar -xvf ./ WMQv700Trial-x86_linux.tar
  3. Before we can run the WMQ installations, we need to accept the license agreement by running the following command:
    ./mqlicense.sh –accept
  4. To run the WebSphere MQ installation, type the following commands:
    rpm -ivh MQSeriesRuntime-7.0.0-0.i386.rpm
    rpm -ivh MQSeriesServer-7.0.0-0.i386.rpm
    rpm -ivh MQSeriesSamples-7.0.0-0.i386.rpm
  5. As a result of running the MQSeriesServer installation, a new user called mqm was created. Before running any WMQ command, we need to switch to this user using the following command:
    su – mqm
  6. Then, we can run commands like the dspmqver command which can be run to check that WMQ was installed correctly. To check whether WMQ is installed, run the following command:
    /opt/mqm/bin/dspmqver

The result will be the following message as shown in the screenshot below:

Creating a queue manager

Before we can complete our WebSphere configuration, we need to create a WMQ queue manager and a queue, then we will use some MQ command line tools to put a test message on an MQ queue and get a message from an MQ queue.

  1. To create a new queue manager called TSTDADQ1, use the following command:
    crtmqm TSTDADQ1
  2. The result will be as shown in the image below.
  3. We can now type the following command to list queue managers:
    dspmq
  4. The result of running the dspmq command is shown in the image below.
  5. To start the queue manager (QM), type the following command:
    strmqm
  6. The result of starting the QM will be similar to the image below.
  7. Now that we have successfully created a QM, we now need to add a queue called LQ.Test where we can put and get messages.
  8. To create a local queue on the TSTDADQ1 QM, type the following commands in order:
    runmqsc TSTDADQ1
  9. You are now running the MQ scripting command line, where you can issue MQ commands to configure the QM.
  10. To create the queue, type the following command and hit Enter:
    define qlocal(LQ.TEST)
  11. Then immediately type the following command:
    end
  12. Hit Enter to complete the QM configuration, as shown by the following screenshot.


You can use the following command to see if your LQ.TEST queue exists.
[code]
echo "dis QLOCAL(*)" | runmqsc TSTDADQ1 | grep -i test
[/code]
You have now added a local queue called Q.Test to the TSTDADQ1 queue manager.
[code]
runmqsc TSTDADQ1
DEFINE LISTENER(TSTDADQ1.listener) TRPTYPE (TCP) PORT(1414)
START LISTENER(TSTDADQ1.listener)
End
[/code]

You can type the following command to ensure that your QM listener is running.
[code]
ps -ef | grep mqlsr
[/code]
The result will be similar to the image below.

To create a default channel, you can run the following command.
[code]
runmqsc TSTDADQ1
DEFINE CHANNEL(SYSTEM.ADMIN.SVRCONN) CHLTYPE(SVRCONN)
End
[/code]

We can now use a sample MQ program called amqsput which we can use to put and get a test message from a queue to ensure that our MQ configuration is working before we continue to configure WebSphere.

Type the following command to put a test message on the LQ.Test queue:
[code lang=”java”]
/opt/mqm/samp/bin/amqsput LQ.TEST TSTDADQ1
[/code]
Then you can type a test message: Test Message and hit Enter; this will put a message on the LQ.Test queue and will exit you from the AMQSPUTQ command tool.

Now that we have put a message on the queue, we can read the message by using the MQ Sample command tool called amqsget. Type the following command to get the message you posted earlier:
[code]
/opt/mqm/samp/bin/amqsget LQ.TEST TSTDADQ1
[/code]
The result will be that all messages on the LQ.TEST queue will be listed and then the tool will timeout after a few seconds as shown below.

We need to do two final steps to complete and that is to add the root user to the mqm group. This is not a standard practice in an enterprise, but we have to do this because our WebSphere installation is running as root. If we did not do this, we would have to reconfigure the user which the WebSphere process is running under and then add the new user to MQ security. To keep things simple, ensure that root is a member of the mqm group, by typing the following command:
[code]
usermod -a -G mqm root
[/code]
We also need to change WMQ security to ensure that all users of the mqm group have access to all the objects of the TSTDADQ1 queue manager. To change WMQ security to give access to all objects in the QM, type the following command:
[code]
setmqaut -m TSTDADQ1 -t qmgr -g mqm +all
[/code]
Now, we are ready to re-continue our configuring WebSphere and create the appropriate QCF and queue destinations to access WMQ from WebSphere.

Creating a WMQ connection factory

Creating a WMQ connection factory is very similar to creating a JMS QCF. However, there are a few differences which will be explained in the following steps. To create a WMQ QCF, log in to the Admin console and navigate to the JMS category of the Resources section found in the left-hand-side panel of the Admin console and click on Queue connection factories. Select the Cell scope and click on New. You will be presented with an option to select a message provider. Select WebSphere MQ messaging provider as shown below and click OK.

You will then be presented with a wizard which will first ask you for the name of the QCF. Type QCF.LQTest in the Name field and type jms/QCF.LQTest in the JNDI
name
field, as shown below.

Click on Next to progress to the next step of the wizard, where you will decide on how to connect to WMQ. As shown in the following screenshot, select the Enter all the required information into this wizard option and then click on Next.

In the Supply queue connection details screen, you will need to type TSTDADQ1 into the Queue manager or queue sharing group name field and click on Next.

On the next screen of the wizard, you will be asked to fill in some connection details.
Ensure that the Transport field is set to Bindings then client. Type localhost in the hostname field and then add the value 1414 to the Port field, and type SYSTEM. ADMIN.SVRCONN into the Server connection channel field as shown below and then click on Next to move on to the next step of the wizard.

On the next page, you will be presented with a button to test your connection to WMQ. If you have set up WMQ correctly, then you will be able to connect and a results page will be displayed confirming a successful connection to WMQ. If you cannot connect at this stage, then you will need to check your MQ setup. Most often it is security that is the problem. If you find you have an issue with security, you can search Google for answers on how to change WMQ security. Once your test is successful, click on Next to move on to the final Summary page which will list your QCF configuration. On the final page of the wizard, click Finish to complete the WMQ QCF configuration and click Save to retain your changes. You will now see two QCF configurations, one for JMS and one for WMQ, as shown below:

Creating a WMQ queue destination

The next step after creating a QCF is to create a queue destination. We will use the queue named LQ.Test which we created on the TSTDADQ1 queue manager. To create a new queue, navigate to the JMS category of the Resources section in the left-hand-side panel of the admin console and click Queues. Click on New to start the queue creation wizard. In the provider selector screen, select WebSphere MQ messaging provider and click on Next. You will then be presented with a page that allows you to specify settings for the queue. In the Name field, type LQ.Test and then type jms/LQ.Test in the JNDI name field. In the Queue name field, type LQ.TEST which is the actual name for the underlying queue, as shown below.
[code]
Useful tip: Optionally, you can type the Queue Manager name,
for example, TSTDADQ1 into the Queue manager or queue
sharing group name field, but if you ever use WMQ clustering,
it is not required and will stop MQ clustering from working correctly.
[/code]

Click on Apply to submit the changes, and then click on Save to retain the changes to the WebSphere configuration repository. You will then be presented with a list of queues as shown below:

We have now configured a WebSphere MQ queue connection factory and a WebSphere MQ queue destination which our test application will use to send and receive messages from WMQ.

Reconfiguring the JMS demo application

Now that we have created a QCF and queue destination using WMQ as the message provider, we will need to reconfigure the JMS Test Tool application to point to the WMQ JNDI names as opposed to the Default Provider JNDI names. When we deployed the application, the installation wizard allowed us the option of re-pointing of the JNDI names. This was because the application’s deployment descriptor declared resource references, which the installation wizard picked up and presented as configurable options in the installation wizard. Even after a deployment is complete, it is possible to reconfigure an application at any time by drilling down into the application configuration. We want to change the JNDI names the application is using for the QCF and queue destination. We are going to change jms/QCF.Test to jms/ QCF.LQTest and jms/Q.Test to jms/LQ.Test. This re-mapping of the applications JNDI will allow the application to use WMQ instead of JMS via the SIB. To change the application’s resource references, click Applications in the left-hand-side panel of the
Admin console, and then expand the Application Types section and click WebSphere
enterprise applications
. Click on the JMS Test Tool from the application list. You will
then be presented with the main application configuration panel. Look for a section called References as shown in the following screenshot:

Click on the Resource references link and change the Target Resource JNDI Name
field to jms/QCF.LQTest as shown below and then click on OK to return back to the
previous page.

Click on Continue if you get any warnings. We have now re-pointed the application’s QCF reference to the new WMQ QCF configuration.
To change the queue destination, we click on the Message destination references link
and change the Target Resource JNDI Name field to jms/LQ.Test as shown below.

We have now completed the re-mapping of resources. Click on Save to make the changes permanent and restart the application server. When you next use the JMS Test Tool application, the sending and receiving of messages will be using WMQ instead of the Default Messaging Provider.
[code]
You can use the following command to show the messages sitting
on the LQ.TEST queue if you wish to see the queue depth (how many
messages are on the queue):

echo "dis ql(*) curdepth where (curdepth gt 0)" |
runmqsc TSTDADQ1
[/code]

Summary

In this chapter, we learned that WebSphere provides a level of abstraction to messaging configuration by allowing resources to be referenced by JNDI. We deployed a message-enabled application which required a queue connection factory and queue destination which it used to send and receive messages. We configured two different implementations of JMS. One implementation used the internal Default Messaging Provider, which required a SIB to be created, and we covered how to create the QCF and queue destinations and bound the applications resource references to those configured in WebSphere.

We then covered how to install WebSphere MQ and larned how to create a queue manager and a queue. Then, in WebSphere, we created a QCF and queue destination using the WebSphere MQ provider and demonstrated how to to re-map our applications resource references to re-point the application to use MQ messaging subsystem as opposed to the internal messaging subsystem.

There are many uses of messaging in enterprise applications and we have essentially covered the key areas for configuring WebSphere to facilitate resources for message-enabled applications.

Filed Under: Servers Tagged With: Messaging, WebSphere

Drools JBoss Rules 5.0 – Human-readable Rules

August 25, 2009 by Krishna Srinivasan Leave a Comment

Drools JBoss Rules 5.0 Developer’s GuideBusiness rules and processes can help your business by providing a level of agility and flexibility. As a developer, you will be largely responsible for implementing these business rules and processes effectively, but implementing them systematically can often be difficult due to their complexity. Drools, or JBoss Rules, makes the process of implementing these rules and processes quicker and handles the complexity, making your life a lot easier!

also read:

  • WebLogic Interview Questions
  • JBoss Portal Server Development
  • Tomcat Interview Questions

This book guides you through various features of Drools, such as rules, ruleflows, decision tables, complex event processing, Drools Rete implementation with various optimizations, and others. It will help you to set up the Drools platform and start creating your own business. It’s easy to start developing with Drools if you follow our real-world examples that are intended to make your life easier.

Starting with an introduction to the basic syntax that is essential for writing rules, the book will guide you through validation and human-readable rules that define, maintain, and support your business agility. As a developer, you will be expected to represent policies, procedures, and constraints regarding how an enterprise conducts its business; this book makes it easier by showing you the ways in which it can be done.

A real-life example of a banking domain allows you to see how the internal workings of the rules engine operate. A loan approval process example shows the use of the Drools Flow module. Parts of a banking fraud detection system are implemented with Drools Fusion module, which is the Complex Event Processing part of Drools. This in turn, will help developers to work on preventing fraudulent users from accessing systems in an illegal way.

Finally, more technical details are shown on the inner workings of Drools, the implementation of the ReteOO algorithm, indexing, node sharing, and partitioning.

What This Book CoversChapter 1: This chapter introduces the reader to the domain of business rules and business processes. It talks about why the standard solutions fail at implementing complex business logic. It shows a possible solution in the form of a declarative programming model. The chapter talks about advantages and disadvantages of Drools. A brief history of Drools is also mentioned.

Chapter 2: This chapter shows us the basics of working with the Drools rule engine—Drools Expert. It starts with a simple example that is explained step-by-step. It begins with the development environment setup, writing a simple rule, and then executing it. The chapter goes through some necessary keywords and concepts that are needed for more complex examples.

Chapter 3: This chapter introduces the reader to a banking domain that will be the basis for examples later in this book. The chapter then goes through an implementation of a decision service for validating this banking domain. A reporting model is designed that holds reports generated by this service.

Chapter 4: This chapter shows how Drools can be used for carrying out complex data transformation tasks. It starts with writing some rules to load the data, continues with the implementation of various transformation rules, and finally puts together the results of this transformation. The chapter shows how we can work with a generic data structure such as a map in Drools.

Chapter 5: The focus of this chapter is on rules that are easy to read and change. Starting with domain specific languages, the chapter shows how to create a data transformation specific language. Next, it focuses on decision tables as another more user-friendly way of representing business rules. An interest rate calculation example is shown. Finally, the chapter introduces the reader to Drools Flow module as a way of managing the rule execution order.

Chapter 6: This chapter talks about executing the validation decision service in a stateful manner. The validation results are accumulated between service calls. This shows another way of interacting with a rule engine. Logical assertions are used to keep the report up-todate. Various ways of serializing a stateful session are discussed.

Chapter 7: This chapter talks about Drools Fusion—another cornerstone of the Drools platform is about writing rules that react to various events. The power of Drools Fusion is shown through a banking fraud detection system. The chapter goes through various features such as events, type declarations, temporal operators, sliding windows, and others.

Chapter 8: This chapter goes into more detail about the workflow aspect of the Drools platform. It is showed through a loan approval service that demonstrates the use of various nodes in a flow. Among other things, the chapter talks about implementing a custom work item, human task, or a sub-flow.

Chapter 9: The purpose of this chapter is to show you how to integrate Drools in a real web application. We’ll go through design and implementation of persistence, business logic, and presentation layers. All of the examples written so far will be integrated into this application.

Chapter 10: The focus of this chapter is to give you an idea about the various ways of testing your business logic. Starting with unit testing, integration testing through acceptance testing that will be shown with the help of the Business Rules Management Server—Guvnor, this chapter provides useful advice on various troubleshooting techniques.

Chapter 11: This chapter shows integration with the Spring Framework. It describes how we can make changes to rules and processes while the application runs. It shows how to use an external build tool such as Ant to compile rules and processes. It talks about the rule execution server that allows us to execute rules remotely. It briefly mentions support of various standards.

Chapter 12: This chapter goes under the hood of the Drools rule engine. By understanding how the technology works, you’ll be able to write more efficient rules and processes. It talks about the ReteOO algorithm, node sharing, node indexing, and rule partitioning for parallel execution.

Human-readable Rules (JBoss Rules 5.0)

Business rules implementations presented so far were aimed mostly at developers. However, it is sometimes needed that these rules are readable and understandable by the business analysts. Ideally, they should be able to change the rules or even write new ones. An important aspect of business rules is their readability and user friendliness. Looking at a rule, you should immediately have an idea of what it is about. In this chapter, we’ll look at Domain Specific Languages (DSLs), decision tables, and rule flows to create human-readable rules.

Domain Specific Language

The domain in this sense represents the business area (for example, life insurance or billing). Rules are expressed with the  terminology of the problem domain. This means that domain experts can understand, validate, and modify these rules more easily.

You can think of DSL as a translator. It defines how to translate sentences from the problem-specific terminology into rules. The translation process is defined in a .dsl file. The sentences themselves are stored in a .dslr file. The result of this process must be a valid .drl file.

Building a simple DSL might look like:

[code lang=”java”] [condition][]There is a Customer with firstName
{name}=$customer : Customer(firstName == {name})
[consequence][]Greet Customer=System.out.println("Hello " +
$customer.getFirstName());
[/code]

Code listing 1: Simple DSL file simple.dsl.

[code] The code listing above contains only two lines (each begins with [).
However, because the lines are too long, they are wrapped effectively
creating four lines. This will be the case in most of the code listings.

When you are using the Drools Eclipse plugin to write this DSL, enter the
text before the first equal sign into the field called <b>Language expression</b>,
the text after equal sign into <b>Rule mapping</b>, leave the object field blank
and select the correct scope.
[/code]

The previous DSL defines two DSL mappings. They map a DSLR sentence to a DRL rule. The first one translates to a condition that matches a Customer object with the specified first name. The first name is captured into a variable called name. This variable is then used in the rule condition. The second line translates to a greeting message that is printed on the console. The following .dslr file can be written based on the previous DSL:

[code lang=”java”] package droolsbook.dsl;
import droolsbook.bank.model.*;
expander simple.dsl
rule "hello rule"
when
There is a Customer with firstName "David"
then
Greet Customer
end
[/code]

Code listing 2: Simple .dslr file (simple.dslr) with rule that greets a customer with name David.

As can be seen, the structure of a .dslr file is the same as the structure of a .drl file. Only the rule conditions and consequences are different. Another thing to note is the line containing expander simple.dsl. It informs Drools how to translate sentences in this file into valid rules. Drools reads the simple.dslr file and tries to translate/expand each line by applying all mappings from the simple.dsl file (it does it in a single pass process, line-by-line from top to bottom). The order of lines is important in a .dsl file. Please note that one condition/consequence must be written on one line, otherwise the expansion won’t work (for example, the condition after the when
clause, from the rule above, must be on one line).

When you are writing .dslr files, consider using the Drools Eclipse plugin. It provides a special editor for .dslr files that has an editing mode and a read-only mode for viewing the resulting .drl file. A simple DSL editor is provided as well.

The result of the translation process will look like the following screenshot:

jboss-rules-1This translation process happens in memory and no .drl file is physically stored. We can now run this example. First of all, a knowledge base must be created from the simple.dsl and simple.dslr files. The process of creating a package using a DSL is as follows (only the package creation is shown, the rest is the same as we’ve seen in Chapter 2, Basic Rules):

jboss-rules-2KnowledgeBuilder acts as the translator. It takes the .dslr file, and based on the .dsl file, creates the DRL. This DRL is then used as normal (we don’t see it; it’s internal to KnowledgeBuilder). The implementation is as follows:

[code lang=”java”] private KnowledgeBase createKnowledgeBaseFromDSL()
throws Exception {
KnowledgeBuilder builder =
KnowledgeBuilderFactory.newKnowledgeBuilder();
builder.add(ResourceFactory.newClassPathResource(
"simple.dsl"), ResourceType.DSL);
builder.add(ResourceFactory.newClassPathResource(
"simple.dslr"), ResourceType.DSLR);
if (builder.hasErrors()) {
throw new RuntimeException(builder.getErrors()
.toString());
}
KnowledgeBase knowledgeBase = KnowledgeBaseFactory
.newKnowledgeBase();
knowledgeBase.addKnowledgePackages(
builder.getKnowledgePackages());
return knowledgeBase;
}
[/code]

Code listing 3: Creating knowledge base from .dsl and .dslr files.

The .dsl and subsequently the .dslr files are passed into KnowledgeBuilder. The rest is similar to what we’ve seen before.

DSL as an interface

DSLs can be also looked at as another level of indirection between your .drl files and business requirements. It works as shown in the following figure:

jboss-rules-3The figure above shows DSL as an interface (dependency diagram). At the top are the business requirements as defined by the business analyst. These requirements are represented as DSL sentences (.dslr file). The DSL then represents the interface between DSL sentences and rule implementation (.drl file) and the domain model. For example, we can change the transformation to make the resulting rules more efficient without changing the language. Further, we can change the language, for example, to make it more user friendly, without changing the rules. All this can be done just by changing the .dsl file.

DSL for validation rules

The first three implemented object/field required rules from Chapter 2, Basic Rules, can be rewritten as:

  • If the Customer does not have an address, then Display warning message
  • If the Customer does not have a phone number or it is blank, then Display error message
  • If the Account does not have an owner, then Display error message for Account

We can clearly see that all of them operate on some object (Customer/Account), test its property (address/phone/owner), and display a message (warning/error) possibly with some context (account). Our validation.dslr file might look like the following code:

[code] expander validation.dsl
rule "address is required"
when
The Customer does not have address
then
Display warning
end
rule "phone number is required"
when
The Customer does not have phone number or it is blank
then
Display error
end
rule "account owner is required"
when
The Account does not have owner
then
Display error for Account
end
[/code]

Code listing 4: First DSL approach at defining the required object/field rules (validation.dslr file).

The conditions could be mapped like this:

[code lang=”java”]
[condition][]The {object} does not have {field}=${object} : {object}(
{field} == null )
[/code]

Code listing 5: validation.dsl.

This covers the address and account conditions completely. For the phone number rule, we have to add the following mapping at the beginning of the validation.dsl file:

[code lang=”java”]
[condition][] or it is blank = == "" ||
[/code]

Code listing 6: Mapping that checks for a blank phone number.

As it stands, the phone number condition will be expanded to:

[code lang=”java”]
$Customer : Customer( phone number == "" || == null )
[/code]

Code listing 7: Unfinished phone number condition.

To correct it, phone number has to be mapped to phoneNumber. This can be done by adding the following at the end of the validation.dsl file:

[code lang=”java”]
[condition][]phone number=phoneNumber
[/code]

Code listing 8: Phone number mapping.

The conditions are working. Now, let’s focus on the consequences. The following mapping will do the job:

[code lang=”java”] [consequence][]Display {message_type} for {object}={message_type}(
kcontext, ${object} );
[consequence][]Display {message_type}={message_type}( kcontext );
[/code]

Code listing 9: Consequence mappings.

The three validation rules are now being expanded to the same .drl representation as we’ve seen in Chapter 2.

File formats

Before we go further, we’ll examine each file format in more detail.

DSL file format

A line in a .dsl file has the following format:

[code lang=”java”]
[<scope>][<Type>]<language expression>=<rule mapping>
[/code]

Code listing 10: The format of one line in a .dsl file.

As we’ve already seen, an example of a line in DSL file might look like this:

[code lang=”java”]
[condition][droolsbook.bank.model.Customer]The Customer does not have
address=Customer(address == null)
[/code]

Code listing 11: Sample line from DSL file (note that it is just one line that has been wrapped).

The scope can have the following values:

  • condition: Specifies that this mapping can be used in the condition part of a rule.
  • consequence: Specifies that this mapping can be used in the consequence part of a rule.
  • *: Specifies that this mapping can be used in both the condition and the consequence part of a rule.
  • keyword: This mapping is applied to the whole file (not just the condition or the consequence part). Used mainly when writing DSLs in languages other than English or to hide the package/import/global statements at the beginning of the file behind a business friendly sentence.

Type can be used to further limit the scope of the mapping. Scope and Type are used by the Drools Eclipse plugin to provide auto-completion when writing .dslr files (when pressing Ctrl + Space, only relevant choices are offered). This is especially useful with the multiple constraints feature (refer to the section, DSL for multiple constraints in a condition).

DSL supports comments by starting the line with the hash character, #. For example:

[code lang=”java”] #this is a comment in a .dsl file
[/code]

RL file format

As a side note, in a .drl file, it is valid to write the whole rule on a single line. This allows us to write more complex DSLs because one sentence in .dslr file can be translated into multiple conditions—even the whole rule. For example, these arevalid rules on a single line:

[code lang=”java”] rule "addressRequired" when Customer( address == null ) then
warning(kcontext); end
[/code]

Code listing 12: addressRequired rule on one line.

Make sure that you add spaces between Drools keywords. Another more complex example of a rule on one line:

[code lang=”java”] rule "studentAccountCustomerAgeLessThan" when Customer( eval (year
sPassedSince(dateOfBirth) >= 27) ) and $account : Account( type ==
Account.Type.STUDENT ) then error(kcontext, $account); System.out.
println("another statement"); end
[/code]

Code listing 13: studentAccountCustomerAgeLessThan rule on one line.

The preceding rule contains two conditions and two Java statements in the consequence block. There is also an optional and keyword between the conditions to make it more readable.

DSLR file format

A . dslr file contains the sentences written using the DSL. The .dslr file is very similar to the .drl file. One thing to note is that by prepending a line with a ‘>’, we can turn off the expander for the line. This allows us to write a hybrid .dslr file that contains traditional DRL rules and DSL rules. For example, if we are not yet sure how to map some complex rule, we can leave it in its original .drl file format.

DSL for multiple constraints in a condition

We’ ll go through more complex DSLs. Let’s look at a standard condition for example:

[code lang=”java”]
Account( owner != null, balance > 100, currency == "EUR" )
[/code]

Code listing 14: Condition that matches some account.

It is difficult to write DSL that will allow us to create conditions with any subset of constraints from the code listing above (without writing down all possible permutations). The ‘-‘ feature comes to the rescue:

[code lang=”java”]
[condition][]There is an Account that=$account : Account( )
[condition][]-has owner=owner != null
[condition][]-has balance greater than {amount}=balance > {amount}
[condition][]-has currency equal to {currency}=currency == {currency}
[/code]

Code listing 15: DSL using the ‘-‘ feature. This can create seven combinations of the constraints.

When the DSL condition starts with ‘-‘, the DSL parser knows that this constraint should be added to the last condition (in a .dslr file). With the preceding DSL, the following condition can be created:

[code lang=”java”] There is an Account that
– has currency equal to "USD"
"has balance greater than 2000"
[/code]

Code listing 16: Condition using the ‘-‘ feature (in a .dslr file).

The ‘-‘ feature increases the fl exibility of the resulting language. It works just fine for simple cases involving only one pair of brackets. In case of multiple brackets in the condition, Drools always adds the constraint to the last pair of brackets. This may not always be what we want. We have to find a different way of specifying multiple constraints in a condition. We can also write our DSL in the following manner:

[code lang=”java”]
[condition][]There is an Account that {constraints} = Account(
{constraints} )
[condition][]has {field} equal to {value}={field} == {value}
[condition][]and has {field} equal to {value}=, {field} == {value}
[/code]

Code listing 17: Flexible DSL that can be expanded to a condition with two field constraints.

With this DSL, the following DSLR can be written:

[code lang=”java”]
There is an Account that has owner equal to null and has balance equal
to 100
[/code]

Code listing 18: DSLR that describes an account with two constraints.

If we want to have more conditions, we can simply duplicate the last line in the DSL. Remember? Translation is a single pass process.

Named capture groups

Som etimes, when a more complex DSL is needed, we need to be more precise at specifying what a valid match is. We can use named capture groups with regular expressions to give us the needed precision. For example:

[code lang=”java”]
{name:[a-zA-Z]+}
[/code]

Code listing 19: Name that matches only characters.

[code]
Regular expressions (java.util.regex.Pattern) can be used not
only for capturing variables but also within the DSL. For example, in
order to carry out case insensitive matching. If we look at the DSL from
code listing 15, the users should be allowed to type Account, account,
ACCOUNT, or even aCcount in their .dslr files. This can be done by
enabling the embedded case insensitive fl ag expression—(?i):
[condition][]There is an (?i:account) that ….

Another useful example is sentences that are sensitive to
gender—(s)?he to support "he" and "she", and so on.

In order to make the sentences space insensitive, Drools automatically
replaces all spaces with \s+. Each \s+ matches one or more spaces. For
example, the following line in a .dslr file will be successfully expanded
by the DSL from code listing 15:
There is an Account that ….
[/code]

DSL for data transformation rules

We’ ll now implement DSL for the data transformation rules from Chapter 4, Data Transformation. We’ll reuse our rule unit tests to verify that we don’t change the functionality of the rules but only their representation. The unit test class will be extended and the method for creating KnowledgeBase will be overridden to use the .dsl file and .dslr file as inputs. Rule names will stay the same. Let’s start with the twoEqualAddressesDifferentInstance rule:

[code lang=”java”]
rule twoEqualAddressesDifferentInstance
when
There is legacy Address-1
There is legacy Address-2
– same as legacy Address-1
then
remove legacy Address-2
Display WARNING for legacy Address-2
end
[/code]

Code listing 20: Rule for removing redundant addresses (dataTransformation.dslr file).

The conditions can be implemented with the following DSL:

[code lang=”java”]
[condition][] legacy {object}-{id} = {object}-{id}
[condition][] There is {object}-{id} = ${object}{id} : Map( this["_
type_"] == "{object}" )
[condition][]- same as {object}-{id} = this == ${object}{id}, eval(
${object}1 != ${object}2 )
[/code]

Code listing 21: DSL for conditions (dataTransformation.dsl file).

The first mapping is a simple translation rule, where we remove the word legacy. The next mapping captures a map with its type. The last mapping includes the equality test with the object identity test. Mapping for consequences is as follows:

[code lang=”java”]
[consequence][] legacy {object}-{id} = ${object}{id}
[consequence][]Display {message_type_enum} for {object}=validationRepo
rt.addMessage(reportFactory.createMessage(Message.Type.{message_type_
enum}, kcontext.getRule().getName(), {object}));
[consequence][]remove {object} = retract( {object} );
[/code]

Code listing 22: DSL for consequences.

The first mapping just removes the word legacy. The second mapping adds a message to validationReport. Finally, the last mapping removes an object from the knowledge session. This is all we need for the twoEqualAddressesDifferentInstance rule.

As you can see, we started with the sentence in the domain specific language (code listing 1) and then we’ve written the transformation to refl ect the rules (from Chapter 4). In reality, this is an iterative process. You’ll modify the .dslr and .dsl files until you are happy with the results. It is also a good idea to write your rules in standard .drl first and only then try to write a DSL for them.

We ‘ll move to the next rule, addressNormalizationUSA:

[code lang=”java”]
rule addressNormalizationUSA
when
There is legacy Address-1
– country is one of "US", "U.S.", "USA", "U.S.A"
then
for legacy Address-1 set country to USA
end
[/code]

Code listing 23: DSLR rule for normalizing address country field. The rule just needs another constraint type:

[code lang=”java”]
[condition][]- country is one of {country_list} = this["country"] in
({country_list})
[/code]

Code listing 24: Another condition mapping.

The consequence is defined with two mappings. The first one will translate the country to an enum and the second will then perform the assignment.

[code lang=”java”]
[consequence][]set country to {country}=set country to Address.
Country.{country}
[consequence][]for {object}set {field} to {value} = modify( {object} )
\{ put("{field}", {value} ) \}
[/code]

Code listing 25: Consequence mapping for the country normalization rule.

Please note that the curly brackets are escaped. Moreover, the original rule used mvel dialect. It is a good idea to write your rules using the same dialect. It makes the DSL easier. Otherwise, the DSL will have to be “dialect aware”.

The other country normalization rule can be written without modifying the DSL. We’ll now continue with unknownCountry rule:

[code lang=”java”]
rule unknownCountry
Apply after address normalizations
when
There is legacy Address-1
– country is not normalized
then
Display ERROR for legacy Address-1
end
[/code]

Code listing 26: DSLR representation of the unknownCountry rule.

The whole sentence Apply after address normalizations is mapped as a keyword mapping:

[code lang=”java”]
[keyword][] Apply after address normalizations = salience -10
[/code]

Code listing 27: salience keyword mapping.

Now, we can use the other rule attributes to achieve the same goal just by changing the DSL.

Additional mapping that is needed:

[code lang=”java”]
[condition][]- country is not normalized = eval(!($Address1.
get("country") instanceof Address.Country))
[/code]

Code listing 28: Another condition mapping.

In the condition mapping, the $Address1 is hard-coded. This is fine for the rules that we have.

As you can imagine, the rest of the rules follow similar principles.

What we have achieved by writing this DSL is better readability. A business analyst can verify the correctness of these rules more easily. We could push this further by defining a complete DSL that can represent any concept from the problem domain. The business analyst will then be able to express any business requirement just by editing the .dslr file.

Decision tables

Decision tables are another form of human-readable rules that are useful when there are lots of similar rules with different values. Rules that share the same conditions with different parameters can be captured in a decision table. Decision tables can be
represented in an Excel spreadsheet (.xls file) or a comma separated values (.csv file) format. Starting from version 5.0, Drools supports web-based decision tables as well. They won’t be discussed in this book; however, they are very similar. Let’s have
a look at a simple decision table in .xls format.

jboss-rules-4The preceding screenshot shows a decision table in validation.xls opened with OpenOffice Calc editor. It shows one decision table for validating a customer. Line 10 shows four columns. The first one defines rule name, the next two define conditions,and the last one is for defining actions/consequences. The next three lines (11-13) represent the individual rules—one line per rule. Each cell defines parameters for conditions/consequences. If a cell doesn’t have a value, that condition/action is ignored. Some rows in the spreadsheet are grouped and hidden (see the two plus (+) signs in the left). This makes the decision tables more user-friendly, especially for
business users. Please note that tables don’t have to start on the first column. The full validation.xls file is as follows:

jboss-rules-5Every file for defining decision tables start with a global configuration section. The configuration consists of name-value pairs. As can be seen from the screenshot above:

  • RuleSet defines the package
  • Import specifies the classes used, including static imported functions
  • Variables is used for global variables
  • Notes can be any text

Further:

  • Functions can be used to write local functions as in .drl format
  • Worksheet specifies the sheet to be used; by default only the first sheet is checked for rules

The RuleTable then denotes the start of the decision table. It has no specific purpose. It is used only to group rules that operate on the same objects and share conditions. The next line defines column types. The following column types are available:

  • CONDITION—defines a single rule condition or constraint, the following row can contain type for this condition, if it doesn’t, then the next row must define full condition (with a type, not just a constraint as in the preceding case).
  • ACTION—rule action. Similar to condition, the next line can contain any global or bound variable. Drools will then assume that the next line is a method that should be called on this global or bound variable.
  • PRIORITY—for defining rule salience.
  • NAME—by default rule names are auto generated, NAME can be used to explicitly specify the name.
  • No-loop or Unloop—specifies the rule no-loop attribute.
  • XOR-GROUP—specifies rule activation-group (this will be discussed in the upcoming section, Drools Flow).

For full configuration options, please consult the Drools manual (http://www.jboss.org/drools/documentation.html).

The next line from the preceding screenshot looks similar to what we see in a .drl file. It is a simple condition that matches any Customer object and exposes this object as the $customer variable. The only difference is that there are no brackets. They will be added automatically by Drools at parsing time. Please note that this line contains only two columns. The first two columns are merged into one column. This is because they operate on the same type (Customer). If we don’t merge the two columns, they’ll match two separate objects (which may or may not be the same instance).

The next line then defines individual constraints (in case of conditions) or code blocks (in case of actions). Special parameters can be used as $param or $1, $2, $3, and so on. The first one is used if our constraint needs only one parameter; otherwise, the $n format should be used.

The following line (corresponds to line 10 in the preceding screenshot showing a decision table in validation.xls file) is for pure informational purposes. It should contain some meaningful description of the column/action so that we don’t have to always look at how it is implemented (by expanding/collapsing rows).

Finally, the actual values follow in subsequent rows. Each line represents one rule. For example, the first line gets translated behind the scenes to the following .drl rule:

[code lang=”java”]
#From row number: 11
rule "addressRequired"
when
$customer : Customer(address == null)
then
warning(kcontext);
end
[/code]

Code listing 29: Generated rule from a decision table.

The .drl rule is exactly the same as we’ve implemented in Chapter 3, Validation. We can even reuse the same unit test to test this rule.

Advantages of a decision table

Here are the advantages of a decision table:

  • It is easy to read and understand.
  • Refactoring is quicker because we just have to change a column definition to change a group of related rules (that is, it is easy to change conditions across group of rules).
  • Isolation is similar to DSL; decision tables can hide the rule implementation details.
  • Provides separation between the rules and data (they are still in one file but separated).
  • Any formatting available in a spreadsheet editor can be applied to present these data in a more readable manner (for example, using a drop-down for a list of values. It can reduce errors from mistyping a value into a cell by allowing only valid values).
  • Eclipse Drools plugin can also validate a spreadsheet. This is very useful when writing rules. The Problems view in Eclipse shows what exactly is wrong with the generated .drl file.

Disadvantages of a decision table

  • It can be awkward to debug/write these rules. Sometimes it helps to convert the spreadsheet to a .drl file, save this file, and fix it, as we’re used to.
  • Decision tables shouldn’t be used if the rules don’t share many conditions.Further, the order of conditions is important. In a decision table, the order of a condition is given by the order of a column. Care should be taken if you want to convert the existing DRL rules into decision tables, as the order of conditions may change (to take advantage of the reuse).
  • XLS is a binary format which makes version management more difficult.

Calculating the interest rate

As an example, we’ll calculate the interest rate based on the account balance, currency, duration, and type. This calculation is ideal for a decision table because we have a lot of constraints that are reused across rules with different data. The decision table looks as follows:

jboss-rules-6Please note that the Account object is used in every condition so the CONDITION columns are merged. We can see the use of parameters $1 and $2. The first line can be read as: For every transactional account with currency EUR, set its interest rate to 0.01
percent (regardless of the balance)
. Another line can be read as: For every savings account whose balance is between 100 EUR and 1000 EUR that is opened for one to three months, set its interest rate to 3 percent. The following rule will be generated:

[code lang=”java”]
#From row number: 16
rule "Interest Calculation_16"
when
$a:Account(type == Account.Type.SAVINGS,
currency == "EUR", balance >= 100 &amp;&amp; < 1000,
monthsBetweenStartAndEndDate >= 1 &amp;&amp; < 3)
then
$a.setInterestRate(new BigDecimal("3.00"));
end
[/code]

Code listing 30: Generated rule for calculating the interest rate.

If we had not used a decision table, we would have to write such rules by hand. Please note that the second condition column in the decision table above doesn’t have any operator or operand. It simply says currency. It is a special feature and this is automatically translated to currency == $param.

The last condition column uses getMonthsBetweenStartAndEndDate method of the Account class.

[code lang=”java”]
private DateMidnight startDate;
private DateMidnight endDate;
/**
* @return number of months between start and end date
*/
public int getMonthsBetweenStartAndEndDate() {
if (startDate == null || endDate == null) {
return 0;
}
return Months.monthsBetween(startDate, endDate)
.getMonths();
}
[/code]

Code listing 31: Implementation of getMonthsBetweenStartAndEndDate method of Account.

The implementation uses the Joda-Time library to do the calculation.

Project setup

The following libraries are needed on the classpath:

  • drools-decisiontables-5.0.1.jar: used for compiling spreadsheets into .drl file format; it knows how to handle .xls and .csv formats.
  • jxl-2.4.2.jar XLS API: used for parsing .xls spreadsheets.

Testing

For testing the interest calculation rules, we’ll use a stateless knowledge session, an account, and a date object. All tests will reuse the stateless session. The test can be set up as follows:

[code lang=”java”]
static StatelessKnowledgeSession session;
Account account;
static DateMidnight DATE;

@BeforeClass
public static void setUpClass() throws Exception {
KnowledgeBase knowledgeBase =
createKnowledgeBaseFromSpreadsheet();
session = knowledgeBase.newStatelessKnowledgeSession();
DATE = new DateMidnight(2008, 1, 1);
}

@Before
public void setUp() throws Exception {
account = new Account();
}
[/code]

Code listing 32: Setup of the decision table test.

The date will be used to set deposit durations. An account is created for every test method. The createKnowledgeBaseFromSpreadsheet method is implemented as follows:

[code lang=”java”]
private static KnowledgeBase createKnowledgeBaseFromSpreadsheet()
throws Exception {
DecisionTableConfiguration dtconf =KnowledgeBuilderFactory
.newDecisionTableConfiguration();
dtconf.setInputType( DecisionTableInputType.XLS );
//dtconf.setInputType( DecisionTableInputType.CSV );
KnowledgeBuilder knowledgeBuilder =
KnowledgeBuilderFactory.newKnowledgeBuilder();
knowledgeBuilder.add(ResourceFactory.newClassPathResource(
"interest calculation.xls"), ResourceType.DTABLE,
dtconf);
//knowledgeBuilder.add(ResourceFactory
// .newClassPathResource("interest calculation.csv"),
// ResourceType.DTABLE, dtconf);

if (knowledgeBuilder.hasErrors()) {
throw new RuntimeException(knowledgeBuilder.getErrors()
.toString());
}
KnowledgeBase knowledgeBase = KnowledgeBaseFactory
.newKnowledgeBase();
knowledgeBase.addKnowledgePackages(
knowledgeBuilder.getKnowledgePackages());
return knowledgeBase;
}
[/code]

Code listing 33: Creating a knowledgeBase from a spreadsheet.

As opposed to the other knowledge definitions, the decision table needs a special configuration that is encapsulated in DecisionTableConfiguration class. This configuration specifies the type of decision table and it is then passed on to the knowledge builder. The commented lines show how to create a knowledge base from a .csv format. The rest should be familiar.

Note if you want to see the generated .drl source, you can get it like this:

[code lang=”java”]
String drlString = DecisionTableFactory
.loadFromInputStream(ResourceFactory
.newClassPathResource("interest calculation.xls")
.getInputStream(), dtconf);
[/code]

Code listing 34: Getting the .drl representation of the decision table.

It is stored in a drlString string variable; it can be printed to the console and used for debugging purposes.

We’ll now write a test for depositing 125 EUR for 40 days:

[code lang=”java”]
@Test
public void deposit125EURfor40Days() throws Exception {
account.setType(Account.Type.SAVINGS);
account.setBalance(new BigDecimal("125.00"));
account.setCurrency("EUR");
account.setStartDate(DATE.minusDays(40));
account.setEndDate(DATE);
session.execute(account);
assertEquals(new BigDecimal("3.00"), account
.getInterestRate());
}
[/code]

Code listing 35: Test for depositing 125 EUR for 40 days.

The preceding test verifies that the correct interest rate is set on the account. And one test for default transactional account rate:

[code lang=”java”] @Test
public void defaultTransactionalRate() throws Exception {
account.setType(Account.Type.TRANSACTIONAL);
account.setCurrency("EUR");
session.execute(account);
assertEquals(new BigDecimal("0.01"), account
.getInterestRate());
}
[/code]

Code listing 36: Test for the default transactional account rate.

The test above, again, verifies that the correct interest rate is set.

Comma Separated values

The XLS spreadsheet can be easily converted into CSV format. Just select Save as CSV in your spreadsheet editor. However, there is one caveat—CSV format doesn’t support merging of columns by default. For overcoming this, Drools has the following workaround: if we add three dots at the end of type declarations, they will be merged into one. It can be seen in the last line of the following CSV excerpt:

[code lang=”java”] "RuleTable Interest Calculation",,,,
"CONDITION","CONDITION","CONDITION","CONDITION","ACTION"
"$a:Account…","$a:Account…","$a:Account…","$a:Account…",
[/code]

Code listing 37: Excerpt from the interest calculation.csv file.

It is the only change that needs to be done. Tests should pass for CSV format as well.

CSV is a text format as opposed to XLS, which is a binary format. Binary format makes version management harder. For example, it is very difficult to merge changes between two binary files. CSV doesn’t have these problems. On the other hand, the presentation suffers.

Rule Templates

If you like the concept of decision tables, you may want to look at Drools Rule Templates. They are similar to the decision tables but more powerful. With Rule Templates, the data is fully separated from the rule (for example, it can come from a database and have different templates over the same data). You have more power in defining the resulting rule. The data can define any part of rule (for example, condition operator, class, or property name). For more information, refer to the Rule Templates section of the Drools Experts User Guide (available at http://www.jboss.org/drools/documentation.html).

Drools Flow

Drools Flow (or ruleflow in short) is another way we can have human readable rules. It is not a substitute to rules as was the case with DSLs and decision tables. It is a way of defining the execution flow between complex rules. The rules are then easier to understand.

Drools Flow can externalize the execution order from the rules. The execution order can be then managed externally. Potentially, you may define more execution orders for one KnowledgeBase.

Drools Flow can be even used as a workflow engine replacement. It can execute arbitrary actions or user-defined work items at specific points within the flow. It can be even persisted as we’ll see in Chapter 8, Drools Flow, which shows a bigger example of using ruleflows.

Drools Agenda

Before we talk about how to manage rule execution order, we have to understand Drools Agenda. When an object is inserted into the knowledge session, Drools tries to match this object with all of the possible rules. If a rule has all of its conditions met, its consequence can be executed. We say that a rule is activated. Drools records this event by placing this rule onto its agenda (it is a collection of activated rules). As you may imagine, many rules can be activated, and also deactivated, depending on what objects are in the rule session. After the fireAllRules method call, Drools picks one rule from the agenda and executes its consequence. It may or may not cause further activations or deactivations. This continues until the Drools Agenda is empty. The purpose of the agenda is to manage the execution order of rules.

Methods for managing rule execution order

The following are the methods for managing the rule execution order (from the user’s perspective). They can be viewed as alternatives to ruleflow. All of them are defined as rule attributes.

  • salience: This is the most basic one. Every rule has a salience value. By default it is set to 0. Rules with higher salience value will fire first. The problem with this approach is that it is hard to maintain. If we want to add new rule with some priority, we may have to shift the priorities of existing rules. It is often hard to figure out why a rule has certain salience, so we have to comment every salience value. It creates an invisible dependency on other rules.
  • activation-group: This used to be called xor-group. When two or more rules with the same activation group are on the agenda, Drools will fire just one of them.
  • agenda-group: Every rule has an agenda group. By default it is MAIN. However, it can be overridden. This allows us to partition Drools Agenda into multiple groups that can be executed separately.

jboss-rules-7The figure above shows partitioned Agenda with activated rules. The matched rules are coming from left and going into Agenda. One rule is chosen from the Agenda at a time and then executed/fired.

At runtime we can programmatically set the active Agenda group (through the getAgenda().getAgendaGroup(String agendaGroup).setFocus() method of KnowledgeRuntime), or declaratively, by setting the rule attribute auto-focus to true. When a rule is activated and has this attribute set to true, the active agenda group is automatically changed to rule’s agenda group. Drools maintains a stack of agenda groups. Whenever the focus is set to a different agenda group, Drools adds this group onto this stack. When there are no rules to fire in the current agenda group, Drools pops from the stack and sets the agenda group to the next one. Agenda groups are similar to ruleflow groups with the exception that ruleflow groups are not stacked. Note that only one instance of each of these attributes is allowed per rule (for example, a rule can only be in one ruleflow-group; however, it can also
define a salience within that group).

Ruleflow

As we’ve already said, ruleflow can externalize the execution order from the rule definitions. Rules just define a ruleflow-group attribute, which is similar to agenda-group. It is then used to define the execution order. A simple ruleflow (in the example.rf file) is shown in the following screenshot:

jboss-rules-8The preceding screenshot shows a ruleflow opened with the Drools Eclipse plugin. On the lefthand side are the components that can be used when building a ruleflow. On the righthand side is the ruleflow itself. It has a Start node which goes to ruleflow group called Group 1. After it finishes execution, an Action is executed, then the flow continues to another ruleflow group called Group 2, and finally it finishes at an End node.

Ruleflow definitions are stored in a file with the .rf extension. This file has an XML format and defines the structure and layout for presentational purposes.

[code] Another useful rule attribute for managing which rules can be activated
is lock-on-active. It is a special form of the no-loop attribute. It can
be used in combination with ruleflow-group or agenda-group. If it
is set to true, and an agenda/ruleflow group becomes active/focused,
it discards any further activations for the rule until a different group
becomes active. Please note that activations that are already on the
agenda will be fired.
[/code]

A ruleflow consists of various nodes. Each node has a name, type, and other specific attributes. You can see and change these attributes by opening the standard Properties view in Eclipse while editing the ruleflow file. The basic node types are
as follows:

  • Start
  • End
  • Action
  • RuleFlowGroup
  • Split
  • Join

They are discussed in the following sections.

Start

It is the initial node. The flow begins here. Each ruleflow needs one start node. This node has no incoming connection—just one outgoing connection.

End

It is a terminal node. When execution reaches this node, the whole ruleflow is terminated (all of the active nodes are canceled). This node has one incoming connection and no outgoing connections.

Action

Used to execute some arbitrary block of code. It is similar to the rule consequence—it can reference global variables and can specify dialect.

RuleFlowGroup

This node will activate a ruleflow-group, as specified by its RuleFlowGroup attribute. It should match the value in ruleflow-group rule attribute.

Split

This node splits the execution flow into one or many branches. It has two properties—name and type. Name is just for display purposes. Type can have three values: AND, OR, and XOR:

  • AND: The execution continues through all of the branches.
  • OR : Each branch has a condition. The condition is basically same as a rule condition. If the condition is true, the ruleflow continues through this branch. There must be at least one condition that is true; otherwise, an exception will be thrown.
  • XOR: Similar to OR type, each branch has a condition, but in this case, with a priority. The ruleflow continues through just one branch, whose condition is true and it has the lowest value in the priority field. There must be at least one condition that is true; otherwise, an exception will be thrown.

The dialog for defining OR and XOR split types looks like the following screenshot:

jboss-rules-9The screenshot above shows Drools Eclipse plugin ruleflow constraint editor. It is accessible from the standard Eclipse Properties view.

Join

It joins multiple branches into one. It has two properties—name and a type. Name is for display purposes. Type decides when the execution will continue. It can have following values:

  • AND: Join waits for all the incoming branches. The execution then continues.
  • XOR: Join node waits for one incoming branch.

Pl ease consult the Drools manual for further node types.

Example

If you look at data transformation rule in Chapter 4, Data Transformation, you’ll see that in some rules we’ve used salience to define rule execution order. For example, all of the addresses needed to be normalized (that is, converted to enum) before we could report the unknown countries. The unknown country rule used salience of -10, which meant that it would fire only after all address normalization rules. We’ll now extract this execution order logic into a ruleflow to demonstrate how it works. The ruleflow might look like the following screenshot:

jboss-rules-10When the execution starts, it goes through the Start node straight into the Split node. In this case, it is an and type split node. It basically creates two parallel branches that will be executed concurrently (note that this doesn’t mean multiple threads). We can see that the flow is explicitly specified. address normalization happens before unknown country reporting. Parallel to this branch is a default ruleflow group. It contains the other rules. Finally, a join node of type and is used to block until all branches complete and then the flow continues to the terminal node. We had to use the Join node (instead of going straight to the End node), because as soon as some branch in a ruleflow reaches the End node, it terminates the whole ruleflow (that is, our branches may be canceled before competition, which is not what we want).

The process ID is set to dataTransformation. Click on the canvas in the ruleflow editor and then in the Properties view (Eclipse Properties plugin), set the ID to this value.

Rules

Next we create copy of dataTransformation.drl file from Chapter 4 and we’ll name it dataTransformation-ruleflow.drl. We’ll make the following changes:

    • Each rule gets new attribute: ruleflow-group “default”
    • Except the address normalization rules for example:

[code lang=”java”] rule addressNormalizationUSA
ruleflow-group "address normalization"
[/code]

Code listing 37: Top part of the USA address normalization rule.

  • Unknown country rule gets the “unknown country” ruleflow group.

KnowledgeBase setup

We c an now create a knowledge base out of the ruleflow file and the .drl file.

[code lang=”java”] static KnowledgeBase createKnowledgeBaseFromRuleFlow()
throws Exception {
KnowledgeBuilder builder = KnowledgeBuilderFactory
.newKnowledgeBuilder();
builder.add(ResourceFactory.newClassPathResource(
"dataTransformation-ruleflow.drl"), ResourceType.DRL);
builder.add(ResourceFactory.newClassPathResource(
"dataTransformation.rf"), ResourceType.DRF);
if (builder.hasErrors()) {
throw new RuntimeException(builder.getErrors()
.toString());
}
KnowledgeBase knowledgeBase = KnowledgeBaseFactory
.newKnowledgeBase();
knowledgeBase.addKnowledgePackages(builder
.getKnowledgePackages());
return knowledgeBase;
}
[/code]

Code listing 38: Method that creates KnoweldgeBase with a ruleflow.

[code] A knowledge base is created from both files .drl and .rf. To achieve
true isolation of unit tests, consider constructing the knowledge base only
from the .drl file or .rf file. That way, the unit tests can focus only on
the relevant part.
[/code]

Tests

The test setup needs to be changed as well. Ruleflows are fully supported only for stateful sessions. Stateful sessions can’t be shared across tests because they maintain state. We need to create a new stateful session for each test. We’ll move the session initialization logic from the setUpClass method that is called once per test class into the intialize method that will be called once per test method:

[code lang=”java”]
static KnowledgeBase knowledgeBase;
StatefulKnowledgeSession session;

@BeforeClass
public static void setUpClass() throws Exception {
knowledgeBase = createKnowledgeBaseFromRuleFlow();
}

@Before
public void initialize() throws Exception {
session = knowledgeBase.newStatefulKnowledgeSession();
[/code]

Code listing 39: Excerpt from the unit test initialization.

Once the stateful session is initialized, we can use it.

We’ll write a test that will create a new address map with an unknown country. This address map will be inserted into the session. We’ll start the ruleflow and execute all of the rules. The test will verify that the unknownCountry rule has been fired:

[code lang=”java”] @Test
public void unknownCountryUnknown() throws Exception {
Map addressMap = new HashMap();
addressMap.put("_type_", "Address");
addressMap.put("country", "no country");

session.insert(addressMap);
session.startProcess("dataTransformation");
session.fireAllRules();

assertTrue(validationReport.contains("unknownCountry"));
}
[/code]

Code listing 40: Test for the unknown country rule with an unknown country.

Note that the order of the three session methods is important. All of the facts need to be in the session before the ruleflow can be started and rules can be executed.

Please note that in order to test this scenario, we didn’t use any agenda filter. This test is more like an integration test where we need to test more rules cooperating together.

Another test verifies that the ruleflow works with a known country:

[code lang=”java”] @Test
public void unknownCountryKnown() throws Exception {
Map addressMap = new HashMap();
addressMap.put("_type_", "Address");
addressMap.put("country", "Ireland");

session.startProcess("dataTransformation");
session.insert(addressMap);
session.fireAllRules();

assertFalse(validationReport.contains("unknownCountry"));
}
[/code]

Code listing 41: Test for the unknown country rule with a known country.

As a stateful session is being used, every test should call the dispose method on the session after it finishes. It can be done in the following manner:

[code lang=”java”]
@After
public void terminate() {
session.dispose();
}
[/code]

Code listing 42: Calling the session.dispose method after every test.

Filed Under: Servers Tagged With: WildFly

  • 1
  • 2
  • Next Page »

Follow Us

  • Facebook
  • Pinterest

As a participant in the Amazon Services LLC Associates Program, this site may earn from qualifying purchases. We may also earn commissions on purchases from other retail websites.

JavaBeat

FEATURED TUTORIALS

Answered: Using Java to Convert Int to String

What is new in Java 6.0 Collections API?

The Java 6.0 Compiler API

Copyright © by JavaBeat · All rights reserved