Building a Sample GUI

Maven and Ivy seem to be fighting each other, and at the moment, the project doesn’t compile on my machine. Apparently, no classes can be found when attempting to run anything.

I’ve been using WindowBuilder Pro from Google (originally from Instantiations) to start making a preliminary Swing GUI which will later be able to actually be used. Luckily, WindowBuilder has a feature which allows one to test the GUI without actually having to run the program, so the Ivy/Maven/Classpath problem can be put off for now.

WindowBuilder, which more pleasant than writing plain Swing code, still leaves a lot to be desire. Simple features such as elements not randomly moving and resizing when you move other, unrelated elements, and anchoring elements to the bottom of the window instead of the top are frequently beyond the scope of WindowBuilder, at least if you want both at the same time. Other gems include the default size of a list to be zero by zero  (you are required to re-size it by dragging with the cursor), WindowMaker sometimes simply quitting when you resize an object to a size it doesn’t like, and buttons repositioning themselves hundreds of pixels off the window so that they are not rendered (elements must be repositioned with the mouse, arrow keys do nothing!). I feel as if I am a samurai, battling against a horde of rodents, some of whom spontaneously combust while others asexually reproduce.

However, I do feel like I’m getting the hang of tricking WindowBuilder into doing what I want, as if I were to somehow convince many of the rodents that the other rodents were made of cheese. While I don’t currently have the GUI finished, it should be reasonably complete within a few days.

UPDATE: Ivy/Maven Problems solved (for now!)!

The Great Integration II: Attack of the Dependencies

I spent about six hours today integrating Terracotta into the prototype. Most of that time wasn’t spent actually copying and updating code, but rather doing support chores. I just added a README two days ago, and now I’ve replaced it with an entire “getting started” document because the project is now THAT complex. Developing it on your system now requires the installation of at least one program plus two Eclipse plugins, followed by setting up a configuration file. And that assumes you already have Eclipse and an SVN plugin installed.

Other than that, I also did some general cleanup in a few files, including the removal of yet another vestige of Maven. Seriously, that thing’s a fricken’ zombie! It just. Won’t. Die. Also I looked into the JAR problem a little more. I found yet another Eclipse plugin (autojar) that’s supposed to do what we want. I tried it, but it didn’t pan out. So I’m still not sure where I’m going with that. I’m going to continue working on it, along with improving the build process, which is currently a little tedious in that you explicitly have to run the Ant build to update module JARs after you make changes.

(This shocking news just in: Richard actually managed to write a blog post that was only two paragraphs!)

The Great Integration

Today, I began work on what I’m calling “The Great Integration”, the goal of which is to merge the Dirmi and Terracotta spikes into the prototype. I began with the Dirmi spike, arguably the easier of the two. This went fairly well. Along the way, I did a few other things, including:

  • Minor refactorings of the code from the Dirmi spike. I decided that the server modules will be called “modules” and not “plugins”, so I refactored some code accordingly. I also changed the package names to conform to the prototype naming scheme, changed the names of some classes and interfaces to better reflect what they are and what they do, and added documentation in a few places.
  • Improved our Ivy dependencies and settings. Of particular concern was my discovery that the IBiblio repository was not being treated as Maven2-compliant! This meant that transitive dependencies were not being resolved properly, as with the JBoss repositories previously. But this time nobody noticed because the one dependency we retrieved from IBiblio didn’t depend on anything else.
  • Introduced a server configuration file that will eventually hold all system-specific settings the server needs to know. For now, the only setting is where files from the client should be uploaded, but in the future, it will hold other settings, like database credentials.
  • Eliminated more bullshit caused by Maven. Seriously, Maven is the most insidious plugin I’ve ever worked with! Once it’s infected your project, it’s almost impossible to get rid of! I think I have it completely eradicated now, though.

I took the liberty of adding a README to the prototype as well. The CFN (Client Facing Node) won’t run without a configuration file, and the client won’t work properly if you don’t run the Ant build to compile the Submission System Module (SSM – new acronym alert!), so I figured I ought to warn people about these things.

