Sunday, January 15, 2017

Template Based Reporting for Sparx Enterprise Architect with Java

Generating EA Model reports

As a regular user of Enterprise Architect who has encountered it accross various projects and organisations I have come to appreciate it as a capable and versatile modelling tool in the software industry. I have been using EA for years now and was always quite happy with it. 

However, recently I have been working on a project that had some reporting needs not supported in the built in reporting tooling. For instance, I could not deviate from the structure of my EA model in my reports. I also needed to be able to create tabular overviews of objects in specific diagrams and could not find an easy solution. This all made it impossible to meet my project's documentation standards using out of the box EA features.

These shortcomings led me to create a standalone reporting tool, which I have named EART (short for Enterprise Architect Reporting Tool).  EART enables one to write templates in the documents themselves, similar to EA's built in generator and therefore adjust the formatting in a WYSIWYG manner. From the template directives, it can query into the EA object model in a more flexible way so that documents can be structured independently from the model. It is also possible to embed the diagrams created by EA in the documents as well.

Having used it only for myself until now, I decided it would be a good idea to share it with others so I put it on github. In this blog post I will explain how it works.

The templating

First, I needed some sort of templating technology for documents that I could customize to act on the EA data. After some looking around I found XdocReport. XdocReport itself uses Apache Freemarker, a very capable and widely used general purpose templating language. I recommend going through the their website to understand the full scope of the Freemarker capabilities.

XdocReport works with the ODT format as well as Word docx and Powerpoint pptx. Note that such documents are nothing more than zipped XML. The XML can therefore be processed by text based templating technologies such as Freemarker. XdocReport takes care of unpacking the zipped documents, then finding and feeding the inline Freemarker directives to the Freemarker engine so it can do the actual merging with the data. After that, it just packs this all up in a proper document again.

XdocReport is well documented but just to get an idea here is a brief exampel of how it works. First create a new docx template document using Word. Insert a field (CTRL-F9), then right click on it and choose 'edit field':


Next choose 'MergeField' from 'Field Names' list. In the 'Field name' property type in the Freemarker directive. For example, let's say we have an Author class with a getName() method. To access the author's name, type in the Freemarker directive ${author.name}.


After entering, you should see the document like below:




From JAVA, one should then invoke XdocReport's XDocReportRegistry and IXDocReport classes to generate a document based on the template. IDocReport should be supplied the context data for the template via a Map as shown below:

After the code above runs, the output document should contain the line 'JK Rowling'.

Accessing the EA model

Now we need to make the EA object model available to Freemarker. Fortunately for Java developers Sparx provides a .jar with a JAVA API. The key is the Repository class, which opens the .eap file which contains all the EA data in the model which I show below. Note this involves actually starting an instance of EA based on that particular .eap file from your JAVA code and then talking to that instance through the JAVA API. Hence I added a shutdownhook to ensure proper cleanup: we just started an EA instance and if we don't end it, it will just continue running even after the JVM exits.


After the model has been opened, you can start browsing through it programmatically by invoking the getModels() method, which will give all root level Packages in the EA model. From there you can get diagrams in a package or elements in a package. This sort of thing we would like to do from Freemarker though, so at this point in the JAVA code we want to just hand Package instances to Freemarker, similar to how we gave it an Author instance earlier. I found this blog from Sparx with some useful info and a picture of the EA object model:



However, there is a mismatch between Sparx's JAVA API and Freemarker. That is because Freemarker templates work only based on JavaBeans convention. Which the Java API supplied by Sparx does not follow for some reason. Meaning that if in your template file you want to access an element's name with ${element.name}, it won't work since Freemarker then expects to find a getName() method on the Element class which is not the case. There is a GetName() method, but it is not accessible since it does not follow JavaBeans convention.

Fortunately Freemarker can also work purely on a Map interface. The solution then, was to create a proxy object to wrap EA's awkward object model in a neat Map interface. Java proxies fit nicely here:
  • we have an interface as proxy target (Java proxies require that) 
  • we can then easily only implement that part of the interface that needs it
  • due to the generic way we can intercept any method call, the proxy logic becomes more compact

Here is a listing of the code: As you can see the proxy only exposes the properties of the proxied object as read-only Map key-value pairs. It does not do all the work itself though. Actually extracting the properties is done by PropertyCollector, which applies a more lenient version of JavaBeans convention for determining what is a property getter. In particular, it does not care for the case of the first letter. Public fields and boolean properties will also be exposed.

Actual wrapping is done by ObjectWrapper, who decides how to wrap an object based on it's type: primitives, Strings and Enums are not wrapped, while Arrays and Iterables will be converted to Lists (more convenient to Freemarker) whose elements are themselves wrapped. A big help here was org.apache.commons.lang3.ClassUtils, which tells if a class is a primitive type or not.

We are not done though. Another inconvinience is that the EA object model is broken up in pieces at some places. By that I mean that sometimes, getting to related elements involve not a 'getXxx' but rather invoking the Repository instance to find that element based on id (see also the picture of the EA objectmodel shown previously). Now in ordinary code I would find this pretty annoying already; but in a templating language this is a burden.

To get over that I used Aspect Oriented Programming to extend the original Sparx Java classes with convinience getters for accessing related objects. For instance, in the code snipped below, some getters are added to the original Connector class from Sparx to retrieve the client and supplier Element of a Connector:

In this way a seamless object model is exposed allowing for clean, readable templates. In the example above, we can just say ${connector.client} in the template document and not be bothered with lookups there. Note the EA object model extensions are a work in progress and do not yet cover the entire object model.

Inserting diagrams from EA

Finally, we want to include images of the model's diagrams into the reports. XdocReport has the basic capbabilities in place: it provides the AbstractImageProvider class for making images available in template. Here is how it works: first we need to go to the template document and add a picture from file (any file will do). Then click on the picture and choose 'Insert' then 'Bookmark':


We must provide a bookmark name, e.g. 'Diagram_1'. XdocReport will then look into the provided context Map (see the first example) and search for a key named 'Diagram_1'. The associated value must be an implementation of AbstractImageProvider.

The AbstractImageProvider works by writing the image's bytes to an OutputStream. But how to get hold of a EA diagram's image as bytes? It would be nice to be able to simply ask the EA Repository for a stream of bytes representing some diagram image but that is not supported. What is possible though is to programmatically ask EA to generate an image file of a particular diagram. This file can then be converted to an InputStream implementation and given to XdocReport which makes it addressable from templates. This is how the code should look like broadly speaking:

Upon startup EART recursively scans the model for diagrams. Then it creates entries on the XdocReport context for each diagram found based on it's name as defined in Enterprise Architect. Since the modeller types in these names himself in EA, they can be easily remembered for use in the template: just type in name_of_diagram as the bookmark name.

Diagram names must as a result be unique otherwise only the last one found will be retained. In addition to that a context package is to be supplied via configuration to EART, which is then used as the starting point for template data and diagram scanning. Uniqueness of diagram names should hold (recursively) within that context package.

Note the actual generation and loading of the image is done only when that particular diagram is used in the template document, and not up front. After that, it is kept in memory.

Executing report generation

In order to create reports, first ensure you have the following:
  • Windows (tested with Windows 7 Professional)
  • a git client (any should do, else just download as zip from github)
  • Word for docx editing (tested with version 2007)
  • Apache Maven (tested with version 3.3.9)
  • JAVA 32 bit jdk (tested with jdk1.8.0_77). 64 bit JAVA won't work because EA is a 32 bit runtime.
  • A local installation of Enterprise Architect (tested with EA version 11)
Use your git client to checkout the code from the git repository or download the zip from github. In the project root directory (where pom.xml is located) run mvn_install_jars.bat and  mvn clean install then wait for the build to complete. In the target subdirectory a zip file should have been created. You can copy this zip to a suitable directory on your computer and unpack it.

Next, go into the unzipped directory and edit the text file named eart.properties (all properties must be specified):

Define the template file in a document editor, and place it in the location referenced by eart.properties. Then open a command prompt in the directory of the jar file and issue this command:

run_report.bat

This will start the generation process and will create an output document with the merged data from EA.

Note the assumption during these steps is that you installed EA in the directory  C:\Program Files (x86)\Sparx Systems\EA\ . Otherwise you will need to edit mvn_install_jars.bat and run_report.bat to reflect that. Also it is assumed that the 32 bit JAVA installation is being referenced in the Windows JAVA_PATH variable.

Closing thoughts

With some glueying together of libraries, it is possible to leverage the XdocReport engine and have template based reporting for Word docx. Besides that pptx and odt files should be supported but that was not tested. EART itself brings seamless object model on top of EA and some convenience for inserting diagram images.

Right now the full EA object model has not yet been extended, so there will be gaps in what is accessible from templates. Additions to the AOP aspects should be easy to make and share via a pull request to the git repository though. Or you could use EART as a library and apply AOP in your own project. Any getter you create should be accessible from Freemarker afterwards automatically.

Meanwhile I am also quite enthusiastic about Freemarker and pleasantly surprised at what it can do. It has all sorts of things to keep templates clean and easier to maintain. It is one of those little gems that makes your work more enjoyable.

Though maybe not a very exciting subject, creating good  documentation from the EA Model can be crucial in effectively communicating the model or complying to standards. Being able to do that without pain, limitations and in an automated fashion is in my opinion a great help to the many Enterprise Architect users worldwide.

The full code including example document templates have been on a git repository. If you have any trouble or have some remark or suggestion, please leave a comment below.