Feb 15 2007

JRuby can save Swing

Julian Doherty

Swing is hard. Needlessly so. With the advent of scripting support on the JVM, why not wrap a light and elegant Ruby layer around Swing? Why keep coding Swing at it’s lowest API level using a heavy-weight language like Java?

I’ve always maintained Swing is a nice framework. It’s just that it’s too low level and Java is a lousy language for programming it in. It’s already possible to code Swing in Ruby by using JRuby. You get some of the Ruby niceness (such as easier method calls, some dynamic typing, and blocks), but you still end up fighting against listeners, layout managers, look-and-feels, event-threads etc before long. Suns trademark API over-engineering casts a long shadow, even into Ruby land.

The Swing API itself is very flexible and powerful, but at a low level. It’s powerful in the same way that a coil of wire and a bunch of tools is a flexible and powerful way to configure the electricals in your house. It’s just that sometimes you only want to plug a few things in and flick a switch to watch a DVD.

So what specifically are the problems?

Swing’s issues

Joshua Marinacci’s blog post Swing has failed. What can we do? from 2003 covers this issue nicely. Joshua points out these flaws which I’d agree with 100%. Nothing much has changed in the years since, except maybe that Swing looks somewhat better now and resembles native apps much more closely.

  • "Swing apps are slow to build."
  • "Swing layout managers suck."
  • "Swing apps are hard to maintain."
  • "Swing is too powerful."
  • "No native features."
  • "Swing apps have a bad history."

What needs to be done?

Joshua’s ideas on what needs to be done to fix Swing are interesting.

(there are more points he makes, but I’m just including the relevant ones)

  • "A structured way of building Swing apps. Something like Struts where each concern (aspect?) has it’s own special place to be stored and manipulated. How do you organize your layout, workflow, validation, intz’ed text, and hooks to the BL? Should you subclass to make frames or use factory code? We need a set of best practices and then a framework to implement them."
  • "A standard cross-tool representation of a GUI that is not Java code. Something that can be moved in and out of different IDEs and build tools. Probably an XML representation or maybe serialized Swing objects."
  • "An intermediate API. Maybe we need a simpler API on top of Swing? A new set of wrapper components which hide a lot of the complexity. Hell, half of the work could be done by just conditionally hiding 3/4 of the API from the Javadocs."

I particularly like the idea of a structured way of building Swing apps. At the moment it’s a free-for-all. Some developers have come up with nice individual patterns for maintaining order, others implement spaghetti, most start out well, but degrade into entropy. This even applies individual screens in some apps! - I’ve seen 6000 line long, single-class monstrosities for a single window! One of Rails main strengths is it’s “Convention over Configuration” approach for separating out and structuring an application. There is no reason why this can’t apply to a Rich Client.

My Ideal Swing/Ruby framework features

So… what would this look like?

  • Structured application layout. Works for Rails. Nuff said.
  • Proper decoupling of model from view. Probably using Martin Fowler’s Presentation Model pattern, or similar.
  • Automatic binding of model to view without glue code. (this makes the last point much easier to implement.) Ruby is perfect for this. You should be able to write something like name_field.bind_to song, :title and be done with it. Ruby should do it’s thing and set up listeners automatically - Even if the model class wasn’t designed with listeners when it was coded.
  • View logic code separated from layout markup. View components and interaction (enable this button with this tooltip etc) should be coded in Ruby. Layout should be stored in a YAML file or similar (please no more XML…). Layout via coding is far too hard for most people to use effectively. Minimize the pain and let the framework take care of the grunt work. We definitely DO NOT want anymore GridBag boilerplate code…
  • Application lifecycle support. Related to having a structured application layout. Provide session support, long lived models etc, and handle startup/shutdown.
  • Minimize the amount of code. You already get this for free by using Ruby, but removing the fluff from Swing is a must. Too much code to achieve too little. It should be possible to scaffold something basic like Rails does, then tweak it if it needs to do more. DRY is part of this, but that just seems like basic common sense for any kind of development in any language.
  • Minimize complexity. Related to minimizing code. Making it easy to use a proper pattern like Presentation Model and removing a lot of the spaghetti listener code by using bindings will help a lot.
  • Testable. It’s really hard to write automated tests for GUIs. Libraries like JFC Unit make it easier, but it’s still pretty heavy going. I don’t know the answer to this one. GUIs always need at least some manual intervention to check the visual layout (a computer can’t tell if it doesn’t “flow” right). Maybe the framework could help by making it easy to substitue mock objects for testing the presentation model code.
  • Make the Right way of doing things the path of least resistance.. This one is important, and I think it is one of Swing’s big weaknesses. This is related to having a good structure, but it goes from there all the way down to how easy the APIs are to use. Rails makes it easy to create good designs and stick to them. Swing makes it hard - as evidenced by the plague of badly thought out Autonomous Views espoused by Sun’s Swing tutorials

