Wednesday, August 16, 2006

Background Threads in Tomcat

I have a task that I want to run once a minute. I have it coded as a command-line app, but getting that app to run as a Windows service is getting to be a pain. And, we also have an instance of Tomcat running on that server, so I started looking at how to get it to run within Tomcat.

This made me a bit nervous at first, as Tomcat does a lot of threaded stuff on its own, and I'd really rather not step on its toes, but after a bit of searching, I found that kicking off your own threads is a fine thing to do in Tomcat, but with a couple of caveats.

First, Tomcat lets apps ("contexts" in Tomcat lingo) be hotswapped, i.e. restarted or removed and replaced with new code, without stopping the VM. This means that you need to wire up your thread to stop when the app (sorry, "context") is stopped. You can write a servlet to watch over your thread (that can actually be the thread itself, too), and have Tomcat instantiate it, by configuring it in web.xml with "<load-on-startup />" included.

The servlet itself will extend HttpServlet (of course), and implement Runnable (if it's to have the thread code in it as well, which is handy. Then, when the destroy() method is called on your servlet, you tell your thread to stop itself (i.e. via a call to Thread.interrupt(), perhaps), as the context is going away.

I found a code sample at http://classes.eclab.byu.edu/462/demos/PrimeSearcher.java that helped, although that sample is coded to call Thread.stop(), which is now deprecated.

Anyway, I now have simple thread doing background processing, nicely cooperating with Tomcat.

Labels:

Monday, August 14, 2006

SQL Server Default Values (or "Why Open Source Is (Still) Better")

In getting our Java app to run on Windows, I'm forced to use SQL Server as a database. (Against my will, I might add.) I have an external application that will be adding rows to a table via ODBC, and I'm thinking it'd be nice to have SQL Server automatically generate a date value for when the row was written. In PostgreSQL, it'd be a default value in the DDL (I think; I've never needed it yet), but I wasn't sure what it'd be in SQL Server, so I tried timestamp.

That didn't look right to me, as the value in Enterprise Mangler displayed as '<binary>', rather than the actual date. Okay, let's try datetime with a default value. Well, that complained about something odd. I googled and found that timestamp *is* what I want, display problems notwithstanding.

Which leads me to today's punchline: when I switched from datetime w/default to timestamp, and tried to save my changes, EM complained about a default value not being appropriate for that datatype. Why, on earth, did EM not clear the default value when I switched datatypes?!

Okay, maybe I'm reading too much into this, but this is a problem you just don't see in open source programs. In the O/S world, the first decent coder to hit that problem would have pulled down the source, fixed the problem, and submitted a patch. The next version of the program would be fixed, perhaps in less than a month, depending on the release cycle. Heck, I was itching to do it, myself, except, whaddya know, I can't get at the code.

But I'll wager that this problem will never get fixed. It's not "important enough" (i.e. to the marketing team) to make it into a bug list, unless it annoys a SQL Server developer enough to make it happen "while he's doing other things" (i.e. without permission).

Harumph. When will I be free of this nonsense?

Labels:

Friday, August 11, 2006

Windows Services and Network Drives

Rather than turn this into a Windows rant (which it easily could become), I'll just skip to the punchline. After a few hours of trying to figure out why my File.exists() and File.isDirectory() calls don't work, now that I've moved the code into Tomcat, running as a service on Windows 2003 Server, I discovered that network drives are not available to services.

More specifically, I got the impression that network drives are mapped by a user for that user, and as such, a service, which doesn't have a user (?), doesn't get the drives that any (other) user specifies. More generally, it's another way that Windows is borken. (Oops, I wasn't going to rant.)

So I got to go back to my client and get him to move the app (whose data I was getting over their net) to the local machine, or figure out how to at least push the files to the local machine. Feh. (rant, rant, rant...)

Wednesday, August 02, 2006

Duplicate Methods in Python

Stumbled across a little gotcha in Python. Python, when it loads a source file, executes the code as a command. For instance, assume the following code:


class Foo:
def method1( self ):
pass


It sees the class statement as a command, with two lines of text following as parameters. Similarly, it sees the def statement as a (sub)command with one line as a parameter. The def 'command' adds (or replaces) the method method1 in the current scope, in this case, class Foo.

Which leads me to my gotcha. The following code is valid, but probably not what you want:


class Foo:
def method1( self ):
print 'Yes'
def method1( self ):
pass


In this case, the first def statement will work, adding a method1 that prints to the class. The second one will work, too, replacing the existing method1 with one that does nothing.

Unfortunately for me, I had added some stubs to the bottom of my source file, then forgot that they were there, and added the real method higher up, and wondered why the method apparently wasn't being executed. Debugging a bit showed me that it was getting called by the calling code, but the call wasn't arriving in the method itself. The 2nd def had replaced the first with a method that did nothing.

Chalk one up to experience.