A WeekBlog – A Post a Day – CONGOv2

So this week I’m faced with a situation I haven’t had in front of me in, well, as long as I’ve been married… at least as long as I’ve had kids in my life.
This week Cat is up in Maine with Zach. I have my normal work going on during the day, but no commitments for the evenings.
A unique opportunity to be sure.
The Plan [tm]
So here’s what I’m going to do. A few months ago I started work on a complete rewrite of CONGO. The rewrite is underway, and has been getting attention fairly regularly over the last couple weeks, but I need to make the final push to an alpha release.
This week, I will dedicate 2 hours a night every night to continuing work on CONGO v2, with the goal of reaching an alpha-testable version by the end of the week. I will also make a post each night with an idea of where my progress is on the rewrite, and what I’ve accomplished. (I do reserve the right to post the next morning if I’m up until Oh-Dark-Thirty coding and fall asleep in the middle of writing an exception handler.)
Anyone wishing to follow the riveting details of my work, I subscribe to the Commit Early, Commit Often philosophy of source code control, so when I’m working, you’ll see commits firing off pretty quickly. If this sounds interesting, you can sign onto the mailing list, or, if you’re uber-hip, subscribe to the RSS feed.
Yeah? So? Why us?
So why bombard ya’ll with my chattering? Well, I work better with encouragement, or if I know folks care about what I’m doing. Curious about bits of CONGO? Ask! Wanna help out? Give a “wow, kick butt, dude. Go for it” comment or two.
Hopefully I’ll have some work to show for tonight, but if not, stay tuned for truly exciting blow by blow Java coding!

primark

Eclipse XML Validation can BITE ME

There are times when I want to take an axe to Eclipse. Today’s particular grief is due to the XML editor. There are numerous faults with it (one of the biggest is that it ‘captures’ the control-pgup and control-pgdn keys into local tabs, so if you have an XML file open, and you use the keystrokes to navigate through your files, when you switch tabs to an XML file, the only way you can view a different file is to click on it), but todays stabbity-stab comes from the validator.
eclipse-48Eclipse shows you errors and warnings in realtime. Usually, they’re fairly accurate. Today I was editing a struts.xml file, and was getting a validation warning. When Eclipse senses a problem with the XML (based on it’s DTD), it tells you “this XML file fails the DTD validation”.
But it doesn’t tell you where.
This completely baffles me. “Somewhere in the following several hundred lines of XML code, there’s a problem. But I won’t tell you where or what it is.”
Off to the W3.org Validation service. I fed the XML file into it, and lo! A detailed description of the problem, and where it was:

Line 26, Column 39:
document type does not allow element "include" here.

<include file="struts-editevent.xml"/>

Was that really that difficult?
Gnar.

Weird Ways of Working

I was gone all weekend on a wonderful camping trip, hence the radio silence. Today I’m back in the saddle, and faced with an annoying situation with my home setup.

I’ve come to the conclusion ‘yawl’ just can’t cut it as a development host. I had no idea that Pentium 4 CPU’s were such garbage. A 2.26 ghz machine isn’t fast enough to do serious work in Eclipse.

Most of my development is done on ‘clipper’, but alas it’s a Windows machine (it can’t help it, it was born that way). I wanted to start fiddling with CONGO (v2.0) via Konqueror, and hit upon running up ye ole VNC viewer on ‘yawl’, and just ‘moving’ the Eclipse environment onto yawl’s desktop.

Lo, it worked remarkably well. Clipper’s monitor is powered down, and I have an Eclipse environment on my Linux KDE desktop, but actually powered by the Windows dual core laptop next to it. I could overlap a Konqueror browse window and flip between it normally, and keyboard interaction was snappy and useful.

It’s not quite like having a local Eclipse install, but it’s mighty close. It gives me a feel for what it’s like for folks having big vmware server installations, and other less fortunate folks dealing with the variety of RDP based solutions, and being able to just pop into an existing running machine and work with it directly.

Really though, I should have a faster desktop machine. Alas, that’ll have to wait, it’s pretty low on the budget tree nowadays. And, in case anyone is curious, that is in fact a snapshot of CONGO v2 running in a pure Java environment – screens and back end all running within a Tomcat server. Sure it looks identical to CONGO v1, but that’s by choice. Quick port to Struts + JSP, then enhance and refactor. Progress is being made.

Revisiting old code, and Good decisions made

