Click here to Skip to main content
15,867,568 members
Articles / Programming Languages / C#
Article

Customizing Code Generation of Telelogic Rhapsody in C with .NET

Rate me:
Please Sign up or sign in to vote.
4.10/5 (5 votes)
30 Aug 2007CPOL7 min read 74.6K   405   10   29
A detailed guide on how to extend the Rhapsody code generator in C#

Introduction

Telelogic Rhapsody in C is a UML modeling tool with strong support for embedded systems. While its built-in code-generator fits many environments nicely, embedded domains like automotive systems do have their specific needs which are rarely satisfied by off-the-shelf code-generators. So either you pay the tool vendor a lot of money to implement your domain requirements or - if the tool allows - you do it yourself. This article describes how code generation in Rhapsody in C (short: RiC) works and what can be customized and how exactly this is done. You may see this article as an extension to RiC's documentation which is not very exhaustive on this topic.

Background on Code Generation in RiC

RiC's code generator produces C source code from a UML model, from now on called the user model. This user model may contain modeling concepts like classes and statemachines that have no direct equivalent in the target programming language C. The RiC code generator therefore applies a set of well-known patterns mapping, e.g. classes, their attributes and methods to C.

The Two Steps of Code Generation

While e.g. for Rhapsody in Ada, this is done in a single step, RiC separates the mapping from actual source code generation and therefore consists of the following two steps:

  1. During Simplification, object-oriented concepts like classes and statemachines are mapped to concepts available in the target programming language. In C, these are concepts like structures and functions. The output of this step is still a UML model with a limited set of used UML features.
  2. In a model-to-text transformation, source code is generated from the simplified model by applying a declarative ruleset consisting e.g. of text templates for structures and operations.

Both steps may be customized. So if you want to change the generated output, you have to make the important design decision very early as to which approach to take. Use the following guideline as a rule of thumb: If you want to add new or change the semantics of existing modeling concepts (e.g. in the form of stereotypes), modify the simplification step. On the other hand, if instead of semantics the location or appearance of a concept in source code matters most, modify the ruleset.

This two step approach nicely fits OMG's MDA philosophy: If the target programming language C is what MDA calls a platform, then the simplification step transforms a platform-independent model (PIM) to a platform-specific model (PSM) and the rules-based step then transforms the PSM to code.

Customization Technologies

Unfortunately the two approaches rely on different underlying technologies, thereby making the integration not easy:

  • The simplification step relies on Rhapsody's COM API. For customization, a new simplifier is implemented invoking Rhapsody's metamodel through COM. Therefore all COM-aware technologies and programming languages may be used, including .NET and C#.
  • The rules-based step is realized by invoking RiC's rules-player. The rules-player executes a certain ruleset, which may be modified in a tool called the rules-composer. Such a ruleset consists of templates and scripts generating the output text. As of today, scripts may be written in proprietary Java-like languages defined by the rules-composer, in Java or as ATL transformations. The underlying metamodels are themselves based on the Eclipse Modeling Framework.

To summarize: simplification lives in the COM world while rules-based code generation lives in the Java/Eclipse world. What is common is the structure of RiC's metamodel: if you know in COM where to find classes you won't have any issue with that in a ruleset either.

This article solely deals with modifying the simplification step in C#. As you most of the time add or change semantics of modeling concepts, this already gets you quite far. Changing the ruleset is out of scope as it would resemble documentation of the rules-composer application.

Preparing the Model

screenshot CustomizableCG

To allow changing or replacing the built-in simplifier, the model must be set up correctly. The user is assumed to know what Rhapsody properties are and where to change them. First of all custom code generation must be enabled by setting the property C_CG::Configuration::CustomizableCG to true as shown in the screenshot.

After this, model elements can be specifically chosen to have custom simplification applied. As this again is done through RiC properties, the typical Rhapsody ways of inheriting properties from parent model elements or stereotypes may also be used. The property names to look for typically start with Simplify.

screenshot Simplify properties

The screenshot shows the corresponding properties for the model element Class. You notice the Default: by changing this to one of the following values, a custom simplification can be switched on for the model element in scope:

  • None simply omits the model element during simplification. Obviously this will lead to the element missing in generated source code as long as the default ruleset is used. A custom ruleset still may access this element through the metamodel.
  • Copy will put a copy of the model element into the simplified model.
  • ByUser leads to invoking a user-defined simplifier that is given the corresponding model element as input.
  • ByUserPostDefault will also call the user-defined simplifier but after the built-in simplifier has done its job.

