MDELite Users Guide (Version 2.3.0)

Don Batory

July 2013

MDELite is an experimental and hands-on approach to explore concepts of Model Driven Engineering (MDE) using Prolog as the language to define conformance constraints and model-to-model transformations.  The basic ideas are described in the paper (which is included with this documentation):
  Read this paper first. After doing so, you can then look at src/MDELite which contains the code of the described application. It implements the category below:

Study the code in src/MDELite -- each "bubble" above represents a class.  Each arrow is a method (drawn from the class that lists the method to the class that is output by the method).  

The hard part is to generate a set of Prolog tables from a diagram.  Use yUML or Violet to create a class diagram.  And then use the Conform program to create its Prolog tables.  Example: the file in the left-most column below is a yUML specification called good.yuml.  The class diagram in the middle column is what yUML draws given this specification.  The Prolog tables that are produced are shown in the right-hand column.

[M|a|b()]
[D|c|d()]
[E|f|g()]
[Program ]-m++[M]
[Program ]-d++[D]
[Program ]-e++[E]
[M]^-[D]
[D]^-[E]
table(yumlClass,[id,"name","fields","methods"]).
yumlClass(c1,'D','c','d()').
yumlClass(c2,'E','f','g()').
yumlClass(c0,'M','a','b()').
yumlClass(c3,'Program ','','').

table(yumlInterface,[id,"name","methods"]).
:- dynamic yumlInterface/3.

table(yumlAssociation,["name1","role1","end1","name2","role2","end2"]).
yumlAssociation('Program ','','','M','m','++').
yumlAssociation('Program ','','','D','d','++').
yumlAssociation('Program ','','','E','e','++').
yumlAssociation('M','','^','D','','').
yumlAssociation('D','','^','E','','').
To convert good.yuml into a set of Prolog tables, run:
> java MDELite.Conform yuml good
File good.yuml.pl is produced, shown above.

In general, filenames in MDELite are typically 3-tuples A.B.C: "A" is the user-chosen-name of a diagram.  "B" is its "type" (such as yuml or violet), and "C" typically is "pl" a Prolog extension.  So when you list a directory in which you have been running MDELite programs, all versions of the same user-chosen-name will be grouped together.

In general, the most difficult programs to write translate non-Prolog source to Prolog.  In MDELite, there are 3 such methods:
Look at their source code to see how they work.

PrintAlias

Occasionally, it is very useful to map a database to another database, where the names of the tables in one database are the same as the names of tables in another.  Prolog insists on tables with unique names.  So here's how you handle such issues, which I'll explain with a simple example.
Create tables A and B as usual.  But for D2.A and D2.B, use different names, such as A2 and B2.  In this way, your prolog model-to-model transformation will reference 4 different tables -- A,B,A2,B2.  Now the key is when you printout database D2 or tables A2 and B2.  Before you print any table of D2, execute the following Prolog predicates:
tableAlias(A2,A).
tableAlias(B2,B).

This tells the print rules to print "A" instead of "A2" when tuples of A2 are being printed.  The same for B.


Encoding of Prolog Tables

It is a matter of engineering to decide what Prolog tables to produce, and then write programs that conform to this format.  Look in libpl for examples.  libpl/yuml.schema.pl defines the "Prolog database" schema of yUML tables (illustrated above).  Here's its current contents:
/* file: yuml.schema.pl */

dbase(yuml,[yumlClass,yumlInterface,yumlAssociation]).

table(yumlClass,[id,"name","fields","methods"]).
table(yumlInterface,[id,"name","methods"]).
table(yumlAssociation,["name1","role1","end1","name2","role2","end2"]).

tuple(yumlClass,L):-yumlClass(I,N,F,M),L=[I,N,F,M].
tuple(yumlInterface,L):-yumlInterface(I,N,M),L=[I,N,M].
tuple(yumlAssociation,L):-yumlAssociation(N1,R1,E1,N2,R2,E2),L=[N1,R1,E1,N2,R2,E2].
A database (dbase) has a name (yuml) and a list of tables (yumlClass, yumlInterface, and yumlAssociation).  Each table has a name (e.g. yumlClass) and a list of attributes.  Attributes whose names are in "double-quotes" will have single-quoted values.  Attributes whose names are not in "double-quotes" have unquoted values.  See the yuml.good.pl tables above for examples.  The last 3 rules called "tuples" are derived from table declarations.  What these rules do is to map tuples of tables to a simple form that is easy to print.  Eventually, tuple declarations will be generated.  But for now, they have to be explicitly written in schema declarations.

Besides schema declarations (which in effect defines a model without constraints), model constraints also need to be specified.  In libpl/yuml.conform.pl you will find the current set of constraints (in Prolog, of course) that are imposed on instances of yuml tables.  Currently 3 constraints are checked:
There may be others that are subsequently added.  If you look at the file, you will see that the last predicate defined (run) evaluates all three predicates.  Such run predicates are standard convension in MDELite:
run :- uniqueNames,circular,icircular.
Another file that is associated with yuml schemas: yuml.run, which simply invokes a Prolog rule to print to standard out a yuml database.  The contents of yuml.run is:
/* file: yuml.run.pl -- output the tables of a Yuml database */

run:-printDbase(yuml).
Finally, one needs to translate yuml Prolog databases to database of other types.  The naming convention for such model-to-model transformations is a Prolog file libpl/yuml2X.pl, where X is the name of another database.  Presently, there is only one other database to which yuml databases are translated, namely to sdb (standard database).  So in file libpl/yuml2sdb.pl you will find the Prolog rules to translate a yuml database into a sdb database.  That is, for each table in sdb, there is a Prolog rule or rules to compute its contents from a yuml table.  A complete translation will print out the sdb tables (into some file).

To see how this is done, look at the src/MDELite/Yumlpl.java file.  This file implements the YumlPL class in the above category.  In particular, look at the code for the toSDB method (whose semantics are to translate a yuml database (i.e., Prolog file) to a sdb database (Prolog file)):
    public SDB toSDB(String extra) {
String[] array = {HomePath.homePath + "libpl/discontiguous.pl",
this.fullName, HomePath.homePath + "libpl/yuml2sdb.pl", HomePath.homePath + "libpl/sdb.schema.pl", HomePath.homePath + "libpl/print.pl", HomePath.homePath + "libpl/sdb.run.pl"};
SDB tmp = new SDB("tmp", array);
SDB result = new SDB(filename + extra);
tmp.executeProlog(result);
result.conform();
tmp.delete();
return result;
}
Here's how this Java method works.  (And if you can understand this method, you can understand them all).  Every file in MDELite corresponds to an MDELite object.  So a yuml.pl file corresponds to a YumlPL object.  A method for YumlPL objects is toSDB(x), listed above.  The "x" parameter is a string concatenated onto the name of a generated prolog file.  Typically x="", the empty string.  Here goes for the rest:
  1. a list of files is produced -- these files will be concatenated to produce a tmp.sdb.pl file.  The first file on the list is libpl/discontiguous.pl, which simply declares that Prolog table declarations will not be listed sequentially. Look at the good.yuml.pl example above: you will see that table declarations are indeed not listed sequentially, but are distributed throughout the file.
  2. the next file on the list is the name of the file to which the YumlPL object is bound (i.e., a textual listing of its database).
  3. next, the rules for translating a YumlPL database to a SDB database are listed, folllowed by a declaration of sdb.schema file, and then a general utility that prints databases.
  4. the SDB tmp variable is created that represents the file tmp.sdb.pl, which is the concatenation of all of the above-listed files.
  5. here's where it gets a little tricky: every MDELite database is both a file and an object.  One has to be created before the other -- there's no other way around this.  So the convention in MDELite coding is to create the object (above: result) first. Then execute the file that produces the Prolog file (result.sdb.pl).  That's what the tmp.executeProlog(result) does: it executes tmp.sdb.pl and produces a file whose name was given in the constructor of the result object.  
  6. OK, so now a result.sdb.pl (SDB database) was produced.  The next thing is to see if it conforms to SDB constraints.  That's what the result.conform() method invocation does.  
  7. the tmp object/file is deleted, and the result (an SDB database) is produced.
Pretty much all MDELite methods are interpreted in the same way.

Outputting non-Prolog Files

Eventually, a Prolog file needs to be translated into a non-Prolog file.  That's where the tool VM2T enters the picture.  Read its documentation here.