Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "MDT/UML2/Introduction to UML2 Profiles"

< MDT‎ | UML2
m (Creating Enumerations)
(Fix loading from a local filesystem)
 
(3 intermediate revisions by the same user not shown)
Line 1: Line 1:
Copyright © 2004, 2011 International Business Machines Corp. and CEA  
+
Copyright © 2004, 2014 International Business Machines Corp., CEA, and others.
  
 
=== Summary  ===
 
=== Summary  ===
Line 5: Line 5:
 
This article describes how to work with profiles using the UML2 plug-ins for Eclipse. In particular, it gives an overview of how to create and apply profiles (and their contents) both programmatically and by using the sample UML editor.  
 
This article describes how to work with profiles using the UML2 plug-ins for Eclipse. In particular, it gives an overview of how to create and apply profiles (and their contents) both programmatically and by using the sample UML editor.  
  
'''Kenn Hussey and James Bruck''' <br> Last Updated: October 16, 2011
+
'''Kenn Hussey and James Bruck''' <br> Last Updated: January 21, 2014
  
 
= Prerequisites  =
 
= Prerequisites  =
  
To start using UML2 (and to follow along with the example in this article), you must have [http://www.eclipse.org/eclipse/ Eclipse], [http://www.eclipse.org/modeling/emf/?project=emf EMF], and [http://www.eclipse.org/modeling/mdt/?project=uml2 UML2] installed. You can either download the [http://www.eclipse.org/downloads/packages/eclipse-modeling-tools/indigosr1 Modeling Tools Package] or follow these steps:  
+
To start using UML2 (and to follow along with the example in this article), you must have [http://www.eclipse.org/eclipse/ Eclipse], [http://www.eclipse.org/modeling/emf/?project=emf EMF], and [http://www.eclipse.org/modeling/mdt/?project=uml2 UML2] installed. You can either download the [http://www.eclipse.org/downloads/packages/eclipse-modeling-tools/lunam4 Modeling Tools Package] or follow these steps:  
  
 
#Download and run Eclipse.  
 
#Download and run Eclipse.  
 
#Select the '''Help &gt; Install New Software…''' menu item.  
 
#Select the '''Help &gt; Install New Software…''' menu item.  
#Select a software site to work with, e.g., '''Indigo - http://download.eclipse.org/releases/indigo'''.  
+
#Select a software site to work with, e.g., '''Luna - http://download.eclipse.org/releases/luna'''.  
 
#Expand the '''Modeling''' tree item.  
 
#Expand the '''Modeling''' tree item.  
 
#Select '''UML2 Extender SDK''' and press the '''Next &gt;''' button.  
 
#Select '''UML2 Extender SDK''' and press the '''Next &gt;''' button.  
Line 29: Line 29:
  
 
[[Image:GSWU2 Introduction.png]]
 
[[Image:GSWU2 Introduction.png]]
 +
 +
The Ecore profile that we will develop is as follows, comprising only the subset of stereotypes dealing with properties.
 +
 +
[[Image:ITU2P Ecore Profile.png]]
  
 
= Getting Started  =
 
= Getting Started  =
 +
 +
[[Image:GSWU2 tip.gif]] Readers who don't want to follow every step of this tutorial may install a working solution from the '''New &rarr; Example...''' wizard, selecting the '''UML2 Example Projects &rarr; Introduction to UML2 Profiles''' sample.  This will be available when [https://bugs.eclipse.org/bugs/show_bug.cgi?id=382342 Enhancement 382342] is resolved and released in a UML2 build.  This includes the finished profile, complete source code, and a launch configuration that runs the stand-alone Java application which creates the profile in the root folder of the example project, applies it to a test model, and manipulates stereotype attributes ("tagged values").
 +
 +
[[Image:ITU2P ExampleWizard.png]]
  
 
Before getting started, you’ll need to create a simple project in your workspace. This project will serve as the container for the profile that we’ll create using the UML editor. To create a simple project for this article, follow these steps:  
 
Before getting started, you’ll need to create a simple project in your workspace. This project will serve as the container for the profile that we’ll create using the UML editor. To create a simple project for this article, follow these steps:  
Line 38: Line 46:
 
#Select the '''File &gt; New &gt; Project...''' menu item.  
 
#Select the '''File &gt; New &gt; Project...''' menu item.  
 
#Select the '''Project''' wizard from the '''General''' category and press the '''Next &gt;''' button.  
 
#Select the '''Project''' wizard from the '''General''' category and press the '''Next &gt;''' button.  
#Enter a project name (i.e., “Introduction to UML2 Profiles”), and press the '''Finish''' button.
+
#Enter a project name (e.g., “Introduction to UML2 Profiles”), and press the '''Finish''' button.
  
 
At this point your workspace should look something like this:  
 
At this point your workspace should look something like this:  
Line 45: Line 53:
  
 
OK, that should be enough to get us going with the UML editor. Now, to follow along with the programmatic approach to creating profiles, we’ll assume that you’ve created a Java class (named, say, “IntroductionToUML2Profiles”) in which you can write some code to construct our sample profile. The code snippets we’ll show assume you’ve defined the following utility methods to give the user information on the program’s status:  
 
OK, that should be enough to get us going with the UML editor. Now, to follow along with the programmatic approach to creating profiles, we’ll assume that you’ve created a Java class (named, say, “IntroductionToUML2Profiles”) in which you can write some code to construct our sample profile. The code snippets we’ll show assume you’ve defined the following utility methods to give the user information on the program’s status:  
<pre>     public static boolean DEBUG = true;
+
<pre>   public static boolean DEBUG = true;
 
   
 
   
    protected static void out(String output) {
+
    protected static void out(String format, Object... args) {
+
        if (DEBUG) {
        if (DEBUG) {
+
            System.out.printf(format, args);
            System.out.println(output);
+
            if (!format.endsWith("%n")) {
        }
+
                System.out.println();
    }
+
            }
+
        }
    protected static void err(String error) {
+
    }
        System.err.println(error);
+
 
    }
+
    protected static void err(String format, Object... args) {
 +
        System.err.printf(format, args);
 +
        if (!format.endsWith("%n")) {
 +
            System.err.println();
 +
        }
 +
    }
 
</pre>  
 
</pre>  
 
A static debug flag can be used to enable or disable verbose information printed to the system’s output stream. Errors will always be printed to the system’s error stream.  
 
A static debug flag can be used to enable or disable verbose information printed to the system’s output stream. Errors will always be printed to the system’s error stream.  
  
All righty then! In each of the following subsections, we’ll look at how to create or manipulate a different kind of UML element, starting with profiles.  
+
All right, then! In each of the following subsections, we’ll look at how to create or manipulate a different kind of UML element, starting with profiles.  
  
 
= Creating Profiles  =
 
= Creating Profiles  =
Line 66: Line 79:
 
At the root of every UML2 profile is a profile element. It defines limited extensions to a reference metamodel (i.e., UML) with the purpose of adapting the metamodel to a specific platform or domain (e.g., EMF). Metaclasses from the reference metamodel are extended via stereotypes, which are defined as part of profiles. To create a profile using the UML editor, follow these steps:  
 
At the root of every UML2 profile is a profile element. It defines limited extensions to a reference metamodel (i.e., UML) with the purpose of adapting the metamodel to a specific platform or domain (e.g., EMF). Metaclasses from the reference metamodel are extended via stereotypes, which are defined as part of profiles. To create a profile using the UML editor, follow these steps:  
  
#Select a project (i.e., '''Introduction to UML2 Profiles''') in the '''Project Explorer''' view and select the '''File &gt; New &gt; Other...''' menu item.  
+
#Select a project (e.g., '''Introduction to UML2 Profiles''') in the '''Project Explorer''' view and select the '''File &gt; New &gt; Other...''' menu item.  
 
#Select the '''UML Model''' wizard from the '''Example EMF Model Creation Wizards''' category and press the '''Next &gt;''' button.  
 
#Select the '''UML Model''' wizard from the '''Example EMF Model Creation Wizards''' category and press the '''Next &gt;''' button.  
#Enter a file name (i.e., “Ecore.profile.uml”) and press the '''Next &gt;''' button.  
+
#Enter a file name (e.g., “Ecore.profile.uml”) and press the '''Next &gt;''' button.  
 
#Select '''Profile''' for the model object and press the '''Finish''' button.  
 
#Select '''Profile''' for the model object and press the '''Finish''' button.  
 
#Select the '''Window &gt; Show View &gt; Properties''' menu item.  
 
#Select the '''Window &gt; Show View &gt; Properties''' menu item.  
 
#Select the '''&lt;Profile&gt;''' element in the UML editor.  
 
#Select the '''&lt;Profile&gt;''' element in the UML editor.  
#Enter a value (i.e., “ecore”) for the '''Name''' property in the '''Properties''' view.
+
#Enter a value (e.g., “ecore”) for the '''Name''' property in the '''Properties''' view.
 +
#(optional) Enter a value (e.g., <nowiki>"http://www.eclipse.org/schema/UML2/examples/ecore"</nowiki>) for the '''URI''' property in the '''Properties''' view.
 +
 
 +
[[Image:GSWU2 tip.gif]] In UML™, packages may be identified uniquely by assigning URIs.  In UML2 profiles, this URI is used as the namespace URI of the Ecore '''EPackage''' representing the profile metadata in EMF.  By specifying this URI explicitly, you can establish a stable namespace URI that will be used by all successive iterations of your profile schema as it evolves over time.  If you omit the URI, one will be generated automatically by UML2 in the Ecore definition.  This default namespace URI is suffixed by an increasing version number, resulting in a different URI in each successive definition.  A consequence of this is that existing models that have an older profile definition applied will have to be migrated to the new version when it is deployed.  This is useful when incompatible changes are made in the profile from one version to the next.  You may, of course, also change the explicitly set URI yourself, when required.
  
 
[[Image:GSWU2 tip.gif]] By convention, resources that contain profiles end with a '''.profile.uml''' file extension in UML2.  
 
[[Image:GSWU2 tip.gif]] By convention, resources that contain profiles end with a '''.profile.uml''' file extension in UML2.  
Line 81: Line 97:
  
 
Let’s look at how to perform the same task using Java code. The code snippet below shows a method that programmatically creates and returns a profile with a specified name.  
 
Let’s look at how to perform the same task using Java code. The code snippet below shows a method that programmatically creates and returns a profile with a specified name.  
<pre>     protected static Profile createProfile(String name) {
+
<pre>   protected static Profile createProfile(String name, String nsURI) {
        Profile profile = UMLFactory.eINSTANCE.createProfile();
+
        Profile profile = UMLFactory.eINSTANCE.createProfile();
        profile.setName(name);
+
        profile.setName(name);
+
        profile.setURI(nsURI);
        out("Profile '" + profile.getQualifiedName() + "' created.");
+
 
+
        out("Profile '%s' created.", profile.getQualifiedName());
        return profile;
+
 
    }
+
        return profile;
 +
    }
 
</pre>  
 
</pre>  
First, we ask the UML factory singleton to create a profile, and we set its name. Then, we output information to the user to let them know that the profile has been successfully created. Finally, we return the profile. You’ll notice most, if not all, of the code snippets in this article will follow this pattern create the element (and set some properties on it), inform the user, and return it.  
+
First, we ask the UML factory singleton to create a profile, and we set its name and URI. Then, we output information to the user to let them know that the profile has been successfully created. Finally, we return the profile. You’ll notice most, if not all, of the code snippets in this article will follow this patterncreate the element (and set some properties on it), inform the user, and return it.  
  
 
OK, let’s see this method in action. For example, we could create a profile named ‘ecore’ as follows:  
 
OK, let’s see this method in action. For example, we could create a profile named ‘ecore’ as follows:  
<pre>         Profile ecoreProfile = createProfile("ecore");
+
<pre>   Profile ecoreProfile = createProfile("ecore", "http://www.eclipse.org/schema/UML2/examples/ecore");
 
</pre>  
 
</pre>  
 
= Importing Primitive Types  =
 
= Importing Primitive Types  =
Line 99: Line 116:
 
Just like a class, a stereotype may have properties, which may be referred to as tag definitions. The types of these properties may be pre-defined in (domain-specific) libraries referenced by the profile. A profile can be made to reference primitive types from libraries (such as those provided in the '''org.eclipse.uml2.uml.resources''' plug-in) by creating an import relationship between the profile and the primitive type. To import a primitive type using the UML editor, follow these steps:  
 
Just like a class, a stereotype may have properties, which may be referred to as tag definitions. The types of these properties may be pre-defined in (domain-specific) libraries referenced by the profile. A profile can be made to reference primitive types from libraries (such as those provided in the '''org.eclipse.uml2.uml.resources''' plug-in) by creating an import relationship between the profile and the primitive type. To import a primitive type using the UML editor, follow these steps:  
  
#Select a package (i.e., '''&lt;Profile&gt; ecore''') in the UML editor.  
+
#Select a package (e.g., '''&lt;Profile&gt; ecore''') in the UML editor.  
 
#Select the '''UML Editor &gt; Package &gt; Import Type...''' menu item.  
 
#Select the '''UML Editor &gt; Package &gt; Import Type...''' menu item.  
#Choose a primitive type (i.e., '''PrimitiveTypes::Boolean'''), press the '''Add''' button, then press the '''OK''' button.
+
#Choose a primitive type (e.g., '''PrimitiveTypes::Boolean'''), press the '''Add''' button, then press the '''OK''' button.
  
[[Image:GSWU2 tip.gif]] Import the other required primitive type ('''PrimitiveTypes::String''') into the Ecore profile using the UML editor.  
+
[[Image:GSWU2 tryit.gif]] Import the other required primitive type ('''PrimitiveTypes::String''') into the Ecore profile using the UML editor.  
  
 
At this point your workspace should look something like this:  
 
At this point your workspace should look something like this:  
Line 110: Line 127:
  
 
Let’s look at how to perform the same task using Java code. The code snippet below shows a method that programmatically imports the primitive type with a specified name from the UML primitive types library into a specified package and returns it.  
 
Let’s look at how to perform the same task using Java code. The code snippet below shows a method that programmatically imports the primitive type with a specified name from the UML primitive types library into a specified package and returns it.  
<pre>     protected static PrimitiveType importPrimitiveType(org.eclipse.uml2.uml.Package package_, String name) {
+
<pre>   protected static PrimitiveType importPrimitiveType(org.eclipse.uml2.uml.Package package_, String name) {
        Model umlLibrary = (Model) load(URI.createURI(UMLResource.UML_PRIMITIVE_TYPES_LIBRARY_URI));
+
        org.eclipse.uml2.uml.Package umlLibrary = (org.eclipse.uml2.uml.Package) load(URI.createURI(UMLResource.UML_PRIMITIVE_TYPES_LIBRARY_URI));
+
 
        PrimitiveType primitiveType = (PrimitiveType) umlLibrary.getOwnedType(name);
+
        PrimitiveType primitiveType = (PrimitiveType) umlLibrary.getOwnedType(name);
+
 
        package_.createElementImport(primitiveType);
+
        package_.createElementImport(primitiveType);
+
 
        out("Primitive type '" + primitiveType.getQualifiedName() + "' imported.");
+
        out("Primitive type '%s' imported.", primitiveType.getQualifiedName());
+
 
        return primitiveType;
+
        return primitiveType;
    }
+
    }
 
</pre>  
 
</pre>  
Here we load the model library containing the UML primitive types ('''Boolean''', '''Integer''', '''Real''', '''String''', and '''UnlimitedNatural''') using a utility method (described later) and a URI defined on the '''UMLResource''' interface. Next, we retrieve the desired (owned) primitive type from the model by name using one of the convenience methods defined in the UML2 API. Finally, we invoke another convenience method to create the element import relationship between the package and the element (with default public visibility), notify the user, and return the primitive type.  
+
Here we load the model library containing the UML primitive types ('''Boolean''', '''Integer''', '''Real''', '''String''', and '''UnlimitedNatural''') using a '''load(...)''' utility method (described later) and a URI defined on the '''UMLResource''' interface. Next, we retrieve the desired (owned) primitive type from the model by name using one of the convenience methods defined in the UML2 API. Finally, we invoke another convenience method to create the element import relationship between the package and the element (with default public visibility), notify the user, and return the primitive type.  
  
 
[[Image:GSWU2 tip.gif]] The UML resources plug-in ('''org.eclipse.uml2.uml.resources''') provides several model libraries (which by convention have a '''.library.uml''' file extension) that contain commonly used primitive types, such as those defined by Java and EMF (in addition to those defined by UML™ itself). These libraries can be accessed using URIs defined on the '''UMLResource''' interface, as shown above.  
 
[[Image:GSWU2 tip.gif]] The UML resources plug-in ('''org.eclipse.uml2.uml.resources''') provides several model libraries (which by convention have a '''.library.uml''' file extension) that contain commonly used primitive types, such as those defined by Java and EMF (in addition to those defined by UML™ itself). These libraries can be accessed using URIs defined on the '''UMLResource''' interface, as shown above.  
Line 129: Line 146:
  
 
OK, let’s see this method in action. For example, we could import the primitive type named ‘Boolean’ into profile ‘ecore’ as follows:  
 
OK, let’s see this method in action. For example, we could import the primitive type named ‘Boolean’ into profile ‘ecore’ as follows:  
<pre>         PrimitiveType booleanPrimitiveType = importPrimitiveType(ecoreProfile, "Boolean");
+
<pre>   PrimitiveType booleanPrimitiveType = importPrimitiveType(ecoreProfile, "Boolean");
 
</pre>  
 
</pre>  
 
[[Image:GSWU2 tryit.gif]] Write code to programmatically import the other required primitive type (i.e., ‘String’) into the Ecore profile.  
 
[[Image:GSWU2 tryit.gif]] Write code to programmatically import the other required primitive type (i.e., ‘String’) into the Ecore profile.  
Line 137: Line 154:
 
As with packages, profiles can contain enumerations. An enumeration is a kind of data type whose instances may be any of a number of user-defined enumeration literals. To create an enumeration using the UML editor, follow these steps:  
 
As with packages, profiles can contain enumerations. An enumeration is a kind of data type whose instances may be any of a number of user-defined enumeration literals. To create an enumeration using the UML editor, follow these steps:  
  
#Select a profile (i.e., '''&lt;Profile&gt; ecore''') in the UML editor.  
+
#Select a profile (e.g., '''&lt;Profile&gt; ecore''') in the UML editor.  
 
#Select the '''New Child &gt; Owned Type &gt;''''''Enumeration''' option from the context menu.  
 
#Select the '''New Child &gt; Owned Type &gt;''''''Enumeration''' option from the context menu.  
#Enter a value (i.e., “VisibilityKind”) for the '''Name''' property in the '''Properties''' view.
+
#Enter a value (e.g., “VisibilityKind”) for the '''Name''' property in the '''Properties''' view.
  
 
[[Image:GSWU2 tryit.gif]] Create the other enumeration (i.e., “FeatureKind”) for the Ecore profile using the UML editor.  
 
[[Image:GSWU2 tryit.gif]] Create the other enumeration (i.e., “FeatureKind”) for the Ecore profile using the UML editor.  
Line 147: Line 164:
 
[[Image:ITU2P CreatingEnumerations.png]]  
 
[[Image:ITU2P CreatingEnumerations.png]]  
  
Let’s look at how to perform the same task using Java code. The code snippet below (from the '''GettingStartedWithUML2''' class) shows a method that programmatically creates and returns an enumeration with a specified name in a specified package.  
+
Let’s look at how to perform the same task using Java code. The code snippet below (which should be familiar from the [[MDT/UML2/Getting Started with UML2|Getting Started with UML2]] article) shows a method that programmatically creates and returns an enumeration with a specified name in a specified package.  
<pre>     protected static Enumeration createEnumeration(org.eclipse.uml2.uml.Package package_, String name) {
+
<pre>   protected static Enumeration createEnumeration(org.eclipse.uml2.uml.Package package_, String name) {
        Enumeration enumeration = package_.createOwnedEnumeraton(name);
+
        Enumeration enumeration = package_.createOwnedEnumeration(name);
+
 
        out("Enumeration '" + enumeration.getQualifiedName() + "' created.");
+
        out("Enumeration '%s' created.", enumeration.getQualifiedName());
+
 
        return enumeration;
+
        return enumeration;
    }
+
    }
 
</pre>  
 
</pre>  
 
Here we call the '''createOwnedEnumeration(String)''' convenience factory method to ask the package to create a primitive type with the specified name as one of its packaged elements.  
 
Here we call the '''createOwnedEnumeration(String)''' convenience factory method to ask the package to create a primitive type with the specified name as one of its packaged elements.  
  
 
OK, let’s see this method in action. For example, we could create an enumeration named ‘VisibilityKind’ in profile ‘ecore’ as follows:  
 
OK, let’s see this method in action. For example, we could create an enumeration named ‘VisibilityKind’ in profile ‘ecore’ as follows:  
<pre>         Enumeration visibilityKindEnumeration = GettingStartedWithUML2.createEnumeration(ecoreProfile, "VisibilityKind");
+
<pre>   Enumeration visibilityKindEnumeration = createEnumeration(ecoreProfile, "VisibilityKind");
 
</pre>  
 
</pre>  
 
[[Image:GSWU2 tryit.gif]] Write code to programmatically create the other enumeration (i.e., ‘FeatureKind’) for the Ecore profile.
 
[[Image:GSWU2 tryit.gif]] Write code to programmatically create the other enumeration (i.e., ‘FeatureKind’) for the Ecore profile.
Line 167: Line 184:
 
An enumeration literal is a user-defined data value for an enumeration. To create an enumeration literal using the UML editor, follow these steps:  
 
An enumeration literal is a user-defined data value for an enumeration. To create an enumeration literal using the UML editor, follow these steps:  
  
#Select an enumeration (i.e., '''&lt;Enumeration&gt; VisibilityKind''') in the UML editor.  
+
#Select an enumeration (e.g., '''&lt;Enumeration&gt; VisibilityKind''') in the UML editor.  
 
#Select the '''New Child &gt; Owned Literal &gt; Enumeration Literal''' option from the context menu.  
 
#Select the '''New Child &gt; Owned Literal &gt; Enumeration Literal''' option from the context menu.  
#Enter a value (i.e., “Unspecified”) for the '''Name''' property in the '''Properties''' view.
+
#Enter a value (e.g., “Unspecified”) for the '''Name''' property in the '''Properties''' view.
  
 
[[Image:GSWU2 tryit.gif]] Create the remaining enumeration literals for the Ecore profile (i.e., “None”, “ReadOnly”, “ReadWrite”, “ReadOnlyUnsettable”, and “ReadWriteUnsettable” for '''&lt;Enumeration&gt; VisibilityKind'''; “Unspecified”, “Simple”, “Attribute”, “Element”, “AttributeWildcard”, “ElementWildcard”, and “Group” for '''&lt;Enumeration&gt; FeatureKind''') using the UML editor.  
 
[[Image:GSWU2 tryit.gif]] Create the remaining enumeration literals for the Ecore profile (i.e., “None”, “ReadOnly”, “ReadWrite”, “ReadOnlyUnsettable”, and “ReadWriteUnsettable” for '''&lt;Enumeration&gt; VisibilityKind'''; “Unspecified”, “Simple”, “Attribute”, “Element”, “AttributeWildcard”, “ElementWildcard”, and “Group” for '''&lt;Enumeration&gt; FeatureKind''') using the UML editor.  
Line 177: Line 194:
 
[[Image:ITU2P CreatingEnumerationLiterals.png]]  
 
[[Image:ITU2P CreatingEnumerationLiterals.png]]  
  
Let’s look at how to perform the same task using Java code. The code snippet below (from the '''GettingStartedWithUML2''' class) shows a method that programmatically creates and returns an enumeration literal with a specified name in a specified enumeration.  
+
Let’s look at how to perform the same task using Java code. The code snippet below shows a method that programmatically creates and returns an enumeration literal with a specified name in a specified enumeration.  
<pre>     protected static EnumerationLiteral createEnumerationLiteral(Enumeration enumeration, String name) {
+
<pre>   protected static EnumerationLiteral createEnumerationLiteral(Enumeration enumeration, String name) {
        EnumerationLiteral enumerationLiteral = enumeration.createOwnedLiteral(name);
+
        EnumerationLiteral enumerationLiteral = enumeration.createOwnedLiteral(name);
+
 
        out("Enumeration literal '" + enumerationLiteral.getQualifiedName() + "' created.");
+
        out("Enumeration literal '%s' created.", enumerationLiteral.getQualifiedName());
+
 
        return enumerationLiteral;
+
        return enumerationLiteral;
    }
+
    }
 
</pre>  
 
</pre>  
 
Here we call the '''createOwnedLiteral(String)''' convenience factory method to ask the enumeration to create an enumeration literal with the specified name as one of its owned literals.  
 
Here we call the '''createOwnedLiteral(String)''' convenience factory method to ask the enumeration to create an enumeration literal with the specified name as one of its owned literals.  
  
 
OK, let’s see this method in action. For example, we could create an enumeration literal named ‘Unspecified’ in enumeration ‘VisibilityKind’ as follows:  
 
OK, let’s see this method in action. For example, we could create an enumeration literal named ‘Unspecified’ in enumeration ‘VisibilityKind’ as follows:  
<pre>         GettingStartedWithUML2.createEnumerationLiteral(visibilityKindEnumeration, "Unspecified");
+
<pre>   createEnumerationLiteral(visibilityKindEnumeration, "Unspecified");
 
</pre>  
 
</pre>  
 
[[Image:GSWU2 tryit.gif]] Write code to programmatically create the remaining enumeration literals (i.e., ‘None’, ‘ReadOnly’, ‘ReadWrite’, ‘ReadOnlyUnsettable’, and ‘ReadWriteUnsettable’ in enumeration ‘VisibilityKind’; ‘Unspecified’, ‘Simple’, ‘Attribute’, ‘Element’, ‘AttributeWildcard’, ‘ElementWildcard’, and ‘Group’ in enumeration ‘FeatureKind’) for the Ecore profile.  
 
[[Image:GSWU2 tryit.gif]] Write code to programmatically create the remaining enumeration literals (i.e., ‘None’, ‘ReadOnly’, ‘ReadWrite’, ‘ReadOnlyUnsettable’, and ‘ReadWriteUnsettable’ in enumeration ‘VisibilityKind’; ‘Unspecified’, ‘Simple’, ‘Attribute’, ‘Element’, ‘AttributeWildcard’, ‘ElementWildcard’, and ‘Group’ in enumeration ‘FeatureKind’) for the Ecore profile.  
Line 197: Line 214:
 
A stereotype defines how an existing metaclass may be extended, and enables the use of platform- or domain-specific terminology or notation in place of, or in addition to, the ones used for the extended metaclass. Each stereotype may extend one or more classes through extensions as part of a profile. To create a stereotype using the UML editor, follow these steps:  
 
A stereotype defines how an existing metaclass may be extended, and enables the use of platform- or domain-specific terminology or notation in place of, or in addition to, the ones used for the extended metaclass. Each stereotype may extend one or more classes through extensions as part of a profile. To create a stereotype using the UML editor, follow these steps:  
  
#Select a profile (i.e., '''&lt;Profile&gt; ecore''') in the UML editor.  
+
#Select a profile (e.g., '''&lt;Profile&gt; ecore''') in the UML editor.  
 
#Select the '''New Child &gt; Owned Stereotype &gt; Stereotype''' option from the context menu.  
 
#Select the '''New Child &gt; Owned Stereotype &gt; Stereotype''' option from the context menu.  
#Enter a value (i.e., “EStructuralFeature”) for the '''Name''' property in the '''Properties''' view.  
+
#Enter a value (e.g., “EStructuralFeature”) for the '''Name''' property in the '''Properties''' view.  
#Select a value (i.e., '''true''') for the '''Is Abstract''' property in the '''Properties''' view.
+
#Select a value (e.g., '''true''') for the '''Is Abstract''' property in the '''Properties''' view.
  
 
[[Image:GSWU2 tryit.gif]] Create the remaining stereotypes for the Ecore profile (i.e., “EAttribute” and “EReference”) using the UML editor.  
 
[[Image:GSWU2 tryit.gif]] Create the remaining stereotypes for the Ecore profile (i.e., “EAttribute” and “EReference”) using the UML editor.  
Line 209: Line 226:
  
 
Let’s look at how to perform the same task using Java code. The code snippet below shows a method that programmatically creates and returns a(n) (abstract) stereotype with a specified name in a specified profile.  
 
Let’s look at how to perform the same task using Java code. The code snippet below shows a method that programmatically creates and returns a(n) (abstract) stereotype with a specified name in a specified profile.  
<pre>     protected static Stereotype createStereotype(Profile profile, String name, boolean isAbstract) {
+
<pre>   protected static Stereotype createStereotype(Profile profile, String name, boolean isAbstract) {
        Stereotype stereotype = profile.createOwnedStereotype(name, isAbstract);
+
        Stereotype stereotype = profile.createOwnedStereotype(name, isAbstract);
+
 
        out("Stereotype '" + stereotype.getQualifiedName() + "' created.");
+
        out("Stereotype '%s' created.", stereotype.getQualifiedName());
+
 
        return stereotype;
+
        return stereotype;
    }
+
    }
 
</pre>  
 
</pre>  
 
Here we call the '''createOwnedStereotype(String, boolean)''' convenience factory method to ask the profile to create a stereotype with the specified name as one of its owned members, and set the '''isAbstract''' attribute of the stereotype based on the specified boolean argument.  
 
Here we call the '''createOwnedStereotype(String, boolean)''' convenience factory method to ask the profile to create a stereotype with the specified name as one of its owned members, and set the '''isAbstract''' attribute of the stereotype based on the specified boolean argument.  
  
 
OK, let’s see this method in action. For example, we could create an abstract stereotype named ‘EStructuralFeature’ in profile ‘ecore’ as follows:  
 
OK, let’s see this method in action. For example, we could create an abstract stereotype named ‘EStructuralFeature’ in profile ‘ecore’ as follows:  
<pre>         Stereotype eStructuralFeatureStereotype = createStereotype(ecoreProfile, "EStructuralFeature", true);
+
<pre>   Stereotype eStructuralFeatureStereotype = createStereotype(ecoreProfile, "EStructuralFeature", true);
 
</pre>  
 
</pre>  
 
[[Image:GSWU2 tryit.gif]] Write code to programmatically create the remaining (non-abstract) stereotypes (i.e., ‘EAttribute’ and ‘EReference’) for the Ecore profile.  
 
[[Image:GSWU2 tryit.gif]] Write code to programmatically create the remaining (non-abstract) stereotypes (i.e., ‘EAttribute’ and ‘EReference’) for the Ecore profile.  
Line 226: Line 243:
 
= Creating Stereotype Generalizations  =
 
= Creating Stereotype Generalizations  =
  
Just like classes, stereotypes may be involved in generalizations. A generalization is a taxonomic relationship between a specific classifier and a more general classifier whereby each instance of the specific classifier is also an indirect instance of, and inherits the features of, the general classifier. To create a stereotype generalization using the UML editor, follow these steps:  
+
Just like classes, stereotypes may be involved in generalizations (stereotypes are a kind of class). A generalization is a taxonomic relationship between a specific classifier and a more general classifier whereby each instance of the specific classifier is also an indirect instance of, and inherits the features of, the general classifier. To create a stereotype generalization using the UML editor, follow these steps:  
  
#Select a stereotype (i.e., '''&lt;Stereotype&gt; EAttribute''') in the UML editor.  
+
#Select a stereotype (e.g., '''&lt;Stereotype&gt; EAttribute''') in the UML editor.  
 
#Select the '''New Child &gt; Generalization &gt; Generalization''' option from the context menu.  
 
#Select the '''New Child &gt; Generalization &gt; Generalization''' option from the context menu.  
#Select a value (i.e., '''ecore::EStructuralFeature''') for the '''General''' property in the '''Properties''' view.
+
#Select a value (e.g., '''ecore::EStructuralFeature''') for the '''General''' property in the '''Properties''' view.
  
 
[[Image:GSWU2 tryit.gif]] Create the other generalization (i.e., between '''EReference''' and '''EStructuralFeature''') for the Ecore profile using the UML editor.  
 
[[Image:GSWU2 tryit.gif]] Create the other generalization (i.e., between '''EReference''' and '''EStructuralFeature''') for the Ecore profile using the UML editor.  
Line 240: Line 257:
 
[[Image:ITU2P CreatingStereotypeGeneralizations.png]]  
 
[[Image:ITU2P CreatingStereotypeGeneralizations.png]]  
  
Let’s look at how to perform the same task using Java code. The code snippet below (from the '''GettingStartedWithUML2''' class) shows a method that programmatically creates and returns generalization between specified specific and general classifiers.  
+
Let’s look at how to perform the same task using Java code. The code snippet below shows a method that programmatically creates and returns generalization between specified specific and general classifiers.  
<pre>     protected static Generalization createGeneralization(Classifier specificClassifier, Classifier generalClassifier) {
+
<pre>   protected static Generalization createGeneralization(Classifier specificClassifier, Classifier generalClassifier) {
        Generalization generalization = specificClassifier.createGeneralization(generalClassifier);
+
        Generalization generalization = specificClassifier.createGeneralization(generalClassifier);
+
 
        out("Generalization " + specificClassifier.getQualifiedName() + " -&gt;&gt; " + generalClassifier.getQualifiedName() + " created.");
+
        out("Generalization %s --|> %s created.", specificClassifier.getQualifiedName(), generalClassifier.getQualifiedName());
+
 
        return generalization;
+
        return generalization;
    }
+
    }
 
</pre>  
 
</pre>  
 
Here we call a convenience factory method on the specific classifier that creates a generalization as one of its children and sets the general classifier to the specified argument.  
 
Here we call a convenience factory method on the specific classifier that creates a generalization as one of its children and sets the general classifier to the specified argument.  
  
 
OK, let’s see this method in action. For example, we could create a generalization between specific stereotype ‘EAttribute’ and general stereotype ‘EStructuralFeature’ as follows:  
 
OK, let’s see this method in action. For example, we could create a generalization between specific stereotype ‘EAttribute’ and general stereotype ‘EStructuralFeature’ as follows:  
<pre>         GettingStartedWithUML2.createGeneralization(eAttributeStereotype, eStructuralFeatureStereotype);
+
<pre>   createGeneralization(eAttributeStereotype, eStructuralFeatureStereotype);
 
</pre>  
 
</pre>  
 
[[Image:GSWU2 tryit.gif]] Write code to programmatically create the other generalization (i.e., between ‘EReference’ and ‘EStructuralFeature’) for the Ecore profile.  
 
[[Image:GSWU2 tryit.gif]] Write code to programmatically create the other generalization (i.e., between ‘EReference’ and ‘EStructuralFeature’) for the Ecore profile.  
Line 260: Line 277:
 
Again just like classes, stereotypes may have properties (attributes). When a stereotype is applied to a model element, the values of the properties may be referred to as tagged values. To create a stereotype property using the UML editor, follow these steps:  
 
Again just like classes, stereotypes may have properties (attributes). When a stereotype is applied to a model element, the values of the properties may be referred to as tagged values. To create a stereotype property using the UML editor, follow these steps:  
  
#Select a stereotype (i.e., '''&lt;Stereotype&gt; EStructuralFeature''') in the UML editor.  
+
#Select a stereotype (e.g., '''&lt;Stereotype&gt; EStructuralFeature''') in the UML editor.  
 
#Select the '''New Child &gt; Owned Attribute &gt; Property''' option from the context menu.  
 
#Select the '''New Child &gt; Owned Attribute &gt; Property''' option from the context menu.  
#Enter a value (i.e., "isTransient”) for the '''Name''' property in the '''Properties''' view.  
+
#Enter a value (e.g., "isTransient”) for the '''Name''' property in the '''Properties''' view.  
#Select a value (i.e., '''PrimitiveTypes::Boolean''') for the '''Type''' property in the '''Properties''' view.  
+
#Select a value (e.g., '''PrimitiveTypes::Boolean''') for the '''Type''' property in the '''Properties''' view.  
#Enter a value (i.e., '''0''') for the '''Lower''' property in the '''Properties''' view.  
+
#Enter a value (e.g., '''0''') for the '''Lower''' property in the '''Properties''' view.  
#Select the property (i.e., '''&lt;Property&gt; isTransient''') in the UML editor.  
+
#Select the property (e.g., '''&lt;Property&gt; isTransient''') in the UML editor.  
#Select the '''New Child &gt; Default Value &gt; Literal Boolean''' option from the context menu.
+
#Select a value (e.g., '''false''') from the pick-list in the '''Default''' property in the '''Properties''' view.
  
[[Image:GSWU2 tip.gif]] Default values for properties (and parameters) are represented as value specifications (first-class objects) in UML™ 2.x. Here we have selected a literal Boolean (whose default value is '''false''') as the default value of our property since its type is '''Boolean'''. If the type of the property were '''String''', we’d have used a literal string instead. Once a default value specification has been created, its value can alternatively be set with the owning property selected via the '''Default''' property in the '''Properties''' view.  
+
[[Image:GSWU2 tip.gif]] Default values for properties (and parameters) are represented as value specifications (first-class objects) in UML™ 2.x. Here we have selected a literal Boolean (whose default value is '''false''') as the default value of our property since its type is '''Boolean'''. If the type of the property were '''String''', we’d have used a literal string instead. Once a default value specification has been created, its value can alternatively be set with the owning property selected via the '''Default''' property in the '''Properties''' view.  For attributes typed by the UML™ standard primitive types or by enumeration types, the '''Default''' property in the property sheet provides assistance in creating value specifications of the appropriate type.  For other types (e.g., custom data types or classes), it is necessary to explicitly create the '''Default Value''' value specification.
  
 
[[Image:GSWU2 tryit.gif]] Create the remaining stereotype properties for the Ecore profile (i.e., “isUnsettable”, “isVolatile”, “visibility”, “xmlName”, “xmlNamespace”, and “xmlFeatureKind” for '''&lt;Stereotype&gt; EStructuralFeature'''; “attributeName” for '''&lt;Stereotype&gt; EAttribute'''; “referenceName” and “isResolveProxies” for '''&lt;Stereotype&gt; EReference''') using the UML editor.  
 
[[Image:GSWU2 tryit.gif]] Create the remaining stereotype properties for the Ecore profile (i.e., “isUnsettable”, “isVolatile”, “visibility”, “xmlName”, “xmlNamespace”, and “xmlFeatureKind” for '''&lt;Stereotype&gt; EStructuralFeature'''; “attributeName” for '''&lt;Stereotype&gt; EAttribute'''; “referenceName” and “isResolveProxies” for '''&lt;Stereotype&gt; EReference''') using the UML editor.  
Line 278: Line 295:
 
[[Image:ITU2P CreatingStereotypeProperties.png]]  
 
[[Image:ITU2P CreatingStereotypeProperties.png]]  
  
Let’s look at how to perform the same task using Java code. The code snippet below (from the '''GettingStartedWithUML2''' class) shows a method that programmatically creates and returns an attribute with a specified upper bound, lower bound, type, and name in a specified class.  
+
Let’s look at how to perform the same task using Java code. The code snippet below shows a method that programmatically creates and returns an attribute with a specified upper bound, lower bound, type, name, and (optionally) default value in a specified class.  
<pre>     protected static Property createAttribute(org.eclipse.uml2.uml.Class class_, String name, Type type, int lowerBound, int upperBound) {
+
<pre>   protected static Property createAttribute(org.eclipse.uml2.uml.Class class_, String name, Type type, int lowerBound, int upperBound, Object defaultValue) {
        Property attribute = class_.createOwnedAttribute(name, type, lowerBound, upperBound);
+
        Property attribute = class_.createOwnedAttribute(name, type, lowerBound, upperBound);
+
 
        StringBuffer sb = new StringBuffer();
+
        if (defaultValue instanceof Boolean) {
+
            LiteralBoolean literal = (LiteralBoolean) attribute.createDefaultValue(null, null, UMLPackage.Literals.LITERAL_BOOLEAN);
        sb.append("Attribute '");
+
            literal.setValue(((Boolean) defaultValue).booleanValue());
+
        } else if (defaultValue instanceof String) {
        sb.append(attribute.getQualifiedName());
+
            if (type instanceof Enumeration) {
+
                InstanceValue value = (InstanceValue) attribute.createDefaultValue(null, null, UMLPackage.Literals.INSTANCE_VALUE);
        sb.append("'&nbsp;: ");
+
                value.setInstance(((Enumeration) type).getOwnedLiteral((String) defaultValue));
+
            } else {
        sb.append(type.getQualifiedName());
+
                LiteralString literal = (LiteralString) attribute.createDefaultValue(null, null, UMLPackage.Literals.LITERAL_STRING);
+
                literal.setValue((String) defaultValue);
        sb.append(" [");
+
            }
        sb.append(lowerBound);
+
        }
        sb.append("..");
+
 
        sb.append(LiteralUnlimitedNatural.UNLIMITED == upperBound&nbsp;? "*"&nbsp;: String.valueOf(upperBound));
+
        out("Attribute '%s' : %s [%s..%s]%s created.", //
        sb.append("]");
+
            attribute.getQualifiedName(), // attribute name
+
            type.getQualifiedName(), // type name
        sb.append(" created.");
+
            lowerBound, // no special case for multiplicity lower bound
+
            (upperBound == LiteralUnlimitedNatural.UNLIMITED)
        out(sb.toString());
+
                ? "*" // special case for unlimited bound
+
                : upperBound, // finite upper bound
        return attribute;
+
            (defaultValue == null)
    }
+
                ? "" // no default value (use type's intrinsic default)
 +
                : String.format(" = %s", defaultValue));
 +
 
 +
        return attribute;
 +
    }
 
</pre>  
 
</pre>  
Here we call the '''createOwnedAttribute(String, Type, int, int)''' convenience factory method to ask the class to create a property as one of its owned attributes, set the type of the attribute to the specified type, and set the lower and upper bounds of the attribute (the factory method creates a literal integer and literal unlimited natural, respectively, and sets its value to the specified integer value).  
+
Here we call the '''createOwnedAttribute(String, Type, int, int)''' convenience factory method to ask the class to create a property as one of its owned attributes, set the type of the attribute to the specified type, and set the lower and upper bounds of the attribute (the factory method creates a literal integer and literal unlimited natural, respectively, and sets its value to the specified integer value).  If a default value is provided, we create a value specification of the appropriate type (in this example, only booleans, strings, and enumeration literals are handled).
  
 
[[Image:GSWU2 tip.gif]] The '''LiteralUnlimitedNatural.UNLIMITED''' constant represents the unlimited value for upper bounds ('''-1'''), as it does in EMF.  
 
[[Image:GSWU2 tip.gif]] The '''LiteralUnlimitedNatural.UNLIMITED''' constant represents the unlimited value for upper bounds ('''-1'''), as it does in EMF.  
  
 
OK, let’s see this method in action. For example, we could create an attribute with multiplicity '''0..1''' of type ‘UMLPrimitiveTypes::Boolean’ named ‘isTransient’ in stereotype ‘EStructuralFeature’ as follows:  
 
OK, let’s see this method in action. For example, we could create an attribute with multiplicity '''0..1''' of type ‘UMLPrimitiveTypes::Boolean’ named ‘isTransient’ in stereotype ‘EStructuralFeature’ as follows:  
<pre>         Property isTransientProperty = GettingStartedWithUML2.createAttribute(eStructuralFeatureStereotype, "isTransient", booleanPrimitiveType, 0, 1);
+
<pre>   Property isTransientProperty = createAttribute(eStructuralFeatureStereotype, "isTransient", booleanPrimitiveType, 0, 1, null);
 
</pre>  
 
</pre>  
 
[[Image:GSWU2 tryit.gif]] Write code to programmatically create the remaining stereotype properties (i.e., ‘isUnsettable’, ‘isVolatile’, ‘visibility’, ‘xmlName’, ‘xmlNamespace’, and ‘xmlFeatureKind’ in stereotype ‘EStructuralFeature’; ‘attributeName’ in stereotype ‘EAttribute’; ‘referenceName’ and ‘isResolveProxies’ in stereotype ‘EReference’) for the Ecore profile.  
 
[[Image:GSWU2 tryit.gif]] Write code to programmatically create the remaining stereotype properties (i.e., ‘isUnsettable’, ‘isVolatile’, ‘visibility’, ‘xmlName’, ‘xmlNamespace’, and ‘xmlFeatureKind’ in stereotype ‘EStructuralFeature’; ‘attributeName’ in stereotype ‘EAttribute’; ‘referenceName’ and ‘isResolveProxies’ in stereotype ‘EReference’) for the Ecore profile.  
Line 316: Line 337:
 
= Referencing Metaclasses  =
 
= Referencing Metaclasses  =
  
A profile is a restricted form of a metamodel that must always be related to a reference metamodel (i.e., UML). A profile cannot be used without its reference metamodel; it defines a limited capability to extend metaclasses of the reference metamodel via stereotypes. Profiles can be made to reference metaclasses from metamodels by creating an import relationship between the profile and the reference metaclass. To reference a metaclass using the UML editor, follow these steps:  
+
A profile is a restricted form of a metamodel that must always be related to a reference metamodel (e.g., UML). A profile cannot be used without its reference metamodel; it defines a limited capability to extend metaclasses of the reference metamodel via stereotypes. Profiles can be made to reference metaclasses from metamodels by creating an import relationship between the profile and the reference metaclass. To reference a metaclass using the UML editor, follow these steps:  
  
#Select a profile (i.e., '''&lt;Profile&gt; ecore''') in the UML editor.  
+
#Select a profile (e.g., '''&lt;Profile&gt; ecore''') in the UML editor.  
 
#Select the '''UML Editor &gt; Profile &gt; Reference Metaclass...''' menu item.  
 
#Select the '''UML Editor &gt; Profile &gt; Reference Metaclass...''' menu item.  
#Choose a metaclass (i.e., '''UML::Property'''), press the '''Add''' button, then press the '''OK''' button.
+
#Choose a metaclass (e.g., '''UML::Property'''), press the '''Add''' button, then press the '''OK''' button.
  
 
At this point your workspace should look something like this:  
 
At this point your workspace should look something like this:  
Line 327: Line 348:
  
 
Let’s look at how to perform the same task using Java code. The code snippet below shows a method that programmatically references the metaclass with a specified name in the UML metamodel from a specified profile and returns it.  
 
Let’s look at how to perform the same task using Java code. The code snippet below shows a method that programmatically references the metaclass with a specified name in the UML metamodel from a specified profile and returns it.  
<pre>     protected static org.eclipse.uml2.uml.Class referenceMetaclass(Profile profile, String name) {
+
<pre>   protected static org.eclipse.uml2.uml.Class referenceMetaclass(Profile profile, String name) {
        Model umlMetamodel = (Model) load(URI.createURI(UMLResource.UML_METAMODEL_URI));
+
        Model umlMetamodel = (Model) load(URI.createURI(UMLResource.UML_METAMODEL_URI));
+
 
        org.eclipse.uml2.uml.Class metaclass = (org.eclipse.uml2.uml.Class) umlMetamodel.getOwnedType(name);
+
        org.eclipse.uml2.uml.Class metaclass = (org.eclipse.uml2.uml.Class) umlMetamodel.getOwnedType(name);
+
 
        profile.createMetaclassReference(metaclass);
+
        profile.createMetaclassReference(metaclass);
+
 
        out("Metaclass '" + metaclass.getQualifiedName() + "' referenced.");
+
        out("Metaclass '%s' referenced.", metaclass.getQualifiedName());
+
 
        return metaclass;
+
        return metaclass;
    }
+
    }
 
</pre>  
 
</pre>  
Here we load the metamodel containing the UML metaclasses using a utility method (described later) and a URI defined on the '''UMLResource''' interface. Next, we retrieve the desired (owned) metaclass from the (meta)model by name using the convenience method. Finally, we invoke another convenience method to create the element import relationship between the profile and the metaclass, notify the user, and return the metaclass.  
+
Here we load the metamodel containing the UML metaclasses using a '''load(...)''' utility method (described later) and a URI defined on the '''UMLResource''' interface. Next, we retrieve the desired (owned) metaclass from the (meta)model by name using the convenience method. Finally, we invoke another convenience method to create the element import relationship between the profile and the metaclass, notify the user, and return the metaclass.  
  
 
[[Image:GSWU2 tip.gif]] The UML resources plug-in ('''org.eclipse.uml2.uml.resources''') provides two metamodels (which by convention have a '''.metamodel.uml''' file extension), UML and Ecore. These metamodels can be accessed using URIs defined on the UMLResource interface, as shown above.  
 
[[Image:GSWU2 tip.gif]] The UML resources plug-in ('''org.eclipse.uml2.uml.resources''') provides two metamodels (which by convention have a '''.metamodel.uml''' file extension), UML and Ecore. These metamodels can be accessed using URIs defined on the UMLResource interface, as shown above.  
  
 
OK, let’s see this method in action. For example, we could reference the metaclass named ‘Property’ from profile ‘ecore’ as follows:  
 
OK, let’s see this method in action. For example, we could reference the metaclass named ‘Property’ from profile ‘ecore’ as follows:  
<pre>         org.eclipse.uml2.uml.Class propertyMetaclass = referenceMetaclass(ecoreProfile, UMLPackage.Literals.PROPERTY.getName());
+
<pre>   org.eclipse.uml2.uml.Class propertyMetaclass = referenceMetaclass(ecoreProfile, UMLPackage.Literals.PROPERTY.getName());
 
</pre>  
 
</pre>  
 
= Creating Extensions  =
 
= Creating Extensions  =
Line 350: Line 371:
 
Extensions are used to indicate that the properties of metaclasses are extended through stereotypes, and give the ability to flexibly apply (and later unapply) stereotypes to elements. An extension is a kind of association, one end of which is an ordinary property, and the other is an extension end. An extension may be required (depending on the lower bound of the extension end), which indicates that an instance of the extending stereotype must be created whenever an instance of the extended metaclass is created. To create an extension using the UML editor, follow these steps:  
 
Extensions are used to indicate that the properties of metaclasses are extended through stereotypes, and give the ability to flexibly apply (and later unapply) stereotypes to elements. An extension is a kind of association, one end of which is an ordinary property, and the other is an extension end. An extension may be required (depending on the lower bound of the extension end), which indicates that an instance of the extending stereotype must be created whenever an instance of the extended metaclass is created. To create an extension using the UML editor, follow these steps:  
  
#Select a stereotype (i.e., '''&lt;Stereotype&gt; EAttribute''') in the UML editor.  
+
#Select a stereotype (e.g., '''&lt;Stereotype&gt; EAttribute''') in the UML editor.  
 
#Select the '''UML Editor &gt; Stereotype &gt; Create Extension...''' menu item.  
 
#Select the '''UML Editor &gt; Stereotype &gt; Create Extension...''' menu item.  
#Choose a metaclass (i.e., '''UML::Property'''), press the '''Add''' button, then press the '''OK''' button.
+
#Choose a metaclass (e.g., '''UML::Property'''), press the '''Add''' button, then press the '''OK''' button.
  
 
[[Image:GSWU2 tryit.gif]] Create the other extension (i.e., between '''UML::Property''' and '''&lt;Stereotype&gt; EReference''') for the Ecore profile using the UML editor.  
 
[[Image:GSWU2 tryit.gif]] Create the other extension (i.e., between '''UML::Property''' and '''&lt;Stereotype&gt; EReference''') for the Ecore profile using the UML editor.  
Line 363: Line 384:
  
 
Let’s look at how to perform the same task using Java code. The code snippet below shows a method that programmatically creates and returns a(n) (required) extension between a specified metaclass and a specified stereotype.  
 
Let’s look at how to perform the same task using Java code. The code snippet below shows a method that programmatically creates and returns a(n) (required) extension between a specified metaclass and a specified stereotype.  
<pre>     protected static Extension createExtension(org.eclipse.uml2.uml.Class metaclass, Stereotype stereotype, boolean required) {
+
<pre>   protected static Extension createExtension(org.eclipse.uml2.uml.Class metaclass, Stereotype stereotype, boolean required) {
        Extension extension = stereotype.createExtension(metaclass, required);
+
        Extension extension = stereotype.createExtension(metaclass, required);
+
 
        out((required&nbsp;? "Required extension '"&nbsp;: "Extension '") + extension.getQualifiedName() + "' created.");
+
        out("%sxtension '%s' created.", //
+
            required
        return extension;
+
                ? "Required e" // it's a required extension
    }
+
                : "E", // an optional extension
 +
            extension.getQualifiedName());
 +
 
 +
        return extension;
 +
    }
 
</pre>  
 
</pre>  
 
Here we call a convenience method on the stereotype that creates an extension (and its ends) between it and a metaclass as one of its siblings (i.e., as a child of its profile namespace). Behind the scenes, the stereotype also creates the ends of the extension, resulting in a new property on the stereotype (with a special name) and an extension end owned by the extension (again, with a special name).  
 
Here we call a convenience method on the stereotype that creates an extension (and its ends) between it and a metaclass as one of its siblings (i.e., as a child of its profile namespace). Behind the scenes, the stereotype also creates the ends of the extension, resulting in a new property on the stereotype (with a special name) and an extension end owned by the extension (again, with a special name).  
  
 
OK, let’s see this method in action. For example, we could create a non-required extension between metaclass ‘Property’ and stereotype ‘EAttribute’ in profile ‘ecore’ as follows:  
 
OK, let’s see this method in action. For example, we could create a non-required extension between metaclass ‘Property’ and stereotype ‘EAttribute’ in profile ‘ecore’ as follows:  
<pre>         createExtension(propertyMetaclass, eAttributeStereotype, false);
+
<pre>   createExtension(propertyMetaclass, eAttributeStereotype, false);
 
</pre>  
 
</pre>  
 
[[Image:GSWU2 tryit.gif]] Write code to programmatically create the other extension (i.e., between metaclass ‘Property’ and stereotype ‘EReference’) for the Ecore profile.
 
[[Image:GSWU2 tryit.gif]] Write code to programmatically create the other extension (i.e., between metaclass ‘Property’ and stereotype ‘EReference’) for the Ecore profile.
Line 380: Line 405:
 
= Defining Profiles  =
 
= Defining Profiles  =
  
There. We’re done creating (a scaled down version of) the Ecore profile, and we’re ready to start using it. But before we can, there’s one final thing we need to do ''define'' it. Since a profile effectively represents an augmentation of a reference metamodel (UML), in order for the extensions we’ve defined to appear as though they’re part of the UML metamodel, they need to be “defined” at the meta-metamodel (i.e., Ecore) level. The implementation of profile support in UML2 supports defining both dynamic and static profile representations. In this article, we'll focus on the former.  
+
There. We’ve finished creating (a scaled down version of) the Ecore profile, and we’re ready to start using it. But before we can, there’s one final thing we need to do''define'' it. Since a profile effectively represents an augmentation of a reference metamodel (UML), in order for the extensions we’ve defined to appear as though they’re part of the UML metamodel, they need to be “defined” at the meta-metamodel (i.e., Ecore) level. The implementation of profile support in UML2 supports defining both dynamic and static profile representations. In this article, we'll focus on the former.  
  
 
When defining a dynamic profile representation, the contents of a profile are converted to an equivalent Ecore format that is stored as an annotation on the profile. Then, when a profile and its stereotypes are applied to a model and its elements, dynamic EMF (see the EMF book for details) is used to store property values for the stereotypes. For the most part, you can ignore this complexity, as long as you remember to define your profile before using it. To define a dynamic profile representation using the UML editor, follow these steps:  
 
When defining a dynamic profile representation, the contents of a profile are converted to an equivalent Ecore format that is stored as an annotation on the profile. Then, when a profile and its stereotypes are applied to a model and its elements, dynamic EMF (see the EMF book for details) is used to store property values for the stereotypes. For the most part, you can ignore this complexity, as long as you remember to define your profile before using it. To define a dynamic profile representation using the UML editor, follow these steps:  
Line 391: Line 416:
 
[[Image:ITU2P DefiningProfiles.png]]  
 
[[Image:ITU2P DefiningProfiles.png]]  
  
You’ll notice that an annotation with source '''http://www.eclipse.org/uml2/2.0.0/UML''' has been attached to the profile. It contains the generated Ecore representation (an Ecore package with classes, attributes, enums, etc.) of the profile. As with extensions, it’s important that this annotation (and its contents) not be modified, since the UML2 profile mechanism depends on these constructs.  
+
You’ll notice that an annotation with source <nowiki>"http://www.eclipse.org/uml2/2.0.0/UML"</nowiki> has been attached to the profile. It contains the generated Ecore representation (an Ecore package with classes, attributes, enums, etc.) of the profile. As with extensions, it’s important that this annotation (and its contents) not be modified, since the UML2 profile mechanism depends on these constructs.  
  
 
Let’s look at how to perform the same task using Java code. The code snippet below shows a method that programmatically defines a specified profile.  
 
Let’s look at how to perform the same task using Java code. The code snippet below shows a method that programmatically defines a specified profile.  
<pre>     protected static void defineProfile(Profile profile) {
+
<pre>   protected static void defineProfile(Profile profile) {
        profile.define();
+
        profile.define();
+
 
        out("Profile '" + profile.getQualifiedName() + "' defined.");
+
        out("Profile '%s' defined.", profile.getQualifiedName());
    }
+
    }
 
</pre>  
 
</pre>  
 
Here we call a convenience method on the profile that generates the Ecore representation of the profile and increments its version.  
 
Here we call a convenience method on the profile that generates the Ecore representation of the profile and increments its version.  
  
 
OK, let’s see this method in action. For example, we could define the ‘ecore’ profile as follows:  
 
OK, let’s see this method in action. For example, we could define the ‘ecore’ profile as follows:  
<pre>         defineProfile(ecoreProfile);
+
<pre>   defineProfile(ecoreProfile);
 
</pre>
 
</pre>
  
Line 413: Line 438:
  
 
It’s that simple. Programmatically, we have a bit more work to do because so far, we’ve been creating our profile in a vacuum, i.e., without a containing resource. The code snippet below shows a method that saves a specified package to a resource with a specified URI.  
 
It’s that simple. Programmatically, we have a bit more work to do because so far, we’ve been creating our profile in a vacuum, i.e., without a containing resource. The code snippet below shows a method that saves a specified package to a resource with a specified URI.  
<pre>    protected static void save(org.eclipse.uml2.uml.Package package_, URI uri) {
+
<pre>   private static final ResourceSet RESOURCE_SET;
        Resource resource = RESOURCE_SET.createResource(uri);
+
 
        resource.getContents().add(package_);
+
    static {
+
        // Create a resource-set to contain the resource(s) that we load and
        try {
+
        // save
            resource.save(null);
+
        RESOURCE_SET = new ResourceSetImpl();
            out("Done.");
+
 
        } catch (IOException ioe) {
+
        // Initialize registrations of resource factories, library models,
            err(ioe.getMessage());
+
        // profiles, Ecore metadata, and other dependencies required for
        }
+
        // serializing and working with UML resources. This is only necessary in
    }
+
        // applications that are not hosted in the Eclipse platform run-time, in
 +
        // which case these registrations are discovered automatically from
 +
        // Eclipse extension points.
 +
        UMLResourcesUtil.init(RESOURCE_SET);
 +
 
 +
    }
 +
 
 +
     protected static void save(org.eclipse.uml2.uml.Package package_, URI uri) {
 +
        // Create the resource to be saved and add the package to it
 +
        Resource resource = RESOURCE_SET.createResource(uri);
 +
        resource.getContents().add(package_);
 +
 
 +
        // And save.
 +
        try {
 +
            resource.save(null);
 +
            out("Done.");
 +
        } catch (IOException ioe) {
 +
            err(ioe.getMessage());
 +
        }
 +
    }
 
</pre>  
 
</pre>  
 
Here we use a statically initialized resource set to create a resource with the specified URI, add the package to the resource’s contents, and ask the resource to save itself using the default options. If an exception occurs, we notify the user via our handy utility method.  
 
Here we use a statically initialized resource set to create a resource with the specified URI, add the package to the resource’s contents, and ask the resource to save itself using the default options. If an exception occurs, we notify the user via our handy utility method.  
  
OK, let’s see this method in action. For example, we could save the ‘ecore’ profile to a resource with URI ‘Ecore.profile.uml’ (relative to a URI passed in as an argument) as follows:  
+
[[Image:GSWU2 tip.gif]] The above example uses the '''UMLResourcesUtil.init(...)''' API introduced in UML2 4.0.0 for the Juno release. As commented in the code snippet, this is not required in code running in the Eclipse Platform run-time, as in that case these registrations are discovered automatically from extension points.
<pre>         save(ecoreProfile, URI.createURI(args[0]).appendSegment("Ecore").appendFileExtension(UMLResource.PROFILE_FILE_EXTENSION));
+
 
 +
OK, let’s see this method in action. For example, we could save the ‘ecore’ profile to a resource with URI ‘Ecore.profile.uml’ (relative to a local filesystem path passed in as an argument) as follows:  
 +
<pre>   save(ecoreProfile, URI.createFileURI(args[0]).appendSegment("Ecore").appendFileExtension(UMLResource.PROFILE_FILE_EXTENSION));
 
</pre>  
 
</pre>  
 
[[Image:GSWU2 tip.gif]] The '''UMLResource.PROFILE_FILE_EXTENSION''' constant represents the file extension for UML2 profiles ('''.profile.uml''').
 
[[Image:GSWU2 tip.gif]] The '''UMLResource.PROFILE_FILE_EXTENSION''' constant represents the file extension for UML2 profiles ('''.profile.uml''').
Line 434: Line 480:
 
= Loading Models  =
 
= Loading Models  =
  
In order to make use of our profile, we’ll need to open a model and load the profile. We’ll use the '''ExtendedPO2''' model that was created in the “Getting Started with UML2” article (you’ll need to copy it into your project and refresh the workspace first).  
+
In order to make use of our profile, we’ll need to open a model and load the profile. We’ll use the '''ExtendedPO2''' model that was created in the [[MDT/UML2/Getting Started with UML2|Getting Started with UML2]] article (you’ll need to copy it into your project and refresh the workspace first).  
  
 
To open a model using the UML editor, follow these steps:  
 
To open a model using the UML editor, follow these steps:  
Line 446: Line 492:
 
#Select the '''UML Editor &gt; Load Resource...''' menu item.  
 
#Select the '''UML Editor &gt; Load Resource...''' menu item.  
 
#Press the '''Browse Workspace...''' button.  
 
#Press the '''Browse Workspace...''' button.  
#Select a resource (i.e., '''Introduction to UML2 Profiles/Ecore.profile.uml''') and press the '''OK''' button.  
+
#Select a resource (e.g., '''Introduction to UML2 Profiles/Ecore.profile.uml''') and press the '''OK''' button.  
 
#Press the '''OK''' button.
 
#Press the '''OK''' button.
  
Line 454: Line 500:
  
 
Programmatically, we have a bit more work to do. The code snippet below shows a method that loads a package from a resource with a specified URI.  
 
Programmatically, we have a bit more work to do. The code snippet below shows a method that loads a package from a resource with a specified URI.  
<pre>     protected static org.eclipse.uml2.uml.Package load(URI uri) {
+
<pre>   protected static org.eclipse.uml2.uml.Package load(URI uri) {
        org.eclipse.uml2.uml.Package package_ = null;
+
        org.eclipse.uml2.uml.Package package_ = null;
+
 
        try {
+
        try {
            Resource resource = RESOURCE_SET.getResource(uri, true);
+
            // Load the requested resource
+
            Resource resource = RESOURCE_SET.getResource(uri, true);
            package_ = (org.eclipse.uml2.uml.Package) EcoreUtil.getObjectByType(resource.getContents(), UMLPackage.Literals.PACKAGE);
+
 
        } catch (WrappedException we) {
+
            // Get the first (should be only) package from it
            err(we.getMessage());
+
            package_ = (org.eclipse.uml2.uml.Package) EcoreUtil.getObjectByType(resource.getContents(), UMLPackage.Literals.PACKAGE);
            System.exit(1);
+
        } catch (WrappedException we) {
        }
+
            err(we.getMessage());
 +
            System.exit(1);
 +
        }
  
        return package_;
+
        return package_;
    }
+
    }
 
</pre>  
 
</pre>  
 
Here we obtain a resource with the specified URI from our statically initialized resource set, asking that it be loaded on demand. Next, we use an EMF utility method to obtain the first object of type '''Package''' from the resource’s contents. If an exception occurs, we notify the user via our handy utility method. Finally, if all is well, we return the package.  
 
Here we obtain a resource with the specified URI from our statically initialized resource set, asking that it be loaded on demand. Next, we use an EMF utility method to obtain the first object of type '''Package''' from the resource’s contents. If an exception occurs, we notify the user via our handy utility method. Finally, if all is well, we return the package.  
Line 473: Line 521:
 
[[Image:GSWU2 tip.gif]] The '''EcoreUtil''' class (provided by EMF) defines a number of utilities that you may find quite useful when working with EMF-based resources.  
 
[[Image:GSWU2 tip.gif]] The '''EcoreUtil''' class (provided by EMF) defines a number of utilities that you may find quite useful when working with EMF-based resources.  
  
OK, let’s see this method in action. For example, we could load the ‘epo2’ model from a resource with URI ‘ExtendedPO2.uml’ (relative to a URI passed in as an argument) as follows:  
+
OK, let’s see this method in action. For example, we could load the ‘epo2’ model from a resource with URI ‘ExtendedPO2.uml’ (relative to a filesystem path passed in as an argument) as follows:  
<pre>         Model epo2Model = (Model) load(URI.createURI(args[0]).appendSegment("ExtendedPO2").appendFileExtension(UMLResource.FILE_EXTENSION));
+
<pre>   Model epo2Model = (Model) load(URI.createFileURI(args[0]).appendSegment("ExtendedPO2").appendFileExtension(UMLResource.FILE_EXTENSION));
 
</pre>
 
</pre>
  
Line 481: Line 529:
 
OK, our profile has been created, defined, saved, and loaded, and we’re ready to apply it to our model. Applying a profile means that it is allowed (but not necessarily required) to apply the stereotypes that are defined in the profile to elements in the package. A profile application is a special type of package import that indicates that a profile has been applied to a package. To apply a profile to a package using the UML editor, follow these steps:  
 
OK, our profile has been created, defined, saved, and loaded, and we’re ready to apply it to our model. Applying a profile means that it is allowed (but not necessarily required) to apply the stereotypes that are defined in the profile to elements in the package. A profile application is a special type of package import that indicates that a profile has been applied to a package. To apply a profile to a package using the UML editor, follow these steps:  
  
#Select a package (i.e., '''&lt;Model&gt; epo2''') in the UML editor.  
+
#Select a package (e.g., '''&lt;Model&gt; epo2''') in the UML editor.  
 
#Select the '''UML Editor &gt; Package &gt; Apply Profile...''' menu item.  
 
#Select the '''UML Editor &gt; Package &gt; Apply Profile...''' menu item.  
#Choose a profile (i.e., '''ecore'''), press the '''Add''' button, then press the '''OK''' button.
+
#Choose a profile (e.g., '''ecore'''), press the '''Add''' button, then press the '''OK''' button.
  
 
[[Image:GSWU2 tip.gif]] Be sure to pick the profile we’ve created instead of the built-in profile provided by the UML resources plug-in (i.e., '''ecore''', not '''Ecore''').  
 
[[Image:GSWU2 tip.gif]] Be sure to pick the profile we’ve created instead of the built-in profile provided by the UML resources plug-in (i.e., '''ecore''', not '''Ecore''').  
Line 491: Line 539:
 
[[Image:ITU2P ApplyingProfiles.png]]  
 
[[Image:ITU2P ApplyingProfiles.png]]  
  
[[Image:GSWU2 tip.gif]] You’ll notice another annotation (with source '''http://www.eclipse.org/uml2/2.0.0/UML''') has been attached, in this case to keep track of the Ecore representation for the definition of the profile that is currently applied to the package. Again, it’s important that this annotation not be modified, since the UML2 profile mechanism depends on this construct. Note that a newer definition of the profile can be applied using the same menu item, and a profile (along with all of its stereotypes) can be unapplied using the '''UML Editor &gt; Package &gt; Unapply Profile...''' menu item.  
+
[[Image:GSWU2 tip.gif]] You’ll notice another annotation (with source <nowiki>"http://www.eclipse.org/uml2/2.0.0/UML"</nowiki>) has been attached, in this case to keep track of the Ecore representation for the definition of the profile that is currently applied to the package. Again, it’s important that this annotation not be modified, since the UML2 profile mechanism depends on this construct. Note that a newer definition of the profile can be applied using the same menu item, and a profile (along with all of its stereotypes) can be unapplied using the '''UML Editor &gt; Package &gt; Unapply Profile...''' menu item.  
  
 
Let’s look at how to perform the same task using Java code. The code snippet below shows a method that programmatically applies a specified profile to a specified package.  
 
Let’s look at how to perform the same task using Java code. The code snippet below shows a method that programmatically applies a specified profile to a specified package.  
<pre>     protected static void applyProfile(org.eclipse.uml2.uml.Package package_, Profile profile) {
+
<pre>   protected static void applyProfile(org.eclipse.uml2.uml.Package package_, Profile profile) {
        package_.applyProfile(profile);
+
        package_.applyProfile(profile);
+
 
        out("Profile '" + profile.getQualifiedName() + "' applied to package '" + package_.getQualifiedName() + "'.");
+
        out("Profile '%s' applied to package '%s'.", profile.getQualifiedName(), package_.getQualifiedName());
    }
+
    }
 
</pre>  
 
</pre>  
 
Here we call a convenience method on the package that creates a profile application on the package and sets the profile as the imported profile.  
 
Here we call a convenience method on the package that creates a profile application on the package and sets the profile as the imported profile.  
  
 
OK, let’s see this method in action. For example, we could apply the ‘ecore’ profile to the ‘epo2’ model as follows:  
 
OK, let’s see this method in action. For example, we could apply the ‘ecore’ profile to the ‘epo2’ model as follows:  
<pre>         applyProfile(epo2Model, ecoreProfile);
+
<pre>   applyProfile(epo2Model, ecoreProfile);
 
</pre>
 
</pre>
  
 
= Applying Stereotypes  =
 
= Applying Stereotypes  =
  
We’re on the home stretch now... Once a profile has been applied to a package, stereotypes defined in the profile can be applied to instances of the appropriate metaclasses (as per the defined extensions). When a stereotype is applied to an element, that element is effectively extended with the properties that are defined as part of the stereotype. To apply a stereotype to an element using the UML editor, follow these steps:  
+
We’re on the home stretch now. Once a profile has been applied to a package, stereotypes defined in the profile can be applied to instances of the appropriate metaclasses (as per the defined extensions). When a stereotype is applied to an element, that element is effectively extended with the properties that are defined as part of the stereotype. To apply a stereotype to an element using the UML editor, follow these steps:  
  
#Select an element (i.e., '''&lt;Property&gt; pendingOrders&nbsp;: PurchaseOrder [0..*]''' in '''&lt;Class&gt; Supplier''') in the UML editor.  
+
#Select an element (e.g., '''&lt;Property&gt; pendingOrders&nbsp;: PurchaseOrder [0..*]''' in '''&lt;Class&gt; Supplier''') in the UML editor.  
 
#Select the '''UML Editor &gt; Element &gt; Apply Stereotype...''' menu item.  
 
#Select the '''UML Editor &gt; Element &gt; Apply Stereotype...''' menu item.  
#Choose a stereotype (i.e., '''ecore::EReference'''), press the '''Add''' button, then press the '''OK''' button.
+
#Choose a stereotype (e.g., '''ecore::EReference'''), press the '''Add''' button, then press the '''OK''' button.
  
 
[[Image:GSWU2 tryit.gif]] Apply the appropriate stereotypes to other properties ('''&lt;Property&gt; shippedOrders&nbsp;: PurchaseOrder [0..*]''' in '''&lt;Class&gt; Supplier'''; '''&lt;Property&gt; totalAmount&nbsp;: int [0..1]''', '''&lt;Property&gt; previousOrder&nbsp;: PurchaseOrder [0..1]''', and '''&lt;Property&gt; customer&nbsp;: Customer''' in '''&lt;Class&gt; PurchaseOrder'''; '''&lt;Property&gt; orders&nbsp;: PurchaseOrder [0..*]''' in '''&lt;Class&gt; Customer''') in the ExtendedPO2 model using the UML editor.  
 
[[Image:GSWU2 tryit.gif]] Apply the appropriate stereotypes to other properties ('''&lt;Property&gt; shippedOrders&nbsp;: PurchaseOrder [0..*]''' in '''&lt;Class&gt; Supplier'''; '''&lt;Property&gt; totalAmount&nbsp;: int [0..1]''', '''&lt;Property&gt; previousOrder&nbsp;: PurchaseOrder [0..1]''', and '''&lt;Property&gt; customer&nbsp;: Customer''' in '''&lt;Class&gt; PurchaseOrder'''; '''&lt;Property&gt; orders&nbsp;: PurchaseOrder [0..*]''' in '''&lt;Class&gt; Customer''') in the ExtendedPO2 model using the UML editor.  
Line 523: Line 571:
  
 
Let’s look at how to perform the same task using Java code. The code snippet below shows a method that programmatically applies a specified stereotype to a specified (named) element.  
 
Let’s look at how to perform the same task using Java code. The code snippet below shows a method that programmatically applies a specified stereotype to a specified (named) element.  
<pre>     protected static void applyStereotype(NamedElement namedElement, Stereotype stereotype) {
+
<pre>   protected static void applyStereotype(NamedElement namedElement, Stereotype stereotype) {
        namedElement.applyStereotype(stereotype);
+
        namedElement.applyStereotype(stereotype);
+
 
        out("Stereotype '" + stereotype.getQualifiedName() + "' applied to element '" + namedElement.getQualifiedName() + "'.");
+
        out("Stereotype '%s' applied to element '%s'.", stereotype.getQualifiedName(), namedElement.getQualifiedName());
    }
+
    }
 
</pre>  
 
</pre>  
 
Here we call a convenience method on the element that creates an instance of the Ecore class representing the specified stereotype (using dynamic EMF) and attaches it to the element using an annotation.  
 
Here we call a convenience method on the element that creates an instance of the Ecore class representing the specified stereotype (using dynamic EMF) and attaches it to the element using an annotation.  
  
 
OK, let’s see this method in action. For example, we could apply the ‘EReference’ stereotype to the ‘pendingOrders’ property of the ‘Supplier’ class in the ‘epo2’ model as follows:  
 
OK, let’s see this method in action. For example, we could apply the ‘EReference’ stereotype to the ‘pendingOrders’ property of the ‘Supplier’ class in the ‘epo2’ model as follows:  
<pre>         org.eclipse.uml2.uml.Class supplierClass = (org.eclipse.uml2.uml.Class) epo2Model.getOwnedType("Supplier");
+
<pre>   org.eclipse.uml2.uml.Class supplierClass = (org.eclipse.uml2.uml.Class) epo2Model.getOwnedType("Supplier");
 
   
 
   
        Property pendingOrdersProperty = supplierClass.getOwnedAttribute("pendingOrders", null);
+
    Property pendingOrdersProperty = supplierClass.getOwnedAttribute("pendingOrders", null);
        applyStereotype(pendingOrdersProperty, eReferenceStereotype);
+
    applyStereotype(pendingOrdersProperty, eReferenceStereotype);
 
</pre>  
 
</pre>  
 
[[Image:GSWU2 tryit.gif]] Write code to programmatically apply the appropriate stereotypes to other properties (i.e., ‘epo2::Supplier::shippedOrders’, ‘epo2::PurchaseOrder::totalAmount’, ‘epo2::PurchaseOrder::previousOrder’, ‘epo2::PurchaseOrder::customer’, and ‘epo2::Customer::orders’) in the ExtendedPO2 model.
 
[[Image:GSWU2 tryit.gif]] Write code to programmatically apply the appropriate stereotypes to other properties (i.e., ‘epo2::Supplier::shippedOrders’, ‘epo2::PurchaseOrder::totalAmount’, ‘epo2::PurchaseOrder::previousOrder’, ‘epo2::PurchaseOrder::customer’, and ‘epo2::Customer::orders’) in the ExtendedPO2 model.
Line 553: Line 601:
  
 
Let’s look at how to perform the same task using Java code. The code snippet below shows a method that programmatically gets and returns the value of a specified property of a specified stereotype for a specified element.  
 
Let’s look at how to perform the same task using Java code. The code snippet below shows a method that programmatically gets and returns the value of a specified property of a specified stereotype for a specified element.  
<pre>     protected static Object getStereotypePropertyValue(NamedElement namedElement, Stereotype stereotype, Property property) {
+
<pre>   protected static Object getStereotypePropertyValue(NamedElement namedElement, Stereotype stereotype, Property property) {
        Object value = namedElement.getValue(stereotype, property.getName());
+
        Object value = namedElement.getValue(stereotype, property.getName());
+
 
        out("Value of stereotype property '" + property.getQualifiedName() + "' on element '" + namedElement.getQualifiedName()
+
        out("Value of stereotype property '%s' on element '%s' is %s.", property.getQualifiedName(), namedElement.getQualifiedName(), value);
            + "' is " + String.valueOf(value) + ".");
+
 
+
        return value;
        return value;
+
    }
    }
+
 
</pre>  
 
</pre>  
 
Here we call a convenience method on the (named) element that retrieves the value of a property with a specified name from the dynamically created Ecore object instance corresponding to the specified applied stereotype, notifies the user, and returns it.  
 
Here we call a convenience method on the (named) element that retrieves the value of a property with a specified name from the dynamically created Ecore object instance corresponding to the specified applied stereotype, notifies the user, and returns it.  
  
 
OK, let’s see this method in action. For example, we could get the value of the ‘isVolatile’ property of the ‘EReference’ stereotype for the ‘pendingOrders’ property of the ‘Supplier’ class in the ‘epo2’ model as follows:  
 
OK, let’s see this method in action. For example, we could get the value of the ‘isVolatile’ property of the ‘EReference’ stereotype for the ‘pendingOrders’ property of the ‘Supplier’ class in the ‘epo2’ model as follows:  
<pre>         getStereotypePropertyValue(pendingOrdersProperty, eReferenceStereotype, isVolatileProperty);
+
<pre>   getStereotypePropertyValue(pendingOrdersProperty, eReferenceStereotype, isVolatileProperty);
 
</pre>  
 
</pre>  
 
[[Image:GSWU2 tryit.gif]] Write code to programmatically get the values of the other stereotype properties for elements in the ExtendedPO2 model.  
 
[[Image:GSWU2 tryit.gif]] Write code to programmatically get the values of the other stereotype properties for elements in the ExtendedPO2 model.  
  
 
The code snippet below shows a method that programmatically sets the value of a specified property of a specified stereotype for a specified element to a specified value.  
 
The code snippet below shows a method that programmatically sets the value of a specified property of a specified stereotype for a specified element to a specified value.  
<pre>     protected static void setStereotypePropertyValue(NamedElement namedElement, Stereotype stereotype, Property property, Object value) {
+
<pre>   protected static void setStereotypePropertyValue(NamedElement namedElement, Stereotype stereotype, Property property, Object value) {
        namedElement.setValue(stereotype, property.getName(), value);
+
        Object valueToSet = value;
+
 
        out("Value of stereotype property '" + property.getQualifiedName() + "' on element '" + namedElement.getQualifiedName()
+
        if ((value instanceof String) && (property.getType() instanceof Enumeration)) {
            + "' set to " + String.valueOf(value) + ".");
+
            // Get the corresponding enumeration literal
    }
+
            valueToSet = ((Enumeration) property.getType()).getOwnedLiteral((String) value);
 +
        }
 +
 
 +
        namedElement.setValue(stereotype, property.getName(), valueToSet);
 +
 
 +
        out("Value of stereotype property '%s' on element '%s' set to %s.", property.getQualifiedName(),
 +
                namedElement.getQualifiedName(), value);
 +
    }
 
</pre>  
 
</pre>  
 
Here we call a convenience method on the (named) element that sets the value of a property with a specified name in the dynamically created Ecore object instance corresponding to the specified applied stereotype and notifies the user.  
 
Here we call a convenience method on the (named) element that sets the value of a property with a specified name in the dynamically created Ecore object instance corresponding to the specified applied stereotype and notifies the user.  
 +
 +
[[Image:GSWU2 tip.gif]] Values of primitive types are represented by the usual Java types:  '''String''', '''Boolean''', '''Integer''', etc.  For values of enumerations, the UML2 API accepts and returns the '''EnumerationLiteral''' instances from the profile model.  For convenience, this utility method allows enumeration values to be set using simply the name of the literal.
  
 
OK, let’s see this method in action. For example, we could set the value of the ‘isVolatile’ property of the ‘EReference’ stereotype for the ‘pendingOrders’ property of the ‘Supplier’ class in the ‘epo2’ model to Boolean.TRUE as follows:  
 
OK, let’s see this method in action. For example, we could set the value of the ‘isVolatile’ property of the ‘EReference’ stereotype for the ‘pendingOrders’ property of the ‘Supplier’ class in the ‘epo2’ model to Boolean.TRUE as follows:  
<pre>         setStereotypePropertyValue(pendingOrdersProperty, eReferenceStereotype, isVolatileProperty, Boolean.TRUE);
+
<pre>   setStereotypePropertyValue(pendingOrdersProperty, eReferenceStereotype, isVolatileProperty, true);
 
</pre>  
 
</pre>  
 
[[Image:GSWU2 tryit.gif]] Write code to programmatically set the values of the other stereotype properties for elements in the ExtendedPO2 model.
 
[[Image:GSWU2 tryit.gif]] Write code to programmatically set the values of the other stereotype properties for elements in the ExtendedPO2 model.
Line 592: Line 648:
 
= References  =
 
= References  =
  
[1] K. Hussey and J. Bruck. “Getting Started with UML2”. International Business Machines Corp. and CEA, 2004, 2011.  
+
[1] K. Hussey and J. Bruck. "[[MDT/UML2/Getting Started with UML2|Getting Started with UML2]]”. International Business Machines Corp., CEA, and others, 2004, 2014.  
  
 
[2] F. Budinsky, D. Steinberg, E. Merks, R. Ellersick, and T. J. Grose. Eclipse Modeling Framework. Pearson Education, Inc., Boston, MA, 2003.
 
[2] F. Budinsky, D. Steinberg, E. Merks, R. Ellersick, and T. J. Grose. Eclipse Modeling Framework. Pearson Education, Inc., Boston, MA, 2003.

Latest revision as of 09:36, 29 May 2014

Copyright © 2004, 2014 International Business Machines Corp., CEA, and others.

Summary

This article describes how to work with profiles using the UML2 plug-ins for Eclipse. In particular, it gives an overview of how to create and apply profiles (and their contents) both programmatically and by using the sample UML editor.

Kenn Hussey and James Bruck
Last Updated: January 21, 2014

Prerequisites

To start using UML2 (and to follow along with the example in this article), you must have Eclipse, EMF, and UML2 installed. You can either download the Modeling Tools Package or follow these steps:

  1. Download and run Eclipse.
  2. Select the Help > Install New Software… menu item.
  3. Select a software site to work with, e.g., Luna - http://download.eclipse.org/releases/luna.
  4. Expand the Modeling tree item.
  5. Select UML2 Extender SDK and press the Next > button.
  6. Review the install details and press the Next > button.
  7. Accept the terms of the license agreement and press the Finish button.
  8. Restart Eclipse when prompted to do so.

GSWU2 Prerequisites.png

At this stage, UML2 and all dependencies should be installed.

Introduction

This article will walk you through the basics of creating and applying profiles using UML2. Using a subset of the Ecore profile (see below) and the model we described in the “Getting Started with UML2” article [1] (the ExtendedPO2 model, shamelessly “borrowed” from the EMF “bible” [2]) as an example, we’ll look at what’s involved in creating some of the more common elements that make up a profile. For each type of element, we’ll first explain the creation process using the sample UML editor and explore how to accomplish the same thing using Java code. Then we’ll look at what’s involved in applying profiles and stereotypes to models. The ExtendedPO2 model is shown below.

GSWU2 Introduction.png

The Ecore profile that we will develop is as follows, comprising only the subset of stereotypes dealing with properties.

ITU2P Ecore Profile.png

Getting Started

GSWU2 tip.gif Readers who don't want to follow every step of this tutorial may install a working solution from the New → Example... wizard, selecting the UML2 Example Projects → Introduction to UML2 Profiles sample. This will be available when Enhancement 382342 is resolved and released in a UML2 build. This includes the finished profile, complete source code, and a launch configuration that runs the stand-alone Java application which creates the profile in the root folder of the example project, applies it to a test model, and manipulates stereotype attributes ("tagged values").

ITU2P ExampleWizard.png

Before getting started, you’ll need to create a simple project in your workspace. This project will serve as the container for the profile that we’ll create using the UML editor. To create a simple project for this article, follow these steps:

  1. Select the Window > Open Perspective > Other… menu item.
  2. Select the Resource perspective and press the OK button.
  3. Select the File > New > Project... menu item.
  4. Select the Project wizard from the General category and press the Next > button.
  5. Enter a project name (e.g., “Introduction to UML2 Profiles”), and press the Finish button.

At this point your workspace should look something like this:

ITU2P GettingStarted.png

OK, that should be enough to get us going with the UML editor. Now, to follow along with the programmatic approach to creating profiles, we’ll assume that you’ve created a Java class (named, say, “IntroductionToUML2Profiles”) in which you can write some code to construct our sample profile. The code snippets we’ll show assume you’ve defined the following utility methods to give the user information on the program’s status:

    public static boolean DEBUG = true;
 
    protected static void out(String format, Object... args) {
        if (DEBUG) {
            System.out.printf(format, args);
            if (!format.endsWith("%n")) {
                System.out.println();
            }
        }
    }

    protected static void err(String format, Object... args) {
        System.err.printf(format, args);
        if (!format.endsWith("%n")) {
            System.err.println();
        }
    }

A static debug flag can be used to enable or disable verbose information printed to the system’s output stream. Errors will always be printed to the system’s error stream.

All right, then! In each of the following subsections, we’ll look at how to create or manipulate a different kind of UML element, starting with profiles.

Creating Profiles

At the root of every UML2 profile is a profile element. It defines limited extensions to a reference metamodel (i.e., UML) with the purpose of adapting the metamodel to a specific platform or domain (e.g., EMF). Metaclasses from the reference metamodel are extended via stereotypes, which are defined as part of profiles. To create a profile using the UML editor, follow these steps:

  1. Select a project (e.g., Introduction to UML2 Profiles) in the Project Explorer view and select the File > New > Other... menu item.
  2. Select the UML Model wizard from the Example EMF Model Creation Wizards category and press the Next > button.
  3. Enter a file name (e.g., “Ecore.profile.uml”) and press the Next > button.
  4. Select Profile for the model object and press the Finish button.
  5. Select the Window > Show View > Properties menu item.
  6. Select the <Profile> element in the UML editor.
  7. Enter a value (e.g., “ecore”) for the Name property in the Properties view.
  8. (optional) Enter a value (e.g., "http://www.eclipse.org/schema/UML2/examples/ecore") for the URI property in the Properties view.

GSWU2 tip.gif In UML™, packages may be identified uniquely by assigning URIs. In UML2 profiles, this URI is used as the namespace URI of the Ecore EPackage representing the profile metadata in EMF. By specifying this URI explicitly, you can establish a stable namespace URI that will be used by all successive iterations of your profile schema as it evolves over time. If you omit the URI, one will be generated automatically by UML2 in the Ecore definition. This default namespace URI is suffixed by an increasing version number, resulting in a different URI in each successive definition. A consequence of this is that existing models that have an older profile definition applied will have to be migrated to the new version when it is deployed. This is useful when incompatible changes are made in the profile from one version to the next. You may, of course, also change the explicitly set URI yourself, when required.

GSWU2 tip.gif By convention, resources that contain profiles end with a .profile.uml file extension in UML2.

At this point your workspace should look something like this:

ITU2P CreatingProfiles.png

Let’s look at how to perform the same task using Java code. The code snippet below shows a method that programmatically creates and returns a profile with a specified name.

    protected static Profile createProfile(String name, String nsURI) {
        Profile profile = UMLFactory.eINSTANCE.createProfile();
        profile.setName(name);
        profile.setURI(nsURI);

        out("Profile '%s' created.", profile.getQualifiedName());

        return profile;
    }

First, we ask the UML factory singleton to create a profile, and we set its name and URI. Then, we output information to the user to let them know that the profile has been successfully created. Finally, we return the profile. You’ll notice most, if not all, of the code snippets in this article will follow this pattern: create the element (and set some properties on it), inform the user, and return it.

OK, let’s see this method in action. For example, we could create a profile named ‘ecore’ as follows:

    Profile ecoreProfile = createProfile("ecore", "http://www.eclipse.org/schema/UML2/examples/ecore");

Importing Primitive Types

Just like a class, a stereotype may have properties, which may be referred to as tag definitions. The types of these properties may be pre-defined in (domain-specific) libraries referenced by the profile. A profile can be made to reference primitive types from libraries (such as those provided in the org.eclipse.uml2.uml.resources plug-in) by creating an import relationship between the profile and the primitive type. To import a primitive type using the UML editor, follow these steps:

  1. Select a package (e.g., <Profile> ecore) in the UML editor.
  2. Select the UML Editor > Package > Import Type... menu item.
  3. Choose a primitive type (e.g., PrimitiveTypes::Boolean), press the Add button, then press the OK button.

GSWU2 tryit.gif Import the other required primitive type (PrimitiveTypes::String) into the Ecore profile using the UML editor.

At this point your workspace should look something like this:

ITU2P ImportingPrimitiveTypes.png

Let’s look at how to perform the same task using Java code. The code snippet below shows a method that programmatically imports the primitive type with a specified name from the UML primitive types library into a specified package and returns it.

    protected static PrimitiveType importPrimitiveType(org.eclipse.uml2.uml.Package package_, String name) {
        org.eclipse.uml2.uml.Package umlLibrary = (org.eclipse.uml2.uml.Package) load(URI.createURI(UMLResource.UML_PRIMITIVE_TYPES_LIBRARY_URI));

        PrimitiveType primitiveType = (PrimitiveType) umlLibrary.getOwnedType(name);

        package_.createElementImport(primitiveType);

        out("Primitive type '%s' imported.", primitiveType.getQualifiedName());

        return primitiveType;
    }

Here we load the model library containing the UML primitive types (Boolean, Integer, Real, String, and UnlimitedNatural) using a load(...) utility method (described later) and a URI defined on the UMLResource interface. Next, we retrieve the desired (owned) primitive type from the model by name using one of the convenience methods defined in the UML2 API. Finally, we invoke another convenience method to create the element import relationship between the package and the element (with default public visibility), notify the user, and return the primitive type.

GSWU2 tip.gif The UML resources plug-in (org.eclipse.uml2.uml.resources) provides several model libraries (which by convention have a .library.uml file extension) that contain commonly used primitive types, such as those defined by Java and EMF (in addition to those defined by UML™ itself). These libraries can be accessed using URIs defined on the UMLResource interface, as shown above.

GSWU2 tip.gif In UML2, a method of the form get<feature name>(String) exists for every feature that can contain or reference named elements. In this case, the package has a feature (ownedType) that can contain types, so we pass the unqualified name of the type we are looking for to the getOwnedType(String) convenience method. Behind the scenes, the package will iterate over all of its owned types and return the first one that it finds that has the specified (unqualified) name.

OK, let’s see this method in action. For example, we could import the primitive type named ‘Boolean’ into profile ‘ecore’ as follows:

    PrimitiveType booleanPrimitiveType = importPrimitiveType(ecoreProfile, "Boolean");

GSWU2 tryit.gif Write code to programmatically import the other required primitive type (i.e., ‘String’) into the Ecore profile.

Creating Enumerations

As with packages, profiles can contain enumerations. An enumeration is a kind of data type whose instances may be any of a number of user-defined enumeration literals. To create an enumeration using the UML editor, follow these steps:

  1. Select a profile (e.g., <Profile> ecore) in the UML editor.
  2. Select the New Child > Owned Type >'Enumeration' option from the context menu.
  3. Enter a value (e.g., “VisibilityKind”) for the Name property in the Properties view.

GSWU2 tryit.gif Create the other enumeration (i.e., “FeatureKind”) for the Ecore profile using the UML editor.

At this point your workspace should look something like this:

ITU2P CreatingEnumerations.png

Let’s look at how to perform the same task using Java code. The code snippet below (which should be familiar from the Getting Started with UML2 article) shows a method that programmatically creates and returns an enumeration with a specified name in a specified package.

    protected static Enumeration createEnumeration(org.eclipse.uml2.uml.Package package_, String name) {
        Enumeration enumeration = package_.createOwnedEnumeration(name);

        out("Enumeration '%s' created.", enumeration.getQualifiedName());

        return enumeration;
    }

Here we call the createOwnedEnumeration(String) convenience factory method to ask the package to create a primitive type with the specified name as one of its packaged elements.

OK, let’s see this method in action. For example, we could create an enumeration named ‘VisibilityKind’ in profile ‘ecore’ as follows:

    Enumeration visibilityKindEnumeration = createEnumeration(ecoreProfile, "VisibilityKind");

GSWU2 tryit.gif Write code to programmatically create the other enumeration (i.e., ‘FeatureKind’) for the Ecore profile.

Creating Enumeration Literals

An enumeration literal is a user-defined data value for an enumeration. To create an enumeration literal using the UML editor, follow these steps:

  1. Select an enumeration (e.g., <Enumeration> VisibilityKind) in the UML editor.
  2. Select the New Child > Owned Literal > Enumeration Literal option from the context menu.
  3. Enter a value (e.g., “Unspecified”) for the Name property in the Properties view.

GSWU2 tryit.gif Create the remaining enumeration literals for the Ecore profile (i.e., “None”, “ReadOnly”, “ReadWrite”, “ReadOnlyUnsettable”, and “ReadWriteUnsettable” for <Enumeration> VisibilityKind; “Unspecified”, “Simple”, “Attribute”, “Element”, “AttributeWildcard”, “ElementWildcard”, and “Group” for <Enumeration> FeatureKind) using the UML editor.

At this point your workspace should look something like this:

ITU2P CreatingEnumerationLiterals.png

Let’s look at how to perform the same task using Java code. The code snippet below shows a method that programmatically creates and returns an enumeration literal with a specified name in a specified enumeration.

    protected static EnumerationLiteral createEnumerationLiteral(Enumeration enumeration, String name) {
        EnumerationLiteral enumerationLiteral = enumeration.createOwnedLiteral(name);

        out("Enumeration literal '%s' created.", enumerationLiteral.getQualifiedName());

        return enumerationLiteral;
    }

Here we call the createOwnedLiteral(String) convenience factory method to ask the enumeration to create an enumeration literal with the specified name as one of its owned literals.

OK, let’s see this method in action. For example, we could create an enumeration literal named ‘Unspecified’ in enumeration ‘VisibilityKind’ as follows:

    createEnumerationLiteral(visibilityKindEnumeration, "Unspecified");

GSWU2 tryit.gif Write code to programmatically create the remaining enumeration literals (i.e., ‘None’, ‘ReadOnly’, ‘ReadWrite’, ‘ReadOnlyUnsettable’, and ‘ReadWriteUnsettable’ in enumeration ‘VisibilityKind’; ‘Unspecified’, ‘Simple’, ‘Attribute’, ‘Element’, ‘AttributeWildcard’, ‘ElementWildcard’, and ‘Group’ in enumeration ‘FeatureKind’) for the Ecore profile.

Creating Stereotypes

A stereotype defines how an existing metaclass may be extended, and enables the use of platform- or domain-specific terminology or notation in place of, or in addition to, the ones used for the extended metaclass. Each stereotype may extend one or more classes through extensions as part of a profile. To create a stereotype using the UML editor, follow these steps:

  1. Select a profile (e.g., <Profile> ecore) in the UML editor.
  2. Select the New Child > Owned Stereotype > Stereotype option from the context menu.
  3. Enter a value (e.g., “EStructuralFeature”) for the Name property in the Properties view.
  4. Select a value (e.g., true) for the Is Abstract property in the Properties view.

GSWU2 tryit.gif Create the remaining stereotypes for the Ecore profile (i.e., “EAttribute” and “EReference”) using the UML editor.

At this point your workspace should look something like this:

ITU2P CreatingStereotypes.png

Let’s look at how to perform the same task using Java code. The code snippet below shows a method that programmatically creates and returns a(n) (abstract) stereotype with a specified name in a specified profile.

    protected static Stereotype createStereotype(Profile profile, String name, boolean isAbstract) {
        Stereotype stereotype = profile.createOwnedStereotype(name, isAbstract);

        out("Stereotype '%s' created.", stereotype.getQualifiedName());

        return stereotype;
    }

Here we call the createOwnedStereotype(String, boolean) convenience factory method to ask the profile to create a stereotype with the specified name as one of its owned members, and set the isAbstract attribute of the stereotype based on the specified boolean argument.

OK, let’s see this method in action. For example, we could create an abstract stereotype named ‘EStructuralFeature’ in profile ‘ecore’ as follows:

    Stereotype eStructuralFeatureStereotype = createStereotype(ecoreProfile, "EStructuralFeature", true);

GSWU2 tryit.gif Write code to programmatically create the remaining (non-abstract) stereotypes (i.e., ‘EAttribute’ and ‘EReference’) for the Ecore profile.

Creating Stereotype Generalizations

Just like classes, stereotypes may be involved in generalizations (stereotypes are a kind of class). A generalization is a taxonomic relationship between a specific classifier and a more general classifier whereby each instance of the specific classifier is also an indirect instance of, and inherits the features of, the general classifier. To create a stereotype generalization using the UML editor, follow these steps:

  1. Select a stereotype (e.g., <Stereotype> EAttribute) in the UML editor.
  2. Select the New Child > Generalization > Generalization option from the context menu.
  3. Select a value (e.g., ecore::EStructuralFeature) for the General property in the Properties view.

GSWU2 tryit.gif Create the other generalization (i.e., between EReference and EStructuralFeature) for the Ecore profile using the UML editor.

GSWU2 tip.gif Be sure to pick the first ecore::EStructuralFeature item (with a lowercase "ecore") instead of the second one (with an uppercase "Ecore"), which comes from the built-in Ecore profile provided by UML2.

At this point your workspace should look something like this:

ITU2P CreatingStereotypeGeneralizations.png

Let’s look at how to perform the same task using Java code. The code snippet below shows a method that programmatically creates and returns generalization between specified specific and general classifiers.

    protected static Generalization createGeneralization(Classifier specificClassifier, Classifier generalClassifier) {
        Generalization generalization = specificClassifier.createGeneralization(generalClassifier);

        out("Generalization %s --|> %s created.", specificClassifier.getQualifiedName(), generalClassifier.getQualifiedName());

        return generalization;
    }

Here we call a convenience factory method on the specific classifier that creates a generalization as one of its children and sets the general classifier to the specified argument.

OK, let’s see this method in action. For example, we could create a generalization between specific stereotype ‘EAttribute’ and general stereotype ‘EStructuralFeature’ as follows:

    createGeneralization(eAttributeStereotype, eStructuralFeatureStereotype);

GSWU2 tryit.gif Write code to programmatically create the other generalization (i.e., between ‘EReference’ and ‘EStructuralFeature’) for the Ecore profile.

Creating Stereotype Properties

Again just like classes, stereotypes may have properties (attributes). When a stereotype is applied to a model element, the values of the properties may be referred to as tagged values. To create a stereotype property using the UML editor, follow these steps:

  1. Select a stereotype (e.g., <Stereotype> EStructuralFeature) in the UML editor.
  2. Select the New Child > Owned Attribute > Property option from the context menu.
  3. Enter a value (e.g., "isTransient”) for the Name property in the Properties view.
  4. Select a value (e.g., PrimitiveTypes::Boolean) for the Type property in the Properties view.
  5. Enter a value (e.g., 0) for the Lower property in the Properties view.
  6. Select the property (e.g., <Property> isTransient) in the UML editor.
  7. Select a value (e.g., false) from the pick-list in the Default property in the Properties view.

GSWU2 tip.gif Default values for properties (and parameters) are represented as value specifications (first-class objects) in UML™ 2.x. Here we have selected a literal Boolean (whose default value is false) as the default value of our property since its type is Boolean. If the type of the property were String, we’d have used a literal string instead. Once a default value specification has been created, its value can alternatively be set with the owning property selected via the Default property in the Properties view. For attributes typed by the UML™ standard primitive types or by enumeration types, the Default property in the property sheet provides assistance in creating value specifications of the appropriate type. For other types (e.g., custom data types or classes), it is necessary to explicitly create the Default Value value specification.

GSWU2 tryit.gif Create the remaining stereotype properties for the Ecore profile (i.e., “isUnsettable”, “isVolatile”, “visibility”, “xmlName”, “xmlNamespace”, and “xmlFeatureKind” for <Stereotype> EStructuralFeature; “attributeName” for <Stereotype> EAttribute; “referenceName” and “isResolveProxies” for <Stereotype> EReference) using the UML editor.

GSWU2 tip.gif Be sure to set the appropriate default value for each stereotype property so that it is consistent with the corresponding property in Ecore. In particular, the default value for the “isResolveProxies” should be a literal Boolean with a value of true instead of the default (!) default value of false. Note also that the types of the “visibility” and “xmlFeatureKind” properties should be the enumerations we created earlier (i.e., ecore::Visibility and ecore::FeatureKind, respectively).

At this point your workspace should look something like this:

ITU2P CreatingStereotypeProperties.png

Let’s look at how to perform the same task using Java code. The code snippet below shows a method that programmatically creates and returns an attribute with a specified upper bound, lower bound, type, name, and (optionally) default value in a specified class.

    protected static Property createAttribute(org.eclipse.uml2.uml.Class class_, String name, Type type, int lowerBound, int upperBound, Object defaultValue) {
        Property attribute = class_.createOwnedAttribute(name, type, lowerBound, upperBound);

        if (defaultValue instanceof Boolean) {
            LiteralBoolean literal = (LiteralBoolean) attribute.createDefaultValue(null, null, UMLPackage.Literals.LITERAL_BOOLEAN);
            literal.setValue(((Boolean) defaultValue).booleanValue());
        } else if (defaultValue instanceof String) {
            if (type instanceof Enumeration) {
                InstanceValue value = (InstanceValue) attribute.createDefaultValue(null, null, UMLPackage.Literals.INSTANCE_VALUE);
                value.setInstance(((Enumeration) type).getOwnedLiteral((String) defaultValue));
            } else {
                LiteralString literal = (LiteralString) attribute.createDefaultValue(null, null, UMLPackage.Literals.LITERAL_STRING);
                literal.setValue((String) defaultValue);
            }
        }

        out("Attribute '%s' : %s [%s..%s]%s created.", //
            attribute.getQualifiedName(), // attribute name
            type.getQualifiedName(), // type name
            lowerBound, // no special case for multiplicity lower bound
            (upperBound == LiteralUnlimitedNatural.UNLIMITED)
                ? "*" // special case for unlimited bound
                : upperBound, // finite upper bound
            (defaultValue == null)
                ? "" // no default value (use type's intrinsic default)
                : String.format(" = %s", defaultValue));

        return attribute;
    }

Here we call the createOwnedAttribute(String, Type, int, int) convenience factory method to ask the class to create a property as one of its owned attributes, set the type of the attribute to the specified type, and set the lower and upper bounds of the attribute (the factory method creates a literal integer and literal unlimited natural, respectively, and sets its value to the specified integer value). If a default value is provided, we create a value specification of the appropriate type (in this example, only booleans, strings, and enumeration literals are handled).

GSWU2 tip.gif The LiteralUnlimitedNatural.UNLIMITED constant represents the unlimited value for upper bounds (-1), as it does in EMF.

OK, let’s see this method in action. For example, we could create an attribute with multiplicity 0..1 of type ‘UMLPrimitiveTypes::Boolean’ named ‘isTransient’ in stereotype ‘EStructuralFeature’ as follows:

    Property isTransientProperty = createAttribute(eStructuralFeatureStereotype, "isTransient", booleanPrimitiveType, 0, 1, null);

GSWU2 tryit.gif Write code to programmatically create the remaining stereotype properties (i.e., ‘isUnsettable’, ‘isVolatile’, ‘visibility’, ‘xmlName’, ‘xmlNamespace’, and ‘xmlFeatureKind’ in stereotype ‘EStructuralFeature’; ‘attributeName’ in stereotype ‘EAttribute’; ‘referenceName’ and ‘isResolveProxies’ in stereotype ‘EReference’) for the Ecore profile.

Referencing Metaclasses

A profile is a restricted form of a metamodel that must always be related to a reference metamodel (e.g., UML). A profile cannot be used without its reference metamodel; it defines a limited capability to extend metaclasses of the reference metamodel via stereotypes. Profiles can be made to reference metaclasses from metamodels by creating an import relationship between the profile and the reference metaclass. To reference a metaclass using the UML editor, follow these steps:

  1. Select a profile (e.g., <Profile> ecore) in the UML editor.
  2. Select the UML Editor > Profile > Reference Metaclass... menu item.
  3. Choose a metaclass (e.g., UML::Property), press the Add button, then press the OK button.

At this point your workspace should look something like this:

ITU2P ReferencingMetaclasses.png

Let’s look at how to perform the same task using Java code. The code snippet below shows a method that programmatically references the metaclass with a specified name in the UML metamodel from a specified profile and returns it.

    protected static org.eclipse.uml2.uml.Class referenceMetaclass(Profile profile, String name) {
        Model umlMetamodel = (Model) load(URI.createURI(UMLResource.UML_METAMODEL_URI));

        org.eclipse.uml2.uml.Class metaclass = (org.eclipse.uml2.uml.Class) umlMetamodel.getOwnedType(name);

        profile.createMetaclassReference(metaclass);

        out("Metaclass '%s' referenced.", metaclass.getQualifiedName());

        return metaclass;
    }

Here we load the metamodel containing the UML metaclasses using a load(...) utility method (described later) and a URI defined on the UMLResource interface. Next, we retrieve the desired (owned) metaclass from the (meta)model by name using the convenience method. Finally, we invoke another convenience method to create the element import relationship between the profile and the metaclass, notify the user, and return the metaclass.

GSWU2 tip.gif The UML resources plug-in (org.eclipse.uml2.uml.resources) provides two metamodels (which by convention have a .metamodel.uml file extension), UML and Ecore. These metamodels can be accessed using URIs defined on the UMLResource interface, as shown above.

OK, let’s see this method in action. For example, we could reference the metaclass named ‘Property’ from profile ‘ecore’ as follows:

    org.eclipse.uml2.uml.Class propertyMetaclass = referenceMetaclass(ecoreProfile, UMLPackage.Literals.PROPERTY.getName());

Creating Extensions

Extensions are used to indicate that the properties of metaclasses are extended through stereotypes, and give the ability to flexibly apply (and later unapply) stereotypes to elements. An extension is a kind of association, one end of which is an ordinary property, and the other is an extension end. An extension may be required (depending on the lower bound of the extension end), which indicates that an instance of the extending stereotype must be created whenever an instance of the extended metaclass is created. To create an extension using the UML editor, follow these steps:

  1. Select a stereotype (e.g., <Stereotype> EAttribute) in the UML editor.
  2. Select the UML Editor > Stereotype > Create Extension... menu item.
  3. Choose a metaclass (e.g., UML::Property), press the Add button, then press the OK button.

GSWU2 tryit.gif Create the other extension (i.e., between UML::Property and <Stereotype> EReference) for the Ecore profile using the UML editor.

At this point your workspace should look something like this:

ITU2P CreatingExtensions.png

GSWU2 tip.gif You’ll notice that a number of new elements have appeared in the UML editor. In particular, you’ll see a new stereotype property with a name of the form base_<metaclass name>, an extension with a name of the form <metaclass name>_<stereotype name>, and an extension end with a name of the form extension_<stereotype name>. It’s important that these elements not be modified, since the UML2 profile mechanism depends on these constructs.

Let’s look at how to perform the same task using Java code. The code snippet below shows a method that programmatically creates and returns a(n) (required) extension between a specified metaclass and a specified stereotype.

    protected static Extension createExtension(org.eclipse.uml2.uml.Class metaclass, Stereotype stereotype, boolean required) {
        Extension extension = stereotype.createExtension(metaclass, required);

        out("%sxtension '%s' created.", //
            required
                ? "Required e" // it's a required extension
                : "E", // an optional extension
            extension.getQualifiedName());

        return extension;
    }

Here we call a convenience method on the stereotype that creates an extension (and its ends) between it and a metaclass as one of its siblings (i.e., as a child of its profile namespace). Behind the scenes, the stereotype also creates the ends of the extension, resulting in a new property on the stereotype (with a special name) and an extension end owned by the extension (again, with a special name).

OK, let’s see this method in action. For example, we could create a non-required extension between metaclass ‘Property’ and stereotype ‘EAttribute’ in profile ‘ecore’ as follows:

    createExtension(propertyMetaclass, eAttributeStereotype, false);

GSWU2 tryit.gif Write code to programmatically create the other extension (i.e., between metaclass ‘Property’ and stereotype ‘EReference’) for the Ecore profile.

Defining Profiles

There. We’ve finished creating (a scaled down version of) the Ecore profile, and we’re ready to start using it. But before we can, there’s one final thing we need to do: define it. Since a profile effectively represents an augmentation of a reference metamodel (UML), in order for the extensions we’ve defined to appear as though they’re part of the UML metamodel, they need to be “defined” at the meta-metamodel (i.e., Ecore) level. The implementation of profile support in UML2 supports defining both dynamic and static profile representations. In this article, we'll focus on the former.

When defining a dynamic profile representation, the contents of a profile are converted to an equivalent Ecore format that is stored as an annotation on the profile. Then, when a profile and its stereotypes are applied to a model and its elements, dynamic EMF (see the EMF book for details) is used to store property values for the stereotypes. For the most part, you can ignore this complexity, as long as you remember to define your profile before using it. To define a dynamic profile representation using the UML editor, follow these steps:

  1. Select a profile (i.e., <Profile> ecore) in the UML editor.
  2. Select the UML Editor > Profile > Define menu item.

At this point your workspace should look something like this:

ITU2P DefiningProfiles.png

You’ll notice that an annotation with source "http://www.eclipse.org/uml2/2.0.0/UML" has been attached to the profile. It contains the generated Ecore representation (an Ecore package with classes, attributes, enums, etc.) of the profile. As with extensions, it’s important that this annotation (and its contents) not be modified, since the UML2 profile mechanism depends on these constructs.

Let’s look at how to perform the same task using Java code. The code snippet below shows a method that programmatically defines a specified profile.

    protected static void defineProfile(Profile profile) {
        profile.define();

        out("Profile '%s' defined.", profile.getQualifiedName());
    }

Here we call a convenience method on the profile that generates the Ecore representation of the profile and increments its version.

OK, let’s see this method in action. For example, we could define the ‘ecore’ profile as follows:

    defineProfile(ecoreProfile);

Saving Profiles

Now that we’ve spent all this time creating and defining a profile, we’d better save our work. When we created our profile using the UML model wizard, a UML resource was created for us, so now all that needs to be done is to serialize the contents of our profile as XMI to a file on disk (i.e., Ecore.profile.uml). To save a profile using the UML editor, follow these steps:

  1. Select the File > Save menu item.

It’s that simple. Programmatically, we have a bit more work to do because so far, we’ve been creating our profile in a vacuum, i.e., without a containing resource. The code snippet below shows a method that saves a specified package to a resource with a specified URI.

    private static final ResourceSet RESOURCE_SET;

    static {
        // Create a resource-set to contain the resource(s) that we load and
        // save
        RESOURCE_SET = new ResourceSetImpl();

        // Initialize registrations of resource factories, library models,
        // profiles, Ecore metadata, and other dependencies required for
        // serializing and working with UML resources. This is only necessary in
        // applications that are not hosted in the Eclipse platform run-time, in
        // which case these registrations are discovered automatically from
        // Eclipse extension points.
        UMLResourcesUtil.init(RESOURCE_SET);

    }

    protected static void save(org.eclipse.uml2.uml.Package package_, URI uri) {
        // Create the resource to be saved and add the package to it
        Resource resource = RESOURCE_SET.createResource(uri);
        resource.getContents().add(package_);

        // And save.
        try {
            resource.save(null);
            out("Done.");
        } catch (IOException ioe) {
            err(ioe.getMessage());
        }
    }

Here we use a statically initialized resource set to create a resource with the specified URI, add the package to the resource’s contents, and ask the resource to save itself using the default options. If an exception occurs, we notify the user via our handy utility method.

GSWU2 tip.gif The above example uses the UMLResourcesUtil.init(...) API introduced in UML2 4.0.0 for the Juno release. As commented in the code snippet, this is not required in code running in the Eclipse Platform run-time, as in that case these registrations are discovered automatically from extension points.

OK, let’s see this method in action. For example, we could save the ‘ecore’ profile to a resource with URI ‘Ecore.profile.uml’ (relative to a local filesystem path passed in as an argument) as follows:

    save(ecoreProfile, URI.createFileURI(args[0]).appendSegment("Ecore").appendFileExtension(UMLResource.PROFILE_FILE_EXTENSION));

GSWU2 tip.gif The UMLResource.PROFILE_FILE_EXTENSION constant represents the file extension for UML2 profiles (.profile.uml).

Loading Models

In order to make use of our profile, we’ll need to open a model and load the profile. We’ll use the ExtendedPO2 model that was created in the Getting Started with UML2 article (you’ll need to copy it into your project and refresh the workspace first).

To open a model using the UML editor, follow these steps:

  1. Double-click on the resource (i.e., ExtendedPO2.uml) in the Navigator view.

Behind the scenes, a resource is obtained from the right kind resource factory (based on the extension ‘.uml’) and loaded, and then a new UML editor is opened and populated with the resource’s contents.

To load a profile (or any resource, actually) using the UML editor, follow these steps:

  1. Select the UML Editor > Load Resource... menu item.
  2. Press the Browse Workspace... button.
  3. Select a resource (e.g., Introduction to UML2 Profiles/Ecore.profile.uml) and press the OK button.
  4. Press the OK button.

At this point your workspace should look something like this:

ITU2P LoadingModels.png

Programmatically, we have a bit more work to do. The code snippet below shows a method that loads a package from a resource with a specified URI.

    protected static org.eclipse.uml2.uml.Package load(URI uri) {
        org.eclipse.uml2.uml.Package package_ = null;

        try {
            // Load the requested resource
            Resource resource = RESOURCE_SET.getResource(uri, true);

            // Get the first (should be only) package from it
            package_ = (org.eclipse.uml2.uml.Package) EcoreUtil.getObjectByType(resource.getContents(), UMLPackage.Literals.PACKAGE);
        } catch (WrappedException we) {
            err(we.getMessage());
            System.exit(1);
        }

        return package_;
    }

Here we obtain a resource with the specified URI from our statically initialized resource set, asking that it be loaded on demand. Next, we use an EMF utility method to obtain the first object of type Package from the resource’s contents. If an exception occurs, we notify the user via our handy utility method. Finally, if all is well, we return the package.

GSWU2 tip.gif The EcoreUtil class (provided by EMF) defines a number of utilities that you may find quite useful when working with EMF-based resources.

OK, let’s see this method in action. For example, we could load the ‘epo2’ model from a resource with URI ‘ExtendedPO2.uml’ (relative to a filesystem path passed in as an argument) as follows:

    Model epo2Model = (Model) load(URI.createFileURI(args[0]).appendSegment("ExtendedPO2").appendFileExtension(UMLResource.FILE_EXTENSION));

Applying Profiles

OK, our profile has been created, defined, saved, and loaded, and we’re ready to apply it to our model. Applying a profile means that it is allowed (but not necessarily required) to apply the stereotypes that are defined in the profile to elements in the package. A profile application is a special type of package import that indicates that a profile has been applied to a package. To apply a profile to a package using the UML editor, follow these steps:

  1. Select a package (e.g., <Model> epo2) in the UML editor.
  2. Select the UML Editor > Package > Apply Profile... menu item.
  3. Choose a profile (e.g., ecore), press the Add button, then press the OK button.

GSWU2 tip.gif Be sure to pick the profile we’ve created instead of the built-in profile provided by the UML resources plug-in (i.e., ecore, not Ecore).

At this point your workspace should look something like this:

ITU2P ApplyingProfiles.png

GSWU2 tip.gif You’ll notice another annotation (with source "http://www.eclipse.org/uml2/2.0.0/UML") has been attached, in this case to keep track of the Ecore representation for the definition of the profile that is currently applied to the package. Again, it’s important that this annotation not be modified, since the UML2 profile mechanism depends on this construct. Note that a newer definition of the profile can be applied using the same menu item, and a profile (along with all of its stereotypes) can be unapplied using the UML Editor > Package > Unapply Profile... menu item.

Let’s look at how to perform the same task using Java code. The code snippet below shows a method that programmatically applies a specified profile to a specified package.

    protected static void applyProfile(org.eclipse.uml2.uml.Package package_, Profile profile) {
        package_.applyProfile(profile);

        out("Profile '%s' applied to package '%s'.", profile.getQualifiedName(), package_.getQualifiedName());
    }

Here we call a convenience method on the package that creates a profile application on the package and sets the profile as the imported profile.

OK, let’s see this method in action. For example, we could apply the ‘ecore’ profile to the ‘epo2’ model as follows:

    applyProfile(epo2Model, ecoreProfile);

Applying Stereotypes

We’re on the home stretch now. Once a profile has been applied to a package, stereotypes defined in the profile can be applied to instances of the appropriate metaclasses (as per the defined extensions). When a stereotype is applied to an element, that element is effectively extended with the properties that are defined as part of the stereotype. To apply a stereotype to an element using the UML editor, follow these steps:

  1. Select an element (e.g., <Property> pendingOrders : PurchaseOrder [0..*] in <Class> Supplier) in the UML editor.
  2. Select the UML Editor > Element > Apply Stereotype... menu item.
  3. Choose a stereotype (e.g., ecore::EReference), press the Add button, then press the OK button.

GSWU2 tryit.gif Apply the appropriate stereotypes to other properties (<Property> shippedOrders : PurchaseOrder [0..*] in <Class> Supplier; <Property> totalAmount : int [0..1], <Property> previousOrder : PurchaseOrder [0..1], and <Property> customer : Customer in <Class> PurchaseOrder; <Property> orders : PurchaseOrder [0..*] in <Class> Customer) in the ExtendedPO2 model using the UML editor.

At this point your workspace should look something like this:

ITU2P ApplyingStereotypes.png

GSWU2 tip.gif A stereotype (and its tagged values) can be unapplied using the UML Editor > Element > Unapply Stereotype... menu item.

Let’s look at how to perform the same task using Java code. The code snippet below shows a method that programmatically applies a specified stereotype to a specified (named) element.

    protected static void applyStereotype(NamedElement namedElement, Stereotype stereotype) {
        namedElement.applyStereotype(stereotype);

        out("Stereotype '%s' applied to element '%s'.", stereotype.getQualifiedName(), namedElement.getQualifiedName());
    }

Here we call a convenience method on the element that creates an instance of the Ecore class representing the specified stereotype (using dynamic EMF) and attaches it to the element using an annotation.

OK, let’s see this method in action. For example, we could apply the ‘EReference’ stereotype to the ‘pendingOrders’ property of the ‘Supplier’ class in the ‘epo2’ model as follows:

    org.eclipse.uml2.uml.Class supplierClass = (org.eclipse.uml2.uml.Class) epo2Model.getOwnedType("Supplier");
 
    Property pendingOrdersProperty = supplierClass.getOwnedAttribute("pendingOrders", null);
    applyStereotype(pendingOrdersProperty, eReferenceStereotype);

GSWU2 tryit.gif Write code to programmatically apply the appropriate stereotypes to other properties (i.e., ‘epo2::Supplier::shippedOrders’, ‘epo2::PurchaseOrder::totalAmount’, ‘epo2::PurchaseOrder::previousOrder’, ‘epo2::PurchaseOrder::customer’, and ‘epo2::Customer::orders’) in the ExtendedPO2 model.

Accessing Stereotype Property Values

At long last, we’re ready to get and set values for the properties (tagged values) defined in our extensions. To get and set the value for a stereotype property using the UML editor, follow these steps:

  1. Select the element to which the stereotyped has been applied (i.e., <<EReference>> <Property> pendingOrders : PurchaseOrder [0..*] in <Class> Supplier) in the UML editor.
  2. Enter or select a value (i.e., false) for the property (i.e., Is Resolve Proxies) under the category named for the stereotype (i.e., EReference) in the Properties view.

GSWU2 tryit.gif Get and set values for other stereotype properties (i.e., Is Transient and Is Volatile under EReference for <<EReference>> <Property> pendingOrders : PurchaseOrder [0..*] in <Class> Supplier; Is Resolve Proxies, Is Transient, and Is Volatile under EReference for <<EReference>> <Property> shippedOrders : PurchaseOrder [0..*] in <Class> Supplier; Is Transient and Is Volatile under EAttribute for <<EAttribute>> <Property> totalAmount : int [0..1] in <Class> PurchaseOrder; Is Resolve Proxies under EReference for <<EReference>> <Property> previousOrder : PurchaseOrder [0..1] in <Class> PurchaseOrder; Is Resolve Proxies under EReference for <<EReference>> <Property> customer : Customer in <Class> PurchaseOrder; Is Resolve Proxies under EReference for <<EReference>> <Property> orders : PurchaseOrder [0..*] in <Class> Customer) in the ExtendedPO2 model using the UML editor.

At this point your workspace should look something like this:

ITU2P AccessingStereotypePropertyValues.png

Let’s look at how to perform the same task using Java code. The code snippet below shows a method that programmatically gets and returns the value of a specified property of a specified stereotype for a specified element.

    protected static Object getStereotypePropertyValue(NamedElement namedElement, Stereotype stereotype, Property property) {
        Object value = namedElement.getValue(stereotype, property.getName());

        out("Value of stereotype property '%s' on element '%s' is %s.", property.getQualifiedName(), namedElement.getQualifiedName(), value);

        return value;
    }

Here we call a convenience method on the (named) element that retrieves the value of a property with a specified name from the dynamically created Ecore object instance corresponding to the specified applied stereotype, notifies the user, and returns it.

OK, let’s see this method in action. For example, we could get the value of the ‘isVolatile’ property of the ‘EReference’ stereotype for the ‘pendingOrders’ property of the ‘Supplier’ class in the ‘epo2’ model as follows:

    getStereotypePropertyValue(pendingOrdersProperty, eReferenceStereotype, isVolatileProperty);

GSWU2 tryit.gif Write code to programmatically get the values of the other stereotype properties for elements in the ExtendedPO2 model.

The code snippet below shows a method that programmatically sets the value of a specified property of a specified stereotype for a specified element to a specified value.

    protected static void setStereotypePropertyValue(NamedElement namedElement, Stereotype stereotype, Property property, Object value) {
        Object valueToSet = value;

        if ((value instanceof String) && (property.getType() instanceof Enumeration)) {
            // Get the corresponding enumeration literal
            valueToSet = ((Enumeration) property.getType()).getOwnedLiteral((String) value);
        }

        namedElement.setValue(stereotype, property.getName(), valueToSet);

        out("Value of stereotype property '%s' on element '%s' set to %s.", property.getQualifiedName(),
                namedElement.getQualifiedName(), value);
    }

Here we call a convenience method on the (named) element that sets the value of a property with a specified name in the dynamically created Ecore object instance corresponding to the specified applied stereotype and notifies the user.

GSWU2 tip.gif Values of primitive types are represented by the usual Java types: String, Boolean, Integer, etc. For values of enumerations, the UML2 API accepts and returns the EnumerationLiteral instances from the profile model. For convenience, this utility method allows enumeration values to be set using simply the name of the literal.

OK, let’s see this method in action. For example, we could set the value of the ‘isVolatile’ property of the ‘EReference’ stereotype for the ‘pendingOrders’ property of the ‘Supplier’ class in the ‘epo2’ model to Boolean.TRUE as follows:

    setStereotypePropertyValue(pendingOrdersProperty, eReferenceStereotype, isVolatileProperty, true);

GSWU2 tryit.gif Write code to programmatically set the values of the other stereotype properties for elements in the ExtendedPO2 model.

Conclusion

Congratulations! If you’ve made it this far, you’ve successfully created and applied a simple profile programmatically and/or using the UML editor. There’s a whole lot more that could be said, but the purpose of this article was just to introduce you to the concepts. Stay tuned for more articles on how to develop tools with UML2.

For more information on UML2, visit the home page or join a discussion in the forum.

References

[1] K. Hussey and J. Bruck. "Getting Started with UML2”. International Business Machines Corp., CEA, and others, 2004, 2014.

[2] F. Budinsky, D. Steinberg, E. Merks, R. Ellersick, and T. J. Grose. Eclipse Modeling Framework. Pearson Education, Inc., Boston, MA, 2003.

Back to the top