Over 5 years ago, I began work on an application called CONGO, a registration and badging system, not only in the vein of “There’s gotta be a better way”, but also to help out a friend who was running registration at con in Philadelphia.

The first versions of CONGO were crude, but worked well – with a custom Swing interface, custom terminals and servers, it was an impressive setup. What wasn’t apparent was this was my first foray into writing any decent sized Java application. I made what I thought at the time were good design decisions, and looking back on 30+ events run, and hundreds of thousands of badges printed, I’d say the design was, for what I knew at the time, solid.

But it’s time to change. With everything I’ve done over the last 3 years in Java and enterprise-level applications, I feel I’m ready to rewrite CONGO into a proper Java based webapp. CONGO 1.0 was part Java, part PHP, part templating. CONGO 2.0 will be a pure java application, based on Struts, and will allow features that I could not shoehorn into the old model

I started work on CONGO2 about a week ago, and I have my first screens working properly and chaining together as they should. Part of this process is factoring in the old logic code, and linking it up with the new presentation layer I’m building using JSPs and Struts. This means making calls to 12,000+ lines of Java code that was written as I was learning the language.

But one thing I did consistently – I documented my methods. Every piece of the CONGO appserver has full Javadocs describing how to call the method, and what it returns

Because I’m doing CONGO2 using modern tools (like Eclipse and Tomcat, my GUI is showing me these docs whenever I try to link to my old code, and is reminding me how to use the old libraries. Why is this remarkable? Because other than generating static documentation, I’ve never actually seen my own comments and documentation popping in interactive windows in my IDE. Until now.

It gives me a little thrill each time I see my own docs pop up as helper windows in Eclipse, showing me comments I made half a decade ago on structures and calls, and reminding me how to use the system.

It wasn’t easy to learn Java, it wasn’t easy to learn Swing, it wasn’t easy to learn JSPs, JSTL, and Struts. But now I do know them – some more than others, and I’m enjoying this massive refactoring of one of my proudest creations.

And now, a word from my day job.

I don’t talk about my day job much. For those outside of the Java Geeky circles, it’s pretty dull stuff. But today has been particularly active, so I thought I’d share some of the bits I learned while teaching myself the wonders of Struts. This can best be summed up by the following revelations…

1) When changing a struts.xml file, within an Eclipse WTP environment, being serviced by Tomcat, WTP does not click that the Tomcat server needs to be restarted. The ‘Dynamic’ part of WTP does not take effect, and no matter how many times you save what you’re working on, it won’t go live in the server until you actually restart Tomcat.

2) Despite all the awesome advances in Eclipse in the last few years, there’s twitches that still drive me absolutely gonzo. One is that the ‘smart insert mode’ (which helpfully closes XML tags and closes quotes and parentheses for you) cannot be turned off globally. You can do it on a per-editor basis, but not globally, so I’m always forgetting to turn it off when I open a new editor. Another is XML syntax validator is still quite twitchy, and occasionally will flag incomplete tags or non-well-formed XML when the file is just fine. A close and re-open fixes it, but ugh.

3) Last, but not least – that which almost got me up on the roof with a high powered rifle. I give you a quiz as my example. One of these two struts.xml configurations apparently tickles a bug in Struts2 and will cause an internal server error and stacktrace with a Null Pointer Exception. The other will not. Can you figure out which is which?

<action name="/*">
<interceptor-ref name="mystack" />
<result name="success">/WEB-INF/jsp/{1}.jsp</result>
<result name="login">/WEB-INF/jsp/index.jsp</result>
</action>
<action name="*">
<interceptor-ref name="mystack" />
<result name="success">/WEB-INF/jsp/{1}.jsp</result>
<result name="login">/WEB-INF/jsp/index.jsp</result>
</action>

Just for fun, here’s the actual stack trace:

