Sunday, May 31, 2009

Dustin's Bookmarks - 31 May 2009 (REST, Java, and JRuby)

I found four resources linked to from DZone to be particularly interesting this week. I am linking to them in this post as a form of glorified bookmark for my own future reference and in case someone else has not seen them already.


Five Things I Used to Forget About Java

The blog post Five Things I Used to Forget About Java could be useful to anyone returning to Java development, anyone new to Java development, or anyone who has not used one the items discussed for a while. The post covers Java approaches for converting String to Integer, use of the ternary operator, instanceof keyword versus Class.isInstance method, implementing comparators, and obtaining the number of command-line arguments passed into a main function.


Is It JRuby?

The useful online tool Is It JRuby? helps deal with the question of whether a particular Ruby gem will work with JRuby. Although many Ruby gems do work well with the JRuby implementation, some Ruby gems (especially the C-based ones) only run with other, non-JRuby implementations of Ruby. This community-driven site helps organize which Ruby gems work with JRuby. I plan to mention this resource in my Colorado Software Summit 2009 presentation Applied JRuby.


RESTGate - Web Client for REST Resources

The online tool RESTGate - Web-Based Client for REST-based Web Services appears to be an easy-to-use (no setup) browser-based client for performing simple testing of and interaction with REST-based web services. I will likely blog on this in more detail in the future and will almost certainly mention this tool in my Colorado Software Summit 2009 presentation RESTful Java.


sqlREST

The sqlREST project looks like an interesting one. This project benefits from use of Java standards, running on Java EE servlet containers and connecting to multiple databases via appropriate JDBC drivers. The goal of this project is to allow easy exposure of database entries via REST-style web services. Like the other Thomas Bayer tool mentioned above (RESTGate), I plan to mention sqlREST as part of my RESTful Java presentation.

Thursday, May 21, 2009

Groovy in Java with JSR 223

I previously blogged on using JavaScript in Java. The same Java Specification Request that allows for JavaScript in Java, JSR 223 ("Scripting for the Java Platform"), allows for including other scripting languages in Java. In this blog posting, I'll briefly look at embedding Groovy code in a Java application via JSR 223 support.

Sun's Java SE 6 includes the Rhino JavaScript engine, but does not include Groovy by default. Fortunately, Groovy 1.6 (I'm using 1.6.2) provides built-in JSR 223 support that makes it really easy to embed Groovy within Java. For example, if my Java application with embedded Groovy is called GroovyInJavaExample, is a class located in the dustin.examples package, and is built into a JAR named ScriptInJava.jar and if Groovy is installed in C:\Program Files\Groovy\Groovy-1.6.2\, I can run the Java+Groovy code as follows:


java -cp dist\ScriptInJava.jar;"C:\Program Files\Groovy\Groovy-1.6.2\lib\*" dustin.examples.GroovyInJavaExample


By including the necessary JARs from the Groovy distribution, the JSR 223 support for Groovy in Java is automatically available.

The code listing for GroovyInJavaExample.java is shown next. It is similar to the example I used in the JavaScript in Java blog example I used previously.


package dustin.examples;

import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

/**
* This example demonstrates using Groovy within Java SE 6.
*/
public class GroovyInJavaExample
{
private final static ScriptEngineManager manager = new ScriptEngineManager();

/** Using java.util.logging. */
private final static Logger LOGGER = Logger.getLogger(
GroovyInJavaExample.class.getName());

private final static String NEW_LINE = System.getProperty("line.separator");

private final static String HEADER_SEPARATOR =
"=======================================================================";

/**
* Write the key information about the provided Script Engine Factories to
* the provided OutputStream.
*
* @param scriptEngineFactories Script Engine Factories for which key data
* should be written to the OutputStream.
* @param out OutputStream to which to write Script Engine Factory details.
*/
public static void writeScriptEngineFactoriesToOutputStream(
final List<ScriptEngineFactory> scriptEngineFactories,
final OutputStream out)
{
printHeader("Available Script Engines", out);
try
{
out.write(NEW_LINE.getBytes());
for (final ScriptEngineFactory scriptEngine : scriptEngineFactories)
{
out.write(
( scriptEngine.getEngineName() + " ("
+ scriptEngine.getEngineVersion() + ")" + NEW_LINE).getBytes());
out.write(
( "\tLanguage: " + scriptEngine.getLanguageName() + "("
+ scriptEngine.getLanguageVersion() + ")" + NEW_LINE).getBytes());
out.write("\tCommon Names/Aliases: ".getBytes());
for (final String engineAlias : scriptEngine.getNames())
{
out.write((engineAlias + " ").getBytes());
}
out.write(NEW_LINE.getBytes());
}
out.write(NEW_LINE.getBytes());
}
catch (IOException ioEx)
{
LOGGER.severe(
"Could not write to provided OutputStream: "
+ ioEx.toString());
}
}

/**
* Show availability of scripting engines supported in this environment.
*/
public static void testSupportedScriptingEngines()
{
writeScriptEngineFactoriesToOutputStream(
manager.getEngineFactories(), System.out);
}

/**
* Process the passed-in Groovy script that should include an assignment
* to a variable with the name prescribed by the provided nameOfOutput and
* may include parameters prescribed by inputParameters.
*
* @param groovyCodeToProcess The String containing Groovy code to
* be evaluated. This String is not checked for any type of validity and
* might possibly lead to the throwing of a ScriptException, which would
* be logged.
* @param nameOfOutput The name of the output variable associated with the
* provided Groovy script.
* @param inputParameters Optional map of parameter names to parameter values
* that might be employed in the provided Groovy script. This map may be
* null if no input parameters are expected in the script.
*/
public static Object processArbitraryGroovy(
final String groovyCodeToProcess,
final String nameOfOutput,
final Map<String, Object> inputParameters)
{
Object result = null;
final ScriptEngine engine = manager.getEngineByName("groovy");
try
{
if (inputParameters != null)
{
for (final Map.Entry<String,Object> parameter :
inputParameters.entrySet())
{
engine.put(parameter.getKey(), parameter.getValue());
}
}
engine.eval(groovyCodeToProcess);
result = engine.get(nameOfOutput);
}
catch (ScriptException scriptException)
{
LOGGER.severe(
"ScriptException encountered trying to write arbitrary Groovy '"
+ groovyCodeToProcess + "': "
+ scriptException.toString());
}
return result;
}

/**
* Write passed-in headerMessage text to provided OutputStream using clear
* header demarcation.
*
* @param headerMessage Text to be written to header.
* @param out OutputStream to which header should be written.
*/
private static void printHeader(
final String headerMessage, final OutputStream out)
{
try
{
out.write((NEW_LINE + HEADER_SEPARATOR + NEW_LINE).getBytes());
out.write((headerMessage + NEW_LINE).getBytes());
out.write((HEADER_SEPARATOR + NEW_LINE).getBytes());
}
catch (IOException ioEx)
{
LOGGER.warning(
"Not able to write header with text '"
+ headerMessage
+ " out to provided OutputStream: " + ioEx.toString());
System.out.println(HEADER_SEPARATOR);
System.out.println(headerMessage);
System.out.println(HEADER_SEPARATOR);
}
}

/**
* Demonstrate execution of an arbitrary JavaScript script within Java that
* does NOT include parameters.
*/
public static void testArbitraryJavaScriptStringEvaluationWithoutParameters()
{
printHeader(
"Display x character consecutively repeated (no parameters).", System.out);
System.out.println(
processArbitraryGroovy("newString = 'x'.multiply(50)", "newString", null));
}

/**
* Demonstrate execution of an arbritrary JavaScript script within Java
* that includes parameters.
*/
public static void testArbitraryJavaScriptStringEvaluationWithParameters()
{
printHeader(
"Display y character consecutively repeated (parameters)",
System.out);
final Map<String, Object> characterRepetitionParameters =
new HashMap<String, Object>();
characterRepetitionParameters.put("character", "y");
characterRepetitionParameters.put("number", 50);
System.out.println(
"New character string is: "
+ processArbitraryGroovy(
"newString = character.multiply(number)",
"newString",
characterRepetitionParameters)
+ NEW_LINE);
}

/**
* Intentionally cause script handling error to show the type of information
* that a ScriptException includes.
*/
public static void testScriptExceptionHandling()
{
printHeader(
"Intentional Script Error to Demonstrate ScriptException", System.out);
System.out.println(
NEW_LINE + processArbitraryGroovy("Garbage In", "none", null));
}

/**
* Main executable for demonstrating running of script code within Java.
*/
public static void main(final String[] arguments)
{
testSupportedScriptingEngines();
testArbitraryJavaScriptStringEvaluationWithoutParameters();
testArbitraryJavaScriptStringEvaluationWithParameters();
testScriptExceptionHandling();
}
}