Even a few of these points would make Swing much more productive and fun. I’ve made a few posts recently that are leading up to this. Over the next few posts I’ll start to experiment with a few more of the pieces to see how it all hangs together. Who knows, maybe I’ll actually get something usable at the end :)


Feb 13 2007

Parallels RC2, Boot Camp, Windows XP, OS X - One Happy Family On My Mac

Julian Doherty

I’ve been using Parallels for a while now to run Windows on my iMac. It’s good for day to day work type stuff. We write client/server software with a Windows client, and PL/SQL Developer is one of the best Oracle developer tools, but is Windows only. However, for more graphically intensive, interactive, networked applications its performance is a bit below par - by which I mean it doesn’t work.

Up until now I’ve had to scavenge around the office and camp some random, vacant low-spec PC when the after hours LAN sessions start. Its a little frustrating when my Mac box has enough grunt to run the games we play (mostly the ‘old but good’ titles from a few years back).

Enter Parallels RC2 (build 3150), with the nice feature of being able to run a Boot Camp Windows install in a virtual machine in OS X. After a couple of hours all the pieces are in place and living together like one big happy family - or at least one of those families with the weird distant relative with stability issues and poor hygiene that everyone awkwardly puts up with on occasions when they have to interact with them, but really can’t stand them (I’m looking at YOU Windows).

End result is that you’ve got a single Windows install, but with the option of booting it to either run natively via Boot Camp (with PC-level performance for Windows apps), or to run it as a VM via Parallels (can run alongside OS X in a window)

Install

The install was pretty straight forward. The Boot Camp docs explained the steps nicely. Once the Boot Camp install was done, its a simple matter to import it into Parallels. All up the install process only took a couple of hours - most of that was installing Windows.

The only trick is deciding whether to format the Windows partition with FAT32 (can see drive from OS X, 32GB limit), or NTFS (larger drive size, better disk usage). I ended up going with FAT32. Maybe I’ll change that latter, but it’s going to require deleting the partition with Boot Camp, recreating it, and reinstalling Windows

Weirdness

Sticking all these round pieces into square holes is handled pretty well by both Parallels and Boot Camp. They’ve both done an admirable job of making it as seamless as it is, however there are a few quirks along the way

  • Windows XP Activation. I had previously been running my copy of Windows XP in a pure Parallels VM. Reinstalling in boot camp was detected as totally different hardware by Windows, which then told me my key was invalid. Likewise when the install is imported into Parallels it is also detected as yet another change. This required a separate call to Microsoft to activate each configuration and a little bit of sweet talking to convince the operator that I’m not driving MS to bankruptcy by installing one copy twice. The magic words they want to hear are "I’m reinstalling Windows XP on the same PC", which is sort of true (if not quite the technical explanation). I was wondering if the same Windows install would complain about being activated twice with two different configs, but so far it seems OK.
  • Parallels doesn’t like windows formatted USB drives. Parallels was running fine for a couple of days, then when I came in the next week it refused to start windows, complaining that "More than one Windows partitions are found. This is not a standard Boot Camp configuration.". Huh? What had changed? I’d plugged in my iPod - which is Windows formatted. This confused Parallels. Unplugging the iPod and trying again worked fine. Once the Windows VM is running, it’s fine to plug the iPod back in. The same thing happened with an NTFS formatted external hard drive as well.