So to invoke a custom simplifier, a model element's Simplify property must be set to either ByUser or ByUserPostDefault, depending on whether the custom transformation is a replacement or an extension of the built-in transformation step.

The screenshot also shows different types of what exactly is simplified for the model element and thereby gives a finer granularity when applying custom transformations to very specific aspects of the current model element. Also note that even though simplification is changed for a parent element like a class, its child elements like operations still have their own simplification settings. This is a very flexible approach, which in some cases may lead to confusion about which simplify property of which metaclass needs to be changed. In that case nothing will spare you a little trial and error session...

Building your Own Simplifier

You can build your own transformation plugin very easily by using the base class I provided in this article. The base class already realizes the interfaces needed by Rhapsody and also implements a clean connect/disconnect protocol.

You use the base class by doing the following:

  1. Download the source file and drop it into your project.
  2. Add a dependency to the COM server rhapsody.exe to your project. This way, RiC's COM API becomes available.
  3. Add a new class MySimplifier to the project and derive it from the base class CodeGenSimplifier.
  4. Implement a constructor for your new class that calls the base class constructor thereby passing a simplifier name that will show up when printing output to Rhapsody's console.
  5. Override the transformation functions as needed. The base class already provides default implementations that have no effect on the model.

Eventually, a very simple simplifier will look like the following example code (you can copy and paste this code, it is complete):

C#
public class MySimplifier : RicTools.CodeGenSimplifier.CodeGenSimplifier
{
    public MySimplifier( )
        : base( "MySimplifier" )
    {
    }

    protected override void OnPostSimplify( RPModelElement userElement, 
	RPModelElement mainSimplifiedElement, string simplificationRequested )
    {
        TraceInformation( "user element = {0}", userElement.getFullPathName() );
        TraceInformation( "main simplified element = {0}", 
			mainSimplifiedElement.getFullPathName() );

        // just a test:
        if( !ShouldAbortGeneration )
        {
            WriteCodeGenMessage( "Applying transformation of description." );
            mainSimplifiedElement.description = 
			"This element has been simplified. Dig this!";
        }
    }
}

The example simply changes the description of a model element after it has been transformed by the built-in generator. You also notice a few convenience functions being called: WriteCodeGenMessage writes output to Rhapsody's build console, TraceInformation and other trace methods write output to trace listeners that may have been set up. The flag ShouldAbortGeneration indicates whether the user hit the abort button in Rhapsody.

For a complete overview of all methods provided by the base class, take a look at the help file I provided with the source code. To connect to a running Rhapsody instance, instantiate your new class and call Connect(). If you then regenerate code with a model prepared as described earlier, your simplifier will be invoked and the generated code will eventually contain the changes you triggered inside implementations of OnSimplify or OnPostSimplify.

Summary

After giving a brief overview of Rhapsody in C's code generation process, the article showed what needs to be done to implement a new custom code generation simplifier in C# built on top of a generic base class. While RiC is used for modeling and code generation in a lot of places, application of advanced features like customization of its code generator does not seem to be widely spread. Partially this may be caused by the lack of in-depth documentation, which is what I tried to address in this article.