When the above code is run, the output is shown in the next screen snapshot.



From this output, we see that the Groovy Scripting Engine is available in addition to the Rhino JavaScript Engine that was available by default with the Sun SDK. We can also see that the two aliases for getting a handle on this scripting engine from within Java code are "groovy" and "Groovy".

The output shown above also shows that using Groovy's .multiply operator method on a String literal works just fine as the "x" and "y" characters are repeated the provided number of times. The examples show how to call arbitrary Groovy code without and with parameters. The final example in the above output also shows the ScriptException encountered when a bad piece of Groovy code is provided to the engine.

Conclusion

Although Groovy is not provided out-of-the-box with the Sun SDK like the Rhino JavaScript engine is, this blog posting has attempted to show that Groovy's built-in support for JSR 223 makes it easy to embed Groovy with Java in a JSR 223 compliant syntax. Because Groovy really is Java, there are other ways to integrate the two, but it is nice to know that JSR 223 syntax can be used with Groovy easily and similarly to JavaScript in Java. Consistency is often a highly desirable goal.

Wednesday, May 20, 2009

JRuby's Ruby-Style Exception Handling

Both Java and Ruby have relatively sophisticated exception handling built-in to the respective languages. Their exception handling techniques have many similarities, but also have some differences in both keywords and in supported exception handling functionality. JRuby allows mixing of Java classes with Ruby code and so it is no surprise that JRuby supports handling of exceptions thrown by Java classes.

Ruby's equivalent of Java's try-catch-finally is begin-rescue-ensure, though Ruby throws in an additional clause with the else clause. The else clause is executed when no declared rescue block is exercised. In other words, if there was an equivalent in Java (there isn't), it would be a block of code that is executed only when none of the the declared catch blocks were executed. Note that the Ruby else is different from Ruby's ensure or Java's finally in that it is only executed if no rescue (equivalent of Java catch) statement is executed while Ruby's ensure and Java's finally are always executed no matter which exceptions were caught or not caught.

Speaking of catching exceptions, Ruby does not have an equivalent of Java's checked exceptions. JRuby (and Groovy by the way) emulate this as well. Java and Ruby throw exceptions in the first place in a very similar manner, though Java uses the keyword throw and Ruby uses the keyword raise.

With the idea that most of the concepts of Java exception handling are highly similar to Ruby exception handling (the notable exceptions being the keywords used, the use of checked exceptions only in Java, and the use of a block of code executed only when no declared exception condition is encountered only in Ruby), it is time to move on to an examples of catching exceptions thrown by a Java class in JRuby code.

Java exceptions, even checked exceptions, do not need to be rescued/caught in JRuby. This is demonstrated in the following code listing in which an SQLRecoverableException (a checked exception) might be thrown (and the called method is declared to throw its parent SQLException) but no explicit exception handling is implemented.

Listing 1 - JRuby Invocation of Java Method Throwing Exception

#!/usr/bin/env jruby -w

include Java
import java.sql.SQLRecoverableException
require 'C:\app\Dustin\product\11.1.0\db_1\jdbc\lib\ojdbc6.jar'
require 'C:\java\examples\jrubyExamples\jrubyExceptionHandling\lib\Dustin.jar'
include_class Java::dustin.examples.jruby.GenericOracleDatabaseAccessor

# 1. "Happy Path" query to demonstrate JRuby/Java interaction works fine
puts "ALL'S WELL"
accessor = GenericOracleDatabaseAccessor.new
puts "#{accessor.perform_database_query \
'jdbc:oracle:thin:@//localhost:1521/orcl',
'select first_name, last_name from employees',
['FIRST_NAME', 'LAST_NAME'].to_java(:string)}"


In the example above, there is a call to a custom Java class (GenericOracleDatabaseAccessor) and method (performDatabaseQuery). That class is shown in the next code listing.


Listing 2 - GenericOracleDatabaseAccessor.java

package dustin.examples.jruby;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import oracle.jdbc.pool.OracleDataSource;

