CrossContext and RequestDispatcher in webapps

This article will describe how to use a crosscontext requestdispatcher to communicate between two servlets in different webapps.

Settings the example

Lets say you have two webapps loaded in tomcat:

  • CustomerPortal (loaded at http://myserver.com/CustomerPortal)
  • EmployeePortal (loaded at http://myserver.com/EmployeePortal)

In the CustomerPortal you want to be able to show an Employee Datasheet by calling:

http://myserver.com/EmployeePortal/employee?id=<employeeid>

and in the EmployeePortal you want to show a Customer Datasheet by calling:

http://myserver.com/CustomerPortal/customer?id=<customerid>

 

Allowing the communication with CrossContext

For each project, add a file named context.xml to the META-INF library that contains the following:

<Context crossContext="true" />

If your webapp already has a context.xml file, just add the crossContext parameter to the context-tag.

Now you have allowed the webapps to communicate. Next step is to do the actual communication.

Perform communication with RequestDispatcher

For doing the communication, we need a RequestDispatcher.

ServletContext sc = this.getServletContext().getContext("/CustomerPortal");
RequestDispatcher disp = s1.getRequestDispatcher("customer?id=" + customerId);               
                
try {
    disp.include(request, response);
}  
catch(Exception e) {
    e.printStackTrace();
}

The above code will call CustomerPortal/customer?id=xxx and include the code received in the current spot of the page. The example is easily changed for calling the EmployeePortal.

Handle the response

In case you want it to be a bit more flexible and handle the response, the following code can be used instead

ServletContext sc = this.getServletContext().getContext("/CustomerPortal");
RequestDispatcher disp = s1.getRequestDispatcher("customer?id=" + customerId); 
StringWriter sw = new StringWriter();
final PrintWriter pw = new PrintWriter(sw);
HttpServletResponse responseWrapper =
    new HttpServletResponseWrapper(response) {
        @Override
        public PrintWriter getWriter() throws IOException {
            return pw;
        }
    };
dispatcher.include(request, responseWrapper);
System.out.println("html from customerportal: " + sw.toString());

Making a Plugin system in Java

Building a plugin system in Java is quite easy. Instead of writing a lot, I will provide an example and comment as we go. The whole project can be downloaded from the bottom of the post :)

A simple calculator using a plugin system

My example will be a simple calculator that uses plugins to perform calculations. The program must be executed from a command line – it cannot be executed through Eclipse since Eclipse cannot capture keyboard input and send it to the program.

CommandInterface.java

package dk.ithelten.calculator;

public abstract class CommandInterface
{
	protected float[] vars;

	public boolean setup(String[] s)
	throws Exception
	{
		vars = new float[s.length - 1];
		for(int i = 0 ; i < vars.length ; i++)
		{
			vars[i] = Float.parseFloat(s[i+1]);
		}
		return verifyInput();
	}

	public abstract String getCommand();
	public abstract float calculate();
	public abstract String getHelp();
	protected abstract boolean verifyInput();
}

This abstract class defines the interface that the plugins must use. I know it is an abstract method and not an interface – I just think it makes it more clear by calling it an interface. Suggestions for a better word than interface are welcome :)

CommandLine.java

This class will be taken one method at a time – makes it easier to explain what is going on. First create the class with only the main method:

package dk.ithelten.calculator;

import java.io.Console;
import java.io.File;
import java.util.HashMap;

public class CommandLine
{
	public static void main(String args[])
	{
		// Verify that a console is available
		Console c = System.console();
		if (c == null)
		{
            System.err.println("No console. Run from prompt");
            System.exit(1);
        }

		// Load the plugins
		loadPlugins();

		// Read input from console and send it to parser
		String input;
		do
		{
			input = c.readLine("> ").toLowerCase();
			parse(input);
		}
		while(!input.equalsIgnoreCase("exit"));
	}
}

The first section verifies that a console is available, then a method is called to load the plugins and finally the input is read and parsed int a loop.

	private static HashMap<String, CommandInterface> commands;

	private static void loadPlugins()
	{
		// create hashmap with available commands
		commands = new HashMap<String, CommandInterface>();

		File plugindir = new File("Plugins"); // the name of the plugin folder
		if(plugindir.isDirectory())
		{
			// Loop through the files found in the plugin folder
			for(File f : plugindir.listFiles())
			{
				int j = f.getName().lastIndexOf(".class");
				// check if it is a class file
				if(f.exists() && f.isFile() && j > 0)
				{
					try
					{
						// Create an instance of the plugin and put it in our hashmap
						String name = f.getName().substring(0,j);
						CommandInterface ci = (CommandInterface)Class.forName("plugins." + name).newInstance();
						commands.put(ci.getCommand().toLowerCase(), ci);
					}
					catch(Exception e)
					{
						e.printStackTrace();
					}
				}
			}
		}
		else
		{
			System.out.println("Error loading plugin dir");
			System.exit(2);
		}
	}

