The Framework

Understanding the underlying Arooa framework.

Introduction

The underlying creation and configuration of jobs is code based mainly on code plagerised from the Ant project. It provides a stand alone framework independant of Oddjob. In acknowlegement of it's beginning the framework is called Arooa - A Rip Off Of Ant.

Components

Arooa, like many application frameworks, uses the idea of a component. There are many definitions of a component, but in Arooa it is simply something which can be dynamically created and added to other components. In Arooa a component is any java.lang.Object with a no argument constructor.

Here is a really simple component.

	  package org.oddjob.devguide;
		
	  public class FirstComponent {
	  }	

You can fire this up with oddjob using the following configuration:

  <oddjob>
    <anything class="learn.oddjob.FirstComponent"/>
  </oddjob>	

Because our component isn't Runnable, Oddjob isn't treating it as a job, so you get a boring icon and you can see some properties - but not much else.

Despite the fact that Oddjob has very little interst in our component Arooa will configure it, initialise it and finally destroy it. The same lifecycle applies for Jobs, Services or plain old Java Objects.

The Lifecycle of a component.

Lets see what the Arooa framework does with your job as it reads the configuration:

At parse time:

  1. The component is created using a no argument constructor either from a class name given as the class attribute or by looking up the tag name the ComponentFactory.

  2. If the configuration element contains an id attribute the component is registered so that it's properties can be gotten at later with the ${} replacement syntax.

  3. If the component has a setContext(ArooaXMLContext context) method it will be called with the context used during parsing. Amongs other things the context contians your components very own RuntimeConfigurable object. This allows your component to configure itself. The framework will configure the component for you so unless you want very special you don't need to implement this method.

  4. constant properties (those which don't contain ${} replacement syntax) are set via the components setXXX().

  5. Child elements are created via the component's createXXX() methods or instantiated and added to the component via its addXXX() methods. This functionality inherited straight from ant but it is preferable to use the stanadard setters as it makes your job more transportable between POJO frameworks.

  6. Child components are added via this components addComponentXXX() or addComponent() method.

  7. init() is called, if it exists.

At run time:

  1. Any element text is set via the addText() method. No ${} substitution takes place for text at them moment but this might change.

  2. Dynamic properties are set. The ${ } values are resolved and the resulting object is set via the setXXX() method in the component and all child elements and values.

  3. Properties declared as elements are resolved and set using the components setXXX(YourType value) or setXXX(String name, YourType value) method.

  4. Remaining child elements are set with the addConfiguredXXX() method. Again this method is inherited from ant, but a using a setter would be the preferred option.

At termination:

  1. If the component has a destroy() method it is called.

Changing the Lifecycle

Your own component can change the default configuration for all it's child elements by implementing a method with the signature ArooaHandler handlerFor(ArooaXMLContext context). The handler you provide will get direct access to the underlying XML configuration.

Alternatively providing a method with the signature ArooaHandler handlerForXXX(ArooaXMLContext context) will receive configuration information for just you components XXX element.

As an example, the ForEach job provides it's own hander which records the child job definition so that it can be used to create a new child job for each of it's values later, when it is executed.

Properties in Detail

A nested property allows complicated types to set using a setXXX(SomeType value) or setXXX(String name, SomeType value).

As an example - here's the code for a simple component with a slightly complicated property.

		
package org.oddjob.devguide;

public class ShoppingComponent {

	private String[] shopping;

	public void setShopping(String[] shopping) {
		this.shopping = shopping;
	}

	public String[] getShopping() {
		return shopping;
	}
}

And this would configure the ShoppingComponent:

  <oddjob>
    <anything class="learn.oddjob.ShoppingComponent">
      <shopping>
        <value value="beer"/>
        <value value="wine"/>
        <value value="piza"/>
      </shopping>
    </anything>
  </oddjob>

Oddjob has a list of types and the Objects to create to interpret the XML. These are known as p roperty proxies. For String[] it creates a ListType which takes care of the shopping element.

The ListType uses a factory to create a value type to populate the list. For the element value, it creates a ValueType object.

The value type can be any object but it can optionally also supply a Object valueFor(Class requested) method which will be used to perform conversions. This allows a ValueType to be both a java.lang.String property as in the above example, and a java.io.InputStream used in, for instance, a copy job.

These objects that provide the 'values' for properties and are of a 'type' have loosly been termed 'value types'. Not to be confused with ValueType.java which is a paticular instance of a 'value type'.

Arooa creates the value types either because the type is defined as property proxy based on the Class of a setter, or by creating the type from a factory definition. The Arooa framweork is then using the valueFor() method, if it exists before setting the property.

This is admittadly quite confusing, but does allow jobs to be written without knowledge of the types that will configure them and does allow for elegant xml. Given this - confusion is a small price to pay.

Once you understand the difference between a 'value type' and a 'property proxy' defining your own is easy. Take a look at examples/devguide/shopping2.xml followed by examples/devguide/shop-oj.xml and examples/devguide/shopping3.xml for examples. One day we'll go through them here.

Property Conversions

When a property gets resolved using ${x.y.z} notation Oddjob uses BeanUtils to do this. It also uses the BeanUtils converters which enable string to be converted to number etc. Please see the BeanUtils documentation for more information.

XML to Java Object Summary

Which method gets called for which bit of XML is slightly confusing so here is a summary.

<comp1 stuff="thing"/>
<comp1>
	<moreStuff stuff="thing"/>
</comp1>

If your component has more than one of the above then which is called is undefined.

<comp1>
  <moreStuff>
    <stuff name="fred" stuff="thin"/>
  </moreStuff>
</comp1>

Index Top Next