All up I’m pretty happy with the set up. Gave it a blast with some Quake 3 action last night and had a great time. Admittedly it’s a pretty old game, but it ran flawlessly with a great frame rate at highest detail. Now I just gotta get in some more practice to not get my butt handed to me by the guys in the office (I beat all the bots though :P )


Feb 7 2007

Transparent Property Change Listeners in Ruby

Julian Doherty

One of my side projects is a framework for building Swing apps using JRuby. I’ve always maintained that Swing is a nice framework - it’s just that Java is a lousy language for writing it in.

One of the areas that Swing is weak in, is binding components to the underlying model. For those unfamiliar with Swing, its designed with a nice way of loosely coupling the model to the GUI components. This is done using listeners - typically Property Change Listeners - which fire whenever the value of some property changes and can be coded to explicitly replicate the state from the model to the view or (vice versa).

…Which is really nice in theory, but in practice it’s not a clean or easy task. It’s usually done badly as there is so much glue code to write if you want a nice pure OO design (developers hate writing boiler plate code). There are Java frameworks like JGoodies Binding and the PropertyChangeSupport class built into the JDK that help out, but in typical Java style, these can get quite complicated, and still require you to carefully manage new Objects to make sure they are manually bound correctly. It usually just ends up being a burden in real life which no one follows properly. (For an example of how NOT to write Swing properly - see Sun’s own Swing tutorials…)

I figured it should be possible to do this in a more Rubyish way. Something that is smooth and easy to use, and provides the best practice as the path of least resistance. I googled a bit and found RubyBeans revisited by Olivier Ansaldi, which seems cool… but involves having to subclass your bean classes from a common base class - some thing I was wanting to avoid. Ideally, the bean classes should be pure and simple Ruby classes build with attr_accessor. (what you’d call a POJO if were in Java land - although this concept is so obvious in Ruby I haven’t even come across a name for it)

Here’s what I came up with:

class ListenerSupport

  public
  def self.listen_to(klass, *properties)
    setup(klass)
    properties.each do |p|
      klass.class_eval do

        alias_method "#{p}_orig=", "#{p}="

        define_method "#{p}=" do |value|
          old_value = send "#{p}"
          send "#{p}_orig=",value
          fire_property_changed p, old_value, value
        end
      end
    end
  end

  private
  def self.setup(klass)
    klass.class_eval do

      def fire_property_changed(prop,pre,post)
        return if pre == post
        @listeners[prop].each do |l|
          l.property_changed(self, prop, pre, post)
        end unless @listeners.nil?
      end

      def add_property_listener(prop,listener)
        @listeners ||= {}
        prop_listeners = @listeners.include?(prop) ? @listeners[prop] : []
        @listeners[prop] = prop_listeners
        prop_listeners << listener unless prop_listeners.include? listener
      end

    end
  end

end

The general idea is that the original class is modified so that all properties that are listened to have their accessor write methods intercepted, and any property change listeners are notified when that property changes.

Let’s walk through how it works:

  • A standard Ruby class with property accessors is created. e.g.
    class RubyBean
      attr_accessor :foo, :bar
    end
  • A call to ListenerSupport.listen_to is made to modify the class to allow properties to be listened to.
    ListenerSupport.listen_to RubyBean, :foo, :bar
  • listen_to adds methods add_property_listener and fire_property_changed to allow listeners to be added to RubyBean for specific properties.
  • listen_to then aliases the original methods foo= and bar= to foo_orig= and bar_orig=. New methods for foo= and bar= are defined that delegate the work to the original method, then call fire_property_changed to notify the listeners.
  • Listeners are called, and any custom action (such as GUI component binding) can be carried out.

An example of this in action

class BeanListener
  def property_changed(obj, property, old_value, new_value)
    puts "#{obj.to_s} updated property:#{property}. old:#{old_value}. new:#{new_value}"
  end
end

class RubyBean
  attr_accessor :foo, :bar
end

ListenerSupport.listen_to RubyBean, :foo, :bar

bean = RubyBean.new
bean.add_property_listener(:foo,BeanListener.new)
bean.add_property_listener(:bar,BeanListener.new)
bean.foo = 'foo1'
bean.foo = 'foo2'
bean.bar = 'bar1'
bean.bar = 'bar2'
bean.bar = 'bar2'

Which outputs:

# updated property:foo. old:. new:foo1
# updated property:foo. old:foo1. new:foo2
# updated property:bar. old:. new:bar1
# updated property:bar. old:bar1. new:bar2

Which shows that the listener is being called each time the property changes :)

Although this doesn’t show any kind of GUI binding, it does show how easy it is to make ordinary Ruby classes (or even Javabeans in JRuby) behave as if they had property change support built in from the start. It’s an important piece of the design a smooth and easy GUI binding framework.

Update - Fixed code after feedback from Pit Capitain in comments - should have used class_eval rather than instance_eval to define new methods in setup()


Feb 5 2007

Ruby / Oracle / Mac OS X pain

Julian Doherty

Environment setup is one of the worst aspects of software development. You can get all hyped up about the latest and greatest technology and techniques, but at some point you’ve got to get your environment set up so you can use them. I’ve spent a good part of this afternoon trying to get Ruby to work with an Oracle database on my Mac OS X box.

Simple huh? Nope. Mostly just old fashioned pain.

A bit of googling initially pointed me to the ruby-oci8 project, which provides a Ruby library for Oracle. I happily download and started working through the install instructions which involves compiling the library. Fine - except for the compilation problems. Seems my Oracle Instant Client install isn’t quite complete.

Next step is a trip to Oracle’s website, which is an altogether separate exercise in frustration - after eventually reviving my developer login (with the help of mailinator and Borat), I stumbled around clicking through a “terms of use - sell your soul agreement” for every… single… page… I eventually find the download I’m after. Cool.

I try to compile ruby-oci8 again, but this time I come up against:

Oracle doesn't support intel mac.
 http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/223854

There are three solutions:
1. Compile ruby as ppc binary.
2. Wait until Oracle releases mac intel binary.
3. Use a third-party ODBC driver and ruby-odbc instead.
    http://www.actualtechnologies.com/

By this time about 2 hours have gone by, and hair is being pulled out in clumps. Admittedly I would have known this if I’d just read the platform specific issues on the ruby-oci8 site.

By now it’s 6pm, and the evening round of CS is starting up. I’ll save this one for tomorrow. Maybe I’ll play around with ODBC, or possibly try using a JDBC driver and using JRuby instead.

The ironic part is that I’m just wanting to "quickly" mock up some code to test out something that will later be implemented properly in Java (oldschool, heavy Java). At this rate it probably would have been quicker to do something quick and nasty in Java and be done with it (which isn’t *that* bad with Eclipse). Lately though, I’m shuddering at the thought of file after file of needless case handling, redundant interfaces, xml config files, and over engineered Sun APIs - even for simple stuff. Environmental pain is probably the lesser of two evils in the long run.


Jan 30 2007

F3/swiby style declaration blocks

Julian Doherty

swiby is a proof of concept framework inspired by F3. Both use a hierarchical block format for defining Java/Swing visual elements. eg:

Frame {
  title "Hello World F3"
  width 200
  content {
    Label {
      text bind(model, :saying)
    }
  }
  visible true
}

I was looking through the documentation, and got curious as to how the class level block declaration is actually implemented in swiby. After a bit of digging around, it is relatively straight forward.

There is some code in swiby that looks kinda like this:

def component_factory(class_name)
  eval %{
    def #{class_name}(&block)
      x = #{class_name}.new
      x.instance_eval(&block)
      x
    end
  }
end

I’ve removed the error handling and some extra functionality, but the basic idea is the same. component_factory is called for each class that is required to be instantiated as a declared block. Here’s an example:

class Foo
end

class Bar
end

component_factory :Foo
component_factory :Bar

my_foo = Foo {
  @my_bar = Bar {
    @baz = 'baz'
  }
}

puts my_foo.inspect

Which outputs:
#<Foo:0x60544 @my_bar=#<Bar:0x604e0 @baz="baz">>

A Foo instance has been created containing a Bar instance, with a variable of baz. This sort of syntax could be useful for DSL implemented in Ruby.

One limitation I ran into, is that calling attr_accessor methods don’t get recognized (they just get defined as local variables that go out of scope at the end of the block) - but that may just be a limitation of useing instance_eval to set the newly created object as the object in scope as self.


Jan 25 2007

Java style stacktrace for JRuby code called from Java

Julian Doherty

As part of a project to write some nice Ruby APIs for creating Swing GUIs, I’ve been a little frustrated with the exceptions from JRuby in the Java code that calls it - particularly getting stack traces, and error messages.

Say you’ve got some code like this:

try {
  new ScriptEngineManager().
      getEngineByName("jruby").
      eval("raise 'foo is too bar'");
} catch (Exception e) {
  e.printStackTrace();
}

You’ll get output that looks something like:

javax.script.ScriptException: org.jruby.exceptions.RaiseException
  at com.sun.script.jruby.JRubyScriptEngine.evalNode(JRubyScriptEngine.java:376)
  at com.sun.script.jruby.JRubyScriptEngine.eval(JRubyScriptEngine.java:138)
  at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:245)
  at Borked.main(Borked.java:9)
Caused by: org.jruby.exceptions.RaiseException

Not very helpful. How are you supposed to know what went wrong where?

After a bit of poking round with the debugger, it turns out there is more information in the exception you get back. You just have to work to get it. The following code will grab the Ruby exception message and stacktrace and spit it back out in the same style as native Java exceptions are output.

try {
  new ScriptEngineManager().
      getEngineByName("jruby").
      eval("raise 'foo is too bar'");
} catch (Exception e) {
  RaiseException re = (RaiseException)e.getCause();
  System.out.println(re.getException().getMetaClass() + ":" + re.getException().toString());
  RubyArray rubyStackTrace = (RubyArray) re.getException().backtrace();
  for(Object stackLine : rubyStackTrace) {
    System.out.println("\tat " + stackLine);
  }
}

Here’s the output from some code I’ve been working on

ArgumentError:unknown key:foo
  at /development/wring/classes/wrung_test.rb:17:in `each'
  at /development/wring/classes/wrung.rb:43:in `populate_defaults'
  at /development/wring/classes/wrung_test.rb:17:in `add_comp'
  at /development/wring/classes/wrung_test.rb:17
  at :0:in `require'
  at :0

Which is pretty much exactly what a Java stack trace would look like - except its for the Ruby code running inside JRuby called by Java.


Nov 9 2006

It was a work of art, in a Jackson Pollock sort of way

Julian Doherty

Yes, It Really is Three Tiers

“It didn’t help when the Java Guru showed off his code, either: a single Servlet where the code for a single method ran over thirty pages (he liked to print stuff out a lot), used string concatenation to build the HTML, interspersed direct call to JDBC, and didn’t contain a single comment. It was a work of art, in a Jackson Pollock sort of way.”

I love the reference to Jackson Pollock. Fits for a lot of the legacy code in the ancient depths of the applications I work on.