Chapter 4 - Advanced Topics

Tree Rendering Strategy

The tree displayed in the code generation dialog shows only classes, interfaces, and packages. To generate code for other kinds of objects (for example states, components, or use cases) you will need a way to tell the tree that it should display these kinds of objects. This way is described in this section. You can give your controller a class implementing the Interface TreeRenderingStrategy with a call of GeneratorController.setTreeRenderingStrategy(TreeRenderingStrategy). This strategy implements two methods that control the tree display:

isTreeElement(Object element):boolean determines whether the given element should be displayed.

getChildren(Object element):Collection returns a collection of all child elements of an object.

In the default implementation for the generation of code from UML -  UMLGeneratorController - the method StaticElementRenderingStrategy.isTreeElement() returns true for UML containing projects, packages, classes, and interfaces. A call to getChildren() returns a list of all the models for a project, and a list of all the owned elements for a package. For all other elements, it returns null. You can subclass the StaticElementRenderingStrategy to get different display behaviors.



Combining Multiple Extensions

The described framework is designed to allow for extensions expressed by an inheritance hierarchy. Your plugin B may extend another code generation from plugin A, and plugin C may also extend B. Usually, the user has to select whether to generate code with A and extensions from B, or A and extensions from C. Generation based on A with extensions from both B and C at the same time is not possible. The two different extensions are, in general, mutually exclusive. This section covers the topic of setting up plugins so that several extensions can be used at the same time, although they may not know of each other and may be plugged in and out of Poseidon at runtime.

You might have one plugin based on Java code generation that produces source code for use cases, and another from a different source that is also based on Java code generation, but generates source code for deployment diagrams. Although they do not influence each other directly, you will not be able to select both extensions at the same time.

The problem is that there may be a conflict between the two extensions: If both of the extensions generate code for the same model element, the code generation framework won't know which extension (i.e. which Generator, Preparator and PreparedElement) is applicable, nor which GeneratorController to use. As the developer of a plugin, you must make sure that your plugin conforms to a specification, so that automatic selection is possible. Following this specification ensures that two plugins do not interfere in their specific capabilities.

There always has to be a concrete Generator instance and a concrete ElementPreparator instance that serve as the basis for code generation. Both of them define a set of default entries (macros and preparation classes) for generation. The Generator instance defines a set of macro libraries to be its default, while the ElementPreparator defines a set of element preparation classes and maps them to element classes. Both definitions can be changed externally. Any entry can be overwritten or new entries can be added. Please note, however, that removal of default entries is not supported.

This way, you can modify the parent's Generator and ElementPreparator classes. You will implicitly make use of the parent's GeneratorController. Another plugin that extends the same addition will also do this, and so you can replace different parts of the parent's generation algorithm while re-using those that are constant. If you design a plugin compatible with other extensions, you have to restrict your extensions to either editing (modifying or adding) template libraries, or editing (modifying or adding) prepared classes, or both. If you need your own GeneratorController, your plugin will not be compatible with others on the same level.

Please note, that there are some limitations to how extensions can be added or combined. First, and perhaps most important, combining external entries (macros and preparation classes) from different origins into one GeneratorController can cause non-deterministic behavior in cases where the same preparation class or macro is added from more than one origin. The sequence of adding these entries determines which implementation is actually used. There is no automatic way out of this. Moreover, activating two incompatible plugins at the same time can also cause inconsistencies.

The template files themselves are not combinable. It is possible, however, to define macros for the code generation and use templates that call these macros (see below). Exchanging the macros would then change the resulting code. By spreading the macros over several libraries, a combination of different features is possible, but limited to modifying the macros that the template uses. Macros with the same name from different origins will be overwritten in a non-predictable way. This is a result of Velocity using a global namespace.

Usually, the plugin providing the Generator and ElementPreparator classes should also provide the ExternalEntryStrategy implementation. Therefore, it is necessary to define decision rules that can do their work without knowing anything about the possible addition plugins. If any knowledge about them is needed, the extensibility is limited severely.



© 2000 - 2010 Gentleware AG
         
                        
 support  documentation  documentation