I’d also like to take this opportunity to clarify something. We refer frequently to a WPISuite Server, as if it were one monolithic program. It’s not, or rather, it won’t be. In actuality, it will be a cluster of Terracotta nodes running in independent JVMs, possibly on different physical machines. It will have two types of nodes: the CFN and the TEN (Test Execution Node). The CFN is arguably the more important of the two. It is the only part of the server that the client talks to directly. The CFN itself does very little, however. All of the real work is being done by CFN modules (like the SSM), which the CFN loads when it starts up. The TEN, meanwhile, is actually a part of the Submission System (SS – another new acronym, one not to be confused with SSM). All it does is run unit tests on assignments submitted by clients through CFNs to SSMs using the TEN modules (not to be confused with the CFN modules) that it loads when it starts up.

Confused? Don’t worry, I’ll make a diagram or something. I think we need to start keeping a formal glossary though, as we’re beginning to accumulate a LOT of project-specific jargon, and it’s only going to get worse from here.

Anyhow, my next step is going to be integrating Terracotta into the prototype. After that, I’m going to focus on setting up a solid build system using Ant. Technically, we’re already using Ant, but only because we need to compile the SSM into a JAR file so the CFN can load it appropriately. This will probably happen over the weekend. And at some point, I’ll whip up a short presentation for our next meeting, seeing as it’s my turn. It’s looking like I’ll have quite a bit to talk about, which is always a good thing.

(And yes, it really is true that We Prefer Initials here.)

Ivy, Hibernate, and overweight JARs

Over the past two days, I’ve engaged in two significant efforts. The first effort was to find a way to build JAR files with minimal dependencies. This is going to be very important for us. Unlike the WPISuite client, we’ll be producing several different JARs from our code, and I’d like them to be self-contained. Doing this, especially using Ant, isn’t particularly complicated. The problem is doing this and not ending up with absurdly enormous JAR files. Sure, you can include all the JARs on the classpath in your JAR… but you probably aren’t using all of those classes, which typically means lots of bloat. And that means longer download times, higher memory usage, and lots of other stuff we’d prefer to avoid. The situation is already out of control: between the Hibernate code that James has been working on (and has now largely finished) and the Dirmi code that I’ve been working on (which could use some cleanup and documentation), we’re already dependent on a whopping eighteen libraries!

Well, my initial attempt to deal with this problem didn’t go so well. My plan was to compile our code, extract the compiled classes from our dependencies, and use Ant’s <classfileset> to build JARs using only the classes we actually need. It seemed to work, until I tried to run the callback test on my Dirmi spike, which spewed exceptions. I’m not sure exactly what the issue is. Possibly there’s some reflection going on that couldn’t be accounted for. As for what to try next, I might try including Dirmi and its Cojen dependency in their entireties and only trying to strip the other libraries. I also found a neat-looking tool called ProGuard that can shrink and optimize Java classes. (It can also perform obfuscation, but we’re not interested in that.) Conveniently, ProGuard has an Ant task. I’m leaning towards trying that next.

The other effort was to switch James’s Hibernate project from Maven to Ivy for dependency management. He made a stab at doing this and ended up very frustrated, with a project that did not build because transitive dependencies weren’t being resolved. I looked into the situation and was initially quite baffled. Eventually, though, the lightbulb appeared over my head and I figured it out. The problem turned out to be two-fold. First, James wrote a resolver configuration that tried to make things MUCH more complicated than they needed to be. A side effect of this was that he used resolvers that don’t support reading Maven POMs, so the transitive dependencies were never found and processed. Second, when you change your resolver configuration, Ivy doesn’t clear its cache, so even after I fixed the above problem, re-resolving didn’t work. Once I figured out that I needed to clear my cache first, everything went swimmingly. Figuring all this out took longer than I care to admit, and stripping out all of the nonsense caused by Maven took a few commits, but it was worth it.

So what’s next? Now that Hibernate is done, James is moving on to Shiro. As for me, I’ve got a pretty long to-do list at the moment:

  • Figure out how to put those overweight JARs on a diet.
  • Merge the Terracotta and Dirmi spikes with the Hibernate spike.
  • Add documentation to the Terracotta and Dirmi spikes.
  • Rewrite the file transfer system using Dirmi pipes to try to improve performance. (Although I’ll probably just mark this as a TODO in the code and come back to it later if there’s time.)
  • Add unit tests for the file transfer system to make sure my security measures are working.

Not sure what I’ll tackle next. I’ll decide when I continue working on the project tomorrow.

IUI

Made an interface for the User Interface server calls with appropriate documentation which tells which types of users should be able to access different information.

Plug it in, plug it in!

I just committed a major update to the Dirmi spike. This update introduces a very simple, but powerful, plugin system using JSPF. Basically, server modules will be self-contained. To “install” a module on the server, you download the module’s JAR file and drop it in the /plugins directory. And that’s it. When the server starts, it will automatically load all of the modules in the plugins directory and interrogate them to determine what functionality they would like to make remotely available. Each export will have a name associated with it, so all the client has to do is call the Registry that the server provides with the name of the export it wants, and the server will return the appropriate object (or rather, a proxy to the appropriate object). A module is allowed to have as many exports as it likes.

This is what I’ve been intending to implement for weeks now, since before break, but actually implementing it proved more time-consuming than I expected. This had less to do with writing code (that only took an hour or two) and more to do with messing with dependency management tools. James has been using Maven on some of his spikes, so I decided to try using it with the Dirmi spike.

The results were a total disaster. I clicked “Enable Dependency Management” and all of a sudden the project was targeting Java 1.4, my source folders weren’t source folders anymore, and all of the dependencies that were still being done the old-fashioned way (because they don’t exist in any Maven repositories that I can find) disappeared from the classpath! It took me forever to figure out how to fix all of that. Then I started trying to work on the plugin stuff and I finally decided to dump Maven. Doing things the Maven way was just going to introduce a ridiculous amount of overhead, and not doing things the Maven way but still trying to use it for just dependency management was more of a headache than it was worth.

Fortunately, there is an alternative: Apache Ivy. Ivy is basically Maven-lite. All it does is handle dependency management. It doesn’t mess with your build process or try to enforce directory structures in your project, so you can continue to have whatever build mechanism and project structure you like. It does use Maven repositories to handle dependency management though, so we can still take advantage of the proliferation of Maven repositories. IvyDE, the Eclipse plugin, is very bare-bones, but I don’t mind manually editing XML files. I had to do that with the supposedly much more comprehensive m2eclipse plugin anyway.

I still think we need to establish our own Maven repository. As I noted in my commit comment, the Dirmi spike alone already depends on four libraries. Of the four, only three are direct dependencies (we rely on Dirmi, which relies on the Cojen library), and only one (Apache commons-io) is available from any public Maven repositories. If we’re going to do dependency management (and I certainly think we should!), then we should either do it right or not at all.

Communication Wars V: The Programmer Strikes Back

As promised in my last post, I whipped up a Dirmi spike yesterday. Local test results were promising, so I committed it a few minutes ago and tested it using t1k1 as I had for Cajo and SIMON. The results were exactly what I was looking for. I also tested file upload performance using the directory upload test. Upload speed averaged out to 53.8 KB/sec. Not shabby, but I think we can do better. I just ran a performance test over at Speedtest.net and that averaged out to 285 KB/sec for uploads. Dirmi, conveniently enough, has a Pipe implementation geared specifically to this sort of problem, so I’ll probably re-implement uploads using that mechanism at some point, which should significantly reduce overhead and improve performance.

I already wrote in my last post about why I think Dirmi is a better choice than Cajo or SIMON, so I won’t bother rehashing that. What’s important is that I intend to move forward using Dirmi, which means that writing a module system just became my top priority. As previously mentioned, the one drawback to Dirmi is that it doesn’t provide the same “registry” functionality that Cajo and SIMON do, so we have to implement that in order to serve many modules from the same port.

I also need to get more familiar with Maven and start using it, because right now I’m still importing dependencies the hard way. I need to learn how to use Maven to define build targets too. It seems like some of the libraries we’re using aren’t available from any Maven repositories, so I also think it would be a good idea to set up our own. I might take a crack at doing that on t1k1 today.

Communication Wars IV: A New Alternative

Just a quick update, since I have to get to class in half an hour. Solutions to the client-server communication problem are just snowballing now. The SIMON spike was good, but I was still bothered, for two reasons. First, the licensing issue that I’ve already discussed ad nauseum. Second, something that I couldn’t put my finger on until a few minutes ago: the fact that the remote method invocations aren’t treated like remote method invocations.

Cajo was the same way, and this is not entirely a bad thing, since it makes writing code a lot easier. But the fact is that a remote method invocation is not a local method invocation and there is potential for failure relating to network problems. As far as I can tell, under Cajo and SIMON, exceptions happen in the event of a failure, but they aren’t explicitly defined, so they’re impossible to catch and deal with.

