Tuesday, March 10, 2009

Generating Strongly-Typed Properties Classes With openArchitectureWare, Part 3: Checks, Workflow, and a Template

Last time I created a sample model using the Properties metamodel that I built in the first post of this series. Now I'm going to put it all together and actually generate something with openArchitectureWare -- not Java code just yet, but rather, a sample .properties file which can be customized and loaded using the Java code that I'll create in the next entry.

Checks
openArchitectureWare provides Check constraints for validating models. For the Properties scheme that I have designed, it makes sense to require models to conform to three constraints:
  1. PropertySet must have a name. I will use this to generate the Java class name.
  2. PropertySet must have a resource name. This will tell me what file to load at runtime.
  3. Properties must have a name. This one is pretty obvious.
Here is how to encode these rules in the Check language (file Checks.chk):
import Properties;

context properties::PropertySet ERROR "PropertySet must have a name" :
Name != null && Name.length > 0;

context properties::PropertySet ERROR "PropertySet must have a resource name" :
ResourceName != null && ResourceName.length > 0;


context properties::Property ERROR "Properties must have a name" : Name != null && Name.length > 0;
The "import" line pulls in the Properties metamodel. Marking these constraints as "ERROR" stops oAW processing with the specified message when such a condition is encountered. The rest of the code is pretty intuitive. Later, when I talk about oAW Workflows, you'll see how this gets wired into the generation process.

Simple Template
It's time to write an oAW template to generate a sample .properties file. This is done with the oAW Xpand language, whose most visible feature is the cute little «chevrons» that mark off the directives. I won't attempt to detail the features of Xpand, but rather point you to the documentation. Suffice to say that it's very easy to get started. Here is a template (PropertiesFileTemplate.xpt) that generates a .properties file from a model:
«IMPORT metamodel»

«DEFINE propertiesFile FOR properties::PropertySet»
«FILE ResourceName + ".SAMPLE"»
«EXPAND property FOREACH Properties-»
«ENDFILE»
«ENDDEFINE»

«DEFINE property FOR properties::Property»
«Name» = «DefaultValue-»
«ENDDEFINE»
When I finally run this in the next section, it will generate a file in .properties format with each property in the model. The file is named based on the value of the ResourceName attribute of the PropertySet. It is suffixed with ".SAMPLE" because presumably it would be customized in a real application. In my next post, I'll use Xpand to achieve the ultimate goal of this project, namely, to generate some Java code to load and wrap these properties. First, though, I need to tie everything together so that the oAW generator can run.

Workflow
"Workflows" are essentially build scripts for openArchitectureWare-based artifacts. They generally end with an extention of ".oaw", and they can be launched directly from Eclipse in an openArchitectureWare project using a "Run As | openArchitectureWare Workflow" context menu item. There are a handful of things that you can do in a workflow, but in my experience, they tend to be pretty boilerplate. Here is one (generator.oaw) that runs Checks and invokes the generator on the PropertiesFileTemplate for our model:
<?xml version="1.0"?>
<workflow>
 <property name="model" value="PropertiesGenerator/src/SamplePropertySet.xmi" />
 <property name="src-gen" value="src-gen" />
 
 <!-- set up EMF for standalone execution -->
 <bean class="org.eclipse.mwe.emf.StandaloneSetup" >
  <platformUri value=".."/>
 </bean>

 <!-- load model and store it in slot 'model' -->
 <component class="org.eclipse.mwe.emf.Reader">
  <uri value="platform:/resource/${model}" />
  <modelSlot value="model" />
 </component>

 <!-- check model -->
 <component class="oaw.check.CheckComponent">
  <metaModel id="mm"
   class="org.eclipse.m2t.type.emf.EmfRegistryMetaModel"/>
  <checkFile value="metamodel::Checks" />
  <emfAllChildrenSlot value="model" />
 </component>

 <!--  generate sample .properties file -->
 <component class="org.openarchitectureware.xpand2.Generator">
  <metaModel idRef="mm"/>
  <expand
   value="template::PropertiesFileTemplate::propertiesFile FOR model" />
  <outlet path="." />
 </component>
</workflow>
In a more serious implementation, the execution of the .oaw file would be integrated in an Ant build using oAW's custom Ant task. For this project, I'll just use the oAW Eclipse runner.

The model to work with is declared as a property at the top of the file. The key sections are the last two -- "check model" and "generate sample .properties file". The only potentially-tricky part is getting the package references right. So here is a snapshot of my project for you to compare to:



Now I actually have a working code generation pipeline set up. To conclude in my next post, I'll write a slightly more sophisticated template to generate Java code, and maybe talk a little bit about code generation philosophy.

No comments: