Skip to main content

skip to main content

developerWorks  >  Rational  >

Extending a UML to Java 5 transformation with Rational Software Architect Version 7

developerWorks
Document options

Document options requiring JavaScript are not displayed

Sample code


My developerWorks needs you!

Connect to your technical community


Rate this page

Help us improve this content


Level: Intermediate

Jim Conallen (jconallen@us.ibm.com), Senior Software Engineer, IBM 

18 Sep 2007

IBM® Rational® Software Architect is a tool for architects and designers of software systems. It combines modeling with the Unified Modeling Language (UML) and developer tools, including a code editor, compiler, and debugger. For connecting these two phases, Rational Software Architect includes a UML-to-Java™ 5 transformation that transforms UML models of classes, interfaces, and enumerations into Java 5 source code. Although the functionality of this transformation is complete, there are those who may want to extend this transformation to include custom elements or conventions or to support a Domain Specific-Language (DSL) extension that they have created. This article introduces the basic elements of creating an extension to this transformation by presenting a simple example.

About the Java 5 transformation feature in Rational Software Architect

IBM Rational Software Architect includes several predefined transformations, some of which transform a UML model into source code. Version 7 introduced a transformation that includes Java 5 features. Like its predecessor, this transformation can be extended. This article walks you through the steps necessary to create a simple example that demonstrates the core capabilities of this functionality.

As with most features in Rational Software Architect, to extend it you use the normal Eclipse extension mechanisms, creating a plug-in and implementing specific extension points. This article does not address general plug-in development (see Resources for recommended articles and examples). Instead, it focuses on just enough plug-in development skills as necessary to create and test a transformation extension.


Figure 1. Overall transformation structure
Diagram of Overall transformation structure

When a transformation is invoked, it begins with the UML model, package, class, interface, or enumeration element, depending on what was selected when the transformation was invoked. The transformation will operate on the selected element (or the entire model if no element is selected) and all of the elements that it contains. This provides many opportunities for a transformation extension author to tap into and contribute to the overall transformation. An extension targets just one part of the overall transformation. You will find a complete list of targets in the appendix (see Downloads).

For this simple example, you will define a simple class-level extension that gets invoked each time that a transformation is ready to transform a UML class element into a Java source file. This extension will do nothing more than look for any keywords defined for this class and use them to add a new Javadoc tag associated with the class in the source code.

You will follow these steps:

  1. Create a new plug-in project for your transformation extension. This project may be combined with other extensions; however, to make this example simple, you will create a new project from scratch.
  2. Add a set of required plug-in dependencies. These plug-ins define the extension point that you are implementing and provide the APIs that you will need to invoke your extension.
  3. Define the extension point in the plug-in descriptor, which identifies the transformation that you are extending and the point within it that you want to make a contribution.
  4. Provide a Java implementation of the class rule that will be invoked each time that the transformation encounters the element type that you indicate.
  5. Test the transformation by invoking a runtime workbench and running a UML-to-Java 5 transformation.


Back to top


Step 1. Create and configure a new plug-in project

The transformation extension begins with a new plug-in project:

  1. Select the menu File > New > Project, and select Plug-in Project from the list of project types, and click Next.
  2. On the first page of the New Plug-In Project wizard, enter a valid project name. The Eclipse convention for plug-ins is to use a URI domain like the one shown in Figure 2.

Figure 2. New Plug-in Project wizard
New Plug-in Project           wizard screen capture

  1. On the second page (Figure 3), update the default Plug-in Name field; the remaining defaults are acceptable.

Figure 3. New Plug-in Project wizard Properties page
New Plug-in Project           wizard Properties page screen capture

On the final page, it is not necessary to select a plug-in template, because there are no templates for transformation extensions, just for new complete transformations.


Figure 4. New Plug-in Project wizard final page
New Plug-in Project           wizard final page screen capture

  1. Uncheck the template option and click the Finish button (Figure 4.)

Figure 4. New Plug-in Project wizard final page When the wizard finishes, it creates a new plug-in project and opens the Overview page of the project descriptor (Figure 5).


Figure 5. New project structure
New project structure screen capture

Step 2. Add required plug-in dependencies

The next step is to add a few plug-ins as dependencies. These plug-ins contain the extension point definitions for the implementation plus APIs that will be used in the implementation of the extension.

  1. Switch to the Dependencies tab (at the bottom of this editor), and add the following plug-ins as dependencies:
    • com.ibm.xtools.modeler
    • com.ibm.xtools.transform.core
    • com.ibm.xtools.transform.uml2.java5
    • org.eclipse.jdt.core
  2. Verify that the plug-ins were added. The resulting list should look similar to Figure 6.

Figure 6. Dependent plug-ins
Dependent plug-ins screen capture

Step 3. Define and implement the extension

The next step is to declare that you are going to provide an implementation to one or more extension points.

Switch to the Extensions tab, and click the Add button to add a new extension. You will then see the dialog box that Figure 7 shows. Enter this extension point: com.ibm.xtools.transform.core.transformationExtensions. When you find it, select it and click Finish.


Figure 7. New Extension dialog
New Extension dialog screen capture

  1. There is more information that needs to be supplied in the extension point definition. These values can be entered through the user interface on the Extension tab page. However, most people find it easier to just edit the raw XML of the plugin.xml file. This file is created the first time that an extension is defined (before that, it was not necessary, so it was not created by the New Project wizard)
  2. Switch to the plugin.xml tab, and you will see the XML source file, which you can edit.
  3. For this example, add the detail shown in Listing 1 to the extension point.

Listing 1. Extension declaration
                
     <extension point="com.ibm.xtools.transform.core.transformationExtensions" >
   
      <TransformationExtension version="1.0.0"
            name="My UML to Java5 Transformation Extensions"
            enabled="true"
            targetTransformation=
            "com.ibm.xtools.transform.uml2.java5.internal.UML2JavaTransform"
            id="com.ibm.rsa.java5.extension.sample.transformationExtensions.id">

         <RuleDefinition
         	name="Javadoc Keyword Rule"
         	class="com.ibm.rsa.java5.extension.sample.ClassKeywordJavadocRule"
         	id="com.ibm.rsa.java5.extension.sample.ClassKeywordJavadocRule.id"/>

         <ExtendTransform
			targetTransform=
			"com.ibm.xtools.transform.uml2.java5.internal.ClassTransform">
            <AddRule id="com.ibm.rsa.java5.extension.sample.ClassKeywordJavadocRule.id"/>
         </ExtendTransform>

      </TransformationExtension>
   
   </extension>
      

The body of an extension element is defined by the extension point provider. In this case, that is the Rational Software Architect Core Transformation component. This extension expects TransformationExtension child elements (one for each type of transformation to extend). Each one of these elements defines which transformation is being extended.

  1. For this simple example, specify a targetTransformation with the ID of com.ibm.xtools.transform.uml2.java5.internal.UML2JavaTransform.
  2. Supply appropriate values for the ID: version number, name, and the Boolean value for enabled.

Each transformation extension defines, as child elements. a rule definition that specifies a class that implements a rule interface. This class does most of the work of contributing to the transformation. It is defined as a separate element, because it is possible for a single class to contribute to multiple parts of a transformation (for example, class, property, and operation).

After all of the rules have been defined, they are matched with the part of the transformation that they will contribute to with ExtendTransform elements. This element defines the part of the transformation that a rule will contribute to. For this, you want to contribute to the extension each time a new class is being transformed, and the value of the targetTransform should be com.ibm.xtools.transform.uml2.java5.internal.ClassTransform. The appendix that you can download from this article page contains a complete listing of target transformation ID (see Resources).

Given that more than one rule can contribute to any particular part of a transformation, they are collected here as child elements of the ExtendTransform element. You have only one rule defined in your project as you are using it here.

Note:
The ID of the rule in the RuleDefinition element must match that of the AddRule element.

Step 4. Provide a Java implementation of the class rule

When you are finished editing this file, save it. You should notice a small error icon in the left margin, next to the line in the plugin.xml file, that specifies the implementation class. This indicates that the class could not be found in the project.

  1. You can double-click the icon and select the prompt to Create a new class. This invokes the New Class wizard, which you can use it to create the class file. You can also manually create the class with the File > New menu. Whichever way you prefer to create Java classes in Eclipse, create one in the designated package and with the correct name.
  2. To make the implementation as easy as possible, extend the Rational Software Architect transformation framework class com.ibm.xtools.transform.uml2.imple.internal.java5.ClassRule. With this class as a super class, there are only three methods that should be overridden.
    • canAccept
    • createTarget
    • isSourceConsumed