Now that I have a better idea what I should be looking for in an RMI solution, I uncovered Dirmi. I know what you’re thinking. Another spike, Rich? Really? Yes, really. I’m not sure if Dirmi is the best solution either, but it resolves some problems I have with Cajo and/or SIMON. For one thing, Dirmi is licensed under the Apache 2.0 license, which (I think) is compatible with the EPL. For another, the documentation is better. A lot of Cajo’s documentation is old and wrong, and a lot of SIMON’s documentation is missing (or hard to comprehend, since the developer appears to be German). None of the three projects have tons of developers constantly working on them, but Dirmi appears to be the most active of them. Dirmi also addresses the issue of dealing with remoting failures quite nicely.

The one significant drawback I’ve spotted so far is that Cajo and SIMON both build in the ability to export multiple objects and make them all available on the same port. Dirmi, on the other hand, only appears to allow exporting one object per port. This can be worked around, though. We just have to code the necessary functionality on top of Dirmi, which shouldn’t be too hard. A smaller drawback exists in that, once again, Dirmi doesn’t appear to have a Maven repository, but I’m not so worried about that.

Finally, I noted last night that file uploading with the SIMON spike seemed a bit slow. I haven’t actually timed it, but I noticed that SIMON currently has a bug open relating to poor performance on Windows 7, so that’s probably the source of the problem.

Back in high gear

So it turns out I lied in my blog post a few hours ago. I just can’t stay away from a good programming problem. I thought about all the possible options and decided to go with my gut response, a SIMON spike.

And boy am I glad I did.

As I wrote in the comment when I committed the spike, you know you’re doing something right when you switch client-server communication frameworks and barely have to change any code to do it. Refitting the code from the Cajo spike was trivial and only took about 15 minutes.

The results? Fabulous.

As promised on the SIMON wiki, firewalls were no trouble at all. I was able to run the file upload tests with no problems and verify that everything comes out on the other side the same way it went in, despite having different processor architectures and different operating systems in play. Performance was a little on the slow side, but we can always optimize later. Right now, I’m just glad to have something that actually works.

Truth be told, I like SIMON better than Cajo for more than just the fact that it eats firewalls for breakfast, lunch, and dinner. It also has, in some respects, much better semantics. For instance, with Cajo, I had to explicitly create a proxy object to pass to the server when I wanted to have callbacks to the client, like so:

ISubmissionSystem ss = (ISubmissionSystem) submissionClient.proxy(refs[0], ISubmissionSystem.class);

ISubmissionCallback sc = (ISubmissionCallback) Cajo.proxy(new SubmissionCallback());
ss.testCallback(sc);

Not horribly ugly, but not exactly pretty either. With SIMON, I don’t have to do that. I just mark the classes that should be remoted with the appropriate annotation and SIMON handles the rest. This code accomplishes the same thing as the Cajo code above:

ISubmissionSystem ss = (ISubmissionSystem) serverLookup.lookup(“submitSys”);

ss.testCallback(new SubmissionCallback());

The one place that I consider to be a little weaker semantically under SIMON is the lookup mechanism. Cajo had the right idea there, in my opinion, by doing lookups using the target interface’s method signatures. SIMON uses names instead. Not a huge problem, but it is a slight drawback.

Of course, there is also still that niggling legal issue. As mentioned, SIMON is licensed under the GPL. Personally, I don’t much care whether our code is licensed under the GPL or the EPL or any other license, but Professor Pollice might. Something to ask about when we meet on Monday. If GPL is a problem, then I’ll have to go back to the drawing board. Alternatively, I suppose there’s a slim chance the author might agree to grant us a free commercial license, which would allow us to license our code however we please, but I wouldn’t bank on it.

The one other outstanding issue is that I haven’t finished examining failure cases yet. I know that if the server fails, the client throws lots of big red exceptions. I know that if the client fails, the server is silent, much as it was with Cajo. At some point, probably over the weekend, I’ll bust out JConsole again to see what’s happening under the hood. If the thread doesn’t go away, though, I don’t think that’s a problem. SIMON has a thread pooling mechanism where the same thread can be reused and can even handle multiple connections at once. I’m not sure what the default settings are though.

