Automatically generating states with VS2010 UML tools and T4

Just for the social aspect of this post, I want to let you know that I am done with my studies :) I am still awaiting my degree but I did finish all the exams, thesis and colloquium. Now I am a Bachelor of Science in Computer Science. Anyway, that is just a degree and does not say anything about my actual qualifications and capabilities. It only says that over the last 3,5 years I dedicated very much of my time to sitting in labs and lectures doing and learning stuff that others think are important. I believe that the really important stuff has to be learned outside of university. Maybe even outside of a job. Follow me on twitter (@halllo).

It really starts here

Since Visual Studio 2010 Beta 2 hit the internet, I found it really sad that they do not have a state diagram as part of their UML tools. Well, I really needed some kind of state modeling so I came up with an solution that really fascinated me. It all started when I was reading Oleg Sych’s amazing blog posts about T4. Especially when I read “UML Modeling and Code Generation in Visual Studio 2010” (http://www.olegsych.com/2010/01/uml-modeling-and-code-generation-in-visual-studio-2010/). So this is where I kind of learned about the opportunities VS2010 enables.

My solution allows you to model states in Visual Studio and automatically generate code. You can use that code to wire up the generated states with your own logic and get all the states and transitioning for free. In this blog post I will demonstrate what I did with T4 and VS2010 Ultimate RC1. In that matter I will show you how you can use my results and am even going to show how I did it. All the source I release as well.

How to use it

I created the possibility to model states with Visual Studio 2010 Ultimate. When you create a new Modeling Project, you cant just create a state diagram. This is very sad, because it would not be too hard to implement for Microsoft, I guess. My approach uses a different perspective on states. In the state pattern you work with states as classes that inherit form a unified state abstraction. Thanks to polymorphic dispatch you can transit between states by setting a current state property in some state context. I kind of used the same idea. First, we will need a class diagram.

image

In the UML Model Explorer we need to specify the “UML State Profile 1”, like in the picture below. This profile is what I created and I will elaborate on it later in this post. Then we create some UML classes. For each class we set the stereotype to “State”.

 image image

After that, it should look something like in the picture below. What we did so far is specifying each class with an UML meta model directive called stereotype. For more information on that, please glean in the UML 2.2 specs, which you can download here: http://www.omg.org/spec/UML/2.2/.

 image

Our classes now represent states in a state machine. For the transitions we need to add associations between the classes. Like the classes, we can specify stereotypes on associations as well. Like you can see in the properties of the stereotype “Transition”, it can either be triggered by an “Event” or by a “Literal”. If you choose “Event”, the name that you give that transition is going to become an event on your state machine. If you choose “Literal”, the state machine becomes capable of handling string input. The name you give the transition in the latter case gets interpreted as a regular expression and if it matches the input, the transition is performed.

image image

After creating all the transitions between the states and naming them, our state diagram should look something like below.

image

State “Class1” transits to state “Class2” if the event “Start” is fired. Then, state “Class2” stays active, as long as the input are digits between “a” and “z”. It the input is a number, state “Class3” gets active and never goes back to “Class2”. When the event “Finish” is fired, the state machine terminates. “Start” and “Finshed” are “Event” transitions, while “[a-z]” and “[0-9]” are “Literal” transitions. It is important to notice, that the states “Class2” and “Class3” have the method Do() defined. These operations have the stereotype “State Behaviour” assigned.

With that, the model of our state machine is complete now. So in order to do something useful with it, we need to create a executable project in VS2010. I just created a Console Application, which I set to be the start project. Then, we need to copy the states template (States.tt) into this new project. I also created this template on which I am going to elaborate later in this post. In the template we need to specify the name of our modeling project so that the template can find it. I just changed this line:

string projectPath = Host.ResolvePath(@”..ModelingProject3ModelingProject3.modelproj”);

In order to generate the code from the modeled states, we need to save this *.tt file or run the custom tool, like in the image below.

image

This generates all the code for the states. Then we can compile the solution and should get no errors. Notice that it is not required to have a project reference to the UML project in the Console Application. Now we can start using the states in code and wire up our own logic. To do this best, I recommend inheriting form the generated class States in namespace StateUser. I did that in the code snippet below. I only wired up calls to WriteLines so that we can see what is going on inside the state machine.

class CustomStates : StateUser.States
{
    public CustomStates()
    {
        base.SetStartState(base.Class1);
        base.Class1.OnExit = () => Console.WriteLine(“Start…”);
        base.Class2.OnDo = () => Console.WriteLine(“Class2.Do()”);
        base.Class3.OnDo = () => Console.WriteLine(“Class3.Do()”);
        base.Class4.OnEntry = () => Console.WriteLine(“Done!”);
    }
}

If you want the machine to do more comprehensive stuff, you need to specify your behaviour by setting up Action expressions. Notice that the OnDo property represents the “Do” operation on the states “Class2” and “Class3”. Now we have our state machine all connected with the logic that we want it to handle. I put the interactions with the state machine directly in the Main method, like in the snippet below.

static void Main(string[] args)
{
    var statecontext = new CustomStates();
    statecontext.Fire_Start();
    statecontext.Input(“b”); statecontext.Do();
    statecontext.Input(“g”); statecontext.Do();
    statecontext.Input(“2”); statecontext.Do();
    statecontext.Input(“u”); statecontext.Do();
    statecontext.Fire_Finish();
}

I call start on it, give it two digits and then a number. When it gets the number it transits into “Class3” and stays there, even when I give it a number again, because this is the behaviour that we modeled with our UML classes. After each input, I call the Do operation. Dependent on the state that the machine is currently in, the corresponding Action is invoked. When I run the application, I get the following output:

Start…
Class2.Do()
Class2.Do()
Class3.Do()
Class3.Do()
Done!

We see that the machine does not leave state “Class3”, once we are in there. Our state machine works! To do all that on your own, you need to download these two files:

  1.  
    1. The “UML State Profile 1”:
      http://cid-e6c5570276bdbe2b.skydrive.live.com/self.aspx/%c3%96ffentlich/umlstateprofile1.Profile
    2. The “States” template:
      http://cid-e6c5570276bdbe2b.skydrive.live.com/self.aspx/%c3%96ffentlich/States.tt

Feel free to use it and give me feedback about what you think. If you want to change the profile or the template code to redistribute them, go ahead. I would be happy to be mentioned though :)

