JeeWiz Home  
The Model-Driven System Builder

JeeWiz Architect's Guide
 
Contents  >   2.  Overview
 


2.8 Name Management

Most companies have development standards that cover the naming of variables and classes in programs, the names of files, the structure and naming of directories.

Generation systems typically build naming conventions directly into the renderings. For example, an EJB component needs a number of related names, such as the names of the various interfaces and the implementation class. If we write Velocity script in this way, we are fixing the naming convention. For example:
public abstract class ${name}BeanImpl extends ${name}Bean {
This script fixes the implementation class as '${name}BeanImpl' and the bean class as '${name}Bean'.

In the large-scale renderings we use in JeeWiz, this makes it tedious to change the naming convention. This is not just an issue for the development team. It also makes it difficult to incorporate the rendering in an existing environment: a customer will have to create a specialised version of the templates, and this will make it difficult to provide centralised maintenance of the templates. The larger and more valuable the renderings, the more impractical a fixed naming convention becomes.

To fix this, JeeWiz allows the rendering to define logical names for things to be produced and map them to the actual string to be used. Changing the naming convention is then simply a matter of changing the mapping - in one place.

This is done in the 'component.properties' file. For example, we could define the logical names of the bean and the implementation class in the component.properties file as follows:
ejbName=${name}Bean
ejbImplName=${name}BeanImpl
This allows us to write the code using logical names:
public abstract class ${ejbImplName} extends ${ejbName} {

 2.8.1  Logical Names Attach To Model Objects
 2.8.2  References in Names and Values
 2.8.3  Declaration Order
 2.8.4  Aggregation
 2.8.5  Inheritance And Delegation

2.8.1  Logical Names Attach To Model Objects
Logical names are attached to model objects. This makes sense: 'ejbName' makes sense for J2EE business objects, but not for an attribute or an application.

The name/value mapping is created as an extra property (placed in the properties HashMap). In other words, the logical names don't have to be defined as properties in the meta-model. This means that the rendering can define logical names without changing the meta-model.

The evaluation of the component.properties happens before almost all of the patterns and templates are processed. However, there is one opportunity - the preIncludeSpec.vm pattern - that is processed even before component.properties is evaluated. This means that properties referenced in component.properties can be set by the preIncludeSpec.vm if necessary. This typically happens if there is a null value or reserved word that needs to be altered before further processing.

All other patterns and templates can use the logical name. If the model object is the context for Velocity, the value can be referenced just by using the logical name - '${ejbImplName}'. Otherwise, a Velocity variable referencing the model object can be used: '${entity.ejbImplName}'. In other words, this is just the same as any other property reference.
2.8.2  References in Names and Values
In common with Java properties files, JeeWiz component.properties files have a number of lines of the form
logical_name = value
The right-hand-side of the line can use literals, pre-existing names, values in the object or its parent tree, or more complex methods exposed as properties (via getters) on the object itself.

We have already shown how substitutions can references to other values, which are evaluated in the context of the current model object. This uses Velocity conventions, so that a getter is used if one exists on the meta-class, otherwise the extra properties HashMap is searched.

As well as a single-word reference, one level of dereference is allowed in values, such as '${parent.name}'.

The logical_name is usually a simple Velocity name. This will then allow the property to be referenced from Velocity scripts using ${logical_name} - i.e., without qualification.

The logical_name can also be a qualified reference such as
association.entity=relation
This uses a HashMap for the 'association' logical name in the extra properties. This is created automatically the first time a qualified reference uses the logical name. JeeWiz then evaluates the right hand side - in this case, 'relation', and puts the value in using the 'entity' key. The value can then be retrieved later using '${association.entity}' to get the type of association used between any meta-class.

HashMaps like this are useful for configuring logical names and configurable mappings.
2.8.3  Declaration Order
Declaration order is observed in component.properties. This means that references to properties set in previous lines of the same component.properties file are specifically allowed and will be evaluated as expected. (This is worth stating because Java property files work differently: the lines are processed in a random order.) Because order is observed, you can set a property based on some calculation, and then later on use that value in another property-setting calculation. For example, the J2EE 'ejb' component.properties file uses this sequence:
ejbDepends=${buildDir}/EJBdepends
markerFile=${ejbDepends}/${name}_depends.txt
In this example, the use of ejbDepends in the second line depends on its being set beforehand - this is why order is important. There are many such interdependencies in the complete set of properties for a meta-class.
2.8.4  Aggregation
In the description on rendering inheritance, we described how
  • some files - the system.properties and Velocity macros - are aggregated across a range of applicable files
  • per-meta-class files are searched for down the rendering inheritance chain and then down the meta-class inheritance chain.
The component.properties feature combines these techniques. In other words, rather than finding the first file and using that, the component.properties feature walks all meta-class types, following the template.properties 'include=' and 'goto=' lines, and within that searches down the meta-model stack for component.properties files. Following this approach, the complete list of component.properties files used for an entity is the component.properties files from the following meta-model and meta-model types:

j2ee ejb-entity
j2ee ejb
bizobject entity
bizobject business-object
bizobject internal-class
object jwclass
object interface
The algorithm for aggregating the various lines of the component.properties is to construct a list of model object properties to be set starting with the least precedent (e.g. the object/interface component.properties above) and proceeding up the list to the top-most component.properties file. This approach allows the higher-level component.properties to build on the calculations and settings of the lower-level.

There is a slight wrinkle here. What if we want to override a logical name, but it is used in other calculations? If the above order were followed exactly, we would then have to copy all the settings of logical names that depend on the overridden name. The wrinkle is that, if a property in one component.properties has previously appeared in another component.properties, the new setting is not added at the end: instead, the original property's value expression is replaced.

This aggregate list of logical name/value expressions, incorporating the override wrinkle, is gathered once (unevaluated) on the first use. Then, the unevaluated list is used to calculate and set the appropriate values for each model object of the same type.

This approach means that the model object has all the properties required by all the levels of rendering that may be required, but it also means that individual logical names can be overridden without knowledge of the calculations made by the lower levels. This means that dependent sequences of logical names in lower levels can be changed and reshipped, even when a customer has overridden some of the logical names in the sequece.

For example, the first three lines in the object/interface component.properties (in resources/java/control/interface) - and therefore the first three properties evaluated for an entity model object - are
classNameToGenerate=${name}
targetDir=${genSourceDir}
outputFilePath=${targetDir}${packagePathPlusSlash}/${classNameToGenerate}.java
However, the classNameToGenerate is overridden by the bizobject/internal-class with
classNameToGenerate=${name}Base
This overrides the value to be calculated for classNameToGenerate - but does not affect the order of evaluation. This overriding therefore means the final evaluation starts off like this:
classNameToGenerate=${name}Base
targetDir=${genSourceDir}
outputFilePath=${targetDir}${packagePathPlusSlash}/${classNameToGenerate}.java
The overriding of the classNameToGenerate alters the final 'outputFilePath' value - but not the calculation performed.
2.8.5  Inheritance And Delegation
Other features that can be used in component.properties of JeeWiz are:
  • definition of directory structures and filenames (in addition to the examples of variable and class names given above)
  • use of properties defined in meta-classes higher in the model object tree (either those defined in the meta-model, or in component.properties)
  • the ability to use the same logical name as a parent, but with a different value on the current model object, which is a consequence of each model object having a different set of properties. This is particularly useful in defining recursive nesting of directory structures (e.g. see component.properties file in resources/base/control/jar_assembly/).
There are limitations to the power of the component.properties feature: conditional logic (if/else) is not possible. In cases where more powerful control of names is required, the preIncludeSpec.vm pattern must be used. This give unrestricted calculation capabilities.  


Copyright (c) 2001-2008 New Technology/enterprise Ltd.