/**
* Class used for demonstration purposes only and should not be used anywhere
* in which security or maintainability matter. The problems with this
* particular Java class include its being in the unnamed package, the extreme
* riskiness of supporting a generic query of any String passed into the method,
* lack of use of PreparedStatement, lack of verification of correct and
* non-null parameters before applying them, etc. In fact, this class is used
* here because its many problems make it easy to have it throw exceptions that
* the JRuby example code can catch and handle.
*/
public class GenericOracleDatabaseAccessor
{
final static String NEW_LINE = System.getProperty("line.separator");

/**
* Perform a generic database query. CAUTION: There are
* numerous reasons why this particular code sample should not be used in
* any real or production settings. It is used here only to demonstrate
* how JRuby supports handling of Java exceptions in a Ruby-like manner. It
* is not a good idea normally to pass in the JDBC URL. The JDBC exception
* handling is also intentionally poor in this example. See class description
* for other failings (mostly intentional) of this class and method..
*
* @param jdbcUrl The JDBC URL for the database connection; a default is
* attempted if this is null.
* @param queryString The query statement to be run against the database.
* @param columnNames Column Names whose values are to be returned in
* resulting String.
* @throws SQLException Checked exception related to use of JDBC.
*/
public String performDatabaseQuery(
final String jdbcUrl,
final String queryString,
final String[] columnNames) throws SQLException
{
final OracleDataSource datasource = new OracleDataSource();
final String url = jdbcUrl == null
? "jdbc:oracle:thin:@//localhost:1521/orcl"
: jdbcUrl;
datasource.setURL(url);
datasource.setUser("hr");
datasource.setPassword("hr");
final Connection connection = datasource.getConnection();
final Statement queryStatement = connection.createStatement();
final ResultSet resultSet = queryStatement.executeQuery(queryString);
final StringBuilder returnString = new StringBuilder();
while (resultSet.next())
{
for (final String columnName : columnNames)
{
returnString.append(resultSet.getObject(columnName)).append(" ");
}
returnString.append(NEW_LINE);
}
resultSet.close();
queryStatement.close();
connection.close();
return returnString.toString();
}
}


As the code listing for GenericOracleDatabaseAccessor above indicates, the main method that is called on that class is called performDatabaseQuery and its accepts three parameters. The JRuby code could have called this method in a traditional Java-style call, but I chose to use a more Ruby-stylistic method call with underscores separating the multiple words in the method name along with parameters passed to the method in Ruby style.

The Java method performDatabaseQuery is declared to throw SQLException (parent of SQLRecoverableException). However, the calling JRuby code did not need to explicitly handle the exception. The above code ran correctly, but how would the exception be handled if it did get thrown? The next JRuby sample code intentionally specifies a non-existent host to force an exception to be thrown.

Listing 3 - Java Exception Thrown But Not Explicitly Handled in JRuby

#!/usr/bin/env jruby -w

include Java
import java.sql.SQLRecoverableException
require 'C:\app\Dustin\product\11.1.0\db_1\jdbc\lib\ojdbc6.jar'
require 'C:\java\examples\jrubyExamples\jrubyExceptionHandling\lib\Dustin.jar'
include_class Java::dustin.examples.jruby.GenericOracleDatabaseAccessor

puts "EXCEPTION WITHOUT HANDLING"
accessor = GenericOracleDatabaseAccessor.new
puts "#{accessor.perform_database_query \
'jdbc:oracle:thin:@//unknownhost:1521/orcl',
'select first_name, last_name from employees',
['FIRST_NAME', 'LAST_NAME'].to_java(:string)}"


Running the above JRuby code leads to the following output.



Although the exception thrown from the Java class was never explicitly handled in the code, the JRuby output shown directly above indicates that the exception is ultimately "handled" by displaying stack trace information. Of particular interest is the NativeException, the JRuby exception that wraps Java exceptions.


Listing 4 - JRuby Code Explicitly Catching Java Exception

#!/usr/bin/env jruby -w

include Java
import java.sql.SQLRecoverableException
require 'C:\app\Dustin\product\11.1.0\db_1\jdbc\lib\ojdbc6.jar'
require 'C:\java\examples\jrubyExamples\jrubyExceptionHandling\lib\Dustin.jar'
include_class Java::dustin.examples.jruby.GenericOracleDatabaseAccessor

puts "RUBY CATCHING OF JAVA EXCEPTION"
accessor = GenericOracleDatabaseAccessor.new
begin
puts "#{accessor.perform_database_query \
'jdbc:oracle:thin:@//unknownhost:1521/orcl',
'select first_name, last_name from employees',
['FIRST_NAME', 'LAST_NAME'].to_java(:string)}"
rescue SQLRecoverableException => sqlRecoverableException
puts "#{sqlRecoverableException}"
puts "Message: #{sqlRecoverableException.message}"
puts "Backtrace: #{sqlRecoverableException.backtrace}"
end


The code in Listing 4 looks like Ruby code, but explicitly catches a Java exception (SQLRecoverableException). The output from running this is shown next.



The same exception can be caught with a Ruby-specific exception as well. This is shown with the next code listing (Listing 5).

Listing 5 - Catching Java Exception in JRuby as Ruby Exception

#!/usr/bin/env jruby -w

include Java
import java.sql.SQLRecoverableException
require 'C:\app\Dustin\product\11.1.0\db_1\jdbc\lib\ojdbc6.jar'
require 'C:\java\examples\jrubyExamples\jrubyExceptionHandling\lib\Dustin.jar'
include_class Java::dustin.examples.jruby.GenericOracleDatabaseAccessor

puts "CATCHING INTENTIONAL EXCEPTION WITH RUBY'S RUNTIME ERROR"
accessor = GenericOracleDatabaseAccessor.new
begin
puts "#{accessor.perform_database_query \
'jdbc:oracle:thin:@//unknownhost:1521/orcl',
'select first_name, last_name from employees',
['FIRST_NAME', 'LAST_NAME'].to_java(:string)}"
rescue RuntimeError => runtimeError
puts "#{runtimeError}"
puts "Message: #{runtimeError.message}"
puts "Backtrace: #{runtimeError.backtrace}"
end


The output for the above code listing is shown next.



Ruby provides the ability to catch multiple exceptions in the same rescue clause (a feature talked about for Java SE 7). With JRuby, we can leverage this functionality to use the same rescue clause to catch a Java-based exception and a Ruby-based exception. This is demonstrated with Listing 6.

Listing 6 - Catching Java and Ruby Exceptions in Same rescue Clause