How it works

To enable the scenario above, I needed to create a custom UML profile. Visual Studio 2010 Ultimate allows that. It is just an XML file with the ending .Profile that needs to be copied to the location below.

C:Program Files (x86)Microsoft Visual Studio 10.0Common7IDEExtensionsMicrosoftArchitecture ToolsUmlProfiles

It also needs to be registered in the “extension.vsixmanifest” file, like below.

…<CustomExtension Type=”Microsoft.VisualStudio.UmlProfile”>umlstateprofile1.Profile</CustomExtension>…

The umlstateprofile1.Profile file itself consists of three parts. The first is the stereotypes tag. Here I defined the stereotypes for IClass, IAssociation and IOperation. The second part contains the names of the meta classes that you provide stereotypes for. The third part is a collection of properties, that you can assign to your stereotypes.

image

The stereotype for the UML Class is really simple. All you need to specify is the name, the display name and the target, which is the IClass in this case.

<stereotype name=”umlstate” displayName=”State”>
  <metaclasses>
    <metaclassMoniker name=”/umlstateprofile1/Microsoft.VisualStudio.Uml.Classes.IClass” />
  </metaclasses>
</stereotype>

The stereotype for the UML Association is a little more. Here you additionally have to provide the parameter indicating whether it is an “Event” or a “Literal” transition.

<stereotype name=”umltransition” displayName=”Transition”>
  <metaclasses>
    <metaclassMoniker name=”/umlstateprofile1/Microsoft.VisualStudio.Uml.Classes.IAssociation” />
  </metaclasses>
  <properties>
    <property name=”transitionaction” displayName=”Transistion Type” defaultValue=”Event”>
      <propertyType>
        <enumerationTypeMoniker name=”/umlstateprofile1/TransitionRuleType”/>
      </propertyType>
    </property>
  </properties>
</stereotype>

The enumeration type is referred to as TransitionRuleType. You have to have this one defined in the propertyTypes tag of the profile file. The definition looks like below.

<enumerationType name=”TransitionRuleType”>
  <enumerationLiterals>
    <enumerationLiteral name=”Literal” displayName=”Literal”/>
    <enumerationLiteral name=”Event” displayName=”Event”/>
  </enumerationLiterals>
</enumerationType>

The stereotype for the operations is equally much as for the association. It is just using a different enumeration type.

<stereotype name=”umlstatebehaviour” displayName=”State Behaviour”>
  <metaclasses>
    <metaclassMoniker name=”/umlstateprofile1/Microsoft.VisualStudio.Uml.Classes.IOperation” />
  </metaclasses>
  <properties>
    <property name=”behaviourtype” displayName=”Behaviour Type” defaultValue=”StateOperation”>
      <propertyType>
        <enumerationTypeMoniker name=”/umlstateprofile1/StateBehaviourType”/>
      </propertyType>
    </property>
  </properties>
</stereotype>

That is it for the UML profile. When there exists a project with things that have these stereotypes assigned, you can access them with code. I wrote that code in a T4 template, but you could also write it in a real application. The important thing is to have the correct namespaces referenced in the template. Since the compilation of the template is handled by Visual Studio, you do not need to provide project references. It is sufficient to just include their T4 using like below.

<#@ assembly name=”Microsoft.VisualStudio.Uml.Interfaces.dll” #>
<#@ assembly name=”Microsoft.VisualStudio.ArchitectureTools.Extensibility.dll” #>
<#@ import namespace=”Microsoft.VisualStudio.Uml.Classes” #>
<#@ import namespace=”Microsoft.VisualStudio.ArchitectureTools.Extensibility” #>

You can then get an instance of an IModelingProjectReader object.

string projectPath = Host.ResolvePath(@”..UmlStateClassUmlStateClass.modelproj”);
IModelingProjectReader project = ModelingProject.LoadReadOnly(projectPath);

Once you have that object, you can ask it for the everything that is in the corresponding project. It makes it easier if they have stereotypes assigned, but its not necessary. Below I iterate over all classes in the project and try to get their umlstate stereotype since this is the one that I defined in the UML profile.

foreach (IType t in types)
{
    IClass c = t as IClass;
    IStereotypeInstance sti = Extensions.GetStereotype(c, “umlstate”);
    if (sti != null) states.Add(new StateRepresentation(c));
}

Visual Studio allows stereotypes to be added to everything that implements IElement. This is pretty much everything so I could write a generic method that retrieves the instance of a stereotype form something that I give it. The kind of stereotype that is retrieved is specified by the stereotype name, which is a string.

public static IStereotypeInstance GetStereotype(IElement element, string stereotype)
{
    if (element == null) return null;
    return element.AppliedStereotypes.FirstOrDefault((sti) => sti.Name == stereotype);
}

When I have an instance of a stereotype, I can ask for its parameters, which i also specify as strings. These strings must be the same as in the UML profile file.

public static string GetStereotypeValue(IStereotypeInstance sti, string typename)
{
    if (sti == null) return null;
    IList<IStereotypePropertyInstance> stParams = sti.PropertyInstances;
    return stParams.FirstOrDefault((p) => p.Name == typename).Value;
}

With these constructs, I am able to get all the information that is required to create the state pattern automatically. The creation is done by the T4 engine. For editing the template I highly recommend the T4 editor form t4-editor.tangible-engineering.com, which is available as a free edition. This version does not support IntelliSense on the classes of “Microsoft.VisualStudio.Uml.Interfaces.dll” and “Microsoft.VisualStudio.ArchitectureTools.Extensibility.dll”, which is unfortunate but worked for me.

Conclusion

I am not generating the exact state pattern (www.dofactory.com/Patterns/PatternState) since I am not generating a class for each state. I rather create an object for each state. The abstract state is that class of these objects. Also the transitions are not hard wired in the methods of the classes. Since I am generating an object for each state I use delegates to provide transitioning behaviour. To enable usage of own logic in combination with the generated state machine, I provide protected members for manipulation through any class inheriting. I even allow rewiring of transitions at runtime.

This makes the generated code a powerful framework that supports all kinds of scenarios and makes the anti-if campaign useable with an UML modeling approach. It is important to know, that changes on the UML model does not effect the generated code directly. The custom tool has to be run in order to let the T4 engine create the code with the latest changes. It is also not a good idea to change the generated code. Every change is going to be overwritten on the next run of the custom tool. It is a better idea to inherit from the generated class. Inheritance is an even better and cleaner way than having partial classes.

I really hope you guys like what I did. I am using this state framework to get rid of ifs and have a generic state pattern creator that allows me to model my states in UML. Visual Studio 2010 Ultimate is an amazing tool. Unfortunately the UML tools are only part of the ultimate version which costs very much. This is why I really enjoy the betas and RCs. Anyway, I if anyone read all the way down here, let me know on twitter at http://www.twitter.com/halllo (@halllo). Please also checkout my website at http://neokc.de/.

Take care!

Manuel Naujoks (Bachelor of Science)

Advertisements