1.
INFO: Server startup in 954 ms
2.
Jun 17, 2008 7:41:14 PM org.apache.catalina.core.StandardWrapperValve invoke
3.
SEVERE: Servlet.service() for servlet default threw exception
4.
java.lang.NullPointerException
5.
at com.opensymphony.xwork2.config.impl.ActionConfigMatcher.convertActionConfig(ActionConfigMatcher.java:168)
6.
at com.opensymphony.xwork2.config.impl.ActionConfigMatcher.match(ActionConfigMatcher.java:144)
7.
at com.opensymphony.xwork2.config.impl.DefaultConfiguration$RuntimeConfigurationImpl.getActionConfig(DefaultConfiguration.java:316)
8.
at com.opensymphony.xwork2.DefaultActionProxy.prepare(DefaultActionProxy.java:169)
9.
at org.apache.struts2.impl.StrutsActionProxyFactory.createActionProxy(StrutsActionProxyFactory.java:41)
10.
at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:494)
11.
at org.apache.struts2.dispatcher.FilterDispatcher.doFilter(FilterDispatcher.java:419)
12.
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:215)
13.
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)
14.
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
15.
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:174)
16.
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
17.
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:117)
18.
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:108)
19.
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:174)
20.
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:874)
21.
at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:665)
22.
at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:528)
23.
at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:81)
24.
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:689)
25.
at java.lang.Thread.run(Thread.java:619)

How the hell am I supposed to debug that?

I finally did, after a good 2 hours of hair-ripping, gnashing of teeth, and spewing my venom upon the #struts IRC support channel.

Coconut gets a facelift

Ever since I first wrote Coconut, the web interface to CONGO, I’ve been using the same stylesheet. It was really my first foray into stylesheet-driven design and layout, and while it was a good first try, it was ugly as sin.
Last night I finally sat down to rewrite the stylesheet into something reasonably attractive. I got rid of the dark background and greytones, and the ‘All Caps’ font styles, and used more pastels.
I’m pretty happy with the result, but for the hundred or so folks who are used to the old look and feel, it’ll be a dramatic change!

Dear Intarweb…

Somewhere, back in the mists of UI design, some bright light came up with the idea of making options in an application or desktop environment selectable by using a mouse to point at a menu along the top of a work area, clicking on the menu, and having it present more options.
This was called a ‘Pull down menu’
Handy! Picks were readily available when needed, and stayed out of the way until requested.
I’m fairly sure the original designers of menuing systems never said to themselves, “Hey guys, I think it would be a good idea to SHOW A PULLDOWN MENU JUST BECAUSE YOUR MOUSE HAPPENED TO ROLL ACROSS IT ON ITS WAY TO PAUSE YOUR MUSIC!
I’m flabbergasted that the ‘popup menu’ has become de rigeur in web pages. It’s a terrible UI design, and consistently gets in the way when trying to do other things. There’s no other menuing system on the planet that does this. Menus should show up when you ASK for them, not because you happen to TOUCH it. That’s what the little button the mouse is for. See? Clicky clicky. Now you try it.
Not that I expect this to change anytime in the near future. There’s a revolution going on in UI design now, with AJAX services redefining what it means to write a UI. Unfortunately, I have yet to see any AJAX application that comes near the functionality of existing systems. It appears programmers are going back to 1985 and starting over, thus jettisoning all the lessons learned in the last 20 years.

Zorching Memory Leaks. I Am Teh Stud

Tonight, I am Da Man.

It’s rare I get to sit down and see, so directly, a problem in the code I’m working on. In this case, while running at Ubercon the other weekend, I noticed that CONGO was showing every sign of a memory leak. After a while I’d get sluggish performance, and eventually I’d get an OutOfMemory error from the JVM. Didn’t look good.

This had me in somewhat of a panic, since Arisia is right around the corner, and I need the system stable and useable for the event. With the help of the wonderous tool that is JConsole, I was able to actually see the memory usage going up in the JVM as I worked with the server. There was definately a problem.

It turns out my hastily set up code to handle changes to my JDBC driver was not being handled correctly. Apparently with the old mm.mysql driver, SQL handles were automatically closed at the end of use. With the new Connector/J driver from MySQL, you had to explicitely issue a close() statement on any Statement, or the handle would never be freed. This was probably always the case, it was just my sloppy code and a twitch of the old driver that made it never come up.

Unfortunately, this necessitated changing just about every SQL call in the server, all 10,000 lines of it. It was long, painful, boring work. I had some help from blk, but it still took a good week of off-hour fiddling to finish the changes and do some basic regression tests.

Tonight, I made the last set of changes, did some basic runthroughs, and didn’t have a single crash. With someone trembling fingers, I started up JConsole again, connected to the application server, and started working with CONGO. Registrant lookups, reports, modifications, creations, subscriptions, convention detail editing – throughout it all, JConsole happily continued showing the normal ‘sawtooth’ pattern of memory usage. Things would get allocated, used, and then the garbage collector would come along and reap the memory.

Success! I had successfully searched for, found, and fixed a major memory leak that was persistent throughout the code.

For those insisting on the details, here’s a properly structured, Prepared, and appropriately exception-managed call to get a number from the database. (And, before I get abusive comments all over the place, the Exception handling here is VERY POOR, and will result in a clean result coming back from the method, even though the call may have crashed. I know, thank you, now go away).

private static int calcRegistered(int cid, String typeName) {
PreparedStatement p = null;
ResultSet rset = null;
String sql = "SELECT count(*) AS total FROM reg_state " +
"WHERE state_cid=? AND state_regtype=? " +
"AND state_registered=1";
int value = 0;
try {
p = cserver.Conn.prepareStatement(sql);
p.setInt(1,cid);
p.setString(2,typeName);
rset = p.executeQuery();
if (rset.next()) {
value = rset.getInt("total");
logger.debug("tcalcRegistered: count for conference '" + cid + "', type '" +
typeName + "' is --: " + value);
}
}
catch (Exception e) {
dumpException(e);
}
finally {
try { p.close(); }
catch (Exception e) { dumpException(e); }
}
return value;
}

I feel all geeklystudly.

Next is to start seriously hammering away at the buglist, and get a test environment set up so other CONGO users can test out the new Merge function against ‘real’ data. If all goes well, we’ll roll this version into production in time to run Arisia.

Deep Breath.

Aaaaand, we’re back.
What an insane couple of days. There’s a whole series of posts brewing in my head right now, but I’ll just touch on probably the one that’s most on my mind.
Last week, I was in mid-preparation for Ubercon, an awesome gaming convention I regularly work down in NJ. CONGO has been pretty idle for the last few months as the summer is not a big time for conventions. With a week to go until Ubercon started, it was time to pull out all the hardware and make sure everything was working.
Well, unsurprisingly, it wasn’t.
The first major issue was coming to the conclusion that endor, the venerable server of dozens of conventions, really wasn’t going to handle Yet Another Apt Upgrade. It was still running on a baseline Debian Sarge install that had been upgraded a dozen times over the years, and finally, after enough apt tweaking had gone on, a dependency just wouldn’t resolve, and the machine would not take new upgrades. It was time to nuke from orbit and reinstall the OS from an Ubuntu baseline.
No problem, sez I. I whip out my Gutsy Gibbon Ubuntu CD, do a quick database dump and backup, install Ubuntu, and restore my home directory and databases. Reinstalled CONGO, loaded the working databases and…
stopped.
See, CONGO was my first big Java application. And as such, it has some… intriguing ways of doing database work. And by ‘intriguing’ I mean butt-ass stupid. In particular, not using PreparedStatements for SQL commands, not checking for failed transactions, etc etc. While this was okay for a fairly static application, once you replace the entire OS underneath it, things start to get a little squirrely. And, well, we had squirrels aplenty.
So over the space of 3 days I basically had to rewrite every SQL interraction in CONGO, resulting in some fairly major code changes, and all of this 3 days before a con.
Add on top of this the fact that I’m also using a brand new printer from Evolis for the first time under Linux. There’s a whole nother post about this experience, but it did bring yet another variable into play. Oh, and did I mention that I rewrote the print routine in CONGO to generate PDFs on the fly and use them for badge rendering? Yep, also new.
Needless to say, things were a little panicy leading up to the event. Fortunately, by Wednesday afternoon, I had things fairly well stabilized, the code worked, endor was stable and functioning properly, and I could start packing for the event with a clear conscience.

The end result? It all worked. The convention went fine, the printer behaved wonderfully, running badges twice as fast as my old Fargo printers, and we had only minor glitches through the weekend. There’s still some work to do to get endor ready for larger events, but for a week that started out with totally broken software, an unuseable server, and an untested printing system, things went mighty well.
Onwards.

Thank you Sun and Ubuntu!

… and the cast of thousands that made installing a Sun JDK onto Linux as simple as:

