Generation Group

A generation group represents a group of types of files. Generation groups are the leaves of a transformation tree. For every generation group you can define a path wherein the generated files are going to be written. If you for instance want some Java source code be written to src/main/java and some Java resource files to src/main/resources, you define at least two generation groups for this purpose.
You can either basic generation group API or you can use the advanced generation API that can be found in the open source component com.gs.gapp.generation-basic

Basic Virtual Developer API

Within a generation group, you employ target classes that implement org.jenerateit.target.TargetI and writer classes that implement org.jenerateit.writer.WriterI. A class that implements org.jenerateit.target.TargetDocumentI has the purpose to handle the actual document content. Writer classes do the actual writing. An instance of org.jenerateit.generationgroup.GenerationGroupConfigI (or more precise org.jenerateit.generationgroup.WriterLocatorI) undertakes the task of finding out, which writer class to use for the actual writing, depending on the given target classes, target class instances, model element types and model elements.

Virtual Developer API

org.jenerateit.generationgroup.WriterLocatorI has two methods that serve the purpose to identify writer classes:

/**
 * Getter for the base writer class.
 * 
 * @param element a model element for the writer class determination
 * @param targetClass a target class for the writer class determination
 * @return a writer class if a file has to be created for the element and target class
 */
Class<? extends WriterI> getWriterClass(Object element,
                                        Class<? extends TargetI<?>> targetClass);

/**
 * Getter for the writer class. 
 * 
 * @param element a model element for the writer class determination
 * @param target a target class instance for the writer class determination
 * @return a writer class or null
 */
Class<? extends WriterI> getWriterClass(Object element, TargetI<?> target);

There are two different steps to determine a writer class:

  1. Decide for a given model element and target class, whether a file has to be created. The first getWriterClass() method is called for this purpose. If that method returns a writer class, that writer class’ transform() method is the entry point for the file generation.
  2. Decide for a given model element and a target instance, whether a writer should write something to the target file. The second getWriterClass() method is called for this purpose.

Matrix for the Determination of Writer Classes for Target Classes

The following matrix elements where there is a ‘w’ read as follows:

  • For model element e(0) a file of type tc(0) is going to be generated.
  • For model element e(1) a file of type tc(2) is going to be generated.
e → tc tc(0) tc(1) tc(2) tc(n)
e(0) w - - -
e(1) - - w -
e(2) - w - -
e(3) - - - -
e(m) - - - w

Matrix for the Determination of Writer Classes for Target Class Instances

The following matrix elements where there is a ‘w’ read as follows:

  • When target file ti(0) is generated, there are writers that contribute something to the file content for the elements e(0), e(2) and e(3).
  • When target file ti(1) is generated, there are writers that contribute something to the file content for the elements e(2).
e → ti ti(0) ti(1) ti(2) ti(n)
e(0) w - - -
e(1) - - w -
e(2) w w - w
e(3) w - w -
e(m) - - - w

Advanced API of com.gs.gapp.generation-basic

Instead of directly implementing org.jenerateit.generationgroup.WriterLocatorI, you can also create a generation group by extending com.gs.gapp.generation.basic.AbstractGenerationGroup. Doing so lets you define your generation group logic in a more declarative way. Also, it is easier to reuse that logic. In your generation group that extends AbstractGenerationGroup, you …

  • define a set of target classes to be used
  • provide a separate class that implements org.jenerateit.generationgroup.WriterLocatorI and extends com.gs.gapp.generation.basic.AbstractWriterLocator

Your writer locator instance that extends com.gs.gapp.generation.basic.AbstractWriterLocator also knows about the set of target classes to be used. Additionally, it manages two sets of com.gs.gapp.generation.basic.WriterMapper instances, where the first set has the purpose to determine base writer classes and the second one to determine writer classes in general (see previous chapter for more details about this). Each com.gs.gapp.generation.basic.WriterMapper instance represents a tuple (model element type, target class, writer class) and encapsulates the logic to determine a writer class for given tuples (model element, target class) and (model element, target class instance).
Most often it is sufficient to check for the type of the model element. But if you need to also check properties of the model element to decide whether a writer has to be used or not, you can extend com.gs.gapp.generation.basic.WriterMapper and overwrite the following method:

/**
 * Overwrite this method if the decision to use this mapper should be depending
 * on the model element's properties. When this method returns false for a given
 * model element, the writer mapper will _not_ be taken into account, even though
 * its sourceClass and targetClass settings might be saying something else.
 * Note that this method returning true does not have any effect if the mapper's
 * sourceClass and targetClass settings are not matching a given source class
 * and target class.
 *
 * @param element
 * @return true when the writer mapper should be used to get a writer class
 */
boolean isResponsibleForElement(ModelElementI element);

Apart form that, the component com.gs.gapp.generation-basic provides some helper classes like for instance com.gs.gapp.generation.basic.MetatypeFilterI that lets you program a filter mechanism to limit the generation of files to a set of model element types. Or com.gs.gapp.generation.basic.target.BasicTextTarget that provides you with some additional standard functionality like the handling of an explicit class to handle generation group options.