This method loads the plugins. The idea is to scan a directory for .class files and then try to cast them to our plugin interface – if that work, they are stored in the hashmap.

	private static void parse(String input)
	{
		String[] s = input.split(" ");
		if(s.length > 0)
		{
			CommandInterface ci = commands.get(s[0]);
			// Print the help screen if the user requests it
			// or if no plugin is found
			if(s[0].equalsIgnoreCase("help") || ci == null)
			{
				printHelp();
			}
			else
			{
				try
				{
					// if parameter input are correct then calculate
					if(ci.setup(s))
					{
						System.out.println("Result: " + ci.calculate());
					}
					// if incorrect parameters, display help
					else
					{
						System.out.println(ci.getHelp());
					}
				}
				catch(Exception e)
				{
					e.printStackTrace();
					System.out.println(ci.getHelp());
				}
			}
		}
		else
		{
			System.out.println("Input Error!");
		}
	}

The parse method reads the command that the user has entered and then finds the correct plugin to handle the calculation.

	private static void printHelp()
	{
		System.out.println("Available commands:");
		for(String cmd : commands.keySet())
		{
			System.out.println("\t" + cmd);
		}
	}

This is just the method to display the available plugins – no magic here.

At this point the system should be running but with no available plugins. The next task ahead is to make some plugins that can perform calculations.

Add.java

package plugins;

import dk.ithelten.calculator.CommandInterface;

public class Add extends CommandInterface
{

	@Override
	public String getCommand()
	{
		return "add";
	}

	@Override
	public float calculate()
	{
		float result = 0;
		for(float f : this.vars)
		{
			result += f;
		}
		return result;
	}

	@Override
	public String getHelp()
	{
		return "Usage: add <a> <b> <c> ....\nExample: add 13 9\n";
	}

	@Override
	protected boolean verifyInput()
	{
		return this.vars.length > 0;
	}

}

A class for addition. It will add from 1 to several numbers and print the result. Notice the package of the class. The reason for the short package for easier human understanding of the plugin structure.

Mult.java

package plugins;

import dk.ithelten.calculator.CommandInterface;

public class Mult extends CommandInterface
{
	@Override
	public String getCommand()
	{
		return "mult";
	}

	@Override
	public float calculate()
	{
		float result = 1;
		for(float f : this.vars)
		{
			result *= f;
		}
		return result;
	}

	@Override
	public String getHelp()
	{
		return "Usage: mult <a> <b> <c> .....\nExample: mult 3 3 4 4";
	}

	@Override
	protected boolean verifyInput()
	{
		return this.vars.length > 0;
	}
}

Basically the same as the Add plugin, but just with multiplication.

Finally

Now our program should be able to run with two plugins. The project can be downloaded as one zip file below that includes build scripts.

Take some time and play around with the program, develop your own plugins for it. The best way to learn is to get your hand dirty :-)

Download calculator plugin example

ORA-01000: Open Cursors in Oracle

During some development at the office, we encountered some problems with Oracle having too many open cursors. We kept getting ORA-01000 error at random times.

What is a cursor

Very simple explained, a cursor in Oracle is a pointer to your result. The more complex explanation is that it is a pointer/handler into the context area where it refers to a chunk of memory that has been allocated. Two types of cursors exist: Implicit cursors and Explicit cursors. For more info on cursors, ask google :)

Problem

At work we have some Java Servlets querying an Oracle database at one day we started getting this error:

ORA-01000: maximum open cursors exceeded

This would block any new connections to Oracle, but over time we would be able to reconnect. A restart of the Servlet Runner (in this case Tomcat) would also enable us to connect again.

The problem arises when too many cursors are open at one time to Oracle. In Oracle it can be defined how many cursors are allowed, but exceeding the normal amount usually indicates that there is another problem. The usual culprit is that the code does not properly close Statements and therefore the cursor remains open until it times out or the program terminates.

Solution to ORA-01000

To start with, I will present a piece of code that will create open cursors:

public static Vector<Integer> incorrect()
{
	Vector<Integer> result = new Vector<Integer>();
	Statement stmt = null;
	ResultSet rs = null;
	try
	{
		stmt = conn.createStatement();
		rs = stmt.executeQuery("SELECT myInt FROM SomeTable");
		while(rs.next())
		{
			result.add(rs.getInt("myInt"));
		}
	}
	catch(SQLException sqle)
	{
		sqle.printStackTrace();
	}
	return result;
}

As it can be seen in the code, the stmt object is never closed. One correct way of writing this method would be:

public static Vector<Integer> correct()
{
	Vector<Integer> result = new Vector<Integer>();
	Statement stmt = null;
	ResultSet rs = null;
	try
	{
		stmt = conn.createStatement();
		rs = stmt.executeQuery("SELECT myInt FROM SomeTable");
		while(rs.next())
		{
			result.add(rs.getInt("myInt"));
		}
	}
	catch(SQLException sqle)
	{
		sqle.printStackTrace();
	}
	finally
	{
		try
		{
			if(rs != null)
			{
				rs.close();
			}
			if(stmt != null)
			{
				stmt.close();
			}
		}
		catch(SQLException e)
		{
			e.printStackTrace();
		}
	}
	return result;
}

The try-catch statement was changed to a try-catch-finally that secures the stmt object to be closed.

To detect Open Cursors before it becomes a problem,  run the following query in Oracle:

SELECT user_name, sql_text FROM v$open_cursor ORDER BY user_name, sql_text;

This will display the last run SQL in each open cursor – but be aware lots of internal Oracle users will also be shown, do not get spooked by that :-)