root@endor:~# apt-get install sun-java6-jdk
Reading package lists… Done
Building dependency tree
Reading state information… Done
The following extra packages will be installed:
gcc-3.3-base java-common libstdc++5 odbcinst1debian1 sun-java6-bin sun-java6-jre unixodbc
Suggested packages:
equivs binfmt-support sun-java6-demo sun-java6-doc sun-java6-source sun-java6-plugin ia32-sun-java6-plugin sun-java6-fonts
ttf-baekmuk ttf-unfonts ttf-unfonts-core ttf-kochi-mincho ttf-sazanami-mincho ttf-arphic-uming libmyodbc odbc-postgresql
libct1
Recommended packages:
libxp6 libnss-mdns gsfonts-x11
The following NEW packages will be installed:
gcc-3.3-base java-common libstdc++5 odbcinst1debian1 sun-java6-bin sun-java6-jdk sun-java6-jre unixodbc
0 upgraded, 8 newly installed, 0 to remove and 0 not upgraded.
Need to get 42.3MB/43.1MB of archives.
After unpacking 128MB of additional disk space will be used.
Do you want to continue [Y/n]?

For those on the sidelines, Sun has not been particularly forthcoming regarding a licensing arrangement that makes the RMS-ites at least mildly comfortable with automating an installation. In point of fact, I believe Debian is still uncomfortable with the whole license arrangement, though they do have it in the non-free repository.
Up until recently, getting Java onto a Linux box was, well, not difficult, but certainly not trivial. I’m happy to say it’s gotten as easy as installing any other package, which, with current package managers, means it’s a breeze.
Yay progress.

A Peek Under the Covers – Windows XP Registry Keys

While working on my current Java project, I needed to better understand how the Preferences API stores data. My initial instinct was to dig around in my home directory looking for a .java/Preferences file or something similar. Perhaps under Linux, this would have been the case, but Preferences is platform agnostic, and under Windows, it uses the Windows Registry.

I’ve long since tried to drive out my knee-jerk reaction to the Registry. The initial implementations of it were awful, and prone to easy corruption. Navigating the registry has never been what one would call ‘simple’, but after a while things settled down a bit and stabilized.

In this case, I was using a simple Java command to store some values for a Webstart launched client:

prefs = Preferences.userRoot().node(nodeName);
prefs.put("ExpoLoginName",userField.getText());
prefs.put("ExpoPassword",new String(passwordField.getPassword()));

Pretty straightforward stuff. In general, the code was working as expected, but I was seeing doubling of some of my values. What I needed to be able to do was actually see the registry stored values themselves, without going through the interface, to see if I was actually storing the values properly, or things were going wrong on the way out.

This unfortunately brought me in contact with the Windows native tool ‘REGEDIT’. This tool came out quite a while ago, and is the defacto standard way of editing, browsing, and searching the Windows Registry. Unfortunately, regedit hasn’t seen any interface upgrades in approximately an eon. It is painfully difficult to work in, and while yes, it gets the job done, little interface quirks can flat out destroy productivity. For example. The FIND function (amazingly, bound to ‘^F’), does in fact let you search the registry for a key or value. But, it is a one-way search, from the current position forward. It does not wrap. It also does not RESET when you change to a new search term. So if your first search finds a match, say, at the 5th from the bottom key (by the way, the window does not scroll to show you where your match hit. You have to scroll it manually), and you decide to search for a second term, it will only search the last 5 rows in the registry.

I lost half an hour searching for keys I KNEW were in the registry, because my first search had set the pointer so low. GAARRRHHHH!

What I found most entertaining about this path was it gave me a chance to look under the thin veneer of civility that Windows brings to the operating system experience. Take for example the screen shot above. Note that the keys stored in the registry have been altered from their internal values. Some bright Windows developer back in the dark ages realized they should tell the difference between an upper case letter and a lower case letter. Rather than, say, writing that into the logic of the registry, they cleverly decided simply to preface upper case characters with a forward slash.

Ah, but that brought up a problem! You could now not store a forward slash into the registry! Not to worry, we’ll just change any forward slashes in the registry to backslashes! Sounds like a great plan!

This sort of tortured logic is what you see happening in student built technology experiments, hacked together during all night jolt-driven marathons. It’s not something you’d see in the largest software company in the world. Their programming practices, in theory vastly improved from the early days, wouldn’t allow such awful hacks.

Would they?

Update – it appears, due to notes in the comments, that the registry values hack is due to Java’s interpolation, not Windows. Java needs to specify slashed items because the backing store being used in this instance (Windows Registry) is case insensitive. If a different backing store were being used, that wouldn’t be happening. My apologies to Redmond for assigning blame. On this one thing. 🙂