Each of these methods accepts a transformation context object that can be queried to gain access to the source and target objects. With this information, you can decide whether you want to process this particular class (canAccept) or whether further processing of this class should stop (isSourceConsumed). If this extension accepts the context, then the createTarget() method is used to make the actual contribution to the transformation.

  1. For this simple transformation extension, return False in the isSourceConsumed method to indicate that further processing should continue, and that the extension does not mean that all of the work of the transformation of this particular element was completed.
  2. Indicate that you can accept a particular class when there is at least one keyword defined. If there are no keywords, there is nothing for you to do, so indicate that you are not interested. You can access the source UML class through the transformation context that is passed in as an argument. The getSource() method on the context should return a reference to a UML class, since we specified in the extension point that we were interested only in Class transforms.
  3. Type the source object to a UML class, and then get the keyword list from it. If the list is empty, then return False.

If there are keywords, then you can expect the createTarget() method to be called. This is where you are expected to make your contribution to the transformation.


Listing 2. Java rule class implementation
                
package com.ibm.rsa.java5.extension.sample;

import java.util.Iterator;
import java.util.List;

import org.eclipse.emf.common.util.EList;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.Javadoc;
import org.eclipse.jdt.core.dom.TagElement;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.uml2.uml.Class;

import com.ibm.xtools.transform.core.ITransformContext;
import com.ibm.xtools.transform.uml2.impl.internal.java5.ClassRule;

public class ClassKeywordJavadocRule extends ClassRule  {

	protected Object createTarget(ITransformContext context) {
		TypeDeclaration target = (TypeDeclaration) context.getTarget();
		Javadoc javadoc = target.getJavadoc();
		List tags = javadoc.tags();

		AST ast = target.getAST();
		
		Class umlCls = (Class) context.getSource();
		EList keywords = umlCls.getKeywords();
		
		for (Iterator iter = keywords.iterator(); iter.hasNext();) {
			String keyword = (String) iter.next();
			TagElement tag = ast.newTagElement();
			tag.setTagName("@" + keyword);
			tags.add(tag);
		}
		return target;
	}

	public boolean isSourceConsumed(ITransformContext context) {
		return false;
	}

	public boolean canAccept(ITransformContext context) {
		Class umlCls = (Class) context.getSource();
		return umlCls.getKeywords().size()>0;
	}
	
}

The first contribution that developers usually make when implementing the createTarget() method is to access the source and target objects for this part of the transformation. Because you have defined this extension to be invoked when the transformation is processing a UML class, you can safely type the target object to an Abstract Syntax Tree (AST) TypeDeclaration object. The Eclipse Java Developer Tools (JDT) project provides all of the APIs for manipulating Java source code. The AST is the object model that parses source code for Eclipse. When this method is invoked, a new TypeDeclaration object is created by the transformation framework. It should be noted that if there is any existing Java source code, this is not made available in the target object. Merging of the newly generated code with any existing code happens after all of the model elements have been transformed.

Discussing the AST in detail is beyond the scope of this article, other than to say that when the extension needs to add new elements to the generated source code, that is done by calling methods on the AST objects. For this simple example, you will just add a new Javadoc tag to the class definition's Javadoc comments. Javadoc is an object type in the AST, and is obtained from the TypeDeclaration object.

  1. From the Javadoc object, get the list of tags that make up this Javadoc. You can add (or remove) tags from the generated source code.
  2. To determine which tag to add, access the source object from the transformation context and cast it to a UML class. From this object, you get the list of keywords (similar to how you did that when implementing the canAccept() method).
  3. With this list, iterate over the keywords and create a new TagElement for each keyword.
  4. Set the name of the tag to the value of the keyword (prefaced with the @ symbol).
  5. Finally, add the new tag to the list of tags for the class Javadocs.

The method must return a target object. Usually, it is the same object that was passed in as a target. This completes the creation and implementation of your transformation extension.

Step 5. Test the extension

Now that you have defined and implemented the extension, it's time to test it. You do this by creating a new debug configuration that opens a new runtime workbench.

  1. To create this configuration, select Run > Debug from the main menu.
  2. In the dialog, create a new Eclipse application configuration and name it appropriately.

