An Improved StarUML Code Generator

In this project you will pair up with a partner to implement a code generator that will generate .java files from a StarUML diagram. (Yes, StarUML already does this, but it doesn't do a good job.)

XPD Documents

Assume we use StarUML to create the following class diagram and save it to a file called demo.uml:

demo.uml is an XPD document. XPD is an XML language. Like an HTML document, an XPD document has a head and a body. The body contains a single object element representing the entire project.

An object element contains an arbitrary mixture of ATTR (attribute), REF (reference), and OBJ (sub-object) elements:

<!ELEMENT OBJ (ATTR | OBJ | REF)+>

All three elements have a name attribute.

ATTR and OBJ elements also have a type attribute.

OBJ elements have an ID attribute called guid:

<!ATTLIST OBJ
   name CDATA REQUIRED
   type CDATA REQUIRED
   guid ID REQUIRED>

REF elements represent references to OBJ elements. The content of an REF element is the guid of some OBJ element.

An ATTR element represents some attribute of its OBJ parent. The name attribute is the name of the OBJ attribute. The type attribute is the type of the value of this attribute, and the content is the value of the attribute.

An OBJ element represents a model, view, or diagram element. A model element refers to a logical UML element such as a UML package, class, association, etc. A diagram element obviously refers to an entire UML diagram such as a class diagram, use case diagram, sequence diagram, etc. A view element refers to an icon contained in some diagram. In this project we are only interested in model elements.

For example, here is an edited version of the XPD element representing the class CCC from the diagram above:

<XPD:OBJ name="OwnedElements[3]" type="UMLClass" guid="U5j...">
   <XPD:ATTR name="Name" type="string">CCC</XPD:ATTR>
   <XPD:ATTR name="#Operations" type="integer">1</XPD:ATTR>
   <XPD:OBJ name="Operations[0]" type="UMLOperation" guid="Gfh...">
      <XPD:ATTR name="Name" type="string">meth4</XPD:ATTR>
      <XPD:REF name="Owner">U5j...</XPD:REF>
   </XPD:OBJ>
   <XPD:ATTR name="#Associations" type="integer">1</XPD:ATTR>
   <XPD:REF name="Associations[0]">pOL...</XPD:REF>
   <XPD:ATTR name="#Attributes" type="integer">1</XPD:ATTR>
   <XPD:OBJ name="Attributes[0]" type="UMLAttribute" guid="ZE8...">
   <XPD:ATTR name="Name" type="string">fld2</XPD:ATTR>
   <XPD:ATTR name="Visibility" type="UMLVisibilityKind">vkPrivate</XPD:ATTR>
   <XPD:ATTR name="TypeExpression" type="string">boolean</XPD:ATTR>
   <XPD:REF name="Owner">U5jqgHFK1UyO4zrcNDPvGgAA</XPD:REF>
</XPD:OBJ>

(Note: XPD documents are easier to read if you view them as XML documents in NetBeans, but then they need to be saved with a .xml extension.)

Poor Man's Reflection

Unfortunately, our code generator can't use Java's built-in reflection because Java objects representing classes, methods, interfaces, etc. are generated from .class files, which are generated from .java files. But out job is to generate these .java files from XPD files in the first place.

Poor man's Reflection is a simplified library of meta-classes. Try implementing the following diagram:

Parsing XPD

Our parser uses Java's DOM API to parse a user specified .uml file. Review CIS 274 notes that discuss DOM. (XML Chapter 6.) Take a look at the javadocs for Node and Element. Here's a good start: Parser.java.

Generating Code

The easy way to do this is to generate a single .java file for the entire package. In this case UMLPackage overrides the inherited generateCode method to create a file. For example, assume the name of the package is ppp. Then generateCode creates a file called pppTest.java that begins:

package ppp;

public class pppTest {
   public static void main(String[] args) {
      System.out.println("entering pppTest.main() ...");
      // TO DO: put test code here
   }
}

It then calls the generateCode method of each UMLType child. These return strings that are appended to pppTest.java.

A better way to do this is to have UMLType override generateCode that creates a file.

See streams.htm for information (probably more than you need) on Character Streams (which is what you need). More specifically, consider using Java's Writer class to generate your files.

In either case, all generated files should compile and run without modification. (Even though they won't do anything.)