Wednesday, January 24, 2007

J2EE, what is it?

It has been a while since I posted. I've been busy training new co-op students and trying to get two projects out the door.

One of the projects runs on JBoss application server. The interface for configuring the application is deployed as a WAR file. So we can update the configuration tools on future releases by just shipping a new WAR file to the customers. The student didn't understand how this works. Here was my 5 minute explanation...

In Java you have JAR files. A JAR file is a ZIP file with a bunch of Java classes in it. You can create a JAR file such that it can be run using 'java -jar'. It just requires the JAR file to have specific files in specific locations. A WAR file is the same idea.

For example, if I want to create the WAR file console.war I might do the following:

- Create the directory C:\console
- Create the directory C:\console\WEB-INF
- Create the directory C:\console\META-INF
- Create the file C:\console\WEB-INF\web.xml
- Create the file C:\console\META-INF\Manifest.mf

This is the basic structure. Now I need the code that will actually get run. Let's say I create the class AdminConsole in the package com.mycompany.myproject.console. Or, in other words, I created the file C:\console\classes\com\mycompany\myproject\console\AdminConsole.class.

The web.xml is defined by J2EE WAR file standards to have a specific format. It might contain something like:
<web-app>
<servlet>
<servlet-name>
com.mycompany.myproject.console.AdminConsole
</servlet-name>
<servlet-class>
com.mycompany.myproject.console.AdminConsole
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>
com.mycompany.myproject.console.AdminConsole
</servlet-name>
<url-pattern>
/console/Admin
</url-pattern>
</servlet-mapping>
</web-app>


The <servlet> tag tells the application server about the class file and the <servlet-mapping> tells the application server when to run the code. So if the server in on the machine darrell.blogger.com the user could enter the following in a web browser:
http://darrell.blogger.com/console/Admin

The <url-pattern> takes the /console/Admin and knows which Java code to run. It will run the AdminConsole.class code. The AdminConsole class has to have specific methods implemented. Just like a desktop application knows to start at:
public static void main(Strings[] args)

The AdminConsole class will extend javax.servlet.http.HttpServlet and will have doGet() and possibly doPost() methods.

With a desktop application, if I wanted to print to the screen I'd use System.out, e.g.
System.out.println("Hello");

but with a servlet I'd have to get the output stream and write to it, e.g.
ServletOutputStream sos = response.getOutputStream();
// uses the methods of ServletOutputStream to write to the web browser
// e.g. sos.write().

Additionally, when you write to the web browser you have to indicate it the data is an image, text, HTML, etc. Before you write you can do things like:
response.setContentType("text/html");

So if you can write a Java application, it is fairly easy to convert to a web application.

Tuesday, January 9, 2007

Making shell scripts atomic

What do you do if you have a shell script that cannot be run twice at the same time, i.e. you have to wait until the script finishes before you can run it a second time.

The solution is to make the script check to see if it is running. If it is not running then let it start. The problem with this is it is possible to have the following scenario:

- start the script
- it checks to see if it is running
- start the script running a second time
- the second script checks to see if it is running
- flag that the first script is running and enter the critical section
- flag that the second script is running and enter the critical section

In other words, the check and the setting of the flag have to be atomic, i.e. you cannot have them be two steps in the script.

The solution is to use ln to create a link. The link will be the setting of the flag and the check. Then you can check the status of the ln command (the flag).

So here is the code to do it:
# Bourne Shell
#!/bin/sh

# create a filename for the ln
LOCK=`echo $0 | awk -F/ '{print $NF}' | awk -F. '{print $1}'`.LOCK

# create the link
ln $0 ${LOCK} 2> /dev/null

# see if we are already running
if [ $? -eq "0" ]; then
echo "running atomic script here"
echo "it just sleeps for 5 seconds"
sleep 5
/bin/rm ${LOCK}
else
echo "script is already running"
fi


Or if you perfer the C shell:
#C shell
#!/bin/csh

# create a filename for the ln
set LOCK=${0:r}.LOCK

# create the link
ln $0 ${LOCK} >& /dev/null

# see if we are already running
if ( ! $status ) then
echo "running atomic script here"
echo "it just sleeps for 5 seconds"
sleep 5
/bin/rm ${LOCK}
else
echo "script is already running"
endif