#!/usr/bin/env jruby -w

include Java
import java.sql.SQLRecoverableException
require 'C:\app\Dustin\product\11.1.0\db_1\jdbc\lib\ojdbc6.jar'
require 'C:\java\examples\jrubyExamples\jrubyExceptionHandling\lib\Dustin.jar'
include_class Java::dustin.examples.jruby.GenericOracleDatabaseAccessor

puts "CATCHING/RESCUING RUBY/JAVA EXCEPTIONS IN SAME RESCUE BLOCK"
accessor = GenericOracleDatabaseAccessor.new
begin
puts "#{accessor.perform_database_query \
'jdbc:oracle:thin:@//unknownhost:1521/orcl',
'select first_name, last_name from employees',
['FIRST_NAME', 'LAST_NAME'].to_java(:string)}"
rescue RuntimeError, SQLRecoverableException => sqlError
puts "#{sqlError}"
puts "Message: #{sqlError.message}"
puts "Backtrace: #{sqlError.backtrace}"
end


The output for this code listing is now shown.



Ruby adds some extra possibilities to exception handling. Besides the rescue keyword, Ruby also provides the ability to execute a block of code if no rescue block is executed. This is indicated with the else keyword. This is different from ensure (Ruby's equivalent of Java's finally) because it only executes if none of the declared rescue blocks is executed.

The next code listing demonstrates this and the screen shot following the code listing shows what the output looks like upon execution.

Listing 7 - Demonstrating Ruby's else and ensure Keywords

#!/usr/bin/env jruby -w

include Java
import java.sql.SQLRecoverableException
require 'C:\app\Dustin\product\11.1.0\db_1\jdbc\lib\ojdbc6.jar'
require 'C:\java\examples\jrubyExamples\jrubyExceptionHandling\lib\Dustin.jar'
include_class Java::dustin.examples.jruby.GenericOracleDatabaseAccessor

puts "USING RUBY'S ELSE AND ENSURE"
accessor = GenericOracleDatabaseAccessor.new
begin
puts "#{accessor.perform_database_query \
'jdbc:oracle:thin:@//localhost:1521/orcl',
'select first_name, last_name from employees',
['FIRST_NAME', 'LAST_NAME'].to_java(:string)}"
rescue RuntimeError, SQLRecoverableException => sqlError
puts "#{sqlError}"
puts "Message: #{sqlError.message}"
puts "Backtrace: #{sqlError.backtrace}"
else
puts "ELSE: Data Access performed without exception!"
ensure
puts "ENSURE: I am always called whether rescue or else is invoked."
end




Conclusion

Exception handling is just one area in which JRuby makes it easy to mix Java and Ruby. This blog posting has covered different ways to handle exceptions thrown by Java classes in JRuby code. Additional resources with different and greater details are listed next.


Additional Resources

Handling Java Exceptions in JRuby (September 2006)

Dealing with Java Exceptions in JRuby (May 2007)

Java and Ruby Working Together (see "Exception handling" section)

Calling Java from JRuby (Wiki page that was last updated 21 March 2009 at time of this writing)

Using Java Classes in JRuby (September 2007)

Ruby Exceptions: Ruby Study Notes

Ruby's Exception Hierarchy (September 2006)

Programming Ruby: Exceptions, Catch, and Throw (2001)

Sunday, May 17, 2009

Colorado Software Summit News

Colorado Software Summit has added new speakers and topics to the agenda for Colorado Software Summit 2009 and has released additional presentations for download from Colorado Software Summit 2008.

The Colorado Software Summit has released four additional presentations from Colorado Software Summit 2008 for publicly available download. The two Tom Harrington presentations are on iPhone development and there are two Denise Hatzidakis presentations on WebSphere sMash and REST. I enjoyed Denise's introductory REST presentation so much last year that I intend to reference it in my Colorado Software Summit 2009 presentation on using REST with Java.

Some new speakers and presentations have been added to the preliminary agenda for Colorado Software Summit 2009. These include two presentations by Eric Schreiner on Groovy and two presentations by Jay Balunas on JavaServer Faces.

If you are thinking about attending this year's edition of the Colorado Software Summit, note that Early Registration lasts through the end of this month (May 2009).

Saturday, May 16, 2009

Not All Help is Helpful

We all are exposed to and often use euphemisms to reference something unpleasant with a more pleasant word or phrase. Popular euphemisms (at least to the user of the euphemism, but often not to the recipient) include workforce realignment, pursuing other opportunities, and headcount restructuring. I have noted that the word "help" is also often used as an euphemism.

"Help" is one of those words that can be what it actually portends to be or can be an euphemism. In this way, it is like "agile development" and many other trendy computer science terms. There are disciplined practitioners who do try to practice agile (think the original creators of the Agile Manifesto), but there are also less scrupulous (or less informed) developers who have corrupted the term "agile" to be a euphemism for no documentation, no design, or lack of anything else they don't want to do. "Help" suffers similar double meanings. On one hand, someone who offers help can really mean it and can really provide it. On the other hand, "help" sometimes is intentionally or unintentionally more of an euphemism for something not so positive.


Alternative Meanings / Implications of "Help"

Offered "help" can sometimes turn out to be the exact opposite of that. In other words, the attempted "help" can actually hinder or slow progress. The following is a brief list of actions that are often thought of as "help," but often are exactly the opposite. I am sure that this is only a subset of the various actions software developers have encountered under the guise of "help" that are really not that helpful.

Micromanaging

It is an ironic twist that well-intentioned folks can actually impede the progress of a project while trying to help it because they too frequently request status, because they override reasonable decisions because they think their approach is quicker, or because they watch over the person's shoulder to make sure they don't make the slightest mistake. All of these can be symptomatic of micromanagement and tend to hinder rather than help. I have blogged before on how the very act of measuring progress can hinder the very progress being measured.

Throwing More 'Resources' At It

Brook's Law is Fred Brooks's "law" from the oft-quoted The Mythical Man-Month in which he states that adding people to a late project simply makes the project later. There are many reasons for this including the delay foisted on the current team to teach the new team members what the existing team members already knew and the added overhead that comes from additional communication needs and miscommunication mistakes. Although The Mythical Man-Month is one of the most frequently quoted and read books in the genre of software development management, it still seems the first thing we want to do with a late project is throw more people at it, even if that doesn't really help.

(Over)Reactionary Tactics

"Help" can be a euphemism for overreaction as well. A client, manager, or colleague may insist on a new and tighter process to "help" avoid mistakes. The action may indeed reduce the likelihood of whatever mistake it was aimed at from occurring, but sometimes does this at far greater cost than the cost of the incident being avoided. For example, if an extra step in a process avoids a type of mistake that happens about once a week and causes 2 hours of downtime for ten developers, but the extra step costs the ten developers one hour per day to implement, the "cure" is worse than the "disease." Often in these cases, a less reactionary and slight change in process is all that is needed.


Making 'Help' Actually Help

There are tactics one can use to increase the odds of offered and provided "help" actually being helpful. Some of them are listed and described here.

Partition Work for the 'Additional Resources'

When provided with additional "help" in the way of new personnel, this can be more helpful if the new personnel work on things with the least need of mentoring and tutoring from existing personnel and if they work on things in which they are least likely to "step on others toes." They might be able to help with things that need to get done but aren't high on the current developers' lists. Depending on the environment, these could include things such as integration testing, user documentation, and so forth.

Tell Others How They Can Help

Perhaps the best way to ensure that intended "help" is actually helpful is to spend a little time figuring out what would actually be helpful and making those observations clear to those providing the help. Clients, supervisors, and colleagues want to succeed and really believe they are helping even when they are not. These well-intended individuals can actually be helpful if they really understand how they can help. The best way to ensure they understand how to be truly helpful is to tell them how they can be helpful. Most of us have little things we want to fix in our code or we have questions or concerns about something we'll be getting to later. We can express these concerns and questions and get additional people involved in resolving these potential issues in advance of actually having to handle them.

Explaining to those in charge what reasonable measures would best resolve problems is especially effective because it can reduce the likelihood of overreaction.

Avoiding Unnecessary 'Help' Altogether

One of the best ways to avoid getting unnecessary "help" or something even worse under the euphemism of "help" is to make sure that those who might be likely to provide such "help" understand that no help is needed. I have never believed that it is a good idea to ignore problems or pretend they are not there. So how does one make sure that unnecessary "help" is not provided even when one has to report bad news? The best way to avoid unnecessary help in such cases is to provide the plan one has already come up with to get out of any bad situations and/or to avoid any particularly costly mistake from happening again. There will be less perceived need to force "help" onto a team that has already observed how to get itself out of a mess and/or avoid a similar mess.


Conclusion

As I stated above, all stakeholders on a given software development project generally want it to succeed and will do what they think is appropriate to increase the chances of success. Unfortunately and both intentionally and unintentionally, this can sometimes lead to "help" that turns out to actually be anything but help. Indeed, it can be easy to start to see "help" as a euphemism for something less desirable such as micromanagement, increased scrutiny, and other actions that actually exacerbate the problem rather than remedying it. We can reduce or minimize the negative effects of well-intentioned but negative "help" by providing our own proposals for how to best get out of a particular bad situation and letting others know what they can do to be truly helpful.

Dustin's Bookmarks - 16 May 2009

There have been some really interesting developments covered recently in the blogosphere that I mention here. I write a blog for numerous reasons, not the least of which is to use certain posts as glorified bookmarks. This blog post certainly fills that purpose as it points to at least two web pages that I'll likely reference in the future.

Microsoft Silverlight and Adobe Flash/AIR News

DevTopics reports that the New York Times is abandoning Silverlight in favor of Adobe AIR and outlines some of the reasons for this decision. Major League Baseball switched from Silverlight to Flash for reasons cited in Why Baseball Benched Microsoft Silverlight. The battle for market dominance continues.


Classic Programming Quotes

Recently posted Classic Programming Quotes has some really funny (and sadly true at the same time) quotes on software development and programming. There are several collections of quotations on the web related to software development, but this is one of my favorite collections. The quotes poke at things I like and thinks I don't like as much, but I had to laugh at some of them even when they poked at things I like. Among other things, the quotes discuss Java, PHP, Perl, XML, and deadlines.


Twenty Very Useful Java Code Snippets for Java Developers

Once I have gained some basic familiarity with a programming language or framework, I often like to get a "Cookbook" or "Recipes" style book for that language or framework. The format and content of these books is good for learning focused approaches to accomplishing specific tasks. In reviewing these recipes, more general concepts and principles are also learned as well. The post 20 Very Useful Java Code Snippets for Java Developers is similar to these types of books.


Codeplay Album Available for Download

In exciting news totally unrelated to software development, Coldplay's live album LeftRightLeftRightLeft has been made available for free download for a limited time.

Tuesday, May 12, 2009

A Great Free Online Books Repository

I recently blogged about the availability of Common Java Cookbook as an open and freely available book focusing on Apache Commons. I also pointed out in that blog post that I had learned of the availability of this book via a DZone post. Another DZone post has now pointed me to an outstanding collection of freely available online technical books.

The E-Books Directory has links to online viewable and downloadable books on subjects as diverse as Ada, C, C++, Java, Ruby, XML, and general software engineering. Although I did not see a link to Common Java Cookbook, the book Apache Jakarta Commons: Reusable Java Components (2005) is linked to from this repository. The freely available online books linked to from this site vary in format; some are PDF, some are HTML, some are zipped PDF and/or HTML, and so forth.

Several books of interest to Java developers that are linked-to from this site include 1000 Java Tips (2005), Beyond Java (2005), Thinking in Enterprise Java (2003), How to Think Like a Computer Scientist (Java Version) [2008], and Introduction to Programming Using Java (2006). There are also several other older editions of well-known Java-related books available here. I found that I was aware of the availability of about 1/3 of the listed books related to Java, but there were some nice surprises.

Books for the Ruby developer include several that most serious Ruby developers were already aware of such as "the Pick Axe Book" (Programming Ruby: A Pragmatic Programmer's Guide, 2000) and why's poignant guide to Ruby (current/2008). One of the listed books here, Ruby Essentials (2007), is available via online HTML for no charge or in PDF for a nominal charge ($4.99 at time of this writing).

Some potentially useful and interesting XML-related books linked to from this repository include SVG Essentials (2002), Processing XML with Java (2002), Essential XML Quick Reference (2001), and An Introduction to XML and Web Technologies (2006).

The Software Engineering section of this repository has links to books on general software engineering such as Building Skills in Object-Oriented Design (2008), Essential Skills for Agile Development (2004), Software Engineering (2008), and The Guide to the Software Engineering Body of Knowledge (2004), but also includes books on other miscellaneous software development subjects. For example, the section includes several books on version control: Version Control with Subversion (2008), Subversion Version Control (2005), Essential CVS (2006), and Version Control with SVK (2004).

As far as I can tell, this is a repository of links to online books rather than a repository of the online books themselves. Many of the books are old in technical years, but some are relatively recent and some cover subjects for which books can age fairly well. In many cases, some of these freely available books might be helpful for at least getting an overall view of a particular concept and then freely available online articles and blogs can be used to supplement and update information. Some of the books are very current and are freely available for reasons other than the age of the book.

When looking at any of these freely available books, I do think it is important to take into account the year published, the effect of the year published on the particular topic, the quality of the author, the quality of the publisher, and so forth. Even though the book is freely available, it is still caveat emptor with your time being the "cost" you pay as the buyer. In some cases, technologies have changed enough that learning from an old edition can actually be more harmful than helpful. In other technologies and concepts, a few years won't make that much of a difference.

Saturday, May 9, 2009

JRuby Supports Java and Ruby Method Names Conventions

Jeff Cohen's blog post Ruby 101: Naming Conventions does a nice job of covering conventions associated with the Ruby programming language. I like how he specifically writes to Java developers and .NET developers to call out differences in conventions from those respective worlds from what is conventional in Ruby.

Because JRuby supports use of Java classes within Ruby code running on the JVM, it is not surprising that differences of convention are more likely to be noticed in JRuby development. One area in which Java and Ruby differ in convention is the naming of methods. JRuby conveniently allows Ruby code calling Java classes to call methods on those Java classes using either a traditional Java method naming convention (with or without parentheses) or using Ruby-friendly syntax (all lowercase letters with underscores separating the different words).

The following simple JRuby script uses the Java System.getProperties() method to get all of the defined system properties. It uses both a traditional Java method name convention and the Ruby-centric equivalent get_properties. Note that I did not need to do anything special to get this support.


# The purpose of this JRuby script is to demonstrate that JRuby supports
# Ruby-consistent method name syntax even on standard Java classes.

# Will be calling Java classes from this JRuby script
include Java

# Need to import System to avoid "uninitialized constant System (NameError)"
import java.lang.System

separator = "=================================================================="

# Java-style:
# The first access of System.getProperties is implemented as would be done in
# 'traditional' Java. The parentheses are not required on getProperties()
# call because it has no parameters passed to it, but the parentheses are
# retained here as more conducive to Java style.
puts separator
puts "CLASSICAL JAVA"
puts separator
puts "#{System.getProperties()}"

# Ruby-style:
# Ruby convention tends to favor separating multiple words in method names
# with underscores rather than with uppercase first letters as is Java's
# convention.
puts separator
puts "RUBY-ED JAVA"
puts separator
puts "#{System.get_properties}"



When the above script is run, both calls to System.getProperties() work exactly the same.

The example so far called a Java method that did not accept any parameters. However, the same support for Ruby method naming convention, Java method naming convention, or some combination of these is supported with methods that accept parameters. The two examples printed to standard output from the next code listing display exactly the same information based on a call to System.getProperty(String).


# Java-style with parameters:
# Can use traditional Java style name and can use or not use parentheses.
# Truly traditional Java-style would employ parentheses, but I wanted to show
# that they are not necessary in JRuby even when using the camel case method
# naming convention.
puts separator
puts "Java Version (Java-style): #{System.getProperty 'java.version'}"
puts separator

# Ruby-style with parameters:
# I could have added parentheses here, but they are only necessary if the
# object returned from the method call needs to have something access on it
# in the same line, which I am not doing here.
puts separator
puts "Java Version (Ruby-style): #{System.get_property 'java.version'}"
puts separator


In this case, I intentionally left the parentheses out of the example that would have otherwise been compliant with Java method naming convention.

I have found it generally best to try to accommodate the conventions of a particular programming language because of the many benefits gained from doing so (improved ability to read and maintain others' code, improved reflection capabilities, improved opportunities for convention over configuration or configuration by exception, and so forth). However, it can be a little less clear sometimes with JRuby, particularly when calling Java classes and methods.

Outside of personal taste, there is nothing better or worse about Java's or Ruby's method naming conventions; rather, they are just different. I have a very slight preference for using the syntax that is compliant with Ruby convention in JRuby code because most of the surrounding JRuby code is Ruby and consistency is often a highly desirable goal. However, on the list of matters of personal tastes and preferences, this ranks way, way down there. It is far more important to me that I can leverage the benefits of Java and the JVM with the benefits of Ruby.

Common Java Cookbook

Like many others in our (software development) profession, I take at least a few minutes out of my day each day to quickly browse DZone topics. Even just reading the topic titles can help me learn new terms and become familiar at the highest-level with new languages, frameworks, and so forth. In most cases, most of us are scouring DZone for "fresh" information or to learn things we didn't even previously realize we needed to know. However, I have observed that, in some cases, it is actually an "older" resource that I was not aware of or a new resource covering an "older" topic that provides the most immediate value. This happened today for me thanks to bloid submitting the post Common Java Cookbook.

The Common Java Cookbook is an online, open book sponsored by Discursive and currently labeled version 0.14 (early Second Edition). This 12-chapter book, as its name suggests, is organized in a style similar to other technical books with Cookbook (such as Java Cookbook) or Recipes (such as Groovy Recipes) in their titles. Indeed, and not coincidentally, Common Java Cookbook is authored by the same author (Timothy O'Brien) of the book Jakarta Commons Cookbook. Common Java Cookbook covers many different aspects of Java development using the libraries of Apache Commons. Perhaps the best way to see the breadth of what is covered is to review the table of contents and to read the Preface (particularly the section What's Inside).

One of the most difficult but most important things about learning to develop in Java is to gain familiarity with the standard libraries and APIs (see also Joshua Bloch's Item 47 in the Second Edition of Effective Java). The Apache Commons provides a second tier of similar libraries and APIs that are similarly worth the investment to become familiar with. Indeed, many of the libraries provided as part of Apache Commons implement some of Bloch's and other experienced Java developers' recommended practices.

For anyone who is new to Java development or at least new to working with the Apache Commons libraries, I'll point out what might be a little confusing: the project now known as Apache Commons was formerly known as Jakarta Commons. One might say that Common Java Cookbook is to Apache Commons as Jakarta Commons Cookbook is to Jakarta Commons.

On the surface, the general availability of a new and improved version of a book devoted to Apache Commons is enough to be excited about. This is certainly a valuable resource that is likely to become only more valuable as it is enhanced. However, it is also an interesting case study for the benefits and drawbacks of open publishing.

Wednesday, May 6, 2009

Code Cannot Be Simpler than the Problem Domain

Most of us have decided that code simplicity is a desirable quality. However, we have also observed that several things limit the simplicity of our code and even exaggerate our code's complexity. These things that make our code more complex than it should be include overuse/abuse of design patterns, overuse/abuse of favorite syntax/code features (such as implementation inheritance), resume-driven development, the Magpie Effect, Not Invented Here Syndrome, and other dysfunctional motivations.

Although many of us see the benefits of striving for simplicity and avoiding unnecessary complexity, I have also observed that in some cases we may overexert ourselves in an effort to achieve simplicity in our code that is not justified by the problem domain being modeled in the code. A general rule that seems obvious but which we often seem to forget is that the code cannot be simpler than the problem domain it describes. It is typically a vain effort to try to write very simple code for a very complex problem domain. We can strive our best to make the code as simple as possible, but the size and complexity of a problem cannot be completely ignored. At some point, the complex functionality must be implemented. As an example, the code for implementing addition should not be as complex as code for implement Fast Fourier Transforms. We can strive to make the FFT implementation as simple as possible, but it will always have a certain degree of complexity simply by the virtue of the problem's own complexity.

We can do some things that make the code appear to be more simple than the problem domain it describes. I describe each of these here, explain how each of them doesn't really make the code simpler than the problem domain, and briefly discuss the tactics we regularly employ to enjoy these perceived simplicity benefits.

Simplifying Assumptions

In a particularly complex problem domain, one of the tactics we can use to make our code simpler is to leverage simplifying assumptions. Note that we've not really written code that is simpler than the problem itself by doing this. Instead, what we've really done is simplified the problem domain to a point where its code can be simpler. These simplifying assumptions not only make our design and code effort easier, but they often make for a more usable tool or software product for our end users.

Codifying the Problem

Code can sometimes appear to be simpler than the problem domain it models because of the fact that we are better at reading the code than we are at reading the other descriptions or design documents related to a particular problem. This does not necessarily mean that the code is simpler than the problem space; it only means that we are more comfortable reading code than we are reading our types of documents. Another person might be more comfortable with the written description. A central takeaway from this is the value of prototyping. Prototyping helps us to flesh out questions and risks in the problem space. The prototype also codifies our understanding of the problem space. Similarly, willingness to refactor is also important in this area because we learn as we codify the problem.

Leveraging the Work of Others

Today, many enterprise functions are provided by an underlying application server, library, toolkit, framework, or domain-specific language. It can seem to the developer using these that many of these enterprise functional benefits come very easily and simply. While they may be easy for the end developer, the overall code (including the code in the product being used) is far from simple. The use of an existing library, framework, toolkit, application server, or other pre-built piece of code does give the impression of greater simplicity thanks to previous work. What this tells us, of course, is the value of reusing good products and not reinventing the wheel unnecessarily.

Conclusion

The effort to achieve coding simplicity in the light of a complex problem domain reminds us of the value of prototyping, of refactoring, of using pre-built libraries and frameworks, and of using simplifying assumptions. It is also important to realize that some problems are so complex and so large that even the simplest, cleanest code may still be rather large and complex to adequately meet expectations. It is admirable to make the code as clean and simple as possible, but the unavoidable fact is that some of the things we must describe in code are themselves complex and their code implementation will have to be complex as well (unless we allow simplifying assumptions as described above).

Monday, May 4, 2009

JRuby, jmx4r, GlassFish, and Viewing Logging Levels

I have blogged previously on using simple remote access of GlassFish via JMX. In this blog posting, I will look briefly at how jmx4r makes this very easy to do from JRuby.

Jeff Mesnil's jmx4r was formerly hosted on Google Code, but is now hosted on github. The jmx4r library is easily installed the Ruby way using Ruby Gems: jruby -S gem install jmx4r (the -S option is significant). The next screen snapshot shows how easy it is.



With the jmx4r gem downloaded and installed, it is now easy to apply jmx4r to "speak JMX" from JRuby. The following code snippet is based on an example available in JMX the Ruby Way with jmx4r.


require 'rubygems'
require 'jmx4r'

JMX::MBean.establish_connection :host => "localhost", :port => 8686
logging = JMX::MBean.find_by_name "java.util.logging:type=Logging"
puts "There are #{logging.logger_names.size} loggers."
logging.logger_names.each do |logger_name|
puts "Logger named #{logger_name} set to logging level #{logging.get_logger_level logger_name}"
end


There aren't a lot of lines to review in this code example. The require 'jmx4r' statement demonstrates our use of jmx4r. The JMX::MBean.establish_connection statement connects to the host and port associated with Glassfish's JMX MBean exposure by default (and can be verified in GlassFish's console output when starting up a domain). The JMX::MBean.find_by_name statement is an MBean query on the MBean with an ObjectName of java.util.logging:type=Logging. This MBean can also be seen from JConsole as shown in the next screen snapshot.



We can also see logging levels in GlassFish's administrative console as shown in the next screen snapshot.



With the view of the logger levels seen in JConsole and in GlassFish's own web-based administrative console, it is now time to see them via our JRuby script. When I run the JRuby script shown above, however, I see a SecurityException.



I need to provide the username and password to avoid this security exception. The default credentials for GlassFish are "admin" for the username and "adminadmin" for the password. These can be added to the above JRuby code, to lead to the code shown next.


require 'rubygems'
require 'jmx4r'

JMX::MBean.establish_connection :host => "localhost", :port => 8686,
:username => "admin", :password => "adminadmin"
logging = JMX::MBean.find_by_name "java.util.logging:type=Logging"
puts "There are #{logging.logger_names.size} loggers."
logging.logger_names.each do |logger_name|
puts "Logger named #{logger_name} set to logging level #{logging.get_logger_level logger_name}"
end


With the credentials properly provided, the JRuby script will now work correctly as demonstrated in the next screen snapshot.



One could use this JRuby+jmx4r to set log levels or to read/set other exposed JMX operations and attributes. This allows JRuby-powered scripts to be easily used in a wide variety of monitoring, management, and administrative roles.

Sunday, May 3, 2009

More Presentations for CSS 2009 Agenda

I was already pretty excited about attending Colorado Software Summit 2009 after seeing the preliminary agenda, but several more must-see presentations have been added since then (and it appears that a few more are still coming as it is still called "Preliminary Agenda"). The preliminary agenda by speaker name now indicates that newly scheduled speakers and topics include Ian Ameline's "An Introduction to Floating Point Math – What every programmer should know (but almost none do)" [an obvious reference to the seminal 1991 mathematically intense classic What Every Computer Scientist Should Know about Floating-Point Arithmetic], Noel Bergman's "Introduction to OSGi Development", Bill Jones's Django-related presentations, Mike Keith's presentations on JPA 2.0 (JSR 317) and Java EE 6 (JSR 316), and Simon Roberts's performance-related presentations.

More Colorado Software Summit 2008 Presentations

The Colorado Software Summit has made more 2008 presentations available for free download. The just-released presentations include Bill Dudney's iPhone-themed presentations "Core Animation on the iPhone: How to Build Animated UI’s" and "Building Location Aware Apps on iPhone: Taking Advantage of the Location Aware Nature of iPhone" as well as Filip Hanik's presentations "Zero Latency HTTP — Using Comet with Apache Tomcat" and "What the Bayeux? Understanding, Using and Developing with the Bayeux Protocol." All four of these presentations are currently available directly from the Colorado Software Summit web page or, for the long term, can be found at the Colorado Software Summit 2008 page.

With the release of these four 2008 presentations, Colorado Software Summit has now released one-third of the 2008 presentations (18 of 54 released so far).

Saturday, May 2, 2009

GroovySql: Groovy JDBC

I have long felt that JDBC is one of the most underrated reliable work horses of the Java world. Although JDBC has proven its value many times over and, in my opinion, ranks up there with servlets and JMS in terms of time-proven worth, JDBC does have its drawbacks. I have written before regarding how the Spring Framework addresses many of the most common JDBC disadvantages. In this blog posting, I will address how Groovy similarly addresses drawbacks of JDBC.

As I wrote about in the article Add Some Spring to Your Oracle JDBC, JDBC can be somewhat tedious to work with due to its single primary checked exception (including the necessity to have nested try/catch blocks) and to other required boilerplate code that the Spring Framework largely covers via its JDBC template. Groovy similarly reduces the amount of boilerplate code required to work with JDBC.

Besides dealing with the handling of an SQLException (or one of the child exceptions introduced in Java SE 6 such as SQLRecoverableException), another task one commonly has had to perform when using JDBC to retrieve data is to iterate over the returned ResultSet. Groovy does much of this for us as shown in the next code listing.

getEmployees.groovy

import groovy.sql.Sql
sql = Sql.newInstance("jdbc:oracle:thin:@localhost:1521:orcl", "hr", "hr",
"oracle.jdbc.pool.OracleDataSource")
sql.eachRow("SELECT employee_id, last_name, first_name FROM employees")
{
println "The employee's name is ${it.first_name} ${it.last_name}."
}


As with all Groovy code samples in this blog post, I am using Groovy more as a scripting language and less as an application development language. In other words, I'm not bothering with making Groovy classes.

The getEmployees.groovy script listed above uses Sql from the groovy.sql package. The Sql.newInstance method is has several overloaded versions and the version accepting a JDBC connection URL, username String, password String, and JDBC driver String is the version used in this example (as well as all other examples in this particular post). In this post's examples, the database is an Oracle database, but any database with a compliant JDBC driver could be used.

When the above code is run, the expected output sentence with each employee's full name is printed.

It is also easy to insert data into the database with GroovySql. The insertion of a new job row in the JOBS table of Oracle's HR schema is shown next.

insertJob.groovy

jobId = "QU_OPER"
jobTitle = "Quarry Operator"
minSalary = 1
maxSalary = 5
import groovy.sql.Sql
sql = Sql.newInstance("jdbc:oracle:thin:@localhost:1521:orcl", "hr", "hr",
"oracle.jdbc.pool.OracleDataSource")
sql.execute(
"""INSERT INTO jobs(job_id, job_title, min_salary, max_salary)
VALUES(${jobId}, ${jobTitle}, ${minSalary}, ${maxSalary})""")


The above example inserts the Quarry Operator position into the database. The values to be inserted are included directly within the Groovy strings using the ${} notation. In the next code listing, I again insert data into the database, but this time use a PreparedStatement approach to insert a new employee who happens to have this new job position of Quarry Operator.

insertEmployee.groovy

employeeId = 2000
firstName = "Fred"
lastName = "Flintstone"
eMail = "fred@slaterockngravel.com"
jobId = "QU_OPER"
hireDate = new java.sql.Date(System.currentTimeMillis())
import groovy.sql.Sql
sql = Sql.newInstance("jdbc:oracle:thin:@localhost:1521:orcl", "hr", "hr",
"oracle.jdbc.pool.OracleDataSource")
sql.execute(
"""INSERT INTO employees(employee_id, first_name, last_name, email, job_id, hire_date)
VALUES(?, ?, ?, ?, ?, ?)""", [employeeId, firstName, lastName, eMail, jobId, hireDate])


The insertion of the employee looked very similar to the insertion of the new job, but used the often preferred PreparedStatement approach instead.

Deleting a row from the table with Groovy is also easy. The following Groovy script removes both rows (job and employee) just added in this post's examples.

removeJobAndEmployee.groovy

import groovy.sql.Sql
sql = Sql.newInstance("jdbc:oracle:thin:@localhost:1521:orcl", "hr", "hr",
"oracle.jdbc.pool.OracleDataSource")
sql.execute("DELETE FROM employees WHERE employee_id = 2000")
sql.execute("DELETE FROM jobs WHERE job_id = ?", ["QU_OPER"])


Because each of the example scripts in this blog post ended with the extension .groovy, they can all be run simply by running "groovy <<scriptName>>". Of course, the particular JDBC driver class for your database of choice (in this case class oracle.jdbc.pool.OracleDataSource in JAR ojdbc6.jar) must also be on the classpath and can be included with the normal -cp option.

Finally, if you have a typo or other database exception, a rather terse message will be printed. To see the full stack trace, using Groovy's -d option. If you are running on Java SE 6, you are likely to see some of the new exceptions that extend SQLException in such exceptional cases.


Conclusion

Groovy can be used within applications that use JDBC, but I especially like it for writing simple tools and scripts that need JDBC. It is also a very rapid method for testing out newly written SQL statements against one's database. Groovy makes an already outstanding technology (JDBC) even easier to use.