Skip to contentMethod: getParamString(Collection)
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: }