Skip to content

Method: handleAspectOperation(GenAspectOperation)

1: package de.fhdw.wtf.generator.writer.writer;
2:
3: import java.io.File;
4: import java.io.IOException;
5: import java.io.StringWriter;
6: import java.util.Collection;
7: import java.util.HashMap;
8: import java.util.Iterator;
9: import java.util.Vector;
10:
11: import org.apache.commons.lang.NotImplementedException;
12: import org.apache.velocity.Template;
13: import org.apache.velocity.VelocityContext;
14: import org.apache.velocity.app.VelocityEngine;
15: import org.apache.velocity.context.Context;
16: import org.apache.velocity.runtime.RuntimeConstants;
17: import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
18:
19: import de.fhdw.wtf.file.FileUtils;
20: import de.fhdw.wtf.generator.java.generatorModel.GenAnyType;
21: import de.fhdw.wtf.generator.java.generatorModel.GenAspect;
22: import de.fhdw.wtf.generator.java.generatorModel.GenAspectOperation;
23: import de.fhdw.wtf.generator.java.generatorModel.GenClass;
24: import de.fhdw.wtf.generator.java.generatorModel.GenClassClass;
25: import de.fhdw.wtf.generator.java.generatorModel.GenException;
26: import de.fhdw.wtf.generator.java.generatorModel.GenExternalClassClass;
27: import de.fhdw.wtf.generator.java.generatorModel.GenFullParsedOperationState;
28: import de.fhdw.wtf.generator.java.generatorModel.GenInterfaceClass;
29: import de.fhdw.wtf.generator.java.generatorModel.GenJavaException;
30: import de.fhdw.wtf.generator.java.generatorModel.GenJavaOperation;
31: import de.fhdw.wtf.generator.java.generatorModel.GenOperation;
32: import de.fhdw.wtf.generator.java.generatorModel.GenOperationModifier;
33: import de.fhdw.wtf.generator.java.generatorModel.GenParameter;
34: import de.fhdw.wtf.generator.java.generatorModel.GenPrimitiveClass;
35: import de.fhdw.wtf.generator.java.generatorModel.GenSimpleOperationState;
36: import de.fhdw.wtf.generator.java.generatorModel.GenType;
37: import de.fhdw.wtf.generator.java.generatorModel.GenTypeReference;
38: import de.fhdw.wtf.generator.java.generatorModel.GenTypeReferenceByName;
39: import de.fhdw.wtf.generator.java.generatorModel.GenTypeReferenceByReference;
40: import de.fhdw.wtf.generator.java.generatorModel.GenUserClass;
41: import de.fhdw.wtf.generator.java.generatorModel.Generic;
42: import de.fhdw.wtf.generator.java.visitor.GenClassClassVisitorReturn;
43: import de.fhdw.wtf.generator.java.visitor.GenClassVisitor;
44: import de.fhdw.wtf.generator.java.visitor.GenOperationStateVisitor;
45: import de.fhdw.wtf.generator.java.visitor.GenOperationVisitorReturn;
46: import de.fhdw.wtf.generator.java.visitor.GenTypeReferenceVisitorReturn;
47:
48: /**
49: *
50: * Abstraction for Java-File writer. Handles all properties that classes and interfaces have in common. Such as:
51: * <ul>
52: * <li>
53: * Name</li>
54: * <li>Comments</li>
55: * <li>
56: * Operations</li>
57: * <li>Inheritance</li>
58: * <li>Non-Generation-Part</li>
59: * <li>imports</li>
60: * </ul>
61: */
62: public abstract class ClassFileWriter {
63:         
64:         static final String TARGED_CLASS_KEY = "targedClass";
65:         private static final String PACKAGE_KEY = "package";
66:         static final String PARAMETER_KEY = "parameter";
67:         private static final String CLASSNAME_KEY = "className";
68:         static final String PARSED_OPERATIONS_KEY = "parsedOperations";
69:         static final String SIMPLE_OPERATIONS_KEY = "simpleOperations";
70:         static final String VISIBILITY_KEY = "visibility";
71:         static final String MODIFIERS_KEY = "modifiers";
72:         static final String NAME_KEY = "name";
73:         private static final String ABSTRACT_KEY = "abstract";
74:         static final String TYP_KEY = "typ";
75:         private static final String RETURN_TYP_KEY = "returnTyp";
76:         static final String CLASS_MODIFIERS_KEY = "classModifiers";
77:         static final String METHOD_KEY = "method";
78:         private static final String NON_GERNATION_PART_KEY = "nonGenerationPart";
79:         private static final String CLASS_COMMENT_KEY = "classComment";
80:         private static final String OPERATION_COMMENT_KEY = "operationComment";
81:         static final String EXTENDS_KEY = "extends";
82:         private static final String IMPLEMENTS_KEY = "implements";
83:         static final String EXCEPTIONS_KEY = "exceptions";
84:         private static final String OPERATION_PARAMETER_KEY = "parameter";
85:         private static final String IMPORTS_KEY = "imports";
86:         static final String GENERICS_PARAMETER_KEY = "genericParam";
87:         static final String GENERICS_CLASS_KEY = "genericsClass";
88:         static final String GENERICS_OPERATION_KEY = "genericsOperation";
89:         static final String INNER_CLASSES_KEY = "innerClasses";
90:         
91:         static final String EXTENDS = "extends ";
92:         private static final String IMPLEMENTS = "implements ";
93:         private static final char PACKAGE_PATH_SEP = '.';
94:         private static final char JAVA_LINE_END = ';';
95:         private static final char FILE_PATH_SEP = '/';
96:         private static final String THROWS = "throws ";
97:         private static final String BLANK = " ";
98:         private static final String COMMA_SPARATE = ", ";
99:         private static final String GENERICS_BEGIN = "<";
100:         private static final String GENERICS_END = ">";
101:         
102:         private final VelocityEngine engine;
103:         private final Template template;
104:         
105:         private final boolean fullyQualified;
106:         
107:         private Context currentContext;
108:         
109:         public ClassFileWriter(final String templateFileName, final boolean fullyQualified) {
110:                 this.engine = new VelocityEngine();
111:                 this.engine.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
112:                 this.engine.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
113:                 this.engine.init();
114:                 this.template = this.engine.getTemplate(templateFileName);
115:                 this.fullyQualified = fullyQualified;
116:         }
117:         
118:         public Context getCurrentContext() {
119:                 return this.currentContext;
120:         }
121:         
122:         /**
123:          * Returns the type name (unqualified if {@link #fullyQualified} is false otherwise fully qualified).
124:          *
125:          * @param type
126:          */
127:         protected String typeToString(final GenType type) {
128:                 if (this.fullyQualified) {
129:                         return type.getFullyQualifiedTypeNameWithGenericArguments();
130:                 } else {
131:                         return type.getName();
132:                 }
133:         }
134:         
135:         /**
136:          * Returns the type name (unqualified if {@link #fullyQualified} is {@code false} otherwise fully qualified) for
137:          * {@link GenTypeReferenceByReference} or the Name Attribute for {@link GenTypeReferenceByName}.
138:          *
139:          * @param typeReference
140:          */
141:         protected String typeToString(final GenTypeReference typeReference) {
142:                 return typeReference.accept(new GenTypeReferenceVisitorReturn<String>() {
143:                         @Override
144:                         public String handle(final GenTypeReferenceByName typeReferenceByName) {
145:                                 return typeReferenceByName.getFullyQualifiedNameWithGenericArguments();
146:                         }
147:                         
148:                         @Override
149:                         public String handle(final GenTypeReferenceByReference typeReferenceByReference) {
150:                                 return ClassFileWriter.this.typeToString(typeReferenceByReference.getTyp());
151:                         }
152:                 });
153:         }
154:         
155:         /**
156:          * Writes the file for the given {@link GenClass} c.
157:          *
158:          * @param c
159:          */
160:         void writeClass(final GenClass c) {
161:                 this.currentContext = new VelocityContext();
162:                 this.setUpContext(c, this.currentContext);
163:         }
164:         
165:         /**
166:          * Writes the file for the given {@link GenClass} <code>c</code>.
167:          *
168:          * @param rootdir
169:          */
170:         protected void writeToFile(final GenClass c, final File rootdir) {
171:                 final String result = this.generateFileContent(this.currentContext);
172:                 final File path = this.createPath(c, rootdir);
173:                 final File file = this.createFile(path, c);
174:                 this.writeFile(result, path, file);
175:         }
176:         
177:         public String writeToString() {
178:                 return this.generateFileContent(this.currentContext);
179:         }
180:         
181:         /**
182:          * Sets up the {@link VelocityContext} with all necessary values for classes.
183:          *
184:          * @param c
185:          * {@link GenClass} class to write
186:          * @param context
187:          * the {@link VelocityContext} for the class
188:          */
189:         private void setUpContext(final GenClass c, final Context context) {
190:                 this.setClassComment(c, context);
191:                 this.setClassName(c, context);
192:                 this.setClassGenerics(c, context);
193:                 this.setImplements(c, context);
194:                 this.setNonGenerationPart(c, context);
195:                 this.setInnerClasses(c, context);
196:         }
197:         
198:         /**
199:          * Sets all generic of the {@link GenClass} <code>c</code>.
200:          *
201:          * @param c
202:          * @param context
203:          */
204:         private void setClassGenerics(final GenClass c, final Context context) {
205:                 final StringBuilder gen = new StringBuilder();
206:                 final Iterator<Generic> i = c.getGenerics().listIterator();
207:                 if (i.hasNext()) {
208:                         gen.append(GENERICS_BEGIN);
209:                 }
210:                 while (i.hasNext()) {
211:                         final Generic current = i.next();
212:                         gen.append(current.toString());
213:                         if (i.hasNext()) {
214:                                 gen.append(COMMA_SPARATE);
215:                         } else {
216:                                 gen.append(GENERICS_END);
217:                         }
218:                 }
219:                 context.put(GENERICS_CLASS_KEY, gen.toString());
220:         }
221:         
222:         /**
223:          * Sets all values for the classcomment of {@link GenClass} c to the {@link Context}.
224:          *
225:          * @param c
226:          * @param context
227:          */
228:         private void setClassComment(final GenClass c, final Context context) {
229:                 context.put(CLASS_COMMENT_KEY, c.getComment().getText());
230:         }
231:         
232:         /**
233:          * Sets all values for the classname of {@link GenClass} c to the {@link Context}.
234:          *
235:          * @param c
236:          * @param context
237:          */
238:         private void setClassName(final GenClass c, final Context context) {
239:                 context.put(CLASSNAME_KEY, c.getName());
240:         }
241:         
242:         Collection<String> getSimpleOperations(final Collection<? extends GenOperation> operations) {
243:                 final Vector<String> simpleOperations = new Vector<>();
244:                 for (final GenOperation operation : operations) {
245:                         operation.getState().accept(new GenOperationStateVisitor() {
246:                                 @Override
247:                                 public void handle(final GenFullParsedOperationState s) {
248:                                         // nothing to do
249:                                 }
250:                                 
251:                                 @Override
252:                                 public void handle(final GenSimpleOperationState s) {
253:                                         simpleOperations.add(s.getFullOperationWithPossibleImplementation());
254:                                 }
255:                         });
256:                 }
257:                 return simpleOperations;
258:         }
259:         
260:         Collection<HashMap<String, Object>> getParsedOperations(final Collection<? extends GenOperation> operations) {
261:                 final Vector<HashMap<String, Object>> parsedOperations = new Vector<>();
262:                 for (final GenOperation operation : operations) {
263:                         operation.getState().accept(new GenOperationStateVisitor() {
264:                                 @Override
265:                                 public void handle(final GenFullParsedOperationState s) {
266:                                         final HashMap<String, Object> current = new HashMap<>();
267:                                         current.put(VISIBILITY_KEY, s.getVisibility().toString());
268:                                         current.put(NAME_KEY, operation.getName());
269:                                         current.put(RETURN_TYP_KEY, ClassFileWriter.this.typeToString(s.getReturntyp()));
270:                                         s.getModifiers().remove(GenOperationModifier.ABSTRACT);
271:                                         final Vector<String> modifiers = new Vector<>();
272:                                         for (final GenOperationModifier mod : s.getModifiers()) {
273:                                                 modifiers.add(mod.toString());
274:                                         }
275:                                         current.put(GENERICS_OPERATION_KEY, ClassFileWriter.this.getGenericString(operation));
276:                                         current.put(MODIFIERS_KEY, modifiers);
277:                                         current.put(METHOD_KEY, s.getMethodBody());
278:                                         current.put(OPERATION_COMMENT_KEY, s.getComment().getText());
279:                                         current.put(OPERATION_PARAMETER_KEY, ClassFileWriter.this.getParamString(operation.getParameters()));
280:                                         current.put(EXCEPTIONS_KEY, ClassFileWriter.this.getExceptionString(s.getExceptions()));
281:                                         operation.accept(new GenOperationVisitorReturn<GenOperation>() {
282:                                                 @Override
283:                                                 public GenOperation handleJavaOperation(final GenJavaOperation operation) {
284:                                                         return operation;
285:                                                 }
286:                                                 
287:                                                 @Override
288:                                                 public GenOperation handleAspectOperation(final GenAspectOperation operation) {
289:                                                         current.put(TARGED_CLASS_KEY, ClassFileWriter.this.typeToString(operation.getOwner()) + ".");
290:                                                         return operation;
291:                                                 }
292:                                         });
293:                                         parsedOperations.add(current);
294:                                 }
295:                                 
296:                                 @Override
297:                                 public void handle(final GenSimpleOperationState s) {
298:                                         // nothing to do
299:                                 }
300:                         });
301:                 }
302:                 return parsedOperations;
303:         }
304:         
305:         /**
306:          * Returns the list of generic.
307:          *
308:          * @param operation
309:          * @return
310:          */
311:         private String getGenericString(final GenOperation operation) {
312:                 final StringBuilder gen = new StringBuilder();
313:                 final Iterator<Generic> i = operation.getGenerics().listIterator();
314:                 if (i.hasNext()) {
315:                         gen.append(GENERICS_BEGIN);
316:                 }
317:                 while (i.hasNext()) {
318:                         final Generic current = i.next();
319:                         String generic = "";
320:                         generic += current.toString();
321:                         gen.append(generic);
322:                         if (i.hasNext()) {
323:                                 gen.append(COMMA_SPARATE);
324:                         } else {
325:                                 gen.append(GENERICS_END);
326:                         }
327:                 }
328:                 return gen.toString();
329:         }
330:         
331:         /**
332:          * Returns the String representing the throws clause. <br>
333:          * <code>throws Exc1, Exc2, ...</code>
334:          *
335:          * @param exceptions
336:          */
337:         protected String getExceptionString(final Collection<GenException> exceptions) {
338:                 if (exceptions.isEmpty()) {
339:                         return "";
340:                 }
341:                 final StringBuilder result = new StringBuilder();
342:                 result.append(THROWS);
343:                 final Iterator<GenException> i = exceptions.iterator();
344:                 while (i.hasNext()) {
345:                         final GenException current = i.next();
346:                         result.append(this.typeToString(current));
347:                         if (i.hasNext()) {
348:                                 result.append(COMMA_SPARATE);
349:                         }
350:                 }
351:                 return result.toString();
352:         }
353:         
354:         /**
355:          * Returns the comma separated parameters.<br>
356:          * <code>Typ1 name1, Typ1 name2, ...</code>
357:          *
358:          * @param parameters
359:          */
360:         protected String getParamString(final Collection<GenParameter> parameters) {
361:                 final StringBuilder params = new StringBuilder();
362:                 final Iterator<GenParameter> i = parameters.iterator();
363:                 while (i.hasNext()) {
364:                         final GenParameter current = i.next();
365:                         params.append(this.typeToString(current.getTyp()));
366:                         final Iterator<Generic> iGen = current.getGenerics().listIterator();
367:                         if (iGen.hasNext()) {
368:                                 params.append(GENERICS_BEGIN);
369:                         }
370:                         while (iGen.hasNext()) {
371:                                 final Generic currentGen = iGen.next();
372:                                 params.append(currentGen.getName());
373:                                 if (iGen.hasNext()) {
374:                                         params.append(COMMA_SPARATE);
375:                                 } else {
376:                                         params.append(GENERICS_END);
377:                                 }
378:                         }
379:                         params.append(BLANK);
380:                         params.append(current.getName());
381:                         if (i.hasNext()) {
382:                                 params.append(COMMA_SPARATE);
383:                         }
384:                 }
385:                 return params.toString();
386:         }
387:         
388:         /**
389:          * Sets the nongenerationpart of {@link GenClass} c to the {@link Context}.
390:          *
391:          * @param c
392:          * @param context
393:          */
394:         private void setNonGenerationPart(final GenClass c, final Context context) {
395:                 context.put(NON_GERNATION_PART_KEY, c.getNonGeneratedPart());
396:         }
397:         
398:         /**
399:          * Creates the Path {@link File} for c.
400:          *
401:          * @param c
402:          */
403:         private File createPath(final GenClass c, final File rootDir) {
404:                 String path = c.getPackag().toString();
405:                 path = path.replace(PACKAGE_PATH_SEP, FILE_PATH_SEP);
406:                 path = path.replace(JAVA_LINE_END, FILE_PATH_SEP);
407:                 return new File(rootDir.getAbsolutePath() + FILE_PATH_SEP + path);
408:         }
409:         
410:         /**
411:          * Creates the {@link File} for class c.
412:          *
413:          * @param path
414:          * @param c
415:          */
416:         private File createFile(final File path, final GenClass c) {
417:                 final String file = path.getAbsolutePath() + FILE_PATH_SEP + c.getName() + c.getFileEnding();
418:                 return new File(file);
419:         }
420:         
421:         /**
422:          * Writes the given result into the file.
423:          *
424:          * @param result
425:          * @param path
426:          * @param file
427:          */
428:         private void writeFile(final String result, final File path, final File file) {
429:                 try {
430:                         System.out.println(" --> " + file.getAbsolutePath());
431:                         FileUtils.overrideToFile(result, path, file);
432:                 } catch (final IOException e) {
433:                         e.printStackTrace();
434:                 }
435:         }
436:         
437:         /**
438:          * Merges the context into the classtemplate.
439:          *
440:          * @param context
441:          */
442:         private String generateFileContent(final Context context) {
443:                 final StringWriter writer = new StringWriter();
444:                 this.template.merge(context, writer);
445:                 return writer.toString();
446:         }
447:         
448:         public abstract String getStringContent(final GenClass c);
449:         
450:         /**
451:          * Sets the template variable for inheritance.
452:          *
453:          * @param context
454:          */
455:         protected void setImplements(final GenClass c, final Context context) {
456:                 final StringBuilder implsS = new StringBuilder();
457:                 final Iterator<GenInterfaceClass> i = c.getImplement().iterator();
458:                 while (i.hasNext()) {
459:                         final GenInterfaceClass current = i.next();
460:                         implsS.append(this.typeToString(current));
461:                         if (i.hasNext()) {
462:                                 implsS.append(COMMA_SPARATE);
463:                         }
464:                 }
465:                 if (!c.getImplement().isEmpty()) {
466:                         c.accept(new GenClassVisitor() {
467:                                 @Override
468:                                 public void handle(final GenInterfaceClass interfaceClass) {
469:                                         context.put(IMPLEMENTS_KEY, EXTENDS + implsS.toString());
470:                                 }
471:                                 
472:                                 @Override
473:                                 public void handle(final GenClassClass classClass) {
474:                                         context.put(IMPLEMENTS_KEY, IMPLEMENTS + implsS.toString());
475:                                 }
476:                                 
477:                                 @Override
478:                                 public void handle(final GenPrimitiveClass primitiveClass) {
479:                                         // nothing to do
480:                                 }
481:                         });
482:                 } else {
483:                         context.put(IMPLEMENTS_KEY, "");
484:                 }
485:         }
486:         
487:         private void setInnerClasses(final GenClass c, final Context context) {
488:                 final Collection<String> innerClassesCollection = new Vector<>();
489:                 final Iterator<GenClassClass> innerClassesIterator = c.getInnerClasses().iterator();
490:                 final boolean subclassesFullyQualified = true;
491:                 while (innerClassesIterator.hasNext()) {
492:                         final GenClassClass current = innerClassesIterator.next();
493:                         final String innerClassAsString = current.accept(new GenClassClassVisitorReturn<String>() {
494:                                 
495:                                 @Override
496:                                 public String handle(final GenException e) {
497:                                         final ExceptionFileWriter subExceptionClassFileWriter =
498:                                                         new ExceptionFileWriter(subclassesFullyQualified);
499:                                         return subExceptionClassFileWriter.getStringContent(e);
500:                                 }
501:                                 
502:                                 @Override
503:                                 public String handle(final GenAnyType anyType) {
504:                                         // TODO handle write inner class for this type
505:                                         throw new NotImplementedException();
506:                                 }
507:                                 
508:                                 @Override
509:                                 public String handle(final GenJavaException javaE) {
510:                                         // TODO handle write inner class for this type
511:                                         throw new NotImplementedException();
512:                                 }
513:                                 
514:                                 @Override
515:                                 public String handle(final GenUserClass userclass) {
516:                                         final JavaClassFileWriter subClassFileWriter = new JavaClassFileWriter(subclassesFullyQualified);
517:                                         return subClassFileWriter.getStringContent(userclass);
518:                                 }
519:                                 
520:                                 @Override
521:                                 public String handle(final GenAspect aspect) {
522:                                         // TODO handle write inner class for this type
523:                                         throw new NotImplementedException();
524:                                 }
525:                                 
526:                                 @Override
527:                                 public String handle(final GenExternalClassClass externalClass) {
528:                                         throw new NotImplementedException();
529:                                 }
530:                         });
531:                         innerClassesCollection.add(innerClassAsString);
532:                 }
533:                 context.put(INNER_CLASSES_KEY, innerClassesCollection);
534:         }
535: }