TDIing out loud

Ramblings on the paradigm-shift that is TDI.

Thursday, November 6, 2008

Exceptional Solutions

There are two types: those that go beyond the call of duty to deliver scalable, available and maintainable integration; and those that are defined by the stack dumps of unhandled exceptions.

How do you keep an AssemblyLine in the air? By catching and dealing with exceptions yourself. This is broadly done in two ways:

1) By putting code in Error Hooks. At the very least, you should log the error. I tend to use a script function to handle this.

function logerror(msg) {
task.logmsg("ERROR", "@@ERROR - " + msg);
task.logmsg("ERROR", "@@ AL[Component]: " + task.getShortName()
+ "[" + error.getString("connectorname") + "]");
task.logmsg("ERROR", "@@ Operation: " + error.getString("operation"));
task.logmsg("ERROR", "@@ Message: " + error.getString("message"));
task.logmsg("ERROR", "@@ Exception: " + error.getString("exception"));
}

Of course, no error report would be complete without a dump of the various Entry objects available -- at least work and conn. Unfortunately, the dumpEntry() call does not let you set the log level. So I made my own:

function attList( e ) {
if (typeof(e) == "undefined" || !e)
return;

var attnames = e.getAttributeNames();
java.util.Arrays.sort(attnames);

var str = "";
for (var name in attnames) {
var att = e.getAttribute(name);
str += "@@ " + name + ": ";

for (var i = 0; i < att.size(); i++)
str += att.getValue(i) + " | ";

str = str.substring(0, str.length-3) + "\n";
}

return str;
}

function dumpEntry( logLevel, e, name ) {
if (typeof(e) == "undefined" || !e)
return;

task.logmsg(logLevel, "\n@@ ******** Entry Dump: " + name + " ********\n"
+ attList( e )
+ "@@ ***************************************\n")
}

And then added it to my error function, making sure not to throw any exceptions whilst calling it:

function logerror( msg ) {
task.logmsg("ERROR", "@@ **** ERROR - " + msg);
task.logmsg("ERROR", "@@ AL[Component]: " + task.getShortName()
+ "[" + thisConnector.getName() + "]");
logval("operation");
logval("message");
logval("exception");
if (typeof(work) != "undefined" && work)
dumpEntry("ERROR", work, "Work");
if (typeof(conn) != "undefined" && conn)
dumpEntry("ERROR", conn, "Conn");
if (typeof(current) != "undefined" && current)
dumpEntry("ERROR", current, "Current");
}

Now it's easy to customize the format of the messages, as well as include other functionality if needed; for example, using a Passive Connector to write out error information, or using java.lang.System.out.println() to print messages to the command window where the TDI Server was started from.

2) Surround any script that can throw exceptions (like library calls) with a try-catch block:

try {
makeSomeCall(); // if this fails, catch below
} catch (exc) {
task.logmsg("@@ Error: " + exc);
}

If you don't handle it, then your AssemblyLine will stop running.

I'm just saying...

No comments: