The GenTemplate
class extends AbstractGenTemplate
and provides a
number of sophisticated capabilities to ease the development of
well-structured GenTemplate implementations. These capabilities come
in three categories: Dependency Declaration,
Context Management and Generator Management. Many of the
individual features are controlled by definitions appearing in the
configure()
method, which should be overridden in GenTemplate
implementations.
The general form of the configure()
method is:
@Override
public void configure() {
define(builder);
define(builder);
...
}
There are various types of builders for use in the configure()
method, which are described in the following sections.
The GenTemplate
class itself is declared with a single type
parameter, <PrimaryType>
, which represents the type of object on
which this GenTemplate will is designed to operate. This is usually
the representation type of a model (e.g. ZenModel
for RAPID-ML
models, Swagger
for Swagger models, etc.). If a GenTemplate has a
primary source, that source must produce values that satisfy the
declared PrimaryType
.
Dependency Declaration
As described earlier, a GenTemplate declares various types of
dependencies, which are then satisfied using information from a
GenTarget file when the GenTemplate is executed. The GenTemplate
class provides builders for use in the configure
method that
generate these dependency declarations.
Primary Source
The PrimarySourceBuilder
class is used to declare a primary source
dependency for this GenTemplate. For example:
define(primarySource() //
ofType(ZenModelSource.class) //
withDescription("Your RAPID-ML model"));
The ofType()
method is overloaded to accept any of:
-
An object that implemtns the ISource
interface
-
The Class
object of a class that implements ISource
-
The fully qualified name of a class that implements ISource
The dependency information is always converted to the final form of a
fully qualified class name string. If you are using a custom source
type, you may not be able to use the first two options, since RepreZen API Studio
may not have access to your class or some of its dependencies.
The builder also supports required()
(default) and optional()
methods to indicate whether the dependency must be satisfied by a
GenTarget.
Named Source
The NamedSourceBuilder
works just like the PrimarySourceBuilder
,
but it attaches a name to the source.
define(namedSource().named("security") //
.ofType(FileSource.class) //
.withDescription("Security information"));
In the above example, the completely generic FileSource
source class
is used, but a case like this might warrant the creation of a more
specialized ISource
implementation so that the security file could
be parsed, validated, and presented in a more convenient form.
Parameter
The ParameterBuilder
class declares GenTemplate parameters to be
bound to values in the GenTarget file.
define(parameter().named("packageName") //
.withDescription( //
"The package name to be used in",
"the generated Java classes") //
.withDefault("*") //
.required());
As shown here, withDescription
can take mulitiple strings, which
will result in a multi-line comment in the generated GenTarget file.
The withDefault
method takes an arbitrary Object
, which will be
serialized as YAML into the GenTarget
file. When your value is not a
primitive scalar type, you may want to use withJsonDefault
instead.
This takes a JSON String argument and parses it into a JsonNode
value, which is then serialized into YAML in the GenTarget file. This
avoids the possibility of a lossy or incorrect representation in the
GenTarget file. You may safely use your own classes, as long as they
can be safely serialized and deserialized using the Jackson library.
Prerequisite
The PrerequisiteBuilder
class declares prerequisite GenTargets that
must be satisfied by this GenTarget.
define(prerequisite().named("xml") //
.on(XMLSchemaGentemplate.class) //
.description("Specify a gentarget that runs the XML Schema GenTemplate") //
.required());
The on()
method is overloaded to permit either a GenTemplate class
instance, a GenTemplate class, or a GenTemplate ID string. The latter
is what is actually stored in a GenTarget file. The former options can
be used as long as the indicated GenTemplate uses its fully qualified
class name as its ID value (which is the default implemented in
AbstractGenTarget
. As with source builders, use of a class name or
instance may make the GenTemplate unusable within RepreZen API Studio.
Context Management
The context object, of type GenTemplateContext
, is instantiated but
left mostly empty by the AbstractGenTemplate
class. The
GenTemplate
class fills out the context object with information that
is needed during execution, providing a one-stop location for all such
information.
All the dependencies declared by the GenTemplate are resolved to
actual values according to the GenTarget, and those values are
included in the information available from the context object.
The methods for accessing context information are:
public IGenTemplate getExecutingGenTemplate()
-
Returns the
GenTemplate instance that is currently executing.
public GenTarget getControllingGenTarget()
-
Returns the GenTarget
through which this GenTemplate is executing.
public ISource<?> getPrimarySource()
-
Returns the primary source
instance associated with this GenTarget execution.
public Map<String, Object> getGenTargetParameters()
-
Returns a map
associating GenTemplate parameter names to their values under the
current GenTarget.
public File getOutputDirectory()
-
Returns the output directory to
receive files generated by this GenTemplate.
public File getCurrentOutputFile()
-
When an output item is
executing, this returns the file to which the generated content will
be written.
public File resolveOutputPath(File path)
-
resolves a relative path
against the output directory.
public GenTemplateDependencies getDependencies()
-
Returns the
dependency information declared by the executing GenTemplate.
public Logger getLogger()
-
Returns the logger object attached to
this GenTemplate.
public GenTemplateTraces getTemplateTraces()
-
Provides access to
trace information from prerequisite GenTarget executions.
public GenTemplateTraceBuilder getTraceBuilder()
-
Provides various
methods by which a GenTemplate can add to the trace information
attached to this GenTarget execution.
public GenTemplateTrace getPrerequisiteTrace(String prerequisiteName)
-
Retrieves the trace information for one of this GenTemplates' declared
prerequisites.
Generator Management
The GenTemplate
class performs generation by executing individual
generators that are configured for the GenTemplate. Configuration is
done in the configure
method override, using builders designed for
generator configuration.
Generators come in four varieties.
Output Item
An output item is an instance of a class that implements the
IOutputItem
interface. This inteface has two type parameters:
PrimaryType
and ItemType
. We’ll discuss ItemType
in
Extract Output Item.
The PrimaryType
of an OutputItem
should match the PrimaryType
of
any GenTemplate
in which it is configured. Output item classes
should generally extend AbstractOutputItem
, or one of the
type-specific extensions of that class. (See [convenience-classes].)
The purpose of an output item is to create a single file at a specific
path relative to the GenTarget’s output directory. Its primary purpose
is to generate the content of this file; the GenTemplate
class will
take care of actually writing the file, as well as recording basic
trace information.
Important methods to override in an output item implementation are:
String generate(PrimaryType primaryValue, ItemType itemValue)
-
Create the content for this output item’s file. If null is returned,
no file is written.
File getOutputFile(PrimaryType primaryValue, ItemType itemValue)
-
Return the file to which this output item’s content should be
written. If the value is not null, it will be used instead of anything
specified in the output item’s configuration (via the
OutputItemBuilder.writing(String)
method, shown below).
Configure an output item using the OutputItemBuilder
, like this:
define(outputItem().named("main") //
.using(MainGenerator.class) //
.writing("${model.name}.html") //
.withDescription("Main output") //
.when("${model.status == \"live\""));
The using
method is overloaded to accept an instance of an output
item, a class that implemnts IOutputItem
, or the fully qualified
name of such a class. Use of class names or instances may cause the
GenTemplate to be unusable in RepreZen API Studio.
The writing
and when
methods take strings that use the MVEL syntax
to produce a String
or a boolean
value, respectively. See
MVEL Guide for
information about MVEL, and see MVEL Bindings for details of
variable bindings in effect when these strings are evaluated.
The writing
method defines a default file name for this output item;
the output item itself can override this default.
The when
method provides conditional output item execution; if the
condition evaluates to false
, the output item will be skipped.
An extract output item is just like an output item, but instead of
operating on an entire model, it operates on a single "item" extracted
from the model. This is where the ItemType
type parameter in the
IOutputItem
interface comes into play.
When an output item is configured, the GenTemplate
class examines
its bound types. If the types bound to PrimaryType
and ItemType
are the same type, the output item is treated as a whole-model output
item. Otherwise, it is treated as an extract output item.
Only specific types are allowed as the item type in an output item,
and the list of allowed types depends on the model type. See
Extract Item Types for currently supported types.
An extract output item is configured exactly the same way as a
whole-model output item. The GenTemplate
recognizes the difference
when it instantiates the output item and inspects its parameterized
types.
Static Resources
The GenTemplate
class can be configured to copy static resources
from your JAR file to the output folder as-is. You don’t need to
implement anything to use this feature; you just add definitions to
your configure
method body, using the StaticResourceBuilder
, as
in:
define(staticResource().copying("css").to("artifacts/css"));
The copying
argument may name a file or a directory, and can specify
a path. Likewise for the to
argument. Precise behavior depends on
these varations:
copying from a… |
to a… |
does this |
file |
nonexisting path |
creates a file at the to-path |
file |
existing file |
replaces the existing file |
file |
existing directory |
adds the file to the folder |
directory |
nonexisting path |
creates a directory at to-path and
recursively copies the from-directory contents there |
directory |
existing file |
operation fails |
directory |
existing directory |
recursively copies the
from-directory contents to the to-directory |
|
The from-path is interpreted relative to the root of the
class path entry (JAR file or file system directory) from which the
GenTarget class was loaded. It is not relative to the GenTarget
class’s location in that JAR file or directory.
|
|
If you have multiple static resource definitions in your configure
method body, the order may be important. For example, both might
create the same file with different contents, with the second
overwriting the first. Or consider this example:
define(staticResource().copying("a/b/c").to("x/y/z"));
define(staticResource().copying("d/e/f").to("x/y/z"));
Assume that the path x/y/z does not already exist in the output
folder, and that a/b/c names a file, while d/e/f names a
directory.
In the order shown above, the second definition will fail at runtime,
because the first will have created a file at /d/e/f . If the two
were reversed, they would succeed, but a/b/c would be copied to
d/e/f/c rather than d/e/f .
|
Dynamic Generator
A dynamic generator is essentially a free-form generator. You can do
whatever you want with it, creating as many or as few files as needed,
based on the input model (or completely ignore the input
model—really, you can do whatever you want! ).
Dynamic generators are useful when your needs are not well handled by
the other options.
Overriding GenTemplate.getGenerator()
Occasionally you may find that even dynamic generators don’t give you
quite the flexibility you need. For example, perhaps it’s important
that you instantiate your generator class once and reuse with
different inputs. The GenTemplate.Generator
class will always
instantiate a new generator each time it needs one, using that class’s
default constructor. Or perhaps your generator needs access to a
database connection, and there’s no good way to pass such a thing.
In these and other cases you might choose to create your own
implementation of IGenTemplate.Generator
and override
GenTemplate.getStaticGenerator()
to return an instance of it. Your
class could then do whatever is needed. If you defined your class as
an extension of GenTemplate.StaticGenerator<PrimaryType>
, you could
still make use of all the capabilities described above, by calling
super.generate
from your own generate
method.
Convenience Classes and Methods
A number of convenience classes are created to make it easier to
create GenTemplates by extending the GenTemplate
class. They are:
Convenience Class |
Equivalent To |
SwaggerGenTemplate
|
GenTemplate<Swagger>
|
SwaggerOutputItem
|
AbstractOutputItem<Swagger, Swagger>
|
SwaggerExtractOutputItem<ItemType>
|
AbstractOutputItem<Swagger, ItemType>
|
SwaggerDynamicGenerator
|
AbstractDynamicGenerator<Swagger>
|
- - - - - - - - -
|
OpenApi3GenTemplate
|
GenTemplate<OpenApi3>
|
OpenApi3OutputItem
|
AbstractOutputItem<OpenApi3, OpenApi3>
|
OpenApi3ExtractOutputItem<ItemType>
|
AbstractOutputItem<OpenApi3, ItemType>
|
OpenApi3DynamicGenerator
|
AbstractDynamicGenerator<OpenApi3>
|
- - - - - - - - -
|
ZenModelGenTemplate
|
GenTemplate<ZenModel>
|
ZenModelOutputItem
|
AbstractOutputItem<ZenModel, ZenModel>
|
ZenModelExtractOutputItem<ItemType extends EObject>
|
AbstractOutputItem<ZenModel, ItemType>
|
ZenModelDynamicGenerator
|
AbstractDynamicGenerator<ZenModel>
|
In addition, convenience methods can be used to define primary sources
for the supported primary types. These can all appear in configure
method overrides in GenTemplate
-derived classes.
Convenience method |
Equivalent long-form definition |
defineZenModelSource()
|
define(primarySource().ofType(ZenModel.class))
|
defineSwaggerSource()
|
define(primarySource().ofType(Swagger.class))
|
defineOpenApi3Source()
|
define(primarySource().ofType(OpenApi3.class))
|