Wednesday, March 24, 2010

Killer Servlet: a performance tuning and garbage collection solution

An applet is a Java application executed by a web browser to show dynamic graphics on the front-end. After the advent of Rich Internet Application (RIA) technologies, applets are disappearing from the tech landscape but once upon a time it was the only way to show rich contents on the front-end. A servlet in brief is a piece of Java code executed on the server side (typically a web server with an embedded servlet engine) to process request, collect data from data source or rendering a well formatted HTML page on the browser.
An applet-servlet communication is typically done where one can not avoid having a thick client such as an applet on the front-end posting requesting and / or receiving feed from the server side. For example, suppose an applet is continuously drawing and updating a graph based on the feeds received from the servers on the stock prices.
Whenever a user is opening an applet on his/her browser, the browser is downloading the applet and starts executing it. The applet draws a nice graph on the front-end (browser) and on the background connects to a server to fetch stock prices. When we had such a situation back in 2001/2002 (original situation has been modified a little to keep the privacy of the project intact) the architecture followed to implement this is as follows.
Among the technical components there were

• A Stock Price Applet with
o a nice graph panel
o a thread to render the graph on the front-end
o a thread to communicate with a servlet at the back-end

• A Stock Price Servlet (HTTPServlet) on the server with a “while” loop in the doPost() method and having some sub-components as below.
o a JMS Listener attached to the Stock price JMS topic
o a shared message cache where the subscriber stored the messages and the servlet used to read from.

• A Stock price JMS Topic on the JMS server

• Multiple Stock price publishers connected with different external Stock servers on the outer end and with the Stock price JMS topis on the inner end (in the server). Figure 1 explains the architecture.


Figure 1

The applet used to run on the browser and communicate (by opening a http stream) with the StockPriceServlet at the back-end. The servlet used to instantiate the JMS subscriber on receiving the applet’s request. The JMS subscriber was connected with the Stock price JMS topic to listen to Stock price update messages. On the other hand the JMS publishers kept adding messages as and when received from the external servers. To keep the http session alive between the applet and the servlet an infinite “while” loop is placed in the doPost() method of the servlet. The communication was a server push within an http session continuation.

Everything was nice and smooth but after serving a certain number of clients (i.e. applets) the server was getting slower and slower. It was a real-time application and delays to a certain extent was permissible but not beyond that.
So we started investigating the reason behind it. We discovered that the StockPriceServlets those were serving the applets on the front-end were kept alive even after the applet window was closed. The reason was the infinite loop in the doPost() method. The JMS subscriber was still alive listening to the JMS topic and throwing the messages to the servlet. The StockPriceServlet was writing the messages on the http response stream without any errors/exceptions because it was unable to sense that the receiver on the other side of the stream (i.e. the applet) has been stopped.

There was an option to put a timeout on the servlet so after a certain period pf time it dies out but that was not optimal. With an increased frequency of updates received by the stock servers the system might choke anytime.
Another option was to send a completion request from the applet to the servlet so that it can come out of the loop. But once the servlet receives the first request from the applet it starts the JMS subscriber and goes inside the loop. Http communications are stateless therefore a new request will invoke a new servlet.

Looking for more options we figured out a way to stop the StockPriceServlet and free up the resources with a programmatic technique. It was quite clear that the servlet needed to be killed on the completion of the applet’s activities. So an event or update needs to be thrown back to the servlet notifying that the applet has been stopped. Based on this update the servlet had to be killed. So we felt the need of an agent on the server side who will receive the notification from the applet’s end. The agent needs to accomplish the following activities.

1. Receives the completion notification from the applet.
2. Identifies the StockPriceServlet instance that was serving the applet.
3. Notify the servlet by updating a flag that makes the servlet to break out from the infinite loop and stop the subscriber attached to it.

So the agent took birth as the KillerServlet (please don’t laugh :) it’s the birth of the terminator ;). Activity 1 can be easily achieved by sending a http request from the applet to the KillerServlet. The most critical was the step 2 i.e. to identify the servlet instance. All servlet instances were maintained by the servlet container and hence getting a hold with them is tough. Well, getting the reference of a servlet from the ServletContext method was easy and official during 2001/2002 , but the issue was to identify the exact subject for kill i.e. a correlation. To establish a correlation the participants in the communication channel i.e. the applet and the servlet should be marked / tagged with a unique id (a correlation id) that can be used later to get a reference of the participants.
Figure 2 explains the modified architecture to include the solution. The solution technique was conceptualized as below.

Figure 2

1. The applet connects with the StockPriceServlet.
2. The StockPriceServlet generates a unique id (correlation id) and sends back the same to the applet with the first response before entering the loop. The StockPriceServlet should have a flag to terminate the while loop e.g. “while(!completed){}” instead of “while(true){}”. The StockPriceServlet should also have a unique id generator (preferably a singleton object).
3. The StockPriceServlet sets an attribute to the ServletContext (ServletContext.setAttribute()) with its own reference against the unique id.
4. Once the applet receives the unique id it should store the same.
5. Once the applet is stopped or terminated it should be able to sense the same (may be by using a JavaScript or a close button) and invoke the KillerServlet with the unique id.
6. The KillerServlet receives the unique id and looks up for the same in the ServletContext. (ServletContext.getAttribute()).
7. On receiving the appropriate reference to the StockPriceServlet instance the KillerServlet should update the completion flag to “true” in the StockPriceServlet instance.
8. Once the while loop is terminated, the StockPriceServlet stops the JMS subscriber and cleans up the message cache.

We did not want to invoke the destroy method to avoid touching the lifecycle controls and left the rest of things on the servlet container.

Monday, March 8, 2010

TOGAF and SOA

I am with a mission to define the technology architecture i.e. the phase D in TOGAF ADM (http://www.opengroup.org/architecture/togaf8-doc/arch/chap03.html). Days are changing, the current trend (try with google) is SOA :)
So everything should be done in SOA way. TOGAF is an architecture framework while SOA is an architectural style. TOGAF does not mention any specific architectural style to be followed, so I can use SOA with out any issue. Technology architecture as defined by TOGAF needs input from the business and application architecture as well.
During the last couple of years people used object oriented paradigm more conveniently with most of the IT system architecture, analysis, design and development. SOA can be used as an architectural style during the analysis (not sure if the business can always be analised in terms of services) design and modeling but once it comes to the implementation arena it's no more SOA. Services are implemented as web services or something else similar to that. Finally it boils down to files, dlls, java classes, exe, xml file etc. It's hard to distinguish the bricks collapsed out of a charch or a library or a skyscraper after an earthquake :)
When there's no abstraction, there's no SOA or object orientation or any other style, they are all the same. Finally all the services and objects are going to be converted to the binary language for the machine to execute.
To me the technology architecture that talks about the concrete deployment environment for a system or application has got very less to do with SOA.
Digging the lower level details of the BPEL process engines or ESBs will return the application server underlying. ESB and BPEL process engines are mostly deployed as applications on the top of an application server for most of the vendors (be it Webspehere or Weblogic).

Wednesday, February 24, 2010

Multimedia search engine

One more abstract useless thought.
Till date the search engines that we use on the internet are also text-based search engines. These search engines will typically have a box to put your text followed by a neat button to click on to begin with the search. On submission of your search request you will get a well formatted page containing all the search results. Usually a bunch of links following different websites are presented. In case it's an image or video search links to the image/video resources are listed.
Computers are intended to become close to human brain with the ability to interact using all the sense organs like human beings. Will you recognize my face from a group photo taken while I was in school? tough :) If you can I must say you have a good eye-sight and power of pattern recognition, that's human brain. I hope someday we will have search engines to upload the image of my face and find out a group photo posted somewhere on the net. Exciting, aint it!! we can do this with many media patterns such as

# image
# video
# sound/music

I could have added more to the list if we had smell, taste and touch :) but we don't have input/output devices for them yet. ooops!! sorry it's not my concept (well every computer user might have thought this way while seeing a lovely photo of a food S/he likes) but has been patented recently (http://www.patentstorm.us/patents/7562816/description.html). I would hope we will see it commercially available in the market soon. Even there are touch printers in the market too (http://www.gizmag.com/sense-taste-smell-touch-printer/13689/).

Image pattern recognition will help greatly in finding out photos from the internet for the purpose of research, investigation.
Sound patterns would track down the copied or pirated music ;) and videos will help in tracking down piracy.

Friday, February 12, 2010

I don't see my words in your design

