View Javadoc

1   package org.ocltf.translation.query;
2   
3   import java.util.List;
4   
5   import org.apache.commons.lang.StringUtils;
6   import org.ocltf.concretesyntax.VariableDeclarationCS;
7   import org.ocltf.concretesyntax.impl.ConcreteSyntaxUtils;
8   import org.ocltf.parser.node.AFeatureCall;
9   import org.ocltf.parser.node.ALogicalExpressionTail;
10  import org.ocltf.parser.node.AOperationContextDeclaration;
11  import org.ocltf.parser.node.APropertyCallExpression;
12  import org.ocltf.parser.node.ARelationalExpressionTail;
13  import org.ocltf.parser.node.AStandardDeclarator;
14  import org.ocltf.parser.node.PRelationalExpression;
15  import org.ocltf.translation.BaseTranslator;
16  import org.ocltf.translation.TranslationUtils;
17  
18  /***
19   * Performs translation to the following:   
20   * <ul> 
21   *     <li>
22   *          Hibernate-QL
23   *     </li>
24   * </ul>
25   * @author Chad Brandon
26   */
27  public class QueryTranslator extends BaseTranslator {
28  
29  	/***
30  	 * Used to save the argument names for the operation which represents the
31  	 * context of the expression being translated.
32  	 */
33  	private List argumentNames = null;
34  
35  	/***
36  	 * Contains the select clause of the query.
37  	 */
38  	private StringBuffer selectClause;
39  
40  	/***
41  	 * Called by super class to reset any objects.
42  	 */
43  	protected void preProcess() {
44  		super.preProcess();
45  		this.selectClause = new StringBuffer();
46          this.declaratorCtr = 0;
47  	}
48      
49      /***
50       * Stores the name of the initial declarator.
51       */
52      private short declaratorCtr;
53      
54      /***
55       * True/false whether or not its the initial declarator. 
56       * We care about this because we must know what the first one is
57       * for differentiating between the first declarator (the beginning of the query)
58       * and any other declarators (the connecting associations).
59       */
60      protected boolean isInitialDeclarator() {
61          boolean isInitialDeclarator = (this.declaratorCtr <= 0);
62          this.declaratorCtr++;
63          return isInitialDeclarator;
64      }
65      
66  	/***
67  	 * Returns true if the name is one of the arguments.
68  	 * 
69  	 * @return boolean true if its an argument
70  	 */
71  	protected boolean isArgument(String name) {
72  		boolean isArgument = this.argumentNames != null;
73  		if (isArgument) {
74  			isArgument = this.argumentNames.contains(name);
75  		}
76  		return isArgument;
77      }	
78       
79  	/***
80  	 * Gets the information about the operation which is the context of this
81  	 * expression.
82  	 */
83  	public void inAOperationContextDeclaration(AOperationContextDeclaration declaration) {
84  		super.inAOperationContextDeclaration(declaration);
85  		VariableDeclarationCS[] variableDeclarations =
86  			ConcreteSyntaxUtils.getVariableDeclarations(
87  				declaration.getOperation());
88  		//set the argument names in a List so that we can retieve them later
89  		this.argumentNames = ConcreteSyntaxUtils.getArgumentNames(variableDeclarations);
90  	}
91  
92  	/***
93  	 * Helps out with 'includesAll', replaces the {1} in the expression fragment
94       * when a declarator is encountered (i.e. '| <variable name>') 
95  	 */
96  	public void inAStandardDeclarator(AStandardDeclarator declarator) {
97  		String methodName = "inAStandardDeclarator";
98  		if (logger.isDebugEnabled()) {
99  			logger.debug(
100 				"performing "
101 					+ methodName
102 					+ " with declarator --> "
103 					+ declarator);
104 		}
105 	
106         String temp = this.selectClause.toString();
107 
108         String declaratorName = 
109         	ConcreteSyntaxUtils.getVariableDeclarations(declarator)[0].getName();
110        
111         //by default we'll assume we're replacing the {1} arg.
112         short replacement = 1;
113         if (this.isInitialDeclarator()) {
114         	//handle differently if its the initial declarator, replacement is {0}
115             replacement = 0;
116         }
117         
118 		//now replace {1} reference
119 		temp =
120 			TranslationUtils.replacePattern(
121 				temp,
122 				String.valueOf(replacement),
123 				declaratorName);
124 		this.selectClause = new StringBuffer(temp);
125 	}
126     
127     /***
128      * Override to handle any propertyCall expressions (
129      * i.e. exists(<expression>), select(<expression>, etc.)
130      */
131     public void inAPropertyCallExpression(APropertyCallExpression expression) {
132         //System.out.println("property call expression: " + expression);
133         this.handleTranslationFragment(expression);     
134     }
135 
136 	/***
137 	 * Override to deal with logical 'and, 'or', 'xor, ... expressions.
138 	 */
139 	public void inALogicalExpressionTail(ALogicalExpressionTail logicalExpressionTail) {
140         this.handleTranslationFragment(logicalExpressionTail);
141 	}
142 
143 	/***
144 	 * Override to deal with relational '<, '>', '=', ... expressions.
145 	 */
146 	public void inARelationalExpressionTail(ARelationalExpressionTail relationalExpressionTail) {
147 		this.handleTranslationFragment(relationalExpressionTail);
148 	}
149 
150 	/***
151 	 * Checks to see if the replacement is an argument and if so replaces the
152 	 * {index} in the fragment with the 'argument' fragment from the template.
153 	 * Otherwise replaces the {index} with the passed in replacement value.
154 	 * 
155 	 * @param fragment the fragment to perform replacement.
156 	 * @param replacement the replacement string
157 	 * @param index the index in the string to replace.
158 	 * @return String the fragment with any replacements.
159 	 */
160 	protected String replaceFragment(
161 		String fragment,
162 		String replacement,
163 		int index) {
164 		fragment = StringUtils.trimToEmpty(fragment);
165 		replacement = StringUtils.trimToEmpty(replacement);
166 		//if 'replacement' is an argument use that for the replacement
167         //in the fragment
168 		if (this.isArgument(replacement)) {
169 			replacement = this.getTranslationFragment("argument");
170 		}
171 		fragment =
172 			TranslationUtils.replacePattern(
173 				fragment,
174 				String.valueOf(index),
175 				replacement);
176 		return fragment;
177 	}
178 
179 	/***
180 	 * Handles any final processing.
181 	 */
182 	protected void postProcess() {
183 		super.postProcess();
184 		//create the final translated expression
185 		String selectClauseTail =
186 			this.getTranslationFragment("selectClauseTail");
187 		String existingExpression =
188 			StringUtils.trimToEmpty(
189 				this.getExpression().getTranslatedExpression());
190         
191 		if (StringUtils.isNotEmpty(selectClauseTail)
192 			&& StringUtils.isNotEmpty(existingExpression)) {
193 			this.selectClause.append(" ");
194 			this.selectClause.append(selectClauseTail);
195 			this.selectClause.append(" ");
196 		}
197 
198 		this.getExpression().insertInTranslatedExpression(
199 			0,
200 			selectClause.toString());
201 	}
202    
203     
204     /*------------------------- Handler methods ---------------------------------------*/
205 
206     /*------------------------- PropertyCallExpression Handler methods ---------------------*/
207     
208     public void handleSubSelect(String translation, Object node) {
209         
210         APropertyCallExpression propertyCallExpression = (APropertyCallExpression)node;
211 
212         String primaryExpression =
213             ConcreteSyntaxUtils.getPrimaryExpression(propertyCallExpression);
214 
215         //set the association which the 'includesAll' indicates (which
216         //is the first feature call from the list of feature calls)
217         translation = this.replaceFragment(
218             translation, 
219             TranslationUtils.trimToEmpty(primaryExpression),
220             0);
221 
222         this.selectClause.append(" ");
223         this.selectClause.append(translation);    	
224     }
225     
226     public void handleIsLike(String translation, Object node) {
227         
228         APropertyCallExpression propertyCallExpression = (APropertyCallExpression)node;
229         List featureCalls = ConcreteSyntaxUtils.getFeatureCalls(propertyCallExpression);        
230         AFeatureCall featureCall = (AFeatureCall)featureCalls.get(0);
231         
232         List params =
233             ConcreteSyntaxUtils.getParameters(featureCall);
234 
235         translation = this.replaceFragment(
236                 translation, 
237                 TranslationUtils.deleteWhitespace(params.get(0)), 
238                 0);
239         translation = this.replaceFragment(
240                 translation, 
241                 TranslationUtils.deleteWhitespace(params.get(1)), 
242                 1);
243 
244         if (StringUtils.isNotEmpty(this.getExpression().getTranslatedExpression())) {
245             this.getExpression().appendSpaceToTranslatedExpression();
246         }
247         this.getExpression().appendToTranslatedExpression(translation);        
248         
249     }
250     
251     public void handleSelect(String translation, Object node) {
252         this.selectClause.append(translation);
253     }
254     
255     public void handleExists(String translation, Object node) {
256 
257         APropertyCallExpression propertyCallExpression = (APropertyCallExpression)node;
258         List featureCalls = ConcreteSyntaxUtils.getFeatureCalls(propertyCallExpression); 
259         AFeatureCall featureCall = (AFeatureCall)featureCalls.get(0);
260 
261         String primaryExpression =
262             ConcreteSyntaxUtils.getPrimaryExpression(propertyCallExpression);
263         
264         if (logger.isDebugEnabled()) {
265             logger.debug("primaryExpression --> '" + primaryExpression + "'");
266         }
267 
268         String parameters = 
269             StringUtils.deleteWhitespace(
270                 ConcreteSyntaxUtils.getParametersAsString(featureCall));        
271         
272         translation = this.replaceFragment(
273         	translation, 
274             primaryExpression, 
275             1);
276         translation = this.replaceFragment(
277             translation, 
278             parameters, 
279             0);
280 
281         this.getExpression().appendSpaceToTranslatedExpression();
282         this.getExpression().appendToTranslatedExpression(translation);
283     }
284     
285     public void handleIsEmpty(String translation, Object node) {
286 
287         APropertyCallExpression propertyCallExpression = (APropertyCallExpression)node;
288 
289         String primaryExpression =
290             ConcreteSyntaxUtils.getPrimaryExpression(propertyCallExpression);
291         if (logger.isDebugEnabled()) {
292             logger.debug("primaryExpression --> '" + primaryExpression + "'");
293         }
294         
295     	translation = this.replaceFragment(translation, primaryExpression, 0);
296         
297         this.getExpression().appendSpaceToTranslatedExpression();
298         this.getExpression().appendToTranslatedExpression(translation);
299         
300     }
301     
302     /*------------------------- Logical Expression Handler (and, or, xor, etc.) ----------------------*/
303   
304     public void handleLogicalExpression(String translation, Object node) {
305         this.getExpression().appendSpaceToTranslatedExpression();
306         this.getExpression().appendToTranslatedExpression(translation);
307     }
308     
309     /*------------------------- Relational Expression Handler (=, <, >, >=, etc.) --------------------*/
310     
311     public void handleRelationalExpression(String translation, Object node) {
312         
313         ARelationalExpressionTail relationalExpressionTail =  
314             (ARelationalExpressionTail)node;
315 
316         String[] leftAndRightExpressions =
317             ConcreteSyntaxUtils.getLeftAndRightExpressions(
318                 (PRelationalExpression) relationalExpressionTail.parent());
319 
320         String leftExpression =
321             StringUtils.deleteWhitespace(leftAndRightExpressions[0]);
322         String rightExpression =
323             StringUtils.deleteWhitespace(leftAndRightExpressions[1]);
324 
325         translation = this.replaceFragment(translation, leftExpression, 0);
326         translation = this.replaceFragment(translation, rightExpression, 1);
327 
328         this.getExpression().appendSpaceToTranslatedExpression();
329         this.getExpression().appendToTranslatedExpression(translation);
330         
331     }
332     
333 }