Windows as a useable Java development environment?

Recently I had to spend a fair amount of time working on CONGO on a Windows XP platform. Stonekeep is doing doing it’s first event where CONGO will be running entirely on Windows XP, so all the environmental stuff I’m used to having under Linux doesn’t work, naturally. Things needed to be updated. This presented many challenges…

Continue reading “Windows as a useable Java development environment?”

Updating Jarindex

Grump. I had no idea, but Jarindex was not working at all. Searches were coming up blank. Frustrating, when it’s supposed to be a handy search tool for finding classes in the vast swampland of Jar files out on the net.
Anyway, I fixed the indexer, and loaded up Hibernate 3.2 and Jboss 4.2.0 into it. Probably should update other packages as well. Currently I have:

apache-ant-1.6.5 eclipse-SDK-3.1.2 jakarta-oro-2.0.8 jboss-4.0.2 jdk1.5.0_04 jetty-5.1.10 junit3.8.1 OROMatcher-1.1.0a velocity-1.4
axis2 hibernate-3.2 jakarta-slide-webdavclient-bin-2.1 jboss-4.2.0.GA jdom-1.0 jpcap-0.01.16-win32 lps-3.1.1 rss_utils_1.1 velocity-tools-1.2

If any Java geeks want to see other packages loaded into it, let me know.

JBoss Release Grumpiness

This is a geek gripe. Particularly for Java programmers. If you’re not doing JEE development, this probably won’t make a lot of sense unless you like seeing open source companies being beaten up for version incompatibilities.
Hello, I’m Dave, and I’m a JBoss developer. (Hi Dave…)
Until recently, I was quite content with the series of tools available for JBoss4, and my chosen IDE, Eclipse. JBoss provided a lovely little plugin interface called JBoss IDE. I encourage people to click on that link, because you’ll walk through a series of redirects until you land on a page that, amazingly, has no information on where to get JBoss IDE! How wonderful!
It turns out that JBoss (now wholly owned by Redhat has pulled JBoss IDE in favor of another Eclipse plugin called Exadel. Fantastic, a new IDE plugin that has a lot more functionality than JBoss-IDE ever had. Lets take a look!
An hour later, and Exadel is installed and running and grand. But. Wait a moment, the latest version of the JBoss application server is 4.2-GA. That’s General Availability. Meaning the platform is released and is the recommended system for users.
Exadel has no configuration support for 4.2-GA. Only for 4.0.x releases.
And JBoss-IDE has been pulled completely (and even it’s ‘2.0.0-beta’ version, the most recent version they posted, did not support 4.2).
“Must be coming out shortly.” So I mailed off to Exadel tech support asking if there was 4.2 support in the works, or when it will come out.
I get a direct, and undeniable response from them:

Dave Belfer-Shevett wrote:
> > Exadel Support Team wrote:
>> > > Exadel Studio Pro is going to be re branded as Red Hat Developer Studio in
>> > > later summer. Red Hat Developer Studio will support JBoss 4.2 .
> >
> > So the answer is “no, it does not support 4.2 now, and won’t until late
> > summer” ?
That’s correct.
-The Exadel Team

Excuse me, but WHAT THE F??? We’ve pulled the old IDE toolset. We’ve released a new product. But you CAN’T USE IT WITH OUR IDE TOOLS! Hahahahha! And you won’t for a couple months. Sorry bout that, have a nice day.
There are workarounds. You can run the jboss server externally in a windows shell and deploy to it. This is a painful arrangement, but I guess I have no choice?
Thanks for leaving us all in the lurch, JBoss.

Getting a release out the door

It feels good when you finally push a release of a product out the door.
The last 2 months I’ve been spending a chunk of time doing updates on Keystone. It’s always fascinating working on code that is pushing 10 years old, seeing things I remember writing during the dotcom boom, and finding other tidbits that make me go “What the HECK was I thinking?”
This release is interesting in that much of the work was pay-for contract updates from a customer who wanted to see some bugs fixed and a few enhancements added in. It’s nice working on something you enjoy, and getting paid for it as well.
The code is just about ready for it’s next major overhaul though. I’m trying to get up the gumption to rip out the entire database back end code and replace it with ADODB. I wrote my own database abstraction layer back in, oh, 1998-ish, but really, the world has moved on a bit since then. It’s time to move with the times.