It has always been a long and tough session to make the business people understand the thought process behind attaining a particular design model. In my career as a software designer I faced several categories of stakeholders for my design such as the IT-managers from the client's side, technical IT people, business people, end-users etc.
Usually we go and meet these users to grab the requirement of the system/application they are looking for and then try to draw a mapping between the requirement and the software logical constructs such as classes, objects, services, components etc. During the process some new terms pop up based on the abstraction of the designer which might not surface the exact word specified in the requirement. Designers try to map the features/requirement of the application with the logical software constructs which is sometimes beyond the understanding of some of the stakeholders.
Based on the technical knowledge on software design of the stakeholder it becomes harder or easier to bridge the gap and make them happy. I am sure all the designers have experienced these kinds of sessions where the audience is shouting at you syaing "I don't see my words in your design, make me understand how are you arriving at this model of yours..". It will be followed by a long discussion of why I did it.
For example, a person who drives a car might not be very familier with the internal structure or mechanism of a chasis or gear box, but you have to make him/her understand how is it related to the process of driving else S/he will not buy the car... I just had this kind of session today :)

Monday, August 25, 2008

Websphere Datapower


IBM came up with a hardware to work as an Enterprise Service Bus (ESB). Well not entirely. It's called Datapower, a part of Websphere SOA solution stack. In our project there's a need to convert data from a mainframe fixed field format to XML and vice versa. So we were looking for a solution that can support a huge volume of transactions in a fraction of second. Using an ESB could be a possible approach but this one is easy to setup and since the conversion is done through hardware, it's really fast. They have three models for the appliance - XS35, XA40 and XI50. We were interested about the XI50 which includes the features of XS35 and XA40. It's a big (approx. 2.5ft / 2ft) blue box weighing nearly 20lbs. (I was about to break my back while trying to carry it). The cooling fans make loud noises. It has got an USB interface to the computer. You can set up the initial configurations using that and then it will let you access a web-interface (embedded as a firmware - like a wireless router) to handle configuration. Among the other main features
  • Transforms disparate message formats - binary, legacy, and XML. It can load XSL templates, so XML to XML translations can be carried out using XSLT.

  • Provides message routing (basic routing using round-robin) and security supporting standards such as WS-Security and WS-SecurityPolicy.

  • Able to connect with MQ, HTTP or FTP.

  • Helps heterogeneous applications to connect to registries and repositories, as well as directly to database.

  • Able to translation modules generated by WTX (Websphere Transformation Extender). We tried this while converting XML from/to fixed field format. So it supports non-XML such as COBOL Copybooks.
  • A piece of routing logic can be injected using the routing policies.

Here is a link for more information http://www-01.ibm.com/software/integration/datapower/

It doesn't support adapters like ESBs. It's a hardware so it can give you a power of processing equivalent to 10 servers running ESBs. Looking at the current prices of servers and the limitations on the customization making a selection will be a little tough. Unless it's not an XML to XML conversion WTX should be kept handy.

Monday, July 14, 2008

Pluggable knowledge base for human brain

I bought my first 1GB USB flash drive in 3300 Indian Rupees ($80 approx.) in 2004. Nowadays I see 4GB flash drives are available in $14.99. It's so cheap these days and I hope someday we are going to have 1TB USB drive in $50 or less. USB has become universal and you can find it in computers, cameras, media players bluetooth devices, external drives; all most any device that's pluggable with a computer.
I remember the movie Terminator to be good instance of man-machine fusion. Imagine someday we all will have an USB port attached to our heads. All our knowledge base will be made available in market in USB drives so that we can plug that into our brain and use them. An idea called Brain-Computer Interface close to this is already out in the market (http://en.wikipedia.org/wiki/Brain-computer_interface).


The OS vendors can see a nice business case in developing a firmware to install in the brain so that it understand and interact with the USB port.
An interpretation layer to translate the data from the external media in a format that the brain can understand (may be an electric pulse language :))
A lucrative business opportunity for Google to come up with a search utility to look up the knowledge base and find out the required material and supply it to the brain :)
We will have knowledge bases available for a doctor, an engineer, a lawyer, software engineer and whatever else you can think of under this sky.
If I need to be a doctor in the morning a pilot in the evening and a cook in the night, I can do every thing very skillfully with all these equipments :)
Well you will still need to practice if you are going for a swimming competition.

Yes you are correct I have some free time to relax my brain and talk rubbish :)

Tuesday, June 17, 2008

Code Generator Part VIII: The generated code

