Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Use Eclipse JET to Automate Model-Driven Development Aspects : Page 2

Get the lowdown on the Eclipse JET code generator and learn how to use it to automate your development processes.

Tags Everywhere
The real power of JET derives from its comprehensive tag library (and its extensibility), which offers out-of-the-box directives suited for the majority of transformation tasks. Default tags are divided into the following four families:
  • Core tags: These are the most important tags. They define directives that affect the model-processing flow (iterators, conditional elements), extract parts of the model via XPath, read and set variables, and nest other transformations into the current one.
  • Format tags: These tags define formatting directives such as case conversions, string replacement, and time formatting.
  • Java tags: These tags define directives specific to Java code generation, such as the creation of Java source files and Java packages and the management of Java import statements.
  • Workspace tags: These tags define directives to interact with the Eclipse workspace, such as the selection and traversal of projects, folders, and files.

In addition to simple tags, such as <c:get /> (prints the result of a given XPath selector), <c:if /> (evaluates the body depending on the result of an XPath text), or <c:choose /> (acts like a switch statement depending on the value of an XPath selector), some additional tags greatly enhance the code-generation capabilities of JET.

The tags <c:load /> and <c:loadContent /> dynamically load another input model in the middle of a current transformation. This allows you to compose submodels into a single output artifact, increasing the flexibility of the tool. The tags <c:userRegion /> and <c:initialCode /> allow the definition of the so-called user regions, sections of generated artifacts that must preserve a developer's modifications without overwriting them when later regenerating the artifact. This is a common need when the model isn't complete enough to drive the generation of all the code and it therefore leaks. The developer then has to deal explicitly with the underlying layer and write some code by hand.

The following listing shows a fictional init() method that preserves user-submitted content when regenerated:

private void init() { <c:userRegion> // BEGIN REGION INIT <c:initialCode unmodifiedMarker="@generated" > // @generated // If you want to personalize this // method, remove the @generated marker // and place your code between the region limits </c:initialCode> // END REGION INIT </c:userRegion> }

If the above tags are insufficient for your needs, you can use the extension point org.eclipse.jet.tagLibraries to contribute new tags to the engine.

Now it's time to discuss some real world examples that will expand your understanding of JET.

Code Generation to Simplify Document Publishing
The first example transforms a complex model into another using only code generation (no MDD here), which relieves the user from this task. Consider the following business requirement for the fictional DevX Bank: produce commercial-quality, feature-rich documents for its customers using the PDF format. The bank development team has no particular skills in producing complex PDFs, but they know HTML since they used it to produce the bank web site. Your task is to enable them to produce their documents in HTML and then use a code generator to translate them into PDF. Additionally, your software solution will support the concept of placeholders (surrounded by double underscores), so that documents can be used as masters that adapt to the customer credentials.

The following HTML file represents the input model for this fictional scenario:

<pdf project="PdfSample" srcdir="src" package="com.devx.pdf" class="MyPdfGenerator"> <html><head> <title>Welcome to Devx Bank!</title> </head><body> <h1>Welcome to Devx Bank!</h1> <p>Dear customer __NAME__ __SURNAME__ ,</p> <p> <span>We are very pleased to welcome you into </span><b>Devx Bank</b><span> !</span> </p> <p> In our bank you will find a variety of savings accounts for every savings goal. You will also be able to access to your account 24/7 thanks to our online banking website! </p> <p>Here are a couple of reminders to prevent phishing:</p> <ul> <li>We will never ask your credentials and passwords by e-mail!</li> <li>We will never ask money transfers by e-mail or at your door!</li> </ul> <p>Your account details:</p> <table> <tr><th>Card</th><th>PIN</th></tr> <tr><td>Debit Card</td><td>__DEBIT_PIN__</td></tr> <tr><td>Credit Card</td><td>__CREDIT_PIN__</td></tr> </table> </body></html> </pdf>

The code generator creates a Java program that relies on an external library to produce PDF content. (iText is used in this example, but any other PDF-generating library would do the job). Therefore, the first task of the template is creating the Java class. To do this, you create a file named main.jet, which will be executed by the JET engine. The following listing shows the file's relevant contents (refer to the source code attached to this article for the complete listing):

<ws:project name="{/pdf/@project}" > <ws:folder path="{/pdf/@srcdir}" > <java:package name="{/pdf/@package}"> <java:class name="{/pdf/@class}" template="templates/PdfGenerator.java.jet" /> </java:package> </ws:folder> </ws:project>

You can see the ws and java families of tags, which interact with the Eclipse workspace to generate a new Java source file. Notice the usage of XPath selectors, such as /pdf/@package and /pdf/@class, to extract attributes from the <pdf /> tag in the input model. In particular, the <java:class /> directive will create a new Java source file, whose content will be produced by the execution of the associated .jet file (which operates on the some model as main.jet).

The entire contents of the PdfGenerator.java.jet are available in the attached source code, but the following listing focuses on the portion that extracts header information from the HTML file and generates the appropriate PDF header with iText library calls:

<c:iterate select="/pdf/html/body/*" var="par" > <c:choose > <c:when test="name($par) = 'h1' "> // Paragraph and Chunk are iText classes aParagraph = new Paragraph(); aParagraph.add( new Chunk("<c:get select="$par" />", new Font(Font.HELVETICA, 15, Font.BOLD))); document.add(aParagraph); </c:when> // ... omissis ... other <c:when> tags for other kind of HTML tags </c:choose> </c:iterate>

The template iterates over all the body tags and, while iterating, assigns each tag to the variable par. Then you test the variable: if it is an HTML H1 header, you insert a static section that creates the appropriate library calls. Finally a <c:get /> tag inserts the content of the H1 tag as the parameter to the iText library call.

When applied to the sample model, the portion of template shown above generates the following code:

aParagraph.add( new Chunk("Welcome to Devx Bank!"), new Font(Font.HELVETICA, 15, Font.BOLD))); document.add(aParagraph);

The full template generates a Java source file that handles placeholders and exposes a generate(File f) method for public use. Figure 1 shows the generated PDF output once the code is compiled and run. (Refer to the attached code for the full program sources.)

Click to enlarge

Figure 1. The PDF File Generated by Executing the Class Produced by Your Template

The DevX Bank team can now use the generated Java file multiple times to mass-produce PDF documents for their customers!

Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.