Meta-Programming in Java

Posted by Peter Donald Thu, 09 Mar 2006 05:33:00 GMT

I have been looking over my old code repository and I came across GEL. GEL was a toolkit that allowed me to define entities and events for HLA using an XML data definition language.

The HLA is a family of specifications developed to promote intereoperability and reuse of simulation assets. Unfortunately there is a significant development effort associated with construction of a HLA-compliant federation. Less than 2% of the 2500+ lines of code in the “Hello World” sample HLA application relates to simulation logic. The integration code is a significant cost and there is often a high-level of coupling between the simulation code and the integration code.

GEL was created to simplify HLA developers task by generating all the integration code from a simulation model defined in an XML document. The HLA developer had the sole responsibility of writing the simulation/logic code. Think of GEL as a a poor-mans MDA (I even planned to have a set of separate generators that would allow the simulation objects to be hosted in a Quake3 game). This approach rocks as you only need to fix and update the code in one place (the generator) and you are far more productive at the higher level of abstraction.

Each simulation object in the GEL XML document resulted in the generation of several Java classes by velocity.

  • a Model class for holding data of a specific instance.
  • a ModelListener class that receives events relating to a Model instance.
  • a HLAPeer class that reflects the data in a Model instance into the HLA runtime.
  • a PersistPeer class that persists the data in a Model instance.
  • a number of Value Object classes to represent various events
  • etc…

I had long believed in having a single high-level model of the domain objects and generating. Prior to XML I had used SGML, INI and custom formats to represent the model. On a number of occasions I have attempted to move the model data into the code to make it easier to keep up to date. I have used C/C++’s macro expansions, XDoclet-like processors and Java 1.5 Annotations at various times.

Six months using Ruby On Rails’ has changed my world view. The model classes are very close to the level at which I would create my domain model. The good thing about ruby is that you can always add more language constructs to make sure the code matches your domain model. (I know Lisp-ers have always raved about this but I have never been able to use lisp in a commercial environment). Things like acts_as_list to order your domain objects, acts_as_versioned to version your domain objects or acts_as_threaded to have a threaded tree representation radically simplify the representation of domain objects.

I have been thinking about how I would do this in Java but most of the neat stuff just does not seem possible without the introduction of a Meta-object Protocol or some sort of load-time class file modification.

Consider a simple simulation object. In ruby I would represent it via

class Kettle < Model::Base
  shared_attr :temperature, :float, :resolution => 1.0, :accuracy => 1.0 
end

In java there is no simple equivalent. I could just define the model in a class like below. However this would probably need to be instrumented during loading so that the runtime could monitor changes to the shared attribute.

public class Kettle extends BaseModel
{
  @SharedAttribute(resolution = 1.0, accuracy = 1.0 )
  private float m_temperature;

  public float getTemperature()
  {
    return m_temperature;
  }

  public void setTemperature(final float temperature)
  {
    m_temperature = temperature;
  }
}

Instrumentation in whatever form it takes is fairly complex even if you use something like AspectJ that is perfect for this scenario. Much more complex than writing the equivalent acts_as_* plugin.

The above only works when the instrumentation code does not need to add any methods. However if you want a simulation object to support shared events you need to be able to subscribe, unsubscribe and generate these events which means you need the same boilerplate code repeated over and over.

I can not think of anyway to do this in java so I guess it is back to generating the Java classes from a central model file. Pity I think I liked the ruby way better.

Posted in  | Tags , , , , ,  | 2 comments | no trackbacks

Upload a file via POST with Net::HTTP

Posted by Peter Donald Thu, 02 Mar 2006 02:57:00 GMT

To upload a file to a website I needed to supply the data with a content type of “multipart/form-data”. The Net:HTTP API does not offer any such functionality, it just accepts raw content data. So I needed to roll my own.

The “multipart/form-data” content type consists of a number of secions separated by --BOUNDARY\r\n and terminated by BOUNDARY--\r\n where BOUNDARY is a string that does not appear in the content of any of the data transmitted to the server.

Each section represents a form field and contains a number of headers, a \r\n, the content and finishes with a \r\n. Normal form fields look like

Content-Disposition: form-data; name="mykey"

mydata

while file fields must include a few more headers.

Content-Disposition: form-data; name="mykey"; filename="filename"
Content-Transfer-Encoding: binary
Content-Type: text/plain

DATADATADATADATADATADATADATA...

To construct the parameters in ruby I use the following code;

def text_to_multipart(key,value)
  return "Content-Disposition: form-data; name=\"#{CGI::escape(key)}\"\r\n" + 
         "\r\n" + 
         "#{value}\r\n"
end

def file_to_multipart(key,filename,mime_type,content)
  return "Content-Disposition: form-data; name=\"#{CGI::escape(key)}\"; filename=\"#{filename}\"\r\n" +
         "Content-Transfer-Encoding: binary\r\n" +
         "Content-Type: #{mime_type}\r\n" + 
         "\r\n" + 
         "#{content}\r\n"
end

To put it all together you need to join the parameters with boundary separators between each section. This can be done via

boundary = '349832898984244898448024464570528145'
query = 
  params.collect {|p| '--' + boundary + "\r\n" + p}.join('') + "--" + boundary + "--\r\n"

The last thing that needs to be done is to make sure that you set the HTTP Header Content-type to multipart/form-data; boundary=BOUNDARY.

A complete example that I extracted from code that uploads a css file to the w3c validator service is as follows.

params = [ 
  file_to_multipart('file','file.css','text/css',data),
  text_to_multipart('warning','1'),
  text_to_multipart('profile','css2'),
  text_to_multipart('usermedium','all') ]

boundary = '349832898984244898448024464570528145'
query = 
  params.collect {|p| '--' + boundary + "\r\n" + p}.join('') + "--" + boundary + "--\r\n"