While this article explained the technical background and provided a simple tool to get a simplifier going in the first place, nothing was said about how the actual transformation code should work. Depending on interest, I will write about this in follow-up articles.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) BMW AG
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Question"Edit Order of dependencies" Feature in Rhapsody Pin
Member 1184631018-Jul-15 6:24
Member 1184631018-Jul-15 6:24 
GeneralLimitations regarding the simplification step Pin
Muechi13-Nov-08 5:16
Muechi13-Nov-08 5:16 
AnswerRe: Limitations regarding the simplification step Pin
Mike Pagel13-Nov-08 5:38
Mike Pagel13-Nov-08 5:38 
GeneralRe: Limitations regarding the simplification step Pin
Muechi13-Nov-08 23:06
Muechi13-Nov-08 23:06 
GeneralRe: Limitations regarding the simplification step Pin
Muechi24-Nov-08 22:35
Muechi24-Nov-08 22:35 
GeneralRe: Limitations regarding the simplification step Pin
Mike Pagel24-Nov-08 22:54
Mike Pagel24-Nov-08 22:54 
GeneralRe: Limitations regarding the simplification step Pin
Muechi24-Nov-08 23:04
Muechi24-Nov-08 23:04 
GeneralRequirement Tag Generation into source code gererated by Rhapsody in C++ and Java. Pin
shridhomne3-Sep-08 20:26
shridhomne3-Sep-08 20:26 
AnswerRe: Requirement Tag Generation into source code gererated by Rhapsody in C++ and Java. Pin
Mike Pagel10-Sep-08 22:55
Mike Pagel10-Sep-08 22:55 
GeneralRhapsody Rules Composer Pin
TheLetti30-Oct-07 13:03
TheLetti30-Oct-07 13:03 
GeneralRe: Rhapsody Rules Composer Pin
Mike Pagel30-Oct-07 21:22
Mike Pagel30-Oct-07 21:22 
QuestionRe: Rhapsody Rules Composer Pin
TheLetti2-Nov-07 3:04
TheLetti2-Nov-07 3:04 
AnswerRe: Rhapsody Rules Composer Pin
Mike Pagel2-Nov-07 3:12
Mike Pagel2-Nov-07 3:12 
QuestionRe: Rhapsody Rules Composer Pin
TheLetti6-Nov-07 4:41
TheLetti6-Nov-07 4:41 
AnswerRe: Rhapsody Rules Composer Pin
Mike Pagel6-Nov-07 9:18
Mike Pagel6-Nov-07 9:18 
QuestionRe: Rhapsody Rules Composer Pin
TheLetti6-Nov-07 12:22
TheLetti6-Nov-07 12:22 
AnswerRe: Rhapsody Rules Composer Pin
Mike Pagel7-Nov-07 1:52
Mike Pagel7-Nov-07 1:52 
QuestionRe: Rhapsody Rules Composer Pin
TheLetti13-Nov-07 11:17
TheLetti13-Nov-07 11:17 
AnswerRe: Rhapsody Rules Composer Pin
Mike Pagel13-Nov-07 20:09
Mike Pagel13-Nov-07 20:09 
Hi Michael,

writing another article on this topic is a good idea, unfortunately, I currently don't have the time... So I'll try responding to your questions directly.

The article says something about how to decide where to apply which kind of transformations or adaptations to the generation process. This is meant as a guideline from which you sometimes have to deviate... like in your case. The reason is that Telelogic creates the statechart execution code (like the dispatch methods) in their built-in simplifier. Now, I totally agree that this may not be the ideal location, but that is how its done.

Therefore you won't find the statechart skeleton code in the RiCWriter ruleset. The ruleset does not know about statecharts. One can argue that this is even ok, since statecharts are not available in C...

As a consequence you are required to perform the changes in a simplification step, which you would trigger by changing the property C_CG.Statechart.Simplify. If you set this to ByUserPostDefault you'll receive the statechart as generated by Rhapsody for your perusal. You will be able to change what was created, e.g. by serching for your stereotypes and implement a different behavior for them. If you want to create textual code in a simplifier you will need to do this through string operations the result of which is then assigned to an operation's body attribute. Not elegant, but it works. You could aso not do it that way, and add your stereotype to the RiCWriter ruleset and there create a new code template. While the latter is cleaner in terms of methodology I am not sure it is worth it.

If I find that Telelogic created cludges like that I'll bitch about it but then get back to work and won't try to improve that part of the architecture, since you then start working against the tool, a fight you eventually will loose... Cry | :((

Not sure I told you that by switching on C_CG.Configuration.ShowCgSimplifiedModelPackage you will be able to browse through the output of the built-in (and your own) simplifiers. This is of great help when reverse-engineering what needs to be written, as documentation of all this is, well, not existing.

Best,
Mike
QuestionRe: Rhapsody Rules Composer Pin
TheLetti14-Nov-07 10:44
TheLetti14-Nov-07 10:44 
AnswerRe: Rhapsody Rules Composer Pin
Mike Pagel14-Nov-07 21:06
Mike Pagel14-Nov-07 21:06 
GeneralRe: Rhapsody Rules Composer Pin
Mike Pagel14-Nov-07 21:33
Mike Pagel14-Nov-07 21:33 
GeneralRe: Rhapsody Rules Composer Pin
TheLetti24-Nov-07 23:37
TheLetti24-Nov-07 23:37 
GeneralRe: Rhapsody Rules Composer Pin
TheLetti11-Dec-07 12:29
TheLetti11-Dec-07 12:29 
GeneralRhapsody code generation in c# Pin
Shridhar Dhomne16-Oct-07 18:00
Shridhar Dhomne16-Oct-07 18:00 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.