Diagram of Deployers
Bob McWhirter
25 November 2008

Thanks to help from Ales, I've been able to really clean up and simplify the JBoss Rails deployers for Microcontainer.  When you use JBoss Microcontainer, you can easily break down your tasks into small, bite-sized chunks.  Because of that, we now have 7 deployers, but each only has a handful of lines.

First, the picture, then we'll walk through it.

Deployers

Of the many deployment stages MC walks through, the JBoss Rails deployment of web apps and schedulers requires only 3: Parse, Describe and Real.

Parsing

The RailsRootReferenceParsingDeployer is responsible for handling any file matching *-rails.yml in your appserver's deploy/ directory.  This is the small YAML file that points to your RAILS_ROOT on disk, injects the RAILS_ENV you wish to deploy in, and sets up the web context root.  This deployer handles the reference file, and emits a RailsMetaData object.

Once the RailsMetaData object is available, the RailsVersionDeployer is fired.  Since we require Rails itself to be in your app's vendor/ directory, we can dig around inside there to find Rails's version.rb, and figure out if we're running a version of at least 2.2.  If we're running 2.1 (non-threadsafe), we just have to change our deployment strategy for some bits.  When this deployer fires and reads the version.rb, it emits a RailsVersionMetaData object, which simply embodies the version number of Rails used by this app.

Meanwhile, unrelated to anything Rails-specific, the YamlScheduleParsingDeployer is on the lookout for any meta-data file named jboss-scheduler.yml.  The scheduler file handles cron tasks inside your app's code. Nothing about the scheduler is inherently Rails-centric, but it is Ruby-centric.  I anticipate being able to use the same deployer to handle schedulers in Merb, or Camping, or any other ruby framework.

The output from parsing a jboss-scheduler.yml is a ScheduleMetaData object.

Describing

While the above-mentioned scheduler stuff is framework-agnostic, it still needs some help from whichever framework it's deployed in.  The ScheduleMetaData contains information such as the name of the Ruby class to instantiate to perform the scheduled job.  It needs some additional information, such as where to look for these classes.  It's also helpful if the scheduler knows the thread-safeness of the framework it's associated it.

So the RailsScheduleDescribeDeployer is hanging around, looking at metadata flow by.  If there's a RailsMetaData, and a RailsVersionMetaData, and a ScheduleMetaData object available in this deloyment, then it'll step in.

By convention, JBoss Rails assumes that scheduled task classes are in the files under $RAILS_ROOT/app/scheduler/.  We also know if Rails is threadsafe or not based upon the version being used.

So the RailsScheduleDescribeDeployer looks at the Rails-specific metadata flowing in, and adjusts the existing Rails-agnostic ScheduleMetaData by adding $RAILS_ROOT/app/scheduler/ to the Ruby load path and setting the thread-safety flag.

Note: This may be better suited as a Post-Parsing stage deployer.  I'm not sure yet.

Real Deployment

The real stage is where the rubber meets the road.  All of this MetaData that's floating around gets converted into instances of BeanMetaData.  Microcontainer's own BeanMetaDataDeployer consumes those, and will instantiate and start() our actual POJOs.  The BeanMetaData simply describes your POJO's Java class name, constructor arguments, properties to set or inject with other POJOs, annotations to apply, and runtime methods (such as start() and stop()) that should be called.

The RailsRuntimeFactoryDeployer sees the RailsMetaData, and creates a BeanMetaData describing a factory to produce initialized JRuby runtimes for your Rails app.  It assigns a predictable name so that other POJOs can find it if they need it.  Other frameworks will be able to deploy factories that are capable of initializing JRuby runtimes for their environments.

The RailsWebDeployer sees the RailsMetaData, and creates a BeanMetaData describing an object that can setup and remove a Tomcat web context for your Rails app.

The ScheduleDeployer creates a BeanMetaData describing object that can add and remove scheduled tasks from the Quartz scheduler embedded in AS5.  This deployer creates BeanMetaDatas that inject the runtime factory described by the RailsRuntimeFactoryDeployer.

All of these BeanMetaData instances then float on by, are grabbed by MC's own BeanMetaDataDeployer.  My classes are instantiated, properties are set, start() is called, and we find ourselves deployed. My deployers also add object-instance JMX annotations to the BeanMetaData objects.  This causes my POJOs to get registered in the MBeanServer and to appear in the JMX console.  Pretty slick.

Conclusion

Overall, I really like Microcontainer's deployment framework.  I don't always completely understand it, and I routinely overlook classes that will do 80% of the work for me.   It's been a long road, but breaking 1 deployer into 7 has simplified everything, honestly.  The chunks are smaller, and more importantly, they are reusable.  I did not want to have to write scheduler logic for each Ruby framework I attack.  MC's multi-stage metadata-driven deployment process really helps.

  • Next Structure prevents chaos
  • Previous Overview Presentation
Copyright 2008-2010 Red Hat, Inc.