text: 17 replies on
  2 pages.
  Most recent reply:
  Jun 30, 2010 10:02 AM
  by
  Morgan Conrad
  This is not just a discussion about Java3d, it is a discussion about builders in Groovy and how they can ease our creational code.
  In my last blog, Java 3D Fun with Groovy, I showed an
  example of using the Java3d libraries via Groovy. The seamless integration with Java made it easy to use all of the Java3d API
  classes, but I whined that it was hard to create a 3d scene in code.
  Actually, I should have been more specific. It was hard to create 3d scene in readable code, and it was hard to get an idea
  of the hierarchy of the elements of a 3d scene by looking at other people's code. This is not an unfamiliar problem, and one which
  Groovy has vastly improved with its builders. I want to illustrate them here.
  Even with a powerful API a lot of our time as software developers is spent just creating stuff. Data structures, domain classes,
  XML, GUI Layouts, Output streams etc. A recurring theme in the creation of all of these is the creation of an objects which
  contains objects. These objects might in turn have their own nested objects and so on. The problem with this, is that your typical
  programming language cannot know anything about the structure of our domain objects, and so our code looks nothing like our
  hierarchy. Say a customer object has an invoice object in it, or a teacher object has many student objects, when we are
  initialising our hierarchy, we invariably have to treat all of the objects as if they had the same hierarchical level.
  Teacher t = new Teacher("Jones")
  Student s1 = new Student("Bob")
  Student s2 = new Student("Sue")
  t.addStudent(s1)
  t.addStudent(s2)
  This looks a bit flat. 5 lines of code, 3 uses of the new keyword (which adds to the amount of text we have to read) and no
  sense of the hierarchical relationship between teachers and students. This is fine in such a simple case, but in a much more
  complicated case this code block would be horrible to read.
  Wouldn't it be nicer to be able to do something like this?:
  teacher ("Jones") {
  student ("Bob"){}
  student ("Sue"){}
  }
  This uses simple-to-read bracket notation, is much less typing and gives a sense of the hierarchy of the data.
  This is what Groovy allows us to do with builders. We essentially have the capacity to create a domain specific language around the
  domain of "building our domain". If this sounds complicated, it isn't. It just means that we can use the minimum amount of syntax
  to specify the boiler plate tasks of creating object instances, whilst at the same time showing their parent / child relationships.
  Groovy builders are an implementation of the GOF Builder pattern, but they are more than that. They make clever use of the powerful
  syntax and dynamism of the language to give you efficient creational code, cleaner than XML and much cleaner than just using
  vanilla Java code.
  <?xml version="1.0"?>
  <teacher name = "Jones">
  <student name = "Bob">
  <student name = "Sue">
  </teacher>
  ..
  Element teacher = doc.createElement("teacher");
  teacher.setAttribute("name", "Jones");
  Element student1 = doc.createElement("student");
  Element student2 = doc.createElement("student");
  student1.setAttribute("name", "Bob");
  student2.setAttribute("name", "Sue");
  teacher.appendChild(student1);
  teacher.appendChild(student2);
  ..
  Yech! Very noisy and very flat. We don't get a real sense of structure of the data from looking at the code, and we are wallowing
  in implementation details of the API, with method calls like setAttribute, appendChild and createElement.
  Groovy supplies a MarkupBuilder() out of the box. Let's look at how we would generate the same XML as above using Groovy.
  def builder = new groovy.xml.MarkupBuilder(writer)
  builder.teacher (name: "Jones") {
  student (name: "Bob") {}
  student (name: "Sue") {}
  }
  Definitely much cleaner and neater.
  It all looks a bit too simple to work, but in fact, if you look at my blog, Creating a Domain Specific Language with Groovy , you will see how you can use method interception and closure
  passing to create "pretend" methods and query their parameters, thus giving you the power to dynamically tailor behaviour. In this
  case, the methods "teacher" and "student" don't actually exist, but Groovy uses the calling mechanism to create the XML on the fly,
  as your code tries to call the methods. In the example above, it writes the resulting XML to the writer passed as a constructor
  parameter to the builder. This gives us an elegant way of constructing a structured XML document.
  I started this blog by saying that I would demonstrate how I could make simple Java3d scenes easier to render. Let me wrap this
  effort in a disclaimer from the start, by saying that the Java3d library is very complex, and I will demonstrate a simple builder
  that can create scenes using a subset of the API. The idea here is not so much to build a complete layer on top of Java3d, as it is
  to illustrate that with certain, complex API's, we can gain enormous power from creating thoughtful builders in Groovy. [As an
  aside, though, creating a library of builders around the Java3d API seems like a really exciting and fun project, so if anyone has
  knowledge of Java3d and is interested in a challenge, let me know!]
  ..
  def universe = new SimpleUniverse()
  def group = new BranchGroup()
  group.addChild(new ColorCube(0.1))
  universe.getViewingPlatform().setNominalViewingTransform()
  universe.addBranchGraph(group)
  ..
  But this presents the same problem as the other examples. There is a hierarchy here, but we certainly can't see it in the code, and
  we are adding children and branch graphs to groups and universes, which looks very complicated. By default, we get this:
  def cube = new ColorCube(0.3)
  def universe = new SimpleUniverse()
  def bGroup = new BranchGroup()
  def rot = new Transform3D()
  def trans = new Transform3D()
  rot.rotX 0.77
  trans.mul rot
  rot.rotY 0.77
  trans.mul rot
  def tGroup = new TransformGroup(trans)
  bGroup.addChild(tGroup)
  tGroup.addChild(cube)
  universe.getViewingPlatform().setNominalViewingTransform()
  universe.addBranchGraph(bGroup)
  Let's look at the builder code that I can use to achieve the identical 3D scene hierarchy before I explain how I have implemented
  the builder:
  new Java3DBuilder().BranchGroup {
  TransformGroup (scale: 0.3, rotX:0.77, rotY:0.77) {
  ColorCube {}
  }
  }
  That's it!! 14 lines down to 3! And look how intuitive it is by comparison. The BranchGroup clearly contains a Transform Group
  which has some parameters, and that in turn contains a ColourCube. Ok, this isn't magic, there is obviously some code needed to do
  this, but it is roughly 100 lines and it takes the form of
  extending an abstract class. The parsing logic is already there and so it really is easy to create a DSL which is intuitive to use,
  clean and simple.
  I also obtained a lot of leverage from the dynamicism of Groovy (features like dynamcic property setting, and constructor calling)
  and was able to implement some powerful default behaviour which covers a lot of the Java 3d classes that I haven't specifically
  considered.
  As I mentioned earlier, implementing a builder is just a question of extending an abstract Java / Groovy class. The full source is
  available here, and the full specification of
  groovy.util.BuilderSupport can be found in the Groovy documentation . The
  methods I was interested in are below:
  public abstract class BuilderSupport extends GroovyObjectSupport {
  ..
  protected abstract void setParent(Object parent, Object child);
  protected abstract Object createNode(Object name);
  protected abstract Object createNode(Object name, Object value);
  protected abstract Object createNode(Object name, Map attributes);
  protected abstract Object createNode(Object name, Map attributes, Object value);
  ..
  }
  This means that when implementing these abstract methods we can decide on the creational behaviour, and build the hierarchy, which
  is what makes the model so powerful. Let's look at some of the highlights.
  def packages = ['com.sun.j3d.utils.universe',
  'com.sun.j3d.utils.geometry',
  'javax.media.j3d',
  'javax.vecmath']
  .. and provided the full package isn't specified (which I have allowed, to resolve any conflicting class names), I use the
  following to create the class:
  for (packageName in packages) {
  try {
  fullName = packageName + '.' + name
  cls = getClass().getClassLoader().loadClass(fullName)
  }
  catch (ClassNotFoundException e) {
  cls = null
  }
  if (cls)
  break
  }
  To obviate the need for huge switch statements, I can use Groovy's dymanic property setting to allow me to set attributes on the
  object. This means that as long as a valid property X exists (where there is a setX on the object), I can set it with the specified
  value. Since Groovy will throw an exception if the property doesn't exist, I can do a lot of the work with the code in the default
  case as below, and for the most part, don't need too much domain knowledge to implement that part of the builder:
  def createNode(name, Map attributes) {
  def node
  switch (name.toLowerCase()) {
  case 'transformgroup':
  node = buildTransformGroup(attributes)
  break
  default:
  node = createNode(name)
  attributes.each {key,val ->
  node.metaClass.setProperty(node,key,val)
  }
  break
  }
  node
  }
  Note the special case of the TransformGroup. More about that below.
  In general, we obviously want to use domain knowledge to ease our build effort. Here, since a TransformGroup always needs a
  Transform, I have combined them in my builder so that what looks like setting a property on a TransformGroup is actually setting it
  on the associated Transform. Under the covers this is creating two nodes with a parent child relationship, so what should be:
  TransformGroup () {
  Transform3D (scale: 0.6, rotX:0.77, rotY:0.77) {
  ColorCube {}
  }
  Is actually more simply declared:
  TransformGroup (scale: 0.6, rotX:0.77, rotY:0.77) {
  ColorCube {}
  }
  attributes.each {key,val ->
  switch (key.toLowerCase()) {
  case ['rotx', 'roty', 'rotz']:
  // invoke the method on the temp. transfrm and multiply together
  temp.metaClass.invokeMethod(temp,key,val)
  transform.mul(temp)
  break
  default:
  transform.metaClass.setProperty(transform,key,val)
  break
  }
  }
  So, in about 100 lines of code, we have a builder which makes it very easy to play with the basic 3d universe. Because a lot of the
  build code is dynamic and generic, I can make use of many of the classes in java3d that I don't know anything about yet, so it
  really is a successful domain specific language. I can now experiment with the library using much simpler code.
  For example, using a Cone is more complicated than the ColorCube because you need to specify a material for
  it. Also, putting two objects into our universe can be done in such a way that they can be rotated and moved independently of each
  other. So if I want to create a cube impaled on a cone, I can experiment with a small body of code that actually gives me a clue
  what it represents. Note that although this is a DSL, and looks somewhat declarative, it is in fact ordinary Groovy code, and so
  any valid Groovy statements can appear in between the node declarations.
  ..
  builder.BranchGroup {
  TransformGroup (scale: 0.4, rotX:0.67, rotY:0.53) {
  ColorCube {}
  }
  TransformGroup (scale: 0.65, rotZ:0.22, translation: new Vector3f(0.1f,0.1f,0.1f)) {
  def appearance = new Appearance()
  appearance.setMaterial(new Material(green,green,green,green, 0.1f))
  Cone(appearance: appearance) {}
  }
  }
  ..
  There is a lot missing from this builder, but it wouldn't be very hard to add. As I said earlier, if you are interested, let me
  know. In general, there is nothing to stop you creating different builders to be used together, or nesting builders to create more
  complicated hierarchies. I hope I have convinced you that builders are a very important part of any API to provide, and failing
  that, a very good approach to creating a layer of abstraction that simplifies the use of existing API's.
  Download the code here.
  GOF Builder Pattern
  Groovy Builder Documentation
  new Teacher("Jones")
  .addStudent("Bob")
  .addStudent("Sue")
  > new Teacher("Jones")
  > .addStudent("Bob")
  > .addStudent("Sue")
  >