Developing a Translation-Library

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.

Generating a Translation-Library

  1. First make sure you have the andromda-translation-library-plugin installed.

  2. 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
                            
  3. 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):

    • IMPORTANT: each one of the resources that is generated at once by the maven translation-library:generate goal can be generated separately (you may want to do this after you've started working on your Translation-Library, if you want to add a new Translation, Translator, etc.). Please see the AndroMDA Translation-Library Plugin documentation for more information.
    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.
    • NOTE: The translation file is named 'Oracle-SQL' because if you'll remember we gave the 'translations' property a value of 'Oracle-SQL', you'll have a translation file generated for each comma separated value specified for the 'translations' property when using the andromda-translation-library-plugin translation-library:generate goal.
    • IMPORTANT: Each translation file has an instance of the expression's context element that is passed in from the translate method of the ExpressionTranslator in a scripting variable calledelement. It can be accessed in the translation template aselement. This allows you to get any information you need from this element and make it available to your translation template during processing.
    src/java/org/andromda/translation/constraint/ConstraintTranslator.java This is the java Translator class mapped within the Translation-Library descriptor: translation-library.xml
    • NOTE: As you'll notice if you look at the descriptor schema, you can have either one Translator instance per descriptor or you can override this default Translation-Library wide Translator with one per translation.
    • NOTE: Also note that the Translator generated is named 'ConstraintTranslator', this is again named after the library during the generation process.
    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.
    • NOTE: There will be a TranslationTest-*.xml file generated for every comma separated value defined by the 'translation' property from the translation-library:generate goal.
  4. 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.
  5. 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.

    • NOTE: If you're using Eclipse as your IDE you can execute the default Eclipse plugin goal: 'maven eclipse' within your Translation-Library directory and this will generate the necessary files for you to import your Translation-Library directory as an Eclipse project.

Adding Translation Capabilities to your Translation-Library

  1. 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>
                            
  2. 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:

    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 -------------------------*/
    }			
                                
  3. Next you'll want to open your Oracle-SQL.vsl translation file and add the following:

    • Fill in the 'name' attribute on the <kind/> element. You need to specify the kind name asinv. 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 typeinv. If the expression had the type'body', then the kind name would need to bebody. See the translation file schema for the possible kind names.)
    • Fill in the '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 withself.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.
    • Fill in the 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.
    • Add the body of the inv kind element. NOTE: the expression $constraintUtils.findTableName($element) allows us to find the SQL table name corresponding to the context ${element} scripting object always available to a translation template. You'll have to add the ${constraintUtils} to your translation template by specifying it in your translation-library descriptor.
    <!-- 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>
                            
  4. 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);
        }
    }			
                            
  5. 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: --> ''
                            
  6. 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>
                            
  7. 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)'
                            

Summary

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:
  1. Generate a Translation-Library if you don't have one.
  2. Add an OCL expression to a <from/> element in your translation test file (Add another <expression/> element to your test file if you already have one being used for a different test, take a look at the schema for what a TranslationTest-*.xml can contain).
  3. Execute the translation test with command maven translation-library:test -Dtrace=true and decide what parser generated method you need to override in your Translator to handle a fragment of the expression: .
  4. Override the parser generated method and provide the method to handle a translation fragment.
  5. Edit your translation template and fill in the name, handlerMethod, kind name and kind body to your translation fragment (or add another fragment if you already have the first generated fragment defined, see the schema for more information) .
  6. Add the handlerMethod from the translation fragment (from previous step) to yourTranslator.
  7. Add the expected translated output to your translation test file as the body of the <to/> element.
  8. Execute the translation test with command maven translation-library:test and see if the expressions equal each other and if the tests pass.
  9. Repeat steps 2 - 8 until you have the translator and translations supporting the language you want.
  • NOTE: You can view the source of the QueryTranslator for the query Translation-Library which may help in implementing your Translator.