7.4 Finding Files in Template Directories
In processing a build, JeeWiz must find a number of files - the build files, the component.properties, and any files referred to in the build files. The main section describes the techniques JeeWiz uses to do this.
JeeWiz provides a wealth of features for finding build files, which can create long search chains. To reduce search times, the results of all searches (files found or not found) are cached, so the search process is only executed once for a given template name/meta-class combination. This means that you should not let the length of the search path for template files deter you from using stacked meta-model directories. In practice, the length of this search chain does not make an appreciable difference in normal use of 10-30 directories in the chain.JeeWiz has a special loader that follows the template directory chain to find these files. The template directory chain starts with the templateDir property you specify in the build properties *.jwp file and then follows the parent model properties chain.
Within each model, the file must be looked for against a particular meta-class, so we use a template directory name based on the xml-style name of the object type - like 'application' or 'ejb-jar' - below the model's control directory. The full path search for therefore is
For example, say we are processing an 'application' object in a WebLogic6 build. If we look for the build.xml file, the paths searched will be
jeewiz/resources/weblogic6/control/application/build.xml jeewiz/resources/j2ee/control/application/build.xmland the file is found in the j2ee model - it produces the standard 'application.xml' required by J2EE.
In describing this search path,
It is obvious how this can be done for a single application server - you just create your own 'overriding' model by creating its control directory and in the 'model.properties' define the parent= property to be the single application server's model (as in its control directory).
But how can you provide a local project's override for many application servers without duplicating a lot of scripts? This will be necessary if you are using a combination of application servers, e.g. JBoss on the desktop and WebLogic for deployment.
The answer is to
(To emphasise: the 'template' property affects the script search path for both templates and patterns. This is a historical name.)
Remember (from the previous section) the search for a given file is defined by
If we specify a template, then this changes to
In other words, the rendering is not defined by the meta-class - the directory underneath the control directory is defined by the 'template' property. For example, if we have
For example, implementation classes in the business object model have a specialised rendering. Therefore, there is a template directory called 'impl-class' in the /bizobject control directory, which holds the templates for the rendering. This is accessed by putting a 'template="impl-class"' on the object.
Note that meta-classes with a 'template' property do not by default inherit the rendering from the meta-class - there may be good reasons to completely divorce the new rendering from it. Of course, it is possible to inherit the rendering, simply by adding a template.properties file with a 'goto' line giving the name of the underlying object.
There are two types of lines you can specify in the template.properties file:
As a hypothetical example, say our stack of models is
Note that the generator effectively restarts the search so the 'myCompany' model is revisited to start the search. This search process occurs for the file 'x.vm' and then is repeated for the file 'y.vm'.
It is possible to have many diversions (there is no limit) during the search for a given file. The 'goto' therefore gives you a way of doing controlled inheritance of templates: you define the search path chain along templates. This is in contrast to the way that Java inheritance works: if a Java object inherits from another object, the search for fields and methods always follows the inheritance order. Although the meta-classes underlying the specifications use Java inheritance, we do not automatically use the same inheritance for searching for templates.
[ You can also use Velocity's #include() feature, but this is less useful because it is a purely textual include: it doesn't do variable substitution. ]
As you would expect, the "filename" value in the #parse is searched for using the search procedures described in this section (i.e. both through template directories and rendering inheritance between meta-classes via template.properties).
#parse() allows you to break a script into parts, promoting modularity and also allowing ease of overriding.
An important facility is the ability to use "super" as the file to parse. With "super", JeeWiz looks from the current file and returns the file that was next in line to be found. In other words, the '#parse("super")' will find the file that would have been found if the current file was not present. This is a JeeWiz-specific extension to Velocity. Note that it means that "super" is a reserved name and shouldn't be used to name template and pattern files.
The 'super' facility is very useful for embellishing existing functionality and can be used in both patterns and templates. A customer-specific extension can add some functionality, then call the super method via '#parse("super")' to continue with the original functionality.
Normally, #parse() requires the target file to be present; a run-time exception results if it is not. However, when "super" is the target file, there does not need to be a 'next in line' file, because JeeWiz, in this special case only, will use a 0-length (empty) file. The effect is to create a no-operation: the #parse() does nothing. This is useful because it means that you can use #parse("super") in an override pattern without wondering whether there is a next-in-line file.
When writing patterns, it is highly advisable to start or end each pattern with #parse("super"), unless there is a good reason not to. When functionality is enhanced by adding further layers of patterns, a pattern without #parse("super") effectively hides any lower layers. When the pattern is first written, this may well be acceptable: the problem only appears later when functionality is added in a lower position in the search order.
For example, say you want to override the build.xml for a component, but then also do the original build.xml. In other words, the current build.xml is a strict addition to the existing build.xml.
To use this feature, the overriding build.xml would look like this:
Note that you can't say 'depends="super"', nice though that would be, because the special meaning for 'super' is implemented by the jwAnt task, whereas 'depends' on a target is done by the normal Ant, which does not know about JeeWiz's overriding feature.
You may want to pay attention to whether the 'super' file should be forced to exist. In the example above, we have show 'super' file not being required - because the 'required' flag on the jwAnt task is set to false. You can also force the super file to exist by setting the 'required' flag on the jwAnt task to true (or leaving it out - it is true by default). In this case, the build will fail if the super file does not exist. If you don't know (or don't care) if there is another build file, set 'required="false".
In large organisations, you might even want to go further than this, and define a standard set of models for company, project and personal overrides. A full WebLogic stack of models would them be
This is an optional use of overrides. There are also required overrides. If a model is marked as 'abstract', it is an indication that the model should not be rendered. Instead, it needs an overriding model to fill in the blanks. This makes sense: the J2EE model must be deployed into a specific application container.
Copyright (c) 2001-2008 New Technology/enterprise Ltd.