response = http.start('jigsaw.w3.org').
  post2("/css-validator/validator",
        query,
        "Content-type" => "multipart/form-data; boundary=" + boundary)

It was a little bit painful to figure out “multipart/form-data” via Ethereal but relatively easy to implement. Hope this helps!

Update 3rd of October, 2006:

Slight correction supplied by Andrew Willis so that last boundary is '--' + boundary + '--' rather than just boundary + '--'.

Posted in  | Tags ,  | no comments | no trackbacks

Removing Stale Rails Sessions

Posted by Peter Donald Wed, 01 Mar 2006 00:53:00 GMT

By default rails does not clear out stale sessions from the session store. To implement this feature I added the following small snippet of code;

class SessionCleaner
  def self.remove_stale_sessions
    CGI::Session::ActiveRecordStore::Session.
      destroy_all( ['updated_on <?', 20.minutes.ago] ) 
  end
end

And then invoke the remove_stale_sessions method every 10 minutes via;

*/10 * * * * ruby /full/path/to/script/runner 
   -e production "SessionCleaner.remove_stale_sessions"

Posted in  | Tags ,  | no comments | no trackbacks

Flexible Application Configuration in Rails

Posted by Peter Donald Tue, 28 Feb 2006 10:37:00 GMT

Most of my rails application have required some form of application specific configuration. When the configuration varies depending on where I deploy it I prefer to externalize the configuration in a YAML file similar to the way database configuration is handled.

I remember reading a blog somewhere that suggested the use of OpenStruct and have since started using the following code placed at the bottom of my config/environment.rb file.

require 'ostruct'
require 'yaml'

ConfigFile = "#{RAILS_ROOT}/config/config.yml"
if File.exist?(ConfigFile)
 ::ApplicationConfig = OpenStruct.new(YAML.load_file(ConfigFile))
end

Consider the scenario where config/config.yml contains;

proxy_config:
  host: proxy.cs.latrobe.edu.au
  port: 8080

I could then access the the configuration data using

>> ApplicationConfig.proxy_config['host'] 
=> "proxy.cs.latrobe.edu.au"
>> ApplicationConfig.proxy_config['port']
=> 8080

To make your code more robust in the scenario where either the proxy configuration is missing or the whole configuration file is missing I generally add in extra guards. Below is an example of the code I use to instantiate a Net:HTTP object. If the configuration file is present and it contains a proxy_config section then the code will attempt to instantiate a Net::HTTP::Proxy object. Otherwise the code will instantiate a plain old Net::HTTP that will not attempt to go via a proxy server.

def http
  if Module.constants.include?("ApplicationConfig") && 
      ApplicationConfig.respond_to?(:proxy_config)
    host = ApplicationConfig.proxy_config['host']
    port = ApplicationConfig.proxy_config['port']
    Net::HTTP::Proxy(host, port)
  else
    Net::HTTP
  end
end

Posted in  | Tags , ,  | no comments | no trackbacks

Returning to Java

Posted by Peter Donald Tue, 17 Jan 2006 23:07:00 GMT

Over the last year I have wandered away from the Java programming language and experimented with different languages. Over the last six months I have had little contact with java programming except for occasionally helping out a student. However most of my time has been spent reading, teaching and programming in other languages such as Ruby (via Ruby On Rails), Prolog, Erlang and a dash of eLisp and Scheme.

I have just returned to working with Java and I find it lacking. Some of the features that java lacks do not really fit with Javas philosophy such as “open” classes. Why java does not support the richness of rubys collection classes is beyond me.

Open Classes

Ruby has the ability to re-open classes and add, remove and rename methods that have already been defined. At times this has been a lifesaver as I could re-open a class that was defined by a framework and fix bugs without having to keep a separate branch for all my dependencies.

This feature also allowed me to ensure that my code worked across different versions of libraries. For example the Struct class differs betweem Ruby 1.8.2 and Ruby 1.8.3 in the way that it handles symbols with ’?’ but I was able to re-open the class and make the behaviour consistent. I have also been able to fix many rails variations and bugs between versions so that my code would work out of the box.

I don’t think this is a feature that Java or any statically typed language should support but it is useful none the less.

Collection Classes

Ruby also has an amazingly nice set of collection classes. While it is true that the classes may include a lot of cruft, I really like the four search methods defined in Enumerable ; select/find_all, detect/find, reject, and collect/map. (select is aliased to find_all or vice versa as is detect and find, and collect and map). I believe they were originally derived from Smalltalks collection classes and it is a pity they did not find their way into java.

Consider doing something like iterating through a unordered list of 3D vertexes and any in front of the plane are placed in a new list but transformed via a matrix associated with the plane.

results = my_vertexes.select {|v| v.in_front?(my_plane) }.
     collect {|v| v.transform(my_matrix)}

While the equivelent java code is something like

LinkedList<Vertex> tempList = new LinkedList<Vertex>()
for( Vertex v : myVertexes )
{
  if( v.isInFront(myPlane) )
  {
    tempList.add( v );
  }
}
LinkedList<Vertex> results = new LinkedList<Vertex>()
for( Vertex v : tempList )
{
    tempList.add( v.transform(myMatrix) );
}

I suspect that both code snippets could be improved but they are only meant to demonstrate a point. Namely that ruby code tends to support the common case with a far shorter syntax and IMHO smaller cognitive load than equivelent code in java. My guess is that java would make it much easier to optimize the code for speed but that is rarely the most important feature of software.

Conclusion

While I am remembering that there is things I miss about java there is also things that I wish java had. I am finding it difficult to live without rubys “blocks” but still looking forward to hacking on java again.

Posted in  | Tags , ,  | no comments | no trackbacks