As the concluding part of the Code Generator series here is an example of how the generator works to generate the code. In this post I am going to present a sample object definition as the input (order.xml) to generate couple of Java source files using the home made code generator.

A piece of code generated using your home made Code Generator

Here is an example of an XML object specification for Customer, Order, OrderItem and Item objects to be supplied as the input for the code generation.


Order.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- order.xml -->
<OOSpec name="Order">
<Package name="">
<Class name="Customer" stereotype="class" visibility="public" baseInterfaces="Transformer">
<Import reference="java.util.Vector"/>
<Attribute name="code"/>
<Attribute name="names" multiplicity="3" defaultValue="Partha,Sarathi,Sengupta"/>
<Attribute name="age" type="integer"/>
<Attribute name="contacts" multiplicity="*"/>
<Operation constructor="yes" documentation="This is default constructor"></Operation>
<Operation directive="" documentation="This is transform operation" name="transform" returnType="string" bodyClassName="com. codegenerator.ToXMLStringBody">
</Operation>
</Class>
<Class name="Order" baseInterfaces="Transformer">
<Attribute name="number"/>
<Attribute name="date" type="date"/>
<Operation constructor="yes"></Operation>
<Operation name="transform" returnType="string" bodyClassName="com. codegenerator.ToXMLStringBody" synchronized="yes">
</Operation>
</Class>
<Class name="OrderItem" baseInterfaces="Transformer">
<Attribute name="number" type="integer"/>
<Attribute name="quantity" type="integer"/>
<Operation constructor="yes"></Operation>
<Operation name="transform" returnType="string" bodyClassName="com. codegenerator.ToXMLStringBody">
</Operation>
</Class>
<Class name="Item" documentation="This is a sample documentation">
<Attribute name="number"/>
<Attribute name="description" defaultValue="This is a description of the item"/>
<Attribute name="price" type="double" defaultValue="2.12"/>
<Operation constructor="yes"></Operation>
<Operation name="transform" returnType="string" visibility="public" bodyClassName="com.codegenerator.ToXMLStringBody">
</Operation>
</Class>
<Class name="Transformer" stereotype="interface" baseInterfaces="java.io.Serializable">
<Operation name="transform" returnType="string"></Operation>
</Class>
</Package>
<Association name="">
<Role class="Customer" multiplicity="1" name="" start="yes" navigable="no"/>
<Role class="Order" multiplicity="2" name="myOrders" navigable="yes"/>
</Association>
<Association name="">
<Role class="Order" multiplicity="1" name="order" start="yes" navigable="no"/>
<Role class="OrderItem" multiplicity="4" name="orderItems" navigable="yes"/>
</Association>
<Association name="">
<Role class="OrderItem" multiplicity="1" name="" start="yes" navigable="no"/>
<Role class="Item" multiplicity="1" name="item" navigable="yes"/>
</Association>
</OOSpec>


The Java source codes generated from the above specification are presented below. Notice how the transform method has been generated differently in each class.
Customer.java

/* This file has been generated by the CodeGenerator */
package com.order;
import java.util.Vector;

public class Customer implements Transformer {
private String code;
private String[] names;
private int age;
private java.util.ArrayList contacts;
private Order[] myOrders;

public String getCode() { return this.code; }
public void setCode(String code) { this.code = code; }
public String[] getNames() { return this.names; }
public void setNames(String[] names) { this.names = names; }
public int getAge() { return this.age; }
public void setAge(int age) {this.age = age;}
public java.util.ArrayList getContacts() {return this.contacts;}
public String getContacts(int index) {return (String)this.contacts.get(index);}
public void setContacts(java.util.ArrayList contacts) {this.contacts = contacts;}
public void addContacts(String contacts) {this.contacts.add(contacts);}
public Order[] getMyOrders() {return this.myOrders;}
public void setMyOrders(Order[] myOrders) { this.myOrders = myOrders;}
public Customer() {
code = new String();
names = new String[3];
names[0] = new String("Partha");
names[1] = new String("Sarathi");
names[2] = new String("Sengupta");
age = 0;
contacts = new java.util.ArrayList();
myOrders = new Order[2];
for(int i=0; i<myOrders.length; i++) { myOrders[i] = new Order(); }
}

/*This is transform operation*/
public String transform() {
StringBuffer sb = new StringBuffer();
if(code != null && !code.toString().equals("")) {
sb.append("<code>"+code+"</code>");
}
else {
sb.append("<code/>");
}
for(int i=0; i<names.length; i++) {
if(names[i] != null && !names[i].toString().equals("")) {
sb.append("<names>"+names[i]+"</names>");
}
Else {
sb.append("<names/>");
}
}
sb.append("<age>"+age+"</age>");

for(int i=0; i<contacts.size(); i++) {
if(contacts.get(i) != null && !contacts.get(i).toString().equals("")) {
sb.append("<contacts>"+((String)contacts.get(i)).toString()+"</contacts>");
}
Else {
sb.append("<contacts/>");
}
}
for(int i=0; i<myOrders.length; i++) {
if(myOrders[i] != null){
sb.append("<myOrders>");
sb.append(myOrders[i].transform());
sb.append("</myOrders>");
}
Else {
sb.append("<myOrders/>");
}
}
return sb.toString();
}
}
Order.java

