Probably the fastest way to get started on writing a Translation-Library is to take a look at the contents of an existing one. Download and take a look at the contents of the Query Translation-Library . In addition, there are sections below which take you through the process step-by-step of generating a Translation-Library structure and then adding the translation capabilities to the generated Translation-Library.
First make sure you have the andromda-translation-library-plugin installed.
Next we need to create the Translation-Library directory that will contain all required resources (you'll be editing these as you develop). We'll call our sample Translation-Library 'constraint'. This is simple with the andromda-translation-library-plugin. After changing to the directory where you want the 'constraint' Translation-Library to be generated, just type the following at the command prompt and answer the questions (you should get output like the following):
$ maven translation-library:generate -o __ __ | \/ |__ _Apache__ ___ | |\/| / _` \ V / -_) ' \ ~ intelligent projects ~ |_| |_\__,_|\_/\___|_||_| v. 1.0.1 Please enter the name to give the new translation-library (i.e. 'constraint'): constraint Please enter a comma separated list of the names of the translations (i.e. 'Hibernate-QL,EJB-QL'): Oracle-SQL build:start: translation-library:validate-generation-params: translation-library:generate: translation-library:validate-generation-params: translation-library:set-shared-properties: translation-library:generate-translation-library-descriptor: [echo] +-------------------------------------------------------------------------------------+ [echo] | G E N E R A T I N G T R A N S L A T I O N - L I B R A R Y D E S C R I P T O R | [echo] +-------------------------------------------------------------------------------------+ [mkdir] Created dir: C:\test\constraint\src\META-INF [echo] Generating translation-library descriptor: constraint/src/META-INF/translation-library.xml translation-library:validate-generation-params: translation-library:generate-translations: [echo] +------------------------------------------------------+ [echo] | G E N E R A T I N G T R A N S L A T I O N ( S ) | [echo] +------------------------------------------------------+ [mkdir] Created dir: C:\test\constraint\src\translations\constraint [echo] Generating translation file: constraint/src/translations/constraint/Oracle-SQL.vsl translation-library:validate-generation-params: translation-library:set-shared-properties: translation-library:generate-translator: [echo] +----------------------------------------------+ [echo] | G E N E R A T I N G T R A N S L A T O R | [echo] +---------------------------------------------=+ [mkdir] Created dir: C:\test\constraint\src\java\org\andromda\translation\constraint [echo] Generating translator file: constraint/src/java/org/andromda/translation/constraint/ConstraintTranslator.java translation-library:set-shared-properties: translation-library:generate-translator-exception: [echo] +----------------------------------------------------------------+ [echo] | G E N E R A T I N G T R A N S L A T O R E X C E P T I O N | [echo] +----------------------------------------------------------------+ [echo] Generating translator exception file: constraint/src/java/org/andromda/translation/constraint/ConstraintTranslatorException.java translation-library:validate-generation-params: translation-library:generate-translation-tests: [echo] +-------------------------------------------------------------------------+ [echo] | G E N E R A T I N G T R A N S L A T I O N - T E S T F I L E ( S ) | [echo] +-------------------------------------------------------------------------+ [mkdir] Created dir: C:\test\constraint\src\test\translations\constraint [echo] Generating translation test file: constraint/src/constraint/src/test/translations/constraint/TranslationTest-Oracle-SQL.xml translation-library:validate-generation-params: translation-library:set-shared-properties: translation-library:generate-translation-library-pom: [echo] +-----------------------------------------------------------------------+ [echo] | G E N E R A T I N G T R A N S L A T I O N - L I B R A R Y P O M | [echo] +-----------------------------------------------------------------------+ [echo] Generating translation-library pom: constraint/project.xml [copy] Copying 1 file to C:\test\constraint BUILD SUCCESSFUL Total time: 13 seconds Finished at: Sun Nov 28 08:42:50 MST 2004
After you've successfully generated your Translation-Library development directory. Change to that directory and take a look at what has been generated (the following table shows what you'll find):
Resource | Description |
---|---|
META-INF/translation-library.xml | The Translation-Library descriptor file. Contains the Translator(s) and Translation files supported by this Translation-Library. Take a look at the schema below for more detail. |
project.xml | The Maven POM for the constraint Translation-Library. This will allow you to build it after its been generated. |
translations/constraint/Oracle-SQL.vsl |
The translation
Velocity
template file.
This allows you to map fragments for Oracle-SQL to OCL fragments which are being
parsed. In
addition to a Velocity template file, it's also an XML document. Take a look at
this
schema
for more detail.
|
src/java/org/andromda/translation/constraint/ConstraintTranslator.java |
This is the java
Translator
class mapped within the Translation-Library descriptor:
translation-library.xml
|
src/java/org/andromda/core/translation/constraint/ConstraintTranslatorException.java | This is the java exception class extending the TranslatorException. For any exception thrown during processing of the ConstraintTranslator, the exception SHOULD be an instance of this class. |
test/translations/constraint/TranslationTest-Oracle-SQL.xml |
This is the XML file that allows you to easily test your Translator/Translation
during development of a Translation-Library. There should be one
Translator-Test-*.xml file per translation. Take a look at its
schema
for more detail.
|
Ok, since you now are within your 'constraint' directory, you can run the translation-library:test goal to make sure everything was setup correctly:
maven translation-library:test.From the previous step, you should have seen some information printed to the screen and at the end it should sayBUILD SUCCESSFUL. If it failed for some reason, then send an email to the andromda-user@lists.sourceforge.net mailing list, because something obviously isn't right. If all the previous steps have succeeded, you're ready to start developing, congratulations! Go on to the next section Adding Translation Capabilities to your Translation-Library.
Now that you've created an empty Translation-Library from the previous section. Its time to start developing your library. The first thing you'll want to do, is add an expression to the body of the <from/> element of your translation test file TranslationTest-Oracle-SQL.xml. Since our example is a 'constraint' Translation-Library, I'll add the expression representing a constraint that expresses "within all LegalAgreements, documentTitle must be unique".
<expression> <from> context LegalAgreement inv: allInstances() -> isUnique(documentTitle) </from> <to> </to> </expression>
We'll now execute the translation-library:test goal once again but this time we'll add the '-Dtrace=true' property. Since we've added an expression to the <from/> element in the previous step, this will allow us to see, in what order and how the OCL parser parses the expression that we added. This is necessary since we'll need to know what methods to override in our ConstraintTranslator class to perform the translation of the expression.
maven translation-library:test -Dtrace=trueYour output should look like the following:
[junit] INFO [TraceTranslator] ======================== Tracing Expression ======================== [junit] INFO [TraceTranslator] context LegalAgreement inv: allInstances() -> isUnique(documentTitle) [junit] INFO [TraceTranslator] ======================== ================== ======================== [junit] INFO [TraceTranslator] caseStart --> 'context LegalAgreement inv : allInstances ( ) -> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] caseAContextDeclaration --> 'context LegalAgreement inv : allInstances ( ) -> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] inAContextDeclaration --> 'context LegalAgreement inv : allInstances ( ) -> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] caseAClassifierContextDeclaration --> 'context LegalAgreement inv : allInstances ( ) -> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] inAClassifierContextDeclaration --> 'context LegalAgreement inv : allInstances ( ) -> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] caseTContext --> 'context' [junit] INFO [TraceTranslator] caseTName --> 'LegalAgreement' [junit] INFO [TraceTranslator] caseAInvClassifierExpressionBody --> 'inv : allInstances ( ) -> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] inAInvClassifierExpressionBody --> 'inv : allInstances ( ) -> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] caseTInv --> 'inv' [junit] INFO [TraceTranslator] caseTColon --> ':' [junit] INFO [TraceTranslator] caseALogicalExpression --> 'allInstances ( ) -> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] inALogicalExpression --> 'allInstances ( ) -> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] caseALogicalExp --> 'allInstances ( ) -> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] inALogicalExp --> 'allInstances ( ) -> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] caseARelationalExpression --> 'allInstances ( ) -> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] inARelationalExpression --> 'allInstances ( ) -> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] caseAAdditiveExpression --> 'allInstances ( ) -> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] inAAdditiveExpression --> 'allInstances ( ) -> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] caseAMultiplicativeExpression --> 'allInstances ( ) -> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] inAMultiplicativeExpression --> 'allInstances ( ) -> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] caseAUnaryExpression --> 'allInstances ( ) -> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] inAUnaryExpression --> 'allInstances ( ) -> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] caseAPropertyCallExpression --> 'allInstances ( ) -> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] inAPropertyCallExpression --> 'allInstances ( ) -> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] caseAFeaturePrimaryExpression --> 'allInstances ( )' [junit] INFO [TraceTranslator] inAFeaturePrimaryExpression --> 'allInstances ( )' [junit] INFO [TraceTranslator] caseAPathName --> 'allInstances' [junit] INFO [TraceTranslator] inAPathName --> 'allInstances' [junit] INFO [TraceTranslator] caseTName --> 'allInstances' [junit] INFO [TraceTranslator] outAPathName --> 'allInstances' [junit] INFO [TraceTranslator] caseAFeatureCallParameters --> '( )' [junit] INFO [TraceTranslator] inAFeatureCallParameters --> '( )' [junit] INFO [TraceTranslator] caseTLParen --> '(' [junit] INFO [TraceTranslator] caseAActualParameterList --> '' [junit] INFO [TraceTranslator] inAActualParameterList --> '' [junit] INFO [TraceTranslator] outAActualParameterList --> '' [junit] INFO [TraceTranslator] caseTRParen --> ')' [junit] INFO [TraceTranslator] outAFeatureCallParameters --> '( )' [junit] INFO [TraceTranslator] outAFeaturePrimaryExpression --> 'allInstances ( )' [junit] INFO [TraceTranslator] caseAArrowPropertyCallExpressionTail --> '-> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] inAArrowPropertyCallExpressionTail --> '-> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] caseTArrow --> '->' [junit] INFO [TraceTranslator] caseAFeatureCall --> 'isUnique ( documentTitle )' [junit] INFO [TraceTranslator] inAFeatureCall --> 'isUnique ( documentTitle )' [junit] INFO [TraceTranslator] caseAPathName --> 'isUnique' [junit] INFO [TraceTranslator] inAPathName --> 'isUnique' [junit] INFO [TraceTranslator] caseTName --> 'isUnique' [junit] INFO [TraceTranslator] outAPathName --> 'isUnique' [junit] INFO [TraceTranslator] caseAFeatureCallParameters --> '( documentTitle )' [junit] INFO [TraceTranslator] inAFeatureCallParameters --> '( documentTitle )' [junit] INFO [TraceTranslator] caseTLParen --> '(' [junit] INFO [TraceTranslator] caseAActualParameterList --> 'documentTitle' [junit] INFO [TraceTranslator] inAActualParameterList --> 'documentTitle' [junit] INFO [TraceTranslator] caseALogicalExpression --> 'documentTitle' [junit] INFO [TraceTranslator] inALogicalExpression --> 'documentTitle' [junit] INFO [TraceTranslator] caseALogicalExp --> 'documentTitle' [junit] INFO [TraceTranslator] inALogicalExp --> 'documentTitle' [junit] INFO [TraceTranslator] caseARelationalExpression --> 'documentTitle' [junit] INFO [TraceTranslator] inARelationalExpression --> 'documentTitle' [junit] INFO [TraceTranslator] caseAAdditiveExpression --> 'documentTitle' [junit] INFO [TraceTranslator] inAAdditiveExpression --> 'documentTitle' [junit] INFO [TraceTranslator] caseAMultiplicativeExpression --> 'documentTitle' [junit] INFO [TraceTranslator] inAMultiplicativeExpression --> 'documentTitle' [junit] INFO [TraceTranslator] caseAUnaryExpression --> 'documentTitle' [junit] INFO [TraceTranslator] inAUnaryExpression --> 'documentTitle' [junit] INFO [TraceTranslator] caseAPropertyCallExpression --> 'documentTitle' [junit] INFO [TraceTranslator] inAPropertyCallExpression --> 'documentTitle' [junit] INFO [TraceTranslator] caseAFeaturePrimaryExpression --> 'documentTitle' [junit] INFO [TraceTranslator] inAFeaturePrimaryExpression --> 'documentTitle' [junit] INFO [TraceTranslator] caseAPathName --> 'documentTitle' [junit] INFO [TraceTranslator] inAPathName --> 'documentTitle' [junit] INFO [TraceTranslator] caseTName --> 'documentTitle' [junit] INFO [TraceTranslator] outAPathName --> 'documentTitle' [junit] INFO [TraceTranslator] outAFeaturePrimaryExpression --> 'documentTitle' [junit] INFO [TraceTranslator] outAPropertyCallExpression --> 'documentTitle' [junit] INFO [TraceTranslator] outAUnaryExpression --> 'documentTitle' [junit] INFO [TraceTranslator] outAMultiplicativeExpression --> 'documentTitle' [junit] INFO [TraceTranslator] outAAdditiveExpression --> 'documentTitle' [junit] INFO [TraceTranslator] outARelationalExpression --> 'documentTitle' [junit] INFO [TraceTranslator] outALogicalExp --> 'documentTitle' [junit] INFO [TraceTranslator] outALogicalExpression --> 'documentTitle' [junit] INFO [TraceTranslator] outAActualParameterList --> 'documentTitle' [junit] INFO [TraceTranslator] caseTRParen --> ')' [junit] INFO [TraceTranslator] outAFeatureCallParameters --> '( documentTitle )' [junit] INFO [TraceTranslator] outAFeatureCall --> 'isUnique ( documentTitle )' [junit] INFO [TraceTranslator] outAArrowPropertyCallExpressionTail --> '-> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] outAPropertyCallExpression --> 'allInstances ( ) -> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] outAUnaryExpression --> 'allInstances ( ) -> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] outAMultiplicativeExpression --> 'allInstances ( ) -> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] outAAdditiveExpression --> 'allInstances ( ) -> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] outARelationalExpression --> 'allInstances ( ) -> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] outALogicalExp --> 'allInstances ( ) -> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] outALogicalExpression --> 'allInstances ( ) -> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] outAInvClassifierExpressionBody --> 'inv : allInstances ( ) -> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] outAClassifierContextDeclaration --> 'context LegalAgreement inv : allInstances ( ) -> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] outAContextDeclaration --> 'context LegalAgreement inv : allInstances ( ) -> isUnique ( documentTitle )' [junit] INFO [TraceTranslator] caseEOF --> '' [junit] INFO [TraceTranslator] ======================== Tracing Complete ========================
In the above output, each method name and its corresponding node value is shown. (i.e. inAClassifierExpressionBody with 'allInstances() -> isUnique ( documentTitle )' says the method 'inAPostfixExpression' is being executed with value of 'allInstances() -> isUnique ( documentTitle )'.) This means that if you want to handle the 'inAPropertyCallExpression' output, you would override this method in your ConstraintTranslator and call the handleTranslationFragment(Node node). Like so:
package org.andromda.translation.constraint; import org.andromda.core.translation.node.APropertyCallExpression; import org.andromda.core.translation.TranslationUtils; /** * Performs translation to the following: * <ul> * * <li> * Oracle-SQL * </li> * * </ul> * * @author Chad Brandon */ public class ConstraintTranslator extends org.andromda.core.translation.BaseTranslator { public void inAPropertyCallExpression(APropertyCallExpression expression) { //ideally, this is the only content that this method should contain //but you may need to do some processing before (or instead of) handling the expression. this.handleTranslationFragment(expression); } /*------------------------- all handler methods go below here -------------------------*/ }
Next you'll want to open your Oracle-SQL.vsl translation file and add the following:
<!-- This is the start of the constraint ('self.allInstances()', '<element name>.allInstances()', or just 'allInstances()') --> <fragment name="(\s*(${elementName}|self)\s*\.)?\s*allInstances().*" handlerMethod="handleAllInstances"> <kind name="inv"> alter table $constraintUtils.findTableName($element) add constraint </kind> </fragment>
We'll now add the handlerMethod definition to the Translator, what we'll do inside of this method is append the translation value (which is the body of the inv kind element from the previous step) to the expression being translated.
package org.andromda.translation.constraint; import org.andromda.core.translation.node.APropertyCallExpression; import org.andromda.core.translation.TranslationUtils; /** * Performs translation to the following: * <ul> * * <li> * Oracle-SQL * </li> * * </ul> * * @author Chad Brandon */ public class ConstraintTranslator extends org.andromda.core.translation.BaseTranslator { public void inAPropertyCallExpression(APropertyCallExpression expression) { //ideally, this is the only content that this method should contain //but you may need to do some processing before (or instead of) handling the expression. this.handleTranslationFragment(expression); } /*------------------------- all handler methods go below here -------------------------*/ /*------------------------- PropertyCallExpression Handler methods ---------------------*/ public void handleAllInstances(String translation, Object node) { //appended the value from the fragment to the expression buffer this.getExpression().appendToTranslatedExpression(translation); } }
Next we'll again run the translation-library:test method, this time not adding the -Dtrace=true property.
maven translation-library:testYour console output should contain the following (in addition to other output). Notice the line:translated: --> 'alter table LegalAgrmt add constraint'. This line tells you the translation test executed and the 'translated' result was the new expression'alter table LegalAgrmt add constraint'. Also look at the line:expected: --> ''. This is telling you your 'expected' translated result is an empty string (Your goal will be to get these two outputs to equal each other). Its an empty string because we have yet to add any content to the <to/> element of your TranslationTest-Oracle-SQL.xml file. We'll do that in the next step.
[junit] 22:08:40,527 INFO [ExpressionTranslationTest] translated: --> 'alter table LegalAgrmt add constraint' [junit] 22:08:40,527 INFO [ExpressionTranslationTest] expected: --> ''
Now we'll add what we expect the translated result to be. Open up your TranslationTest-Oracle-SQL.xml file, and add some content to the <to/> element body. What we are adding is what the 'from' element should be translated 'to' in Oracle SQL:
<expression> <from> context LegalAgreement inv: self.allInstances() -> isUnique(documentTitle) </from> <to> alter table LegalAgrmt add constraint UniqueLADT UNIQUE (Document_Title) </to> </expression>
For the final step of our little tutorial, we'll again run the translation test maven goal: translation-library:test to see if our 'translated' and 'expected' outputs match (of course they won't since the only thing we have added to our Oracle-SQL.vsl translation file so far is a fragment for handling the allInstances() operation). This time you should at least see that you have a value for your 'expected' output, and this is good, because you have something to compare against while adding to your translation template (Oracle-SQL.vsl) and translator (ConstraintTranslator):
[junit] 12:53:52,174 INFO [ExpressionTranslationTest] translated: --> 'alter table LegalAgrmt add constraint' [junit] 12:53:52,174 INFO [ExpressionTranslationTest] expected: --> 'alter table LegalAgrmt add constraint UniqueLADT UNIQUE(Document_Title)'
Ok that's it! You're job now is to continue the process of getting the 'expected' and 'translated' expressions to equal each other (and get the Junit test cases to pass when running the Maven translation-library:test goal) by repeating the steps above. To summarize you'll repeat the following steps over and over again until you have the translator and translations supporting the language you want.
Summary of Steps: