MWE2 and UML

A while ago I wrote a blog about Extremely Ajaxified Web Applications, which was trying to explain the challenges of the modern web application development in the days of everything programmed in an asynchronous way and how this cause a strain on the classical development techniques.

I proposed a Model Driven Approach with Spring Web Flow, Primefaces and State Machines. The part of the solution is to produces a runnable State Machine from UML Diagrams.

In the original blog I used the OpenArchitectureWare Framework to create Spring Configuration and Java code. In the time period that I wrote the blog, OpenArchitectureWere was in the process of transferring the development to the Eclipse Platform und was under incubation period with the name of M2T with version 0.72.

Lately to test some new ideas with the framework, I tried to build the project and to my shock discovered all the artifacts from the version 0.72 disappeared from Maven Repositories. I thought no problem lets find the new versions of the artifacts and make the build runnable.

Ohh boy, I was wrong, I don’t know it is intentional or not but I think Eclipse Team was trying to demotivate people to M2T/Xpand with UML models, some of the very critical components (mainly org.eclipse.xtend.typesystem.uml2 artifact) was not published to any Maven repository and was only available as OSGI dependency.

My old build structure could not deal with this so I had to make extensive changes. This blog is about this changes because during my struggles I couldn’t find anybody else mentioning and proposing solution to the similar problem. All the resources I found in the internet proposing solutions when all the artifacts are available in Maven Repositories or build as Eclipse Plugins.

Personally I want that my framework to be accessible to everybody, so they should just download it from the GitHub (with this command: git clone -b MWE2 git@github.com:mehmetsalgar/swf_statemachine.git) and run the Maven project without extensive configurations. That proved to be a quite a challenge.

There are some examples on the internet how to configure a MWE2 workflow for UML but none is newer then 3 years, it seems no one dealed with the problem lately as long as dependencies are available in Maven Repository everything works seamlessly.

New pattern is using exec-maven-plugin to run a MWE2.

    <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>exec-maven-plugin</artifactId>
         <executions>
          <execution>
            <phase>generate-sources</phase>
            <goals>
              <goal>java</goal>
            </goals>
           </execution>
          </executions>
        <configuration>
          <includeProjectDependencies>false</includeProjectDependencies>
          <includePluginDependencies>true</includePluginDependencies>
          <cleanupDaemonThreads>false</cleanupDaemonThreads>
          <stopUnresponsiveDaemonThreads>true</stopUnresponsiveDaemonThreads>
          <classpathScope>compile</classpathScope>
          <mainClass>org.eclipse.emf.mwe2.launch.runtime.Mwe2Launcher</mainClass>
          <additionalClasspathElements>
            <additionalClasspathElement>src/main/resources</additionalClasspathElement>
          </additionalClasspathElements>
          <arguments>
            <argument>file://${project.basedir}/src/main/resources/workflow.mwe2</argument>
            <argument>
              -p
            </argument>
            <argument>
              runtimeProject=${project.basedir}
            </argument>
          </arguments>
        </configuration>
        <dependencies>
          <dependency>
            <groupId>org.salgar.swf_statemachine</groupId>
            <artifactId>swf_statemachine_eclipse_dependencies</artifactId>
            <version>${project.version}</version>
            <classifier>repackaged</classifier>
          </dependency>
          <dependency>
            <groupId>org.fornax.cartridges</groupId>
            <artifactId>fornax-cartridges-uml2-javabasic-generator</artifactId>
            <version>${fornax.javabasic.cartridge.version}</version>
            <exclusions>
              <exclusion>
                <groupId>org.eclipse.uml2.uml</groupId>
                <artifactId>resources</artifactId>
              </exclusion>
              .......
            </exclusions>
          </dependency>
          <dependency>
            <groupId>org.salgar.swf_statemachine</groupId>
            <artifactId>swf_statemachine_fornax_extension</artifactId>
            <version>${project.version}</version>
            <exclusions>
              <exclusion>
                <groupId>org.eclipse.xtext</groupId>
                <artifactId>org.eclipse.xtext.xtext</artifactId>
              </exclusion>
            </exclusions>
          </dependency>
        </dependencies>
      </plugin>

exec-maven-plugin will run the class org.eclipse.emf.mwe2.launch.runtime.Mwe2Launcher which is actually the core of the fornax-oaw-m2-plugin.

It will accept as parameter the name of the workflow file.

            <argument>file://${project.basedir}/src/main/resources/workflow.mwe2</argument>
            <argument>
              -p
            </argument>
            <argument>
              runtimeProject=${project.basedir}
            </argument>

and execute it with the help of dependency information provided for the classes workflow needs it.

       <dependencies>
          .......
          <dependency>
            <groupId>org.fornax.cartridges</groupId>
            <artifactId>fornax-cartridges-uml2-javabasic-generator</artifactId>
            <version>${fornax.javabasic.cartridge.version}</version>
            <exclusions>
              <exclusion>
                <groupId>org.eclipse.uml2.uml</groupId>
                <artifactId>resources</artifactId>
              </exclusion>
              ....
            </exclusions>
          </dependency>
          ........
        </dependencies>

but it has its own hickups, for example if you have some M2T templates also in your workflow that is included in the same Maven project, it will not able to see in its classpath. For some odd reason it does not include the artifacts from the resource paths of the Maven project even the argument

<includeProjectDependencies>false</includeProjectDependencies>

is set to true.

To fix this problem I have to add the following configuration to the plugin configuration.

          <additionalClasspathElements>
            <additionalClasspathElement>src/main/resources</additionalClasspathElement>
          </additionalClasspathElements>

this will ensure that artifacts from the same project are visible also.

Now I hear you saying, seems straight forward what is the big deal? Everything fine and dandy when all the dependencies are in the Maven Repositories. For some odd reason, org.eclipse.xtend.typesystem.uml2 artifact is not. If you try to insert this as dependency to the exec-maven-plugin, your build will fail.

This artifact is available, at least I can find, only in Eclipse P2/OSGI repositories and unfortunately Maven out of the box can’t discover them. For this we need the help of another Maven Plugin, tycho-maven-plugin, its whole purpose is the integration of Eclipse RCP projects to the Maven projects.

This plugin can scan the MANIFEST.MF files of OSGI/Eclipse RCP projects and discover their dependencies from Eclipse p2 repositories. For this we must first define in our project these p2 Repositories as following.

For my purposes I need it the followings

   <repository>
      <id>4_6.repo.eclipse.org</id>
      <name>Project Repository - Releases</name>
      <url>http://download.eclipse.org/eclipse/updates/4.6</url>
      <layout>p2</layout>
    </repository>
    <repository>
      <id>4_5.repo.eclipse.org</id>
      <name>Project Repository - Releases</name>
      <url>http://download.eclipse.org/eclipse/updates/4.5</url>
      <layout>p2</layout>
    </repository>
    <repository>
      <id>indigo.repo.eclipse.org</id>
      <name>Project Repository - Releases</name>
      <url>http://download.eclipse.org/releases/indigo/</url>
      <layout>p2</layout>
    </repository>
    <repository>
      <id>xtext</id>
      <url>http://download.eclipse.org/modeling/tmf/xtext/updates/composite/releases/</url>
      <layout>p2</layout>
    </repository>

please pay attention to the ‘p2’ element, this tells Maven that is a p2 Repository is and it will not be evaluated a normal Maven dependencies but only for certain type of projects, for ex eclipse-plugin, eclipse-feature, etc…

Ok, so we need dependencies that does not exist in Maven Repositories then we should take them from p2 Repositories and we need a plugin to this for us and this plugin called tycho-maven-plugin. This plugin when it see the maven packaging type eclipse-plugin, eclipse-feature, etc.. it will look to the MANIFEST.MF file (which is OSGI definition of the artifact a la Maven) that lies in META-INF directory and try to locate stated dependencies over p2 repositories.

This is independent of Maven Dependencies resolving mechanism.

So if we look to the my previously stated problem that org.eclipse.xtend.typesystem.uml2 artifact is not in the Maven Repositories but in p2 repositories, it is clear that we have to use the tycho and eclipse-plugin packaging type. If you do this the exec-maven-plugin plugin will work correctly and successfully execute MWE2 Workflow if we set the following setting in the exec-maven-plugin ‘true’. This will ensure that dependencies resolved from tycho plugin will be visible to the exec-maven-plugin.

