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