One of my goals this year for smartermeter is to make it usable on Windows. There are several ways to accomplish this but I chose to use JRuby and Swing (with a dash of profligacy to simplify Swing layouts). This approach allows me to reuse the core library while providing an appropriate interface on top.
Aside: This approach isn’t for the faint of heart. Unfortunately I’ve only recently found that out. For some reason I thought using JRuby would be straightforward and simple. I’ve always admired the project from a far but hadn’t really used it until now. While I can say that it’s robust and cool it has a while to go before being simple or easy. As with any bleeding edge software, it has rough edges and needs some time to get past them.
The first approach I took was to simply see what would happen if I ran smartermeter unmodified in JRuby. The first issue that came up was that nokogiri 1.4.x uses FFI when run in Java. It should just work but didn’t. After trying everything I knew, it turned out that there was a bug in the version of JRuby (anything less than 1.5.6) that prevented FFI from working. Even after upgrading JRuby I couldn’t get it to work. However along the way I found out that FFI nokogiri is deprecated at which point I thought it best to switch to the unreleased version of nokogiri (which is pure Java).
On my first attempt of using the pure Java nokogiri I thought it was broken as well. In reality it was just taking longer than a minute to load. However with a load that long it might as well have been broken. I tried increasing the heap which didn’t help (in case it was swapping).
At this point I almost abandoned the whole endevaour (with a plan to rewrite smartermeter without nokogiri). But I figured I would try one last test. I locally installed JRuby and nokogiri (instead of loading them from a single jar) and low and behold it only took less than a second to load. It turns embedding nokogiri within a jar drastically slows it down although I don’t understand why. My guess is that it has something to do with JRuby’s classloader and embedded Java jars.
I went back and removed the rawr packaging I had previously added to smartermeter (as it placed everything into a single jar) and replaced it with a rake task that just includes all of the gems in a folder. Thinking I was almost done I tried to execute smartermeter again but couldn’t get the JRuby
-S switch to work on 1.5.6. It turns out that’s also a bug because the
-S works just fine on 1.6.0.RC2. At this point things are almost working properly and the application begins to run until I reach the final error.
It turns out that not all JRE’s of the same version are equal. If Java doesn’t detect multiple languages on your system it fails to install
charsets.jar. Unfortunately mechanize uses this jar to guess the character set of retrieved documents. For my specific application, I know the character set of the documents I’m fetching so I just overrode the method to avoid further complications.
Success! The next steps are to create an executable to launch smartermeter with a double click and to create an installer to place things in the appropriate folder structure. I’ve looked at NSIS and lzpack. lzpack seems more crossplatform but doesn’t look native to a windows user. NSIS looks more native to a windows user but the installer must be built on windows. If you’ve heard of something better let me know.