/* This file has been generated by the CodeGenerator */

package com.order;
import java.util.*;

public class Order implements Transformer{
private String number;
private java.util.Date date;
private OrderItem[] orderItems;
public String getNumber() {return this.number;}
public void setNumber(String number) { this.number = number; }
public java.util.Date getDate() { return this.date; }
public void setDate(java.util.Date date) { this.date = date; }
public OrderItem[] getOrderItems() { return this.orderItems; }
public void setOrderItems(OrderItem[] orderItems) { this.orderItems = orderItems; }
public Order(){
number = new String();
date = new java.util.Date();
orderItems = new OrderItem[4];
for(int i=0; i<orderItems.length; i++) {
orderItems[i] = new OrderItem();
}
}
public synchronized String transform() {
StringBuffer sb = new StringBuffer();
if(number != null && !number.toString().equals("")){
sb.append("<number>"+number+"</number>");
}
else {
sb.append("<number/>");
}
if(date != null && !date.toString().equals("")) {
sb.append("<date>"+date+"</date>");
}
else {
sb.append("<date/>");
}
for(int i=0; i<orderItems.length; i++) {
if(orderItems[i] != null){
sb.append("<orderItems>");
sb.append(orderItems[i].transform());
sb.append("</orderItems>");
}
else {
sb.append("<orderItems/>");
}
}
return sb.toString();
}
}
Item.java

/* This file has been generated by the CodeGenerator */

package com.order;
import java.util.*;

/*This is a sample documentation*/
public class Item implements java.io.Serializable{
private String number;
private String description;
private double price;
public String getNumber() { return this.number; }
public void setNumber(String number) { this.number = number; }
public String getDescription() { return this.description; }
public void setDescription(String description) { this.description = description; }
public double getPrice() { return this.price; }
public void setPrice(double price) { this.price = price; }
public Item() {
number = new String();
description = new String("This is a description of the item");
price = 2.12;
}
public String transform(){
StringBuffer sb = new StringBuffer();
if(number != null && !number.toString().equals("")){
sb.append("<number>"+number+"</number>");
}
else{
sb.append("<number/>");
}
if(description != null && !description.toString().equals("")) {
sb.append("<description>"+description+"</description>");
}
else{
sb.append("<description/>");
}
sb.append("<price>"+price+"</price>");
return sb.toString();
}
}
OrderItem.java

/* This file has been generated by the CodeGenerator */

package com.order;
import java.util.*;

public class OrderItem implements Transformer{
private int number;
private int quantity;
private Item item;
public int getNumber(){ return this.number; }
public void setNumber(int number) { this.number = number; }
public int getQuantity(){ return this.quantity; }
public void setQuantity(int quantity){ this.quantity = quantity; }
public Item getItem(){ return this.item; }
public void setItem(Item item){ this.item = item; }
public OrderItem(){
number = 0;
quantity = 0;
item = new Item();
}
public String transform(){
StringBuffer sb = new StringBuffer();
sb.append("<number>"+number+"</number>");
sb.append("<quantity>"+quantity+"</quantity>");
if(item != null && !item.toString().equals("")) {
sb.append("<item>");
sb.append(item.transform());
sb.append("</item>");
}
else{
sb.append("<item/>");
}
return sb.toString();
}
}
Hope this article will help those who are looking for preliminary information on the concepts and technologies used in code generation. Please feel free to leave your comments.

The Rarest Skill in Software Engineering · Enterprise Architecture · 30 Years in the Trenches The Rarest Skill in Softwar...