Tip:
You can change the location of the workspace, and it is usually a good idea to choose a new location to avoid inadvertently affecting an existing workspace.

  1. Leave the remaining default settings as they are (Figure 8).

Figure 8. New debug configuration
New debug           configuration screen capture

  1. When you have finished editing the configuration, click Debug to start a new instance of Eclipse. This new instance will have the transformation extension that you just created installed as a plug-in.
  2. To test the extension, you need to create a new Java project and a UML model in that project within the new instance of the Eclipse shell.
  3. Within the UML model, create a test package and class, and include a few attributes or operations. The resulting workspace should look something like that of Figure 9.

Figure 9. Test project in runtime workbench
Test project in runtime workbench screen capture

Next, you need to add a keyword to the class, because your extension will work only on a class that has a keyword defined.

  1. Select the class and then the Stereotypes sub-tab in the Properties view.
  2. Enter text in the Keywords field (Figure 10).

Figure 10. Setting the keywords property
Setting the keywords property screen capture

With the test project and model set, you now need to create a new transformation configuration that defines the main parameters of the UML-to-Java 5 transformation.

  1. Select File > New from the main menu.
  2. Under the Transformations category, select Transformation Configuration, and then click Next (Figure 11.).

Figure 11. Creating a new transformation configuration
Creating a new transformation configuration screen capture

  1. There are many transformation types that are included with Rational Software Architect. Choose the UML-to-Java 5 transformation (Figure 12), because that is the one for the extension that you created.
  2. Give it an appropriate name. This will be used as the file name of the configuration in the Java project.

Figure 12. Selecting the transformation
Selecting the transformation screen capture

  1. The first things that you need to specify in a transformation configuration are the source model and the target project.
    • Be sure to select the UML model, because it appears under the Models virtual folder, and not the actual .emx file.
    • Select the target by choosing the Java project itself (Figure 13).

Figure 13. Setting the source and targets for the transformation
Setting the source  and targets for the transformation screen capture

  1. Optionally, you can turn off the automatic generation of get and set methods on the next configuration setup page (Figure 14), and experiment with the other options on the remaining pages. However, for this simple test, accepting the defaults clicking Finish should work.

Figure 14. Transformation configuration options
Transformation configuration options screen capture

Now that the configuration has been created, it can be invoked. For the life of this project, it does not have to be created again.

  1. To invoke the transformation and your extension to it, select the class in the diagram, invoke the popup menu, and select Transform > My UML to Java5 Transform Test.tc > UML to Java V5.0 (Figure 15).

Figure 15. Invoking the transformation
Invoking the           transformation screen capture

Figure 16 shows the results of the transformation. You can see that a Javadoc tag that matches the value of the keyword that you added is included in the Javadocs of the class.


Figure 16. Results of generated code
Results of           generated code screen capture

Conclusion

This simple example of a UML-to-Java 5 extension was meant just to demonstrate the basic mechanism for creating extensions. Real-life extensions would most likely be more intelligent, using information in the model and making more interesting changes to the generated code or even adding companion artifacts to the source code. The important point to take away from this article is that creating extensions to existing transforms makes a lot of sense when you want to leverage all of the existing work and just need to make small changes or contributions to the output. Having one common transformation that generates the code, as well as other artifacts (deployment descriptors or companion files, for example) also simplifies the development process, because you need to run only one transformation rather than many.




Back to top


Download

DescriptionNameSizeDownload method
List of transformation targetsUML_to_Java5_transformation_targets.pdf32KBHTTP
Information about download methods


Resources

Learn

Get products and technologies

Discuss


About the author

Jim Conallen

Jim Conallen is a software engineer in IBM Software Group's Rational Model-Driven Development Strategy team, where he is actively involved in applying the Object Management Group's (OMG) Model-Driven Architecture (MDA) initiative to IBM's Rational model tooling. Jim is a frequent conference speaker and article writer. His areas of expertise include Web application development, where he developed the Web Application Extension for UML (WAE), an extension to the UML that lets developers model web-centric architectures with UML at appropriate levels of abstraction and detail. This work served as the basis for IBM Rational Rose and IBM Rational XDE Web Modeling functionality.




Rate this page


Please take a moment to complete this form to help us better serve you.



 


 


Not
useful
Extremely
useful
 


Share this....

digg Digg this story del.icio.us del.icio.us Slashdot Slashdot it!



Back to top