| |
Jostraca generates code by creating small external programs that
produce the actual output. This makes Jostraca different from most
other code generation tools, which tend to rely on special template
languages. Instead, Jostraca is designed with the philosophy that
template scripting should be done in an ordinary programming language
that the developer is already familiar with.
To enable this approach, Jostraca has to compile the template into a
small program in the template scripting language. In effect, all
Jostraca does is turn the template into a big list of print
statements. While this has the advantage of using a familiar language
for template scripting, the downside is that the external program has
to be compiled and executed by Jostraca.
The process of turning a template into generated code proceeds as follows:
- Find and load the template file
-
Templates can specified as file paths, or referenced as library
templates (the setting
main.TemplatePath specifies the
list of folders to search for library templates).
Once the initial template file is loaded, the contents of the file are searched for a @conf
directive (which is required), and any @include directives are resolved.
Any settings in any @conf sections found are stored and assigned to the template. Template level
settings override system settings, but are in turn overridden by command line options.
- Determine template script
-
The programming language used for template scripting is determined by
the
main.TemplateScript setting. This is usually placed
in the template @conf directive (the default is
java). Once the template script is determined, the script
specific settings are loaded from the conf folder. For
example, Perl specific settings are in
conf/perl.conf. The script specific settings determine
the exact processing operations that will then be performed on the
template.
- Process template
-
The template is then processed by passing through a number of discrete
steps. These steps are script language specific. The main ones are covered in the following items.
- Prepare template
- This processing step performs any special processing related to system properties and version compatibility.
- Parse template
- The hard work. The template contents are parsed into an internal data structure.
- Merge template into WriterFormat
-
This is where the source code of the
CodeWriter program
is created. Jostraca uses special templates located in the
format folder to specify the source code of the
CodeWriter program. These CodeWriter
templates are known as WriterFormats. The
WriterFormat for the current template is specified by the
main.CodeWriterFormat setting. Normally this is specified
by the default configuration, but custom WriterFormats
can be also be used. The WriterFormat templates use a
special syntax and are independent from standard Jostraca templates.
The template content is merged into the WriterFormat template by
inserting template sections into marked positions in the
WriterFormat. Of course, the actual source code (that big
list of print statements) that is inserted is created by Jostraca
before insertion.
- Save template CodeWriter and other files
-
Once the
CodeWriter program is created, the source text
of the CodeWriter is saved to disk so that is can be
compiled and executed. Other files may also be saved, such as template
metadata properties files.
- Compile CodeWriter program
-
Jostraca now attempts to compile the
CodeWriter
program. This is only necessary for compiled languages. If the
template script is Perl, for example, this stage is not present. For
languages other than Java, compilation involves running the compiler
program externally as a separate process. This of course can lead to
many types of error as the external compiler may have many types of
dependency. In general, you should ensure that the Jostraca execution
environment is also suitable for running the compiler. You can use the
-v option to get verbose output from Jostraca. This
output also shows the exact command used to execute the external
compiler, which can be very useful for debugging. You can also use the
main.ExternalCompilerOptions and
main.ExternalCompiler settings to control this command.
Note that in order to execute external compiler commands, the folders
containing the external compiler programs should be in your
PATH environment variable.
For Java, the are two ways of compiling the
CodeWriter. Normally, Jostraca attempts to compile a Java
CodeWriter by running the Sun compiler inside the Java
process. This means that you need to put the rt.jar jar
file from the Java JDK into your CLASSPATH. This option
is usually much faster that running javac externally. If
compilation is done internally, then you also need to ensure that the
CLASSPATH used to run Jostraca includes all the classes
that your template references. The standard jostraca execution scripts
( jostraca.bat and jostraca.sh ) include the
contents of the CLASSPATH environment variable in the
Jostraca classpath, so normally all you need to do to use
additional classes in your template is to put them in your normal
CLASSPATH. You can also construct your own jostraca
execution scripts as a special case. When running Jostraca from Ant,
this is not necessary as you can define the classpath used in the
build.xml file.
If the Sun compiler cannot
be found (because rt.jar is not in your
CLASSPATH), then Jostraca will use javac to
compile the CodeWriter. The classpath used in this case
also includes the contents of the CLASSPATH environment
variable, but you can also use java.ClassPath,
java.ClassPathPrefix, and
java.ClassPathSuffix to control this classpath. Again,
use the -v option to see the full javac
command if your CodeWriter does not compile due to
ClassNotFound errors.
- Execute CodeWriter to generate code
-
This stage, finally, is where your template (that is, the
CodeWriter created from the template) is executed to
actually produce output. This stage is similar to the compilation
stage, in that for many template script languages such as Perl or
Python, an external command must be executed to run the
CodeWriter. Once again, you can use the -v
option to see the actual execution command.
For Java, the same issues (in particular, the
CLASSPATH issues) apply as for compilation. In the
normal case, Jostraca will attempt to dynamically load the
CodeWriter class and execute it within the Jostraca
process. If you wish to execute the CodeWriter externally as a
separate process, then you you have to specify the setting:
main.process.Controller = org.jostraca.process.ExternalJavaController
Jython templates are special case. Since Jython runs under the JVM, the location of the
Jython installation folder must be specified manually, so that the Jython libraries can be found.
Thus, Jython templates require the jython.home setting to be present and set to the
absolute folder path of the Jython installation. This setting can be placed in the template
@conf section, or specified on the command line:
jostraca -Djython.home=JYTHON_HOME jython-template.jtm
Jython CodeWriters are normally executed internally using the PythonInterpreter class.
To execute the CodeWriter externally using the jython execution script, use the setting
main.process.Controller = org.jostraca.process.ExternalJythonController
The standard CodeWriter for all languages also performs
some actions when creating the output files. First, any output files
that already exist are backed up to a .jostraca folder in
the current folder. You can stop this backup action by using the
-B command line option. The CodeWriter also outputs the
names of any files that are created. This information is used by
Jostraca to create the metadata properties file. Note that if you
prevent the creation of the metadata properties file (using
-M for example), then the template service method
_getProperty will not return any values.
Controlling the CodeWriter
Jostraca attempts to do the least amount of work necessary to create the generated output files.
In the default case, Jostraca will use previously saved template metadata to compare the modification times
of the output files and the template to see if generation is actually necessary. If not, the CodeWriter is not
compiled or executed and Jostraca exits. Jostraca also checks to see if CodeWriter compilation is necessary,
and if not, will only execute the existing CodeWriter. This case occurs when resource files specified
on the command line as template arguments have changed, but the template itself has not changed.
To see how Jostraca determines the required actions, use the -v command line option.
Sometimes you will need to force Jostraca to perform certain operations. The command line options controlling CodeWriter compilation are -c: always compile CodeWriter, and -C: do not compile CodeWriter.
You may need to force recompilation if the file modification times are out of synchronisation.
You can also control whether Jostraca executes the CodeWriter. You may not always actually want the CodeWriter to
run directly. In the case where you are creating the CodeWriter from the template, so that you can use it later in your
own programs, all you want to do is compile the CodeWriter program, but not execute it. You can use the
-G option to prevent Jostraca from executing the CodeWriter. Conversely, -g will
force Jostraca to execute the CodeWriter.
Generating Multiple Templates
You can generate more than one template at a time using Jostraca. You
can specify a list of templates on the command line. For example:
jostraca foo.jtm bar.jtm baz.jtm resources.xml
All arguments to Jostraca that end in .jtm are assumed to be
templates. You can also use the -l option to force
Jostraca to consider all arguments to be template files. If you have a
long list of templates, you can put them in a file, one per line, and
reference the file using the -t command line option. When
using Jostraca from Ant, multiple templates can be specified using the
templateList attribute, or by inserting multiple
template sub-elements.
When generating multiple templates, all resource files (that is,
non-template files, like resources.xml in the example above) that are
specified on the command line are assumed to apply to all
templates. This can cause all templates to be regenerated when file
modification times are changed.
When generating multiple templates, Jostraca processes the template by performing each processing stage on all
templates in turn. That means that all templates are first parsed, and then all CodeWriters are created,
and so on. This approach is taken so that the CodeWriters can all be compiled together in one compilation phase,
which greatly speeds up code generation.
|