Anyway, it’s 2AM and I’m calling it quits for the night morning. Expect to see more on this over the next few days.

(Vaguely related addendum: the fact that we’re using t1k1 and t1k2 is really starting to bug the crap out of me. I installed Eclipse on t1k1 so I could run the spikes, and the latest version available under the Package Manager is Ganymede! So I downloaded Helios for SPARC/Solaris from Eclipse.org and tried that. It runs, but it crashes at the drop of a hat, so it’s basically unusable.)

Stuck in neutral

*Sigh* Well, you knew that couldn’t last forever…

I’ve spent most of the day today working on Cajo. The code for transferring entire directory structures is now finished and committed, and it works great when the client and server are both on my computer. Unfortunately, it doesn’t work so well when the client is on my computer and the server is on t1k1. It took me a few minutes to figure out what the problem was. Since it seemed like the method call was never returning, my first suspect was an infinite loop, but there were no loops in my code that could ever be infinite. Then I thought that maybe an exception was happening server-side that wasn’t making it back to the client, so I coded a quick test and discovered that wasn’t the problem either.

So what’s the problem? You probably already know the answer. Say it with me, everybody…

NAT!

Yep, that wonderful technology that keeps my desktop, my laptop, and my TiVo hidden behind a single public IP address cripples Cajo. Or more accurately, it cripples Java RMI, and Cajo happens to run on top of that. The problem stems from the fact that RMI doesn’t just create one connection, it creates one in each direction. Which is a problem when you want the server to execute callbacks on the client, and the client is behind NAT or a firewall and can’t receive a connection from the server.

So how do we deal with this? Well, so far, I’ve come up with several possible solutions, all of which fall somewhere between “bad” and “worse”:

  • Cajo actually has a way of dealing with this problem, using what they call a ClientProxy. The problem is that this solution is charitably described as a hack. Also, I don’t completely understand how to use it (their example sucks and is out of date), but it looks like it would be pretty messy.
  • Moving down into the bowels of RMI, we could provide our own implementations of RMI sockets. RMI Doves appears to be pretty much what we would need, but it’s not free and also apparently not being developed any more. I haven’t found anything else like it, so we’d have to roll our own. I think we’d need to mess with Cajo’s code as well.
  • The transport-level bridge solution described here. This would involve finding or writing an RMI proxy server of some sort, and I think this would still require changes to Cajo to work.
  • We could use UPnP to forward the appropriate port. I found a library that would make this very easy. It would solve the problem nicely… as long as NAT is the problem (and not, say, a strict corporate firewall) and the router supports UPnP. It’s basically still a hack, cleaner than the ClientProxy option but not necessarily solving all possible problems.
  • We could just not use callbacks. Instead of having the server “pull” the files from the client, the client would “push” them to the server. This would mean having different mechanisms for transferring files, depending on which way we want to go (we need to support both directions), which kinda sucks because I specifically designed FileTransfer to be direction-agnostic to avoid that problem. Also, if anything else we ever do requires a callback, we’re still screwed.
  • We could change protocols to something that doesn’t have the firewall problems that RMI does. Of course, all of these alternative protocols have other problems, which was the whole reason we picked Cajo in the first place. I did find a new possibility: SIMON. SIMON actually seems fairly similar to Cajo in terms of API, but is not built on top of RMI. There are some annotations involved, but I don’t think there’s any bytecode magic going on. The larger problem is that it’s licensed under the GPL, which would mean that all of our code would have to be GPL as well, rather than the much more liberal EPL that the rest of WPISuite is currently licensed under. On the plus side, it does have a Maven repository, which Cajo does not seem to have.

All of these options suck, in my opinion, and I’m really not sure what to do. The UPnP solution is fairly simple and probably fixes the problem for 90% of cases, but that still leaves some people out in the cold. The “don’t use callbacks” solution would fix this problem and we probably won’t need or use callbacks for anything else, but we’re trying to provide a flexible infrastructure for future teams to take advantage of, and not supporting callbacks is highly detrimental to that goal. I’m leaning towards a SIMON spike to see if that’s feasible, because SIMON looks a lot more flexible than RMI, but it does have that licensing drawback.

But none of that is going to happen today or tomorrow. Whatever I decide to do will get worked on over the weekend.

Follow

Get every new post delivered to your Inbox.