Table Of Contents

Previous topic

Setting up AGX Tests

Next topic

AGX Overview

This Page

Under the hood

Introducing the tree transformation framework

Basically AGX consists of transformation processing components and a crafty I/O concept. Latter could be used apart from tree transformation tasks as well to read and write data.

The transform components treat all input/output data as tree, which makes it possible to use the chain for several usecases, like:

  • code generation
  • data exchange
  • data conversion
  • [fill in your use-case here]

The major use-case and main goal of AGX is to generate Python code from an source, such as UML.

The framework is based on the Zope Component Architecture (ZCA), thus pluggable and highly customizable.

We tried to make extension work for developers as easy and as less code expensive as possible at the same time.

Thus its easy to write own generators and hook them in existing transformation chains. Extending i.e. UML models by profiles with stereotypes and tagged values and providing additional generators enables new behavior in your generated code.

Naming Conventions

There exist several namespaces which contain core components and logical groups of components. Please follow the naming conventions when providing your own modules.

agx.core
contains all transform related components and some base implementations aimed to be used or derived from when providing own components.
node.ext.*
packages contain concrete I/O related implementations, i.e. for XML, UML, file-system directory, python-code, ...
agx.transform.*
packages providing specific source and target tree instances for the transformation chain- I.e. agx.transform.xml2uml provides an node.ext.xml tree as source and an node.ext.uml tree as target.
agx.generator.*
packages are containing specific generator logic. Most of the time this is a bunch of registered handlers for a transform. This handlers are responsible to read from the source tree desired information and write nodes to the target tree and are called by the transformation chain.

Components of the transformation chain

The AGX transformation chain provided by agx.core consists out several components. These are decoupled by ZCA.

Controller
The start point is usally the Controller. It loads the configuration, then iterates over the chain (or pipeline) of registered transformations walking from one source-tree over one or more intermediate trees to the target-tree. For each step with each pair source and target it calls the processor with source, target and transform. The target of the first transform is the the source of the second and so on. The last target is called to get persisted.
Processor
Responsible to invoke all registered Generator instances of the transform the Processor is working on. Generators are having an execution order defined by dependencies. The processor takes care of this. Before a generator is invoked the TargetHandler is looked up and initialised with the target. The Generator is called with source and handler wrapped target.
Generator

It walks recursivly through the whole source tree. For each node found it

  • calls the TargetHandler with the source node and
  • invokes a Dispatcher with source node and the handler wrapped target.
Dispatcher

Looks up all Handler instances registered for the current transform and generator. For each Handler it

  • checks whether the source node applies to the Scope (if one is defined) of the handler and
  • call the handler with the ource and target node if scope matches.
Handler
Responsible to do atomic transformation related tasks. Finally here data may be transfered from source to target. I.e creation and adding of target nodes, copy data to specific target nodes, collecting data on Token instances and any other required task.
Token
For information and data exchange inside the transformation chain there exist an object called Token. Every handler can create and set or read an already existing token, which exists unique per transform by name.

Overall Process of the Pipelined Multi Pass Tree Transformation

AGX core provides a generic pipelined multi pass tree transformation. It is based on source tree traversal and dispatching to handlers. The core itself provides the basic toolset and logic for such a transform. Setup, configuration and handlers must be provided by the application using AGX.

pipelined transformations
First process a source tree A and create target tree B of it. In next iteration tree B is the source tree and new target tree C is created.
multi pass processing
In each tree processing step one or more generators are called. Each generator traverse the full source tree again.
dispatched generation
target trees are generated by prioritized handlers. Scope detection is used to filter handlers responsible for the currently traversed source node.

The overall process is described by the following diagram:

msc {
hscale = "1.5";

controller,processor,generator,dispatcher;

controller->controller [ label = "initialize with path/file of source and target" ];
controller=>controller [ label = "fetch configuration" ];
--- [label = "iterate over transform names", textcolor="maroon",linecolor="red"];
controller=>controller [ label = "lookup transform" ];
controller=>controller [ label = "create source using transform" ];
controller=>controller [ label = "if no source factored use previos target as source" ];
controller=>controller [ label = "create target using transform and source" ];
controller=>controller [ label = "create processor for transform" ];
controller=>processor [ label = "process target" ];
processor=>processor [ label = "lookup generators for transform"];
--- [label = "iterate over generators", textcolor="olive",linecolor="green"];
processor=>processor [ label = "lookup targethandler for generator"];
processor=>processor [ label = "set anchor of targethandler to target"];
processor=>generator [ label = "call generator with source and targethandler"];
generator=>generator [ label = "lookup dispatcher with same name as generator" ];
--- [label = "walk through source tree top to bottom, depth last.", textcolor="orange",linecolor="orange"];
generator=>generator [ label = "preprocess target, call it with current source node" ];
generator=>dispatcher [ label = "call dispatcher with source-node and targethandler" ];
dispatcher=>dispatcher [ label = "lookup all ordered handlers"];
--- [label = "iterate over handlers", textcolor="purple",linecolor="fuchsia"];
dispatcher=>dispatcher [ label = "lookup scope"];
dispatcher=>dispatcher [ label = "if not scope(source) matches, next()"];
dispatcher rbox dispatcher [ label = "call handler(source, target)"];
dispatcher=>dispatcher [ label = "next()"];
--- [label = "end iteration over handlers", textcolor="purple",linecolor="fuchsia"];
generator<-dispatcher [ label = "dispatching done"];
--- [label = "end walking source tree", textcolor="orange",linecolor="orange"];
processor<-generator [ label = "generation done" ];
processor=>processor [ label = "next"];
--- [label = "end iteration over generators", textcolor="olive",linecolor="green"];
controller<=processor [ label = "return target" ];
controller=>controller [ label = "next" ];
--- [label = "end iteration over transform names",textcolor="maroon",linecolor="red"];
controller=>controller [ label = "persist last target" ];
}