001package org.andromda.translation.ocl.query; 002 003import java.util.HashMap; 004import java.util.Map; 005import org.andromda.core.translation.TranslationUtils; 006import org.apache.commons.lang.StringUtils; 007 008/** 009 * Performs translation to the following: <ul> <li>EJB-QL</li> </ul> 010 * 011 * @author Chad Brandon 012 */ 013public class EjbQLTranslator 014 extends QueryTranslator 015{ 016 /** 017 * Used to replace the 'counter' reference in the EJB-QL template 018 */ 019 private static final String ARG_COUNTER = "counter"; 020 021 /** 022 * Keeps track of an incrementing argument number. 023 */ 024 private short argCounter; 025 026 /** 027 * Holds the arguments which have previously been used during translation. The key is the argument name BEFORE 028 * translation, and the value is the argument name AFTER translation. 029 */ 030 private Map<String, String> usedArguments = new HashMap<String, String>(); 031 032 /** 033 * Called by super class to reset any objects. 034 */ 035 public void preProcess() 036 { 037 super.preProcess(); 038 this.usedArguments.clear(); 039 this.resetArgCounter(); 040 } 041 042 /** 043 * Resets the argCounter variable to its beginning value. 044 */ 045 private void resetArgCounter() 046 { 047 this.argCounter = 1; 048 } 049 050 /** 051 * Returns a String representing an incrementing number. It increments and returns the next value each time this 052 * method is called. 053 * 054 * @return String the counter represented by a String. 055 */ 056 protected String getCounter() 057 { 058 return String.valueOf(argCounter++); 059 } 060 061 /** 062 * Checks to see if the replacement is an argument and if so replaces the {index} in the fragment with the 063 * 'argument' fragment from the template. Otherwise replaces the {index} with the passed in replacement value. 064 * 065 * @param fragment 066 * @param replacement 067 * @param index 068 * @return String the fragment with any replacements. 069 */ 070 protected String replaceFragment(String fragment, String replacement, int index) 071 { 072 if (this.isOperationArgument(replacement)) 073 { 074 // get the used argument and if it exists, use that for the 075 // replacement, otherwise use a new one. 076 String usedArgument = this.usedArguments.get(replacement); 077 if (StringUtils.isEmpty(usedArgument)) 078 { 079 String argument = this.getTranslationFragment("argument"); 080 argument = this.replaceCounterPattern(argument); 081 this.usedArguments.put(replacement, argument); 082 replacement = argument; 083 } 084 else 085 { 086 replacement = usedArgument; 087 } 088 } 089 return super.replaceFragment(fragment, replacement, index); 090 } 091 092 /** 093 * Handles the replacement of the references to 'counter' with the incrementing counter (currently just used for 094 * EJB-QL translation) --> may want to find a cleaner way to do this. 095 * @param fragment 096 * @return fragment 097 */ 098 protected String replaceCounterPattern(String fragment) 099 { 100 if (TranslationUtils.containsPattern(fragment, EjbQLTranslator.ARG_COUNTER)) 101 { 102 fragment = TranslationUtils.replacePattern(fragment, EjbQLTranslator.ARG_COUNTER, this.getCounter()); 103 } 104 return fragment; 105 } 106}