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 seperated 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):
cd constraint
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 say BUILD SUCCESSFUL
. If it failed
for some reason, then send an email to the
[email protected]
mailing list, because something obviously isn't right. If all the previous steps have succeeded, you're
ready to start developing, congradulations! 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=true
Your 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:
packageorg.andromda.translation.constraint;importorg.andromda.core.translation.node.APropertyCallExpression;importorg.andromda.core.translation.TranslationUtils;/** * Performs translation to the following: * <ul> * * <li> * Oracle-SQL * </li> * * </ul> * * @author Chad Brandon */publicclassConstraintTranslatorextendsorg.andromda.core.translation.BaseTranslator {publicvoidinAPropertyCallExpression(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:
'name'
attribute on the <kind/> element. You need
to specify the kind name as inv. You also need to give some content
to the kind element. (NOTE: If you'll remember from the previous step
the expression type we defined was of type inv. If the expression
had the type 'body'
, then the kind name would need to be body.
See the translation file
schema
for the possible
kind names.)
'name'
attribute on the <fragment/> element
with a name or regular expression that will be matched from the OCL expression
during translation. The
ConstraintTranslator
is what will match these fragments during the translation process. Since our
constraint expression
begins with allInstances()
and we know that allInstances()
can begin with self.allInstances()
,
${element.name}.allInstances()
, or just plain old allInstances()
we'll want to give this fragment name
a regular expression that will match
on one of these three allInstances() patterns.
NOTE: There is a goal called
translation-library:test-regex
that will
allow you to test your regular expressions while writing them for your fragment names which
comes in very handy.
handlerMethod
attribute name with the name
of the method that will handle processing of this fragment. We'll call it
handleAllInstances
since that is what its doing.
<!-- This is the start of the constraint ('self.allInstances()', '<element name>.allInstances()', or just 'allInstances()') --><fragmentname="(\s*(${elementName}|self)\s*\.)?\s*allInstances().*"handlerMethod="handleAllInstances"> <kindname="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.
packageorg.andromda.translation.constraint;importorg.andromda.core.translation.node.APropertyCallExpression;importorg.andromda.core.translation.TranslationUtils;/** * Performs translation to the following: * <ul> * * <li> * Oracle-SQL * </li> * * </ul> * * @author Chad Brandon */publicclassConstraintTranslatorextendsorg.andromda.core.translation.BaseTranslator {publicvoidinAPropertyCallExpression(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 ---------------------*/publicvoidhandleAllInstances(String translation, Object node) {//appended the value from the fragment to the expression bufferthis.getExpression().appendToTranslatedExpression(translation); } }
Next we'll again run the translation-library:test method, this time not adding the -Dtrace=true property.
maven translation-library:test
Your 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.