1 package org.andromda.translation.ocl.testsuite;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.net.URL;
6 import java.util.HashMap;
7 import java.util.Map;
8 import javassist.CannotCompileException;
9 import javassist.ClassPool;
10 import javassist.CtClass;
11 import javassist.CtField;
12 import javassist.CtMethod;
13 import javassist.LoaderClassPath;
14 import javassist.NotFoundException;
15 import org.andromda.core.common.AndroMDALogger;
16 import org.andromda.core.common.ExceptionUtils;
17 import org.andromda.core.common.ResourceUtils;
18 import org.andromda.core.translation.Expression;
19 import org.andromda.core.translation.TranslationUtils;
20 import org.andromda.core.translation.Translator;
21 import org.andromda.core.translation.TranslatorException;
22 import org.andromda.translation.ocl.BaseTranslator;
23 import org.apache.log4j.Logger;
24
25
26
27
28
29
30
31
32
33 public class TraceTranslator
34 extends BaseTranslator
35 {
36 private static final Logger logger = Logger.getLogger(TraceTranslator.class);
37
38 private static final String INA_PREFIX = "inA";
39 private static final String OUTA_PREFIX = "outA";
40 private static final String CASE_PREFIX = "case";
41
42 private Map<CtMethod, String> methods = new HashMap<CtMethod, String>();
43
44
45
46
47
48 private static final String FIELD_ADAPTED = "adapted";
49
50 private ClassPool pool;
51
52
53
54
55 public TraceTranslator()
56 {
57 }
58
59
60
61
62
63
64
65 public static Translator getInstance()
66 {
67 final String debugMethodName = "TraceTranslator.getInstance";
68 if (logger.isDebugEnabled())
69 {
70 logger.debug("performing " + debugMethodName);
71 }
72 try
73 {
74 TraceTranslator oclTranslator = new TraceTranslator();
75 Translator translator = oclTranslator;
76 if (oclTranslator.needsAdaption())
77 {
78
79 if (logger.isInfoEnabled())
80 {
81 logger.info(" OCL Translator has not been adapted --> adapting");
82 }
83 translator = (Translator) oclTranslator.getAdaptedTranslationClass().newInstance();
84 }
85 return translator;
86 }
87 catch (Exception ex)
88 {
89 String errMsg = "Error performing " + debugMethodName;
90 logger.error(errMsg, ex);
91 throw new TranslatorException(errMsg, ex);
92 }
93 }
94
95
96
97
98 public Expression translate(String translationName, String expression, Object contextElement)
99 {
100 if (logger.isInfoEnabled())
101 {
102 logger.info("======================== Tracing Expression ========================");
103 logger.info(TranslationUtils.removeExtraWhitespace(expression));
104 logger.info("======================== ================== ========================");
105 }
106 Expression expressionObj = super.translate(translationName, expression, contextElement);
107 if (logger.isInfoEnabled())
108 {
109 logger.info("======================== Tracing Complete ========================");
110 }
111 return expressionObj;
112 }
113
114
115
116
117
118
119
120 protected boolean needsAdaption()
121 {
122 boolean needsAdaption = false;
123 try
124 {
125 this.getClass().getDeclaredField(FIELD_ADAPTED);
126 }
127 catch (NoSuchFieldException ex)
128 {
129 needsAdaption = true;
130 }
131 return needsAdaption;
132 }
133
134
135
136
137
138
139
140
141
142 protected Class getAdaptedTranslationClass() throws NotFoundException, CannotCompileException, IOException
143 {
144
145 Class thisClass = this.getClass();
146 this.pool = TranslatorClassPool.getPool(thisClass.getClassLoader());
147
148 CtClass ctTranslatorClass = pool.get(thisClass.getName());
149
150 CtField adaptedField = new CtField(CtClass.booleanType, FIELD_ADAPTED, ctTranslatorClass);
151
152 ctTranslatorClass.addField(adaptedField);
153
154
155 CtMethod[] analysisMethods = ctTranslatorClass.getMethods();
156
157 if (analysisMethods != null)
158 {
159
160 int methodNum = analysisMethods.length;
161
162 for (int ctr = 0; ctr < methodNum; ctr++)
163 {
164 CtMethod method = analysisMethods[ctr];
165 String methodName = method.getName();
166
167 if (methodName.startsWith(INA_PREFIX))
168 {
169
170 this.methods.put(method, this.getInAMethodBody(method));
171 } else if (methodName.startsWith(OUTA_PREFIX))
172 {
173
174 this.methods.put(method, this.getOutAMethodBody(method));
175 } else if (methodName.startsWith(CASE_PREFIX))
176 {
177
178 this.methods.put(method, this.getCaseMethodBody(method));
179 }
180 }
181
182
183 for (CtMethod method : this.methods.keySet())
184 {
185 CtMethod newMethod = new CtMethod(method, ctTranslatorClass, null);
186 String methodBody = this.methods.get(method);
187 newMethod.setBody(methodBody);
188 ctTranslatorClass.addMethod(newMethod);
189 }
190
191 }
192 this.writeAdaptedClass(ctTranslatorClass);
193 return ctTranslatorClass.toClass();
194 }
195
196
197
198
199
200 protected void writeAdaptedClass(CtClass pTranslatorClass)
201 {
202 final String methodName = "TraceTranslator.writeAdaptedClass";
203 if (logger.isDebugEnabled())
204 {
205 logger.debug("performing " + methodName);
206 }
207 try
208 {
209 File dir = this.getAdaptedClassOutputDirectory();
210 if (logger.isDebugEnabled())
211 {
212 final String className = this.getClass().getName();
213 logger.debug("writing className '" + className + "' to directory --> " + '\'' + dir + '\'');
214 }
215 pTranslatorClass.writeFile(dir.getPath());
216 }
217 catch (Exception ex)
218 {
219 String errMsg = "Error performing " + methodName;
220 logger.error(errMsg, ex);
221 throw new TranslatorException(errMsg, ex);
222 }
223 }
224
225
226
227
228
229
230 protected File getAdaptedClassOutputDirectory()
231 {
232 final String methodName = "TraceTranslator.getAdaptedClassOutputDirectory";
233 Class thisClass = this.getClass();
234 URL classAsResource = ResourceUtils.getClassResource(thisClass.getName());
235 File file = new File(classAsResource.getFile());
236 File dir = file.getParentFile();
237 if (dir == null)
238 {
239 throw new TranslatorException(methodName + " - can not retrieve directory for file '" + file + '\'');
240 }
241 String className = thisClass.getName();
242 int index = className.indexOf('.');
243 String basePackage = null;
244 if (index != -1)
245 {
246 basePackage = className.substring(0, index);
247 }
248 if (basePackage != null)
249 {
250 while (!dir.toString().endsWith(basePackage))
251 {
252 dir = dir.getParentFile();
253 }
254 dir = dir.getParentFile();
255 }
256 return dir;
257 }
258
259
260
261
262
263
264
265 protected String getCaseMethodBody(CtMethod method)
266 {
267 ExceptionUtils.checkNull("method", method);
268 StringBuilder methodBody = new StringBuilder("{");
269 String methodName = method.getName();
270 methodBody.append("String methodName = \"").append(methodName).append("\";");
271 methodBody.append(this.getMethodTrace(method));
272
273
274
275 methodBody.append("super.").append(methodName).append("($1);");
276 methodBody.append('}');
277 return methodBody.toString();
278 }
279
280
281
282
283
284
285
286 protected String getInAMethodBody(CtMethod method)
287 {
288 ExceptionUtils.checkNull("method", method);
289 StringBuilder methodBody = new StringBuilder("{");
290 String methodName = method.getName();
291 methodBody.append("String methodName = \"").append(methodName).append("\";");
292 methodBody.append(this.getMethodTrace(method));
293
294
295
296 methodBody.append("super.").append(methodName).append("($1);");
297 methodBody.append('}');
298 return methodBody.toString();
299 }
300
301
302
303
304
305
306
307 protected String getOutAMethodBody(CtMethod method)
308 {
309 ExceptionUtils.checkNull("method", method);
310 StringBuilder methodBody = new StringBuilder("{");
311 String methodName = method.getName();
312 methodBody.append("String methodName = \"").append(methodName).append("\";");
313 methodBody.append(this.getMethodTrace(method));
314
315
316
317 methodBody.append("super.").append(methodName).append("($1);");
318 methodBody.append('}');
319 return methodBody.toString();
320 }
321
322
323
324
325
326
327
328
329 protected String getOclFragmentName(CtMethod method)
330 {
331 ExceptionUtils.checkNull("method", method);
332 String fragment = method.getName();
333 String prefix = this.getMethodPrefix(method);
334 int index = fragment.indexOf(prefix);
335 if (index != -1)
336 {
337 fragment = fragment.substring(index + prefix.length(), fragment.length());
338 }
339 return fragment;
340 }
341
342
343
344
345
346
347
348 protected String getMethodPrefix(CtMethod method)
349 {
350 ExceptionUtils.checkNull("method", method);
351 String mName = method.getName();
352 String prefix = INA_PREFIX;
353 if (mName.startsWith(OUTA_PREFIX))
354 {
355 prefix = OUTA_PREFIX;
356 }
357 return prefix;
358 }
359
360
361
362
363
364
365
366 protected String getMethodTrace(CtMethod method)
367 {
368 ExceptionUtils.checkNull("method", method);
369 StringBuilder buf = new StringBuilder("if (logger.isInfoEnabled()) {logger.info(\"");
370 buf.append("\" + methodName + \" --> ");
371
372 buf.append("'\" + org.andromda.core.translation.TranslationUtils.trimToEmpty($1) + \"'\");}");
373 return buf.toString();
374 }
375
376
377
378
379
380
381
382 private static class TranslatorClassPool
383 extends ClassPool
384 {
385
386 private static final Logger logger = Logger.getLogger(TranslatorClassPool.class);
387
388 protected TranslatorClassPool()
389 {
390 super(ClassPool.getDefault());
391 if (logger.isInfoEnabled())
392 {
393 logger.debug("instantiating new TranslatorClassPool");
394 }
395 }
396
397
398
399
400
401
402
403 protected static ClassPool getPool(ClassLoader loader)
404 {
405 if (loader == null)
406 {
407 loader = Thread.currentThread().getContextClassLoader();
408 }
409 TranslatorClassPool pool = new TranslatorClassPool();
410 pool.insertClassPath(new LoaderClassPath(loader));
411 return pool;
412 }
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432 @SuppressWarnings("unused")
433 public Class writeAsClass(String classname) throws NotFoundException, IOException, CannotCompileException
434 {
435 try
436 {
437 final CtClass ctTranslatorClass = get(classname);
438 return classLoader.loadClass(classname, ctTranslatorClass.toBytecode());
439 }
440 catch (ClassFormatError e)
441 {
442 throw new CannotCompileException(e, classname);
443 }
444 }
445
446
447
448
449 static class LocalClassLoader
450 extends ClassLoader
451 {
452
453
454
455
456
457 public LocalClassLoader(ClassLoader parent)
458 {
459 super(parent);
460 }
461
462
463
464
465
466
467
468
469
470 public Class loadClass(String name, byte[] classfile) throws ClassFormatError
471 {
472 Class c = defineClass(name, classfile, 0, classfile.length);
473 resolveClass(c);
474 return c;
475 }
476 }
477
478
479
480
481
482
483 private static LocalClassLoader classLoader = new LocalClassLoader(LocalClassLoader.class.getClassLoader());
484 }
485
486
487
488
489 protected static void adaptClass()
490 {
491 if (logger.isInfoEnabled())
492 {
493 logger.info("adapting class for OCL parser");
494 }
495 TraceTranslator translator = new TraceTranslator();
496 if (translator.needsAdaption())
497 {
498 try
499 {
500 translator.getAdaptedTranslationClass();
501 }
502 catch (Throwable th)
503 {
504 logger.error(th);
505 }
506 }
507 }
508
509
510
511
512
513
514 public static void main(String[] args)
515 {
516 try
517 {
518 AndroMDALogger.initialize();
519 TraceTranslator.adaptClass();
520 }
521 catch (Throwable th)
522 {
523 logger.error(th);
524 }
525 }
526
527
528
529
530
531
532 @Override
533 public void postProcess()
534 {
535
536 }
537 }