Aocl
Tooling in MDE is a long-term problem. Aocl is a response to this. It is a pure-Java alternative for OCL (Object Constraint Language) and other specialized languages used in MDE today. Aocl has syntax similar to that OCL -- except with a Java favor. Here is the original paper on Aocl. This document shows you how to use Aocl. The big picture is in text and category diagram below:
That's it. Follow the links above to learn more about each step.
Write a CDSpec of Your Class Diagram
The first step is to define the class diagram (no constraints!) of your target metamodel. This is written as a CDSpec file, which is documented here. An example file, startrek.cdspec.pl, is shown below, along with its PlantUML png file. (Click here to see how to generate this png file).

| classDiagram startrek.
table(starship,[name,type]).
table(crewman,['fname','lname',species]).
table(commander,[rank]).
table(lieutenant,[specialty]).
subtable(crewman,[commander,lieutenant]).
assoc(assgnnt,starship,onBoard,BLACK_DIAMOND,crewman,hasCrew,BLANK).
|
Converting a CDSpec to Aocl
The Meta4 tool takes a single .cdspec.pl file as input (whose tail ".cdspec.pl" is added if not given):
C>java M4.CDSpec2CD startrek
Meta4 promptly converts the CDSpec file into a CD file and runs conformance tests. If no errors are produced, Meta4 proceeds to create a package under its NetBeans directory Meta4/Allegory/x, where x is the name of the x.cdspec.pl file that was submitted. A set of files are produced; they are:
- File x.schema.pl -- the MDELite relational schema for x.cdspec.pl
- Let T be the name of a class in the x.cdspec.pl file. For each T, two files are produced:
- T.java -- implements a tuple of type T and Aocl operations on such tuples
- TTable -- implements a table of T tuples and Aocl operations on such tables
- Database.java -- implements a database of all T tables
- Lang.java -- a set of static classes that provide basic utilities for Aocl processing
These files are discussed in a bit more detail below.
Schema File
Here is the MDELite relational schema declaration derived from StarTrek.cdspec.pl: There are 4 tables (Crewman, Commander, Lieutenant, and Starship), each with their own attributes. All tuples start with a String identifier field, id. Object diagrams that conform to the StarTrek.cdspec.pl file are database files (with name y.StartTrek.pl) that conform to the schema below.
dbase(startrek,[starship,crewman,commander,lieutenant]).
table(starship,[id,name,type]).
table(crewman,[id,"fname","lname",species,onBoard:starship]).
table(commander,[id,"fname","lname",species,onBoard:starship,rank]).
table(lieutenant,[id,"fname","lname",species,onBoard:starship,specialty]).
subtable(crewman,[commander,lieutenant]).
Tuple Files (<T>.java)
Look at the Crewman class. It has 3 fields, fname, lname, and onBoard. It also has a (manufactured) id, which is inherited from superclass TuPle and is always the first field of a tuple, otherwise there is nothing special here.
public class crewman extends TuPle {
public String fname;
public String lname;
public String species;
public starship onBoard;
public crewman(String id, String fname, String lname, String species) {
this.id = id;
this.fname = fname;
this.lname = lname;
this.species = species;
}
Nowjjjjj, let's look at the rest of Crewman. There is a toString method that uses the Java String Formatter. The only unusual thing here is the expression "__(onboard)", which extracts the String id field of the referenced Starship tuple. The onBoard() method implements a right-semijoin: given a Crewman tuple a Starship table with a single tuple (the Starship to which this Crewman is assigned) is returned. static final String fmt = "crewman(%s,%s,%s,%s,%s).\n";
@Override
public String toString() {
return String.format(fmt,id,q(fname),q(lname),species,__(onBoard));
}
Now look at the Lieutenant class, a subclass of Crewman. It has 5 fields, 4 of which are inherited from Crewman, and one (speciality) specified to Lieutenants. (A call to the Crewman constructor could have been used, but it was easy enough to simply unroll the assignments of all superclass constructors).
public class lieutenant extends crewman {
public String specialty;
public lieutenant(String id, String fname, String lname, String species, starship onBoard, String specialty) {
this.id = id;
this.fname = fname;
this.lname = lname;
this.species = species;
this.onBoard = onBoard;
this.specialty = specialty;
}
The rest of Lieutenant is similar to Crewman: there is a toString method that uses the Java String Formatter. The onBoard() right-semijoin method is inherited from Crewman. static final String fmt = "lieutenant(%s,%s,%s,%s,%s,%s).\n";
@Override
public String toString() {
return String.format(fmt,id,q(fname),q(lname),species,__(onBoard),specialty);
}
Table Files (<T>Table.java)
Now let's look at the CrewmanTable. It has constructors to create empty or singleton tables -- these are tables that eventually will contain the result of some relational table operation.
public class crewmanTable extends TaBle {
// constructors for creating empty or singleton tables
public crewmanTable(Database db) {
this(db,null);
}
public crewmanTable(Database db, crewman t) {
this.db = db;
initTupleList(t);
}
The next methods are for projecting singleton columns of primitive types into a 1-column table; it is important for these operations to preserve duplicates. public STRINGTable id() {
STRINGTable st = new STRINGTable(db);
tuples.forEach(t -> st.add(new STRING(t.id)));
return st;
}
public STRINGTable fname() {
STRINGTable st = new STRINGTable(db);
tuples.forEach(t -> st.add(new STRING(t.fname)));
return st;
}
public STRINGTable lname() {
STRINGTable st = new STRINGTable(db);
tuples.forEach(t -> st.add(new STRING(t.lname)));
return st;
}
public STRINGTable species() {
STRINGTable st = new STRINGTable(db);
tuples.forEach(t -> st.add(new STRING(t.species)));
return st;
}
The final method, onBoard(), implements a right-semijoin of a (qualified) table of Crewman tuples with the full Starship table; duplicate Starship tuples are removed:
public starshipTable onBoard() {
starshipTable result = new starshipTable(db);
for (crewman w : tuples()) {
if (!result.contains(w.onBoard))
result.add(w.onBoard);
}
return result; // diamondLeft
}
Database File
A Database object contains a set of tables, in this case, a table for Crewman
public class Database {
public starshipTable starship = starshipTable.BaseRelation(this);
public crewmanTable crewman = crewmanTable.BaseRelation(this);
public commanderTable commander = commanderTable.BaseRelation(this);
public lieutenantTable lieutenant = lieutenantTable.BaseRelation(this);
private DB db;
public Database() {}
public Database(String filename) {
// Step 1: Read the database, throw exception if errors found and hal
... // internal details of database loading
}
public void print(PrintStream out) {
out.format("dbase(startrek,[starship,crewman,commander,lieutenant]).\n\n");
starship.printLocal(out);
crewman.printLocal(out);
commander.printLocal(out);
lieutenant.printLocal(out);
out.format("subtable(crewman,[commander,lieutenant]).\n");
}