So you can ask what is the problem then. First of all final artifact that I want to create in my feasibility project is a Web Application. So the artifacts that I create with my Model Driven approach should be included to Web Application’s war artifact. An eclipse-plugin artifact will cause me problems to include in a web application.

We have a dilemma here, we have some dependencies that we need from p2 repository, so we have to use eclipse-plugin packaging type but also I have to have this artifact in a war archive so I need jar packaging type. I spend considerable amount to solve this paradox but I could not manage the way I described until now so I have to try something else.

There was a proposed solution in the internet about if a project need OSGI/Eclipse RCP dependencies to build an interim project with packaging type eclipse-plugin and let the tycho plugin gets the dependency then use maven dependency plugin to expand all the classes in the downloaded p2 dependencies and package them again with assembly plugin so later model creation projects with MWE2 can use those.

So for the people coming here from other blog I just created a new project ‘swf_statemachine_eclipse_dependencies’ which states in MANIFEST.MF file what dependencies are necessary.

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: org.salgar.swf_statemachine_eclipse_dependencies
Bundle-SymbolicName: swf_statemachine_eclipse_dependencies; singleton:=true
Bundle-Version: 1.0.0.qualifier
Require-Bundle: org.eclipse.xtext;bundle-version="[2.8.3,2.8.4)";visibility:=reexport,
 org.eclipse.xtext.xbase;bundle-version="[2.8.3,2.8.4)";resolution:=optional;visibility:=reexport,
 org.eclipse.xtext.generator;bundle-version="[2.8.3,2.8.4)";resolution:=optional,
 org.apache.log4j;bundle-version="1.2.15";visibility:=reexport,
 org.apache.commons.logging;bundle-version="1.0.4";resolution:=optional;visibility:=reexport,
 org.eclipse.emf.codegen.ecore;resolution:=optional,
 org.eclipse.emf.mwe.utils;resolution:=optional,
 org.eclipse.emf.mwe2.launch;resolution:=optional,
 org.eclipse.uml2.uml,
 org.eclipse.xtext.util,
 org.eclipse.emf.ecore,
 org.eclipse.emf.common,
 org.antlr.runtime,
 org.eclipse.xtext.common.types,
 org.eclipse.uml2.codegen.ecore;bundle-version="1.7.0",
 org.eclipse.xtend.typesystem.uml2,
 org.eclipse.xpand
Bundle-Vendor: salgar

and maven-dependency-plugin which unpack dependencies

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <executions>
          <execution>
            <id>unpack-dependencies</id>
            <phase>package</phase>
            <goals>
              <goal>unpack-dependencies</goal>
            </goals>
            <configuration>
              <outputDirectory>${project.build.directory}/dependency</outputDirectory>
              <overWriteReleases>false</overWriteReleases>
              <overWriteSnapshots>true</overWriteSnapshots>
            </configuration>
          </execution>
        </executions>
      </plugin>

and maven-assembly-plugin which is packing all the classes again.

     <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
        <configuration>
          <descriptors>
            <descriptor>src/main/assembly/repackaged.xml</descriptor>
          </descriptors>
        </configuration>
        <executions>
          <execution>
            <id>make-assembly</id>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
      </plugin>

and the assembly configuration repackaged.xml.

<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
    <id>repackaged</id>
    <formats>
        <format>jar</format>
    </formats>
    <includeBaseDirectory>false</includeBaseDirectory>
    <fileSets>
      <fileSet>
        <directory>${project.build.directory}/dependency/</directory>
        <outputDirectory>/</outputDirectory>
        <useDefaultExcludes>true</useDefaultExcludes>
      </fileSet>
    </fileSets>
</assembly>

which will create an artifact with ‘repackaged’ if we reference with a classifier ‘repackaged’ maven will able to find it as dependency for exec plugin.

     <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <executions>
          <execution>
            <phase>generate-sources</phase>
            <goals>
              <goal>java</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <includeProjectDependencies>false</includeProjectDependencies>
          <includePluginDependencies>true</includePluginDependencies>
          <cleanupDaemonThreads>false</cleanupDaemonThreads>
          <stopUnresponsiveDaemonThreads>true</stopUnresponsiveDaemonThreads>
          <classpathScope>compile</classpathScope>
          <mainClass>org.eclipse.emf.mwe2.launch.runtime.Mwe2Launcher</mainClass>
          <additionalClasspathElements>
            <additionalClasspathElement>src/main/resources</additionalClasspathElement>
          </additionalClasspathElements>
          <arguments>
            <argument>file://${project.basedir}/src/main/resources/workflow.mwe2</argument>
            <argument>
              -p
            </argument>
            <argument>
              runtimeProject=${project.basedir}
            </argument>
          </arguments>
        </configuration>
        <dependencies>
          <dependency>
            <groupId>org.salgar.swf_statemachine</groupId>
            <artifactId>swf_statemachine_eclipse_dependencies</artifactId>
            <version>${project.version}</version>
            <classifier>repackaged</classifier>
          </dependency>
          .........
      </plugin>

With this we solved our problem related to the ‘org.eclipse.xtend.typesystem.uml2’ artifact.

There are also substantial changes how the MWE2 worklflow configured compared to my previous blog entry, so I like to mention those instead of modifying the original blog.

My MWE2 workflow look like following at the moment, it has now really similarity to Java code, may be to Groovy.

module swf_statemachine_sm_model

import org.eclipse.emf.mwe.utils.*
import org.eclipse.xtext.generator.*
import org.eclipse.xtext.ui.generator.*
import org.eclipse.xpand2.*

import org.salgar.swf_statemachine.uml2.model.ExtendedUML2Metamodel

import org.salgar.swf_statemachine.uml2.Setup
import org.eclipse.xtend.typesystem.uml2.*
import org.eclipse.xtend.typesystem.uml2.UML2MetaModel
import org.eclipse.xtend.typesystem.emf.XmiReader
import org.eclipse.xtend.typesystem.uml2.profile.ProfilingExtensions.XmiReader
import org.eclipse.xtend.typesystem.uml2.profile.ProfileMetaModel
import org.eclipse.emf.mwe.utils.Reader
var targetDir = "src-gen"
var fileEncoding = "Cp1252"
var modelPath = "src/model"
var projectName = "swf_statemachine_sm_model"
var runtimeProject

var list.set.property = 'order'
var type_header_text = ""
var annotation_source_key = ""
var type_footer_text = ""
var javabasic_entities = ""
var classes_operation_implementation_strategy ="none"
var javabasic_generateSerialVersionUID = "true"
var use_overridden_equals_hashcode_toString= "true"
var java_version = "5"
var generate_additional_collection_methods = ""

Workflow {
	bean = org.eclipse.emf.mwe.utils.StandaloneSetup {
		platformUri=".."
		projectMapping = { projectName = "${projectName}" path = "${runtimeProject}" }
		projectMapping = { projectName = "swf_statemachine_domain" path = "../swf_statemachine_domain" }
		logResourceUriMap = false
		scanClassPath = false
	}
	bean = org.eclipse.xtend.typesystem.uml2.Setup {
 		standardUML2Setup = true
 	}
 	bean = org.eclipse.xtend.typesystem.uml2.UML2MetaModel : umlMM { }

 	bean = org.eclipse.xtend.typesystem.uml2.profile.ProfileMetaModel : swf_statemachine {
 		profile = "platform:/resource/swf_statemachine_sm_model/src/main/resources/swf_statemachine.profile.uml"
 	}
 	
 	bean = org.eclipse.xtend.typesystem.uml2.profile.ProfileMetaModel : datatype {
 		profile = "platform:/resource/swf_statemachine_domain/src/main/resources/model/Datatype.profile.uml"
 	}
 	
 	bean = org.eclipse.xtend.typesystem.uml2.profile.ProfileMetaModel : java {
 		profile = "platform:/resource/swf_statemachine_domain/src/main/resources/model/Java.profile.uml"
 	}
 	
 	component = org.eclipse.emf.mwe.utils.Reader {
 		uri = "platform:/resource/swf_statemachine_sm_model/src/main/resources/model/TechdemoModel.uml"
 		modelSlot = "model"
 	}
 	
 	 	component = org.eclipse.xpand2.Generator : enumerationGenerator {
 		metaModel = umlMM
 		metaModel = swf_statemachine
 		
 		globalVarDef = { name = "list_set_property" value = "'${list.set.property}'" }
 		globalVarDef = { name = "type_header_text" value = "''" }
 		globalVarDef = { name = "annotation_source_key" value = "''" }
 		globalVarDef = { name = "type_footer_text" value = "''" }
 		globalVarDef = { name = "javabasic_entities" value = "''" }
 		globalVarDef = { name = "classes_operation_implementation_strategy" value = "'${classes_operation_implementation_strategy}'" }
 		globalVarDef = { name = "javabasic_generateSerialVersionUID" value = "'${javabasic_generateSerialVersionUID}'" }
 		globalVarDef = { name = "use_overridden_equals_hashcode_toString" value = "'${use_overridden_equals_hashcode_toString}'" }
 		globalVarDef = { name = "java_version" value = "${java_version}" }
 		
 		fileEncoding = "ISO-8859-1"
 		outlet = { path = "${runtimeProject}/src/generated/java" postprocessor = org.eclipse.xpand2.output.JavaBeautifier {} }

		advice = "templates::advices::javaBasicAssociationAdvices"
		
		expand = "template::stateMachineEnumeration::Root FOR model"
 	}
 	
 	component = org.eclipse.xpand2.Generator : springGenerator {
 		metaModel = umlMM
 		metaModel = swf_statemachine
 		
 		fileEncoding = "ISO-8859-1"
 		outlet = { path = "${runtimeProject}/src/generated/resources"  postprocessor = org.salgar.m2t.xml.XmlBeautifier {} }
		
		expand = "template::stateMachineSpring::Spring FOR model"
 	}
 
 	component = org.eclipse.xpand2.Generator : javaGenerator {
 		metaModel = umlMM
 		metaModel = datatype
 		metaModel = java
 		globalVarDef = { name = "list_set_property" value = "'${list.set.property}'" }
 		globalVarDef = { name = "type_header_text" value = "''" }
 		globalVarDef = { name = "annotation_source_key" value = "''" }
 		globalVarDef = { name = "type_footer_text" value = "''" }
 		globalVarDef = { name = "javabasic_entities" value = "''" }
 		globalVarDef = { name = "classes_operation_implementation_strategy" value = "'${classes_operation_implementation_strategy}'" }
 		globalVarDef = { name = "javabasic_generateSerialVersionUID" value = "'${javabasic_generateSerialVersionUID}'" }
 		globalVarDef = { name = "use_overridden_equals_hashcode_toString" value = "'${use_overridden_equals_hashcode_toString}'" }
 		globalVarDef = { name = "java_version" value = "${java_version}" }
 		
 		fileEncoding = "ISO-8859-1"
 		outlet = { path = "${runtimeProject}/src/generated/java" postprocessor = org.eclipse.xpand2.output.JavaBeautifier {} }

		advice = "templates::advices::javaBasicAssociationAdvices"
		
		expand = "template::Root::Root FOR model"
 	}
}

first you have import java package that you are interested.

Secondly, one thing that cause me lots of headaches, while MWE2 / M2T is now integrated to Eclipse their first priority is to make run under Eclipse, the way I try to build the project under Maven and completely free from other environmental restrictions, was causing problems. MWE2 calls this standalone setup and for this purpose the projects needs Project Mapping to simulate Eclipse Platform environment.

This is not good documented at all and I have to debug MWE2 code understand what is going on unfortunately when this mapping is not done some really unexpected things stop working, like custom UML Profiles containing Steorotypes. When I didn’t not correctly made this mapping this Custom UML Profiles stopped working.

The following element defines the mapping.

         bean = org.eclipse.emf.mwe.utils.StandaloneSetup {
		platformUri=".."
		projectMapping = { projectName = "${projectName}" path = "${runtimeProject}" }
		projectMapping = { projectName = "swf_statemachine_domain" path = "../swf_statemachine_domain" }
		logResourceUriMap = false
		scanClassPath = false
	}

For the MWE2 workflow that are in our current workflow ‘projectMapping = { projectName = “${projectName}” path = “${runtimeProject}” }’ is enough it gets the necessary information from Maven build with ‘projectName’ and ‘runtimeProject’ variables.

‘runtimeProject’ is configured via ‘exec-maven-plugin’

      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <executions>
          ......
        </executions>
        <configuration>
          ......
          <arguments>
            <argument>file://${project.basedir}/src/main/resources/workflow.mwe2</argument>
            <argument>
              -p
            </argument>
            <argument>
              runtimeProject=${project.basedir}
            </argument>
          </arguments>
        </configuration>
        <dependencies>
          .........
      </plugin>

For the element ‘projectMapping = { projectName = “swf_statemachine_domain” path = “../swf_statemachine_domain” }’ which contains for me the Custom UML Profile we have to define manually.

So why this mapping is important, while MWE2 like to reference things in platform pattern like the following.

 	bean = org.eclipse.xtend.typesystem.uml2.profile.ProfileMetaModel : swf_statemachine {
 		profile = "platform:/resource/swf_statemachine_sm_model/src/main/resources/swf_statemachine.profile.uml"
 	}

if you didn’t made the mappings or don’t match with yours, you will get exceptions for the mentioned resources.

One more thing that annoyed me, in the previous version of the MWE you could use a property file for the properties in your M2T templates (i am using Fornax Javabasic Generator templates) to keep the workflow files clean but it seems that this feature is disappeared now I have to put the properties in the workflow and defines as followed.

       component = org.eclipse.xpand2.Generator : javaGenerator {
 		metaModel = umlMM
 		metaModel = datatype
 		metaModel = java
 		globalVarDef = { name = "list_set_property" value = "'${list.set.property}'" }
 		globalVarDef = { name = "type_header_text" value = "''" }
 		globalVarDef = { name = "annotation_source_key" value = "''" }
 		globalVarDef = { name = "type_footer_text" value = "''" }
 		globalVarDef = { name = "javabasic_entities" value = "''" }
 		globalVarDef = { name = "classes_operation_implementation_strategy" value = "'${classes_operation_implementation_strategy}'" }
 		globalVarDef = { name = "javabasic_generateSerialVersionUID" value = "'${javabasic_generateSerialVersionUID}'" }
 		globalVarDef = { name = "use_overridden_equals_hashcode_toString" value = "'${use_overridden_equals_hashcode_toString}'" }
 		globalVarDef = { name = "java_version" value = "${java_version}" }
 		
 		fileEncoding = "ISO-8859-1"
 		outlet = { path = "${runtimeProject}/src/generated/java" postprocessor = org.eclipse.xpand2.output.JavaBeautifier {} }

		advice = "templates::advices::javaBasicAssociationAdvices"
		
		expand = "template::Root::Root FOR model"
 	}

I could not find a way to use property file, if anybody that read this blog knows it please write it to the comment session so I can change it.

‘globalVarDef = { name = “list_set_property” value = “‘${list.set.property}'” }’ element will populate the collection of Global Variables for ‘org.eclipse.xpand2.Generator’.

Actually we are nearly at the end, one last thing I like to mention, I am using Javabasic Generator templates from the Fornax, latest version still works but it seems its development is stopped, it also reference old maven dependencies, for this reason I have to exclude those and provide newer versions. May be another follow up project exist that does similar things now but while they are working for me I didn’t researched too much, if anybody knows anything about it, I will appreciate the tip.

Well as always I hope somebody find this blog useful.

Advertisements

About Mehmet Salgar

Mehmet Salgar
This entry was posted in Fornax, M2T, Maven, MDA, MDD, MDSD, MWE, MWE2, OSGI, Software Development, State Machine, Topcased, Tycho, UML, XText. Bookmark the permalink.

One Response to MWE2 and UML

  1. Pingback: Extremely Ajaxified Web Application with Spring Webflow, Primefaces and State Machines | Mehmet Salgar's Blog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s