YANG typedefs generation as class with extends key word
[controller.git] / opendaylight / sal / yang-prototype / code-generator / binding-java-api-generator / src / main / java / org / opendaylight / controller / sal / java / api / generator / GeneratorUtil.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.controller.sal.java.api.generator;
9
10 import static org.opendaylight.controller.sal.java.api.generator.Constants.*;
11
12 import java.util.ArrayList;
13 import java.util.Iterator;
14 import java.util.LinkedHashMap;
15 import java.util.List;
16 import java.util.Map;
17
18 import org.opendaylight.controller.binding.generator.util.TypeConstants;
19 import org.opendaylight.controller.sal.binding.model.api.*;
20 import org.opendaylight.controller.binding.generator.util.Types;
21 import org.opendaylight.controller.sal.binding.model.api.Enumeration.Pair;
22 import org.opendaylight.controller.sal.binding.model.api.MethodSignature.Parameter;
23
24 public final class GeneratorUtil {
25
26     private GeneratorUtil() {
27     }
28
29     public static String createIfcDeclaration(final GeneratedType genType, final String indent,
30             final Map<String, String> availableImports) {
31         return createFileDeclaration(IFC, genType, indent, availableImports, false, false);
32     }
33
34     public static String createClassDeclaration(final GeneratedTransferObject genTransferObject, final String indent,
35             final Map<String, String> availableImports, boolean isIdentity, boolean isInnerClass) {
36         return createFileDeclaration(CLASS, genTransferObject, indent, availableImports, isIdentity, isInnerClass);
37     }
38
39     public static String createPackageDeclaration(final String packageName) {
40         return PKG + GAP + packageName + SC;
41     }
42
43     private static String createFileDeclaration(final String type, final GeneratedType genType, final String indent,
44             final Map<String, String> availableImports, boolean isIdentity, boolean innerClass) {
45         final StringBuilder builder = new StringBuilder();
46         final String currentPkg = genType.getPackageName();
47
48         createComment(builder, genType.getComment(), indent);
49
50         if (!genType.getAnnotations().isEmpty()) {
51             final List<AnnotationType> annotations = genType.getAnnotations();
52             appendAnnotations(builder, annotations);
53             builder.append(NL);
54         }
55
56         if (innerClass) {
57             builder.append(indent + PUBLIC + GAP + STATIC + GAP + FINAL + GAP + type + GAP + genType.getName() + GAP);
58         } else if (isIdentity) {
59             if (!(CLASS.equals(type))) {
60                 throw new IllegalArgumentException("'identity' has to be generated as a class");
61             }
62             builder.append(indent + PUBLIC + GAP + ABSTRACT + GAP + type + GAP + genType.getName() + GAP);
63         } else {
64             builder.append(indent + PUBLIC + GAP + type + GAP + genType.getName() + GAP);
65         }
66
67         if (genType instanceof GeneratedTransferObject) {
68             GeneratedTransferObject genTO = (GeneratedTransferObject) genType;
69
70             if (genTO.getExtends() != null) {
71                 builder.append(EXTENDS + GAP);
72                 String gtoString = getExplicitType(genTO.getExtends(), availableImports, currentPkg);
73                 builder.append(gtoString + GAP);
74             }
75         }
76
77         final List<Type> genImplements = genType.getImplements();
78         if (!genImplements.isEmpty()) {
79             if (genType instanceof GeneratedTransferObject) {
80                 builder.append(IMPLEMENTS + GAP);
81             } else {
82                 builder.append(EXTENDS + GAP);
83             }
84             builder.append(getExplicitType(genImplements.get(0), availableImports, currentPkg));
85
86             for (int i = 1; i < genImplements.size(); ++i) {
87                 builder.append(", ");
88                 builder.append(getExplicitType(genImplements.get(i), availableImports, currentPkg));
89             }
90         }
91         builder.append(GAP + LCB);
92         return builder.toString();
93     }
94
95     private static StringBuilder appendAnnotations(final StringBuilder builder, final List<AnnotationType> annotations) {
96         if ((builder != null) && (annotations != null)) {
97             for (final AnnotationType annotation : annotations) {
98                 builder.append("@");
99                 builder.append(annotation.getPackageName());
100                 builder.append(".");
101                 builder.append(annotation.getName());
102
103                 if (annotation.containsParameters()) {
104                     builder.append("(");
105                     final List<AnnotationType.Parameter> parameters = annotation.getParameters();
106                     appendAnnotationParams(builder, parameters);
107                     builder.append(")");
108                 }
109             }
110         }
111         return builder;
112     }
113
114     private static StringBuilder appendAnnotationParams(final StringBuilder builder,
115             final List<AnnotationType.Parameter> parameters) {
116         if (parameters != null) {
117             int i = 0;
118             for (final AnnotationType.Parameter param : parameters) {
119                 if (param == null) {
120                     continue;
121                 }
122                 if (i > 0) {
123                     builder.append(", ");
124                 }
125                 final String paramName = param.getName();
126                 if (param.getValue() != null) {
127                     builder.append(paramName);
128                     builder.append(" = ");
129                     builder.append(param.getValue());
130                 } else {
131                     builder.append(paramName);
132                     builder.append(" = {");
133                     final List<String> values = param.getValues();
134                     builder.append(values.get(0));
135                     for (int j = 1; j < values.size(); ++j) {
136                         builder.append(", ");
137                         builder.append(values.get(j));
138                     }
139                     builder.append("}");
140                 }
141                 i++;
142             }
143         }
144         return builder;
145     }
146
147     public static String createConstant(final Constant constant, final String indent,
148             final Map<String, String> availableImports, final String currentPkg) {
149         final StringBuilder builder = new StringBuilder();
150         if (constant == null)
151             throw new IllegalArgumentException();
152         builder.append(indent + PUBLIC + GAP + STATIC + GAP + FINAL + GAP);
153         builder.append(getExplicitType(constant.getType(), availableImports, currentPkg) + GAP + constant.getName());
154         builder.append(GAP + "=" + GAP);
155
156         if (constant.getName().equals(TypeConstants.PATTERN_CONSTANT_NAME)) {
157             return "";
158         } else {
159             builder.append(constant.getValue());
160         }
161         builder.append(SC);
162
163         return builder.toString();
164     }
165
166     public static String createField(final GeneratedProperty property, final String indent,
167             final Map<String, String> availableImports, final String currentPkg) {
168         final StringBuilder builder = new StringBuilder();
169         if (!property.getAnnotations().isEmpty()) {
170             final List<AnnotationType> annotations = property.getAnnotations();
171             appendAnnotations(builder, annotations);
172             builder.append(NL);
173         }
174         builder.append(indent + PRIVATE + GAP);
175         builder.append(getExplicitType(property.getReturnType(), availableImports, currentPkg) + GAP
176                 + property.getName());
177         builder.append(SC);
178         return builder.toString();
179     }
180
181     /**
182      * Create method declaration in interface.
183      * 
184      * @param method
185      * @param indent
186      * @return
187      */
188     public static String createMethodDeclaration(final MethodSignature method, final String indent,
189             Map<String, String> availableImports, final String currentPkg) {
190         final StringBuilder builder = new StringBuilder();
191
192         if (method == null) {
193             throw new IllegalArgumentException("Method Signature parameter MUST be specified and cannot be NULL!");
194         }
195
196         final String comment = method.getComment();
197         final String name = method.getName();
198         if (name == null) {
199             throw new IllegalStateException("Method Name cannot be NULL!");
200         }
201
202         final Type type = method.getReturnType();
203         if (type == null) {
204             throw new IllegalStateException("Method Return type cannot be NULL!");
205         }
206
207         final List<Parameter> parameters = method.getParameters();
208
209         createComment(builder, comment, indent);
210         builder.append(NL);
211
212         if (!method.getAnnotations().isEmpty()) {
213             builder.append(indent);
214             final List<AnnotationType> annotations = method.getAnnotations();
215             appendAnnotations(builder, annotations);
216             builder.append(NL);
217         }
218
219         builder.append(indent + getExplicitType(type, availableImports, currentPkg) + GAP + name);
220         builder.append(LB);
221         for (int i = 0; i < parameters.size(); i++) {
222             Parameter p = parameters.get(i);
223             String separator = COMMA;
224             if (i + 1 == parameters.size()) {
225                 separator = "";
226             }
227             builder.append(getExplicitType(p.getType(), availableImports, currentPkg) + GAP + p.getName() + separator);
228         }
229         builder.append(RB);
230         builder.append(SC);
231
232         return builder.toString();
233     }
234
235     public static String createConstructor(final GeneratedTransferObject genTransferObject, final String indent,
236             final Map<String, String> availableImports, final boolean isIdentity, final boolean oneConstructor) {
237         if (genTransferObject == null) {
238             throw new IllegalArgumentException("Generated transfer object can't be null");
239         }
240         if (indent == null) {
241             throw new IllegalArgumentException("String with indent can't be null");
242         }
243         if (availableImports == null) {
244             throw new IllegalArgumentException("Map of available imports can't be null");
245         }
246         GeneratedTransferObject genTOTopParent = getTopParrentTransportObject(genTransferObject);
247         final List<GeneratedProperty> ctorProperties = resolveReadOnlyPropertiesFromTO(genTransferObject
248                 .getProperties());
249         final List<GeneratedProperty> ctorPropertiesAllParents = getPropertiesOfAllParents(genTransferObject
250                 .getExtends());
251
252         final String currentPkg = genTransferObject.getPackageName();
253         final String className = genTransferObject.getName();
254
255         String constructorPart = "";
256         if (oneConstructor) {
257             if (genTOTopParent != genTransferObject && genTOTopParent.isUnionType()) {
258                 constructorPart = createConstructorForEveryParentProperty(indent, isIdentity, ctorProperties,
259                         ctorPropertiesAllParents, availableImports, currentPkg, className);
260
261             } else {
262                 constructorPart = createOneConstructor(indent, isIdentity, ctorProperties, ctorPropertiesAllParents,
263                         availableImports, currentPkg, className);
264             }
265
266         } else { // union won't be extended
267             constructorPart = createConstructorForEveryProperty(indent, isIdentity, ctorProperties,
268                     ctorPropertiesAllParents, availableImports, currentPkg, className);
269         }
270
271         return constructorPart;
272     }
273
274     private static String createOneConstructor(final String indent, boolean isIdentity,
275             final List<GeneratedProperty> properties, final List<GeneratedProperty> propertiesAllParents,
276             final Map<String, String> availableImports, final String currentPkg, final String className) {
277         if (indent == null) {
278             throw new IllegalArgumentException("String with indent can't be null");
279         }
280         if (properties == null) {
281             throw new IllegalArgumentException("List of generated properties can't be null");
282         }
283         if (propertiesAllParents == null) {
284             throw new IllegalArgumentException(
285                     "List of generated properties of all parent transport objects can't be null");
286         }
287         if (availableImports == null) {
288             throw new IllegalArgumentException("Map of available imports can't be null");
289         }
290         if (currentPkg == null) {
291             throw new IllegalArgumentException("String with current package can't be null");
292         }
293         if (className == null) {
294             throw new IllegalArgumentException("String with class name can't be null");
295         }
296
297         final StringBuilder builder = new StringBuilder();
298
299         List<GeneratedProperty> propertiesAll = new ArrayList<GeneratedProperty>(properties);
300         propertiesAll.addAll(propertiesAllParents);
301
302         builder.append(createConstructorDeclarationToLeftParenthesis(className, indent, isIdentity));
303         builder.append(createMethodPropertiesDeclaration(propertiesAll, availableImports, currentPkg, COMMA + GAP));
304         builder.append(createConstructorDeclarationFromRightParenthesis());
305         builder.append(createConstructorSuper(propertiesAllParents, indent));
306         builder.append(createClassPropertiesInitialization(propertiesAll, indent));
307         builder.append(createConstructorClosingPart(indent));
308         return builder.toString();
309     }
310
311     private static String createConstructorForEveryParentProperty(final String indent, final boolean isIdentity,
312             final List<GeneratedProperty> properties, final List<GeneratedProperty> propertiesAllParents,
313             final Map<String, String> availableImports, final String currentPkg, final String className) {
314         if (indent == null) {
315             throw new IllegalArgumentException("String with indent can't be null");
316         }
317         if (properties == null) {
318             throw new IllegalArgumentException("List of generated properties can't be null");
319         }
320         if (propertiesAllParents == null) {
321             throw new IllegalArgumentException(
322                     "List of generated properties of all parent transport objects can't be null");
323         }
324         if (availableImports == null) {
325             throw new IllegalArgumentException("Map of available imports can't be null");
326         }
327         if (currentPkg == null) {
328             throw new IllegalArgumentException("String with current package can't be null");
329         }
330         if (className == null) {
331             throw new IllegalArgumentException("String with class name can't be null");
332         }
333         final StringBuilder builder = new StringBuilder();
334         GeneratedProperty parentProperty;
335         Iterator<GeneratedProperty> parentPropertyIterator = propertiesAllParents.iterator();
336
337         do {
338             parentProperty = null;
339             if (parentPropertyIterator.hasNext()) {
340                 parentProperty = parentPropertyIterator.next();
341             }
342
343             List<GeneratedProperty> propertiesAndParentProperties = new ArrayList<GeneratedProperty>();
344             if (parentProperty != null) {
345                 propertiesAndParentProperties.add(parentProperty);
346             }
347             propertiesAndParentProperties.addAll(properties);
348
349             builder.append(createConstructorDeclarationToLeftParenthesis(className, indent, isIdentity));
350             builder.append(createMethodPropertiesDeclaration(propertiesAndParentProperties, availableImports,
351                     currentPkg, COMMA + GAP));
352             builder.append(createConstructorDeclarationFromRightParenthesis());
353             builder.append(createConstructorSuper(parentProperty, indent));
354             builder.append(createClassPropertiesInitialization(properties, indent));
355             builder.append(createConstructorClosingPart(indent));
356         } while (parentPropertyIterator.hasNext());
357
358         return builder.toString();
359     }
360
361     private static String createConstructorForEveryProperty(final String indent, final boolean isIdentity,
362             final List<GeneratedProperty> properties, final List<GeneratedProperty> propertiesAllParents,
363             final Map<String, String> availableImports, final String currentPkg, final String className) {
364         if (indent == null) {
365             throw new IllegalArgumentException("String with indent can't be null");
366         }
367         if (properties == null) {
368             throw new IllegalArgumentException("List of generated properties can't be null");
369         }
370         if (propertiesAllParents == null) {
371             throw new IllegalArgumentException(
372                     "List of generated properties of all parent transport objects can't be null");
373         }
374         if (availableImports == null) {
375             throw new IllegalArgumentException("Map of available imports can't be null");
376         }
377         if (currentPkg == null) {
378             throw new IllegalArgumentException("String with current package can't be null");
379         }
380         if (className == null) {
381             throw new IllegalArgumentException("String with class name can't be null");
382         }
383
384         final StringBuilder builder = new StringBuilder();
385
386         GeneratedProperty property;
387         Iterator<GeneratedProperty> propertyIterator = properties.iterator();
388
389         do {
390             property = null;
391             if (propertyIterator.hasNext()) {
392                 property = propertyIterator.next();
393             }
394
395             List<GeneratedProperty> propertyAndTopParentProperties = new ArrayList<GeneratedProperty>();
396             if (property != null) {
397                 propertyAndTopParentProperties.add(property);
398             }
399             propertyAndTopParentProperties.addAll(propertiesAllParents);
400
401             builder.append(createConstructorDeclarationToLeftParenthesis(className, indent, isIdentity));
402             builder.append(createMethodPropertiesDeclaration(propertyAndTopParentProperties, availableImports,
403                     currentPkg, COMMA + GAP));
404             builder.append(createConstructorDeclarationFromRightParenthesis());
405             builder.append(createConstructorSuper(propertiesAllParents, indent));
406             builder.append(createClassPropertyInitialization(property, indent));
407             builder.append(createConstructorClosingPart(indent));
408         } while (propertyIterator.hasNext());
409
410         return builder.toString();
411     }
412
413     /**
414      * The method selects from input list of properties only those which have
415      * read only attribute set to true.
416      * 
417      * @param properties
418      *            contains list of properties of generated transfer object
419      * @return subset of <code>properties</code> which have read only attribute
420      *         set to true
421      */
422     private static List<GeneratedProperty> resolveReadOnlyPropertiesFromTO(List<GeneratedProperty> properties) {
423         List<GeneratedProperty> readOnlyProperties = new ArrayList<GeneratedProperty>();
424         if (properties != null) {
425             for (final GeneratedProperty property : properties) {
426                 if (property.isReadOnly()) {
427                     readOnlyProperties.add(property);
428                 }
429             }
430         }
431         return readOnlyProperties;
432     }
433
434     private static String createMethodPropertiesDeclaration(final List<GeneratedProperty> parameters,
435             final Map<String, String> availableImports, final String currentPkg, final String parameterSeparator) {
436         StringBuilder builder = new StringBuilder();
437         if (parameters == null) {
438             throw new IllegalArgumentException("List of generated properties can't be null");
439         }
440         if (availableImports == null) {
441             throw new IllegalArgumentException("Map of available imports can't be null");
442         }
443         if (currentPkg == null) {
444             throw new IllegalArgumentException("String with current package can't be null");
445         }
446         if (parameterSeparator == null) {
447             throw new IllegalArgumentException("String with separator of parameters can't be null");
448         }
449
450         for (final GeneratedProperty parameter : parameters) {
451             builder.append(createMethodPropertyDeclaration(parameter, availableImports, currentPkg));
452             builder.append(parameterSeparator);
453         }
454         if (!parameters.isEmpty()) {
455             builder = builder.delete(builder.length() - parameterSeparator.length(), builder.length());
456         }
457         return builder.toString();
458     }
459
460     private static String createConstructorDeclarationToLeftParenthesis(final String className, final String indent,
461             final boolean isIdentity) {
462         if (className == null) {
463             throw new IllegalArgumentException("String with class name can't be null");
464         }
465         if (indent == null) {
466             throw new IllegalArgumentException("String with indent can't be null");
467         }
468         final StringBuilder builder = new StringBuilder();
469         builder.append(indent);
470         builder.append(isIdentity ? PROTECTED : PUBLIC);
471         builder.append(GAP);
472         builder.append(className);
473         builder.append(LB);
474         return builder.toString();
475     }
476
477     private static String createConstructorDeclarationFromRightParenthesis() {
478         final StringBuilder builder = new StringBuilder();
479         builder.append(RB + GAP + LCB + NL);
480         return builder.toString();
481     }
482
483     private static String createConstructorSuper(final List<GeneratedProperty> propertiesAllParents, final String indent) {
484         if (indent == null) {
485             throw new IllegalArgumentException("String with indent can't be null");
486         }
487         if (propertiesAllParents == null) {
488             throw new IllegalArgumentException("List of all parent's properties can't be null");
489         }
490         StringBuilder builder = new StringBuilder();
491         builder.append(indent + TAB + "super(");
492         String propertySeparator = COMMA + GAP;
493         for (GeneratedProperty superProperty : propertiesAllParents) {
494             builder.append(superProperty.getName());
495             builder.append(propertySeparator);
496         }
497         if (!propertiesAllParents.isEmpty()) {
498             builder = builder.delete(builder.length() - propertySeparator.length(), builder.length());
499         }
500
501         builder.append(");" + NL);
502         return builder.toString();
503     }
504
505     private static String createConstructorSuper(final GeneratedProperty parentProperty, final String indent) {
506         if (indent == null) {
507             throw new IllegalArgumentException("String with indent can't be null");
508         }
509         if (parentProperty == null) {
510             throw new IllegalArgumentException("Parent property can't be null");
511         }
512         StringBuilder builder = new StringBuilder();
513         if (parentProperty != null) {
514             builder.append(indent + TAB + "super(");
515             builder.append(parentProperty.getName());
516             builder.append(");" + NL);
517         }
518         return builder.toString();
519     }
520
521     private static String createConstructorClosingPart(final String indent) {
522         if (indent == null) {
523             throw new IllegalArgumentException("String with indent can't be null");
524         }
525         final StringBuilder builder = new StringBuilder();
526         builder.append(indent);
527         builder.append(RCB);
528         builder.append(NL + NL);
529         return builder.toString();
530     }
531
532     private static String createClassPropertiesInitialization(final List<GeneratedProperty> properties,
533             final String indent) {
534         if (indent == null) {
535             throw new IllegalArgumentException("String with indent can't be null");
536         }
537         if (properties == null) {
538             throw new IllegalArgumentException("List of generated class properties can't be null");
539         }
540         final StringBuilder builder = new StringBuilder();
541         for (final GeneratedProperty property : properties) {
542             createClassPropertyInitialization(property, indent);
543         }
544         return builder.toString();
545     }
546
547     private static String createClassPropertyInitialization(final GeneratedProperty property, final String indent) {
548         if (indent == null) {
549             throw new IllegalArgumentException("String with indent can't be null");
550         }
551         if (property == null) {
552             throw new IllegalArgumentException("List of generated class properties can't be null");
553         }
554         final StringBuilder builder = new StringBuilder();
555         builder.append(indent);
556         builder.append(TAB);
557         builder.append("this.");
558         builder.append(property.getName());
559         builder.append(" = ");
560         builder.append(property.getName());
561         builder.append(SC);
562         builder.append(NL);
563         return builder.toString();
564     }
565
566     private static String createMethodPropertyDeclaration(final GeneratedProperty property,
567             final Map<String, String> availableImports, final String currentPkg) {
568         if (property == null) {
569             throw new IllegalArgumentException("Generated property can't be null");
570         }
571         if (availableImports == null) {
572             throw new IllegalArgumentException("Map of available imports can't be null");
573         }
574         if (currentPkg == null) {
575             throw new IllegalArgumentException("String with current package can't be null");
576         }
577         final StringBuilder builder = new StringBuilder();
578         builder.append(getExplicitType(property.getReturnType(), availableImports, currentPkg));
579         builder.append(GAP);
580         builder.append(property.getName());
581         return builder.toString();
582     }
583
584     public static String createGetter(final GeneratedProperty property, final String indent,
585             final Map<String, String> availableImports, final String currentPkg) {
586         final StringBuilder builder = new StringBuilder();
587
588         final Type type = property.getReturnType();
589         final String varName = property.getName();
590         final char first = Character.toUpperCase(varName.charAt(0));
591         final String methodName = "get" + first + varName.substring(1);
592
593         builder.append(indent + PUBLIC + GAP + getExplicitType(type, availableImports, currentPkg) + GAP + methodName);
594         builder.append(LB + RB + LCB + NL);
595
596         String currentIndent = indent + TAB;
597
598         builder.append(currentIndent + "return " + varName + SC + NL);
599
600         builder.append(indent + RCB);
601         return builder.toString();
602     }
603
604     public static String createSetter(final GeneratedProperty property, final String indent,
605             final Map<String, String> availableImports, final String currentPkg) {
606         final StringBuilder builder = new StringBuilder();
607
608         final Type type = property.getReturnType();
609         final String varName = property.getName();
610         final char first = Character.toUpperCase(varName.charAt(0));
611         final String methodName = "set" + first + varName.substring(1);
612
613         builder.append(indent + PUBLIC + GAP + "void" + GAP + methodName);
614         builder.append(LB + getExplicitType(type, availableImports, currentPkg) + GAP + varName + RB + LCB + NL);
615         String currentIndent = indent + TAB;
616         builder.append(currentIndent + "this." + varName + " = " + varName + SC + NL);
617         builder.append(indent + RCB);
618         return builder.toString();
619     }
620
621     public static String createHashCode(final List<GeneratedProperty> properties, final String indent) {
622         StringBuilder builder = new StringBuilder();
623         builder.append(indent + "public int hashCode() {" + NL);
624         builder.append(indent + TAB + "final int prime = 31;" + NL);
625         builder.append(indent + TAB + "int result = 1;" + NL);
626
627         for (GeneratedProperty property : properties) {
628             String fieldName = property.getName();
629             builder.append(indent + TAB + "result = prime * result + ((" + fieldName + " == null) ? 0 : " + fieldName
630                     + ".hashCode());" + NL);
631         }
632
633         builder.append(indent + TAB + "return result;" + NL);
634         builder.append(indent + RCB + NL);
635         return builder.toString();
636     }
637
638     public static String createEquals(final GeneratedTransferObject type, final List<GeneratedProperty> properties,
639             final String indent) {
640         final StringBuilder builder = new StringBuilder();
641         final String indent1 = indent + TAB;
642         final String indent2 = indent1 + TAB;
643         final String indent3 = indent2 + TAB;
644
645         builder.append(indent + "public boolean equals(Object obj) {" + NL);
646         builder.append(indent1 + "if (this == obj) {" + NL);
647         builder.append(indent2 + "return true;" + NL);
648         builder.append(indent1 + "}" + NL);
649         builder.append(indent1 + "if (obj == null) {" + NL);
650         builder.append(indent2 + "return false;" + NL);
651         builder.append(indent1 + "}" + NL);
652         builder.append(indent1 + "if (getClass() != obj.getClass()) {" + NL);
653         builder.append(indent2 + "return false;" + NL);
654         builder.append(indent1 + "}" + NL);
655
656         String typeStr = type.getName();
657         builder.append(indent1 + typeStr + " other = (" + typeStr + ") obj;" + NL);
658
659         for (final GeneratedProperty property : properties) {
660             String fieldName = property.getName();
661             builder.append(indent1 + "if (" + fieldName + " == null) {" + NL);
662             builder.append(indent2 + "if (other." + fieldName + " != null) {" + NL);
663             builder.append(indent3 + "return false;" + NL);
664             builder.append(indent2 + "}" + NL);
665             builder.append(indent1 + "} else if (!" + fieldName + ".equals(other." + fieldName + ")) {" + NL);
666             builder.append(indent2 + "return false;" + NL);
667             builder.append(indent1 + "}" + NL);
668         }
669
670         builder.append(indent1 + "return true;" + NL);
671         builder.append(indent + RCB + NL);
672         return builder.toString();
673     }
674
675     public static String createToString(final GeneratedTransferObject type, final List<GeneratedProperty> properties,
676             final String indent) {
677         StringBuilder builder = new StringBuilder();
678         builder.append(indent);
679         builder.append("public String toString() {");
680         builder.append(NL);
681         builder.append(indent);
682         builder.append(TAB);
683         builder.append("StringBuilder builder = new StringBuilder();");
684         builder.append(NL);
685         builder.append(indent);
686         builder.append(TAB);
687         builder.append("builder.append(\"");
688         builder.append(type.getName());
689         builder.append(" [");
690
691         boolean first = true;
692         for (final GeneratedProperty property : properties) {
693             if (first) {
694                 builder.append(property.getName());
695                 builder.append("=\");");
696                 builder.append(NL);
697                 builder.append(indent);
698                 builder.append(TAB);
699                 builder.append("builder.append(");
700                 builder.append(property.getName());
701                 builder.append(");");
702                 first = false;
703             } else {
704                 builder.append(NL);
705                 builder.append(indent);
706                 builder.append(TAB);
707                 builder.append("builder.append(\", ");
708                 builder.append(property.getName());
709                 builder.append("=\");");
710                 builder.append(NL);
711                 builder.append(indent);
712                 builder.append(TAB);
713                 builder.append("builder.append(");
714                 builder.append(property.getName());
715                 builder.append(");");
716             }
717         }
718         builder.append(NL);
719         builder.append(indent);
720         builder.append(TAB);
721         builder.append("builder.append(\"]\");");
722         builder.append(NL);
723         builder.append(indent);
724         builder.append(TAB);
725         builder.append("return builder.toString();");
726
727         builder.append(NL);
728         builder.append(indent);
729         builder.append(RCB);
730         builder.append(NL);
731         return builder.toString();
732     }
733
734     public static String createEnum(final Enumeration enumeration, final String indent) {
735         if (enumeration == null || indent == null)
736             throw new IllegalArgumentException();
737         final StringBuilder builder = new StringBuilder(indent + PUBLIC + GAP + ENUM + GAP + enumeration.getName()
738                 + GAP + LCB + NL);
739
740         String separator = COMMA + NL;
741         final List<Pair> values = enumeration.getValues();
742
743         for (int i = 0; i < values.size(); i++) {
744             if (i + 1 == values.size()) {
745                 separator = SC;
746             }
747             builder.append(indent + TAB + values.get(i).getName() + LB + values.get(i).getValue() + RB + separator);
748         }
749         builder.append(NL);
750         builder.append(NL);
751         final String ENUMERATION_NAME = "value";
752         final String ENUMERATION_TYPE = "int";
753         builder.append(indent + TAB + ENUMERATION_TYPE + GAP + ENUMERATION_NAME + SC);
754         builder.append(NL);
755         builder.append(indent + TAB + PRIVATE + GAP + enumeration.getName() + LB + ENUMERATION_TYPE + GAP
756                 + ENUMERATION_NAME + RB + GAP + LCB + NL);
757         builder.append(indent + TAB + TAB + "this." + ENUMERATION_NAME + GAP + "=" + GAP + ENUMERATION_NAME + SC + NL);
758         builder.append(indent + TAB + RCB + NL);
759
760         builder.append(indent + RCB);
761         builder.append(NL);
762         return builder.toString();
763     }
764
765     private static String getExplicitType(final Type type, final Map<String, String> imports, final String currentPkg) {
766         if (type == null) {
767             throw new IllegalArgumentException("Type parameter MUST be specified and cannot be NULL!");
768         }
769         if (type.getName() == null) {
770             throw new IllegalArgumentException("Type name cannot be NULL!");
771         }
772         if (type.getPackageName() == null) {
773             throw new IllegalArgumentException("Type cannot have Package Name referenced as NULL!");
774         }
775         if (imports == null) {
776             throw new IllegalArgumentException("Imports Map cannot be NULL!");
777         }
778
779         final String typePackageName = type.getPackageName();
780         final String typeName = type.getName();
781         final String importedPackageName = imports.get(typeName);
782         if (typePackageName.equals(importedPackageName) || typePackageName.equals(currentPkg)) {
783             final StringBuilder builder = new StringBuilder(type.getName());
784             if (type instanceof ParameterizedType) {
785                 final ParameterizedType pType = (ParameterizedType) type;
786                 final Type[] pTypes = pType.getActualTypeArguments();
787                 builder.append("<");
788                 builder.append(getParameters(pTypes, imports, currentPkg));
789                 builder.append(">");
790             }
791             if (builder.toString().equals("Void")) {
792                 return "void";
793             }
794             return builder.toString();
795         } else {
796             final StringBuilder builder = new StringBuilder();
797             if (typePackageName.startsWith("java.lang")) {
798                 builder.append(type.getName());
799             } else {
800                 if (!typePackageName.isEmpty()) {
801                     builder.append(typePackageName + "." + type.getName());
802                 } else {
803                     builder.append(type.getName());
804                 }
805             }
806             if (type.equals(Types.voidType())) {
807                 return "void";
808             }
809             if (type instanceof ParameterizedType) {
810                 final ParameterizedType pType = (ParameterizedType) type;
811                 final Type[] pTypes = pType.getActualTypeArguments();
812                 builder.append("<");
813                 builder.append(getParameters(pTypes, imports, currentPkg));
814                 builder.append(">");
815             }
816             return builder.toString();
817         }
818     }
819
820     private static String getParameters(final Type[] pTypes, Map<String, String> availableImports, String currentPkg) {
821         final StringBuilder builder = new StringBuilder();
822         for (int i = 0; i < pTypes.length; i++) {
823             final Type t = pTypes[i];
824
825             String separator = COMMA;
826             if (i == (pTypes.length - 1)) {
827                 separator = "";
828             }
829
830             String wildcardParam = "";
831             if (t.equals(Types.voidType())) {
832                 builder.append("java.lang.Void" + separator);
833                 continue;
834             } else {
835
836                 if (t instanceof WildcardType) {
837                     wildcardParam = "? extends ";
838                 }
839
840                 builder.append(wildcardParam + getExplicitType(t, availableImports, currentPkg) + separator);
841             }
842         }
843         return builder.toString();
844     }
845
846     private static void createComment(final StringBuilder builder, final String comment, final String indent) {
847         if (comment != null && comment.length() > 0) {
848             builder.append(indent + "/*" + NL);
849             builder.append(indent + comment + NL);
850             builder.append(indent + "*/" + NL);
851         }
852     }
853
854     public static Map<String, String> createImports(GeneratedType genType) {
855         if (genType == null) {
856             throw new IllegalArgumentException("Generated Type cannot be NULL!");
857         }
858         final Map<String, String> imports = new LinkedHashMap<>();
859         List<GeneratedType> childGeneratedTypes = genType.getEnclosedTypes();
860         if (!childGeneratedTypes.isEmpty()) {
861             for (GeneratedType genTypeChild : childGeneratedTypes) {
862                 imports.putAll(createImports(genTypeChild));
863             }
864         }
865
866         final List<Constant> constants = genType.getConstantDefinitions();
867         final List<MethodSignature> methods = genType.getMethodDefinitions();
868         final List<Type> impl = genType.getImplements();
869
870         // IMPLEMENTATIONS
871         if (impl != null) {
872             for (final Type type : impl) {
873                 putTypeIntoImports(genType, type, imports);
874             }
875         }
876
877         // CONSTANTS
878         if (constants != null) {
879             for (final Constant constant : constants) {
880                 final Type constantType = constant.getType();
881                 putTypeIntoImports(genType, constantType, imports);
882             }
883         }
884
885         // REGULAR EXPRESSION
886         if (genType instanceof GeneratedTransferObject) {
887             if (isConstantInTO(TypeConstants.PATTERN_CONSTANT_NAME, (GeneratedTransferObject) genType)) {
888                 putTypeIntoImports(genType, Types.typeForClass(java.util.regex.Pattern.class), imports);
889                 putTypeIntoImports(genType, Types.typeForClass(java.util.Arrays.class), imports);
890                 putTypeIntoImports(genType, Types.typeForClass(java.util.ArrayList.class), imports);
891             }
892         }
893
894         // METHODS
895         if (methods != null) {
896             for (final MethodSignature method : methods) {
897                 final Type methodReturnType = method.getReturnType();
898                 putTypeIntoImports(genType, methodReturnType, imports);
899                 for (final MethodSignature.Parameter methodParam : method.getParameters()) {
900                     putTypeIntoImports(genType, methodParam.getType(), imports);
901                 }
902             }
903         }
904
905         // PROPERTIES
906         if (genType instanceof GeneratedTransferObject) {
907             final GeneratedTransferObject genTO = (GeneratedTransferObject) genType;
908             final List<GeneratedProperty> properties = genTO.getProperties();
909             if (properties != null) {
910                 for (GeneratedProperty property : properties) {
911                     final Type propertyType = property.getReturnType();
912                     putTypeIntoImports(genType, propertyType, imports);
913                 }
914             }
915         }
916
917         return imports;
918     }
919
920     public static Map<String, String> createChildImports(GeneratedType genType) {
921         Map<String, String> childImports = new LinkedHashMap<>();
922         List<GeneratedType> childGeneratedTypes = genType.getEnclosedTypes();
923         if (!childGeneratedTypes.isEmpty()) {
924             for (GeneratedType genTypeChild : childGeneratedTypes) {
925                 createChildImports(genTypeChild);
926                 childImports.put(genTypeChild.getName(), genTypeChild.getPackageName());
927             }
928         }
929         return childImports;
930     }
931
932     private static void putTypeIntoImports(final GeneratedType parentGenType, final Type type,
933             final Map<String, String> imports) {
934         if (parentGenType == null) {
935             throw new IllegalArgumentException("Parent Generated Type parameter MUST be specified and cannot be "
936                     + "NULL!");
937         }
938         if (parentGenType.getName() == null) {
939             throw new IllegalArgumentException("Parent Generated Type name cannot be NULL!");
940         }
941         if (parentGenType.getPackageName() == null) {
942             throw new IllegalArgumentException("Parent Generated Type cannot have Package Name referenced as NULL!");
943         }
944         if (type == null) {
945             throw new IllegalArgumentException("Type parameter MUST be specified and cannot be NULL!");
946         }
947         if (type.getName() == null) {
948             throw new IllegalArgumentException("Type name cannot be NULL!");
949         }
950         if (type.getPackageName() == null) {
951             throw new IllegalArgumentException("Type cannot have Package Name referenced as NULL!");
952         }
953
954         final String typeName = type.getName();
955         final String typePackageName = type.getPackageName();
956         final String parentTypeName = parentGenType.getName();
957         final String parentTypePackageName = parentGenType.getPackageName();
958         if (typeName.equals(parentTypeName) || typePackageName.startsWith("java.lang")
959                 || typePackageName.equals(parentTypePackageName) || typePackageName.isEmpty()) {
960             return;
961         }
962         if (!imports.containsKey(typeName)) {
963             imports.put(typeName, typePackageName);
964         }
965         if (type instanceof ParameterizedType) {
966             final ParameterizedType paramType = (ParameterizedType) type;
967             final Type[] params = paramType.getActualTypeArguments();
968             for (Type param : params) {
969                 putTypeIntoImports(parentGenType, param, imports);
970             }
971         }
972     }
973
974     public static List<String> createImportLines(final Map<String, String> imports,
975             final Map<String, String> innerTypeImports) {
976         final List<String> importLines = new ArrayList<>();
977
978         for (Map.Entry<String, String> entry : imports.entrySet()) {
979             final String typeName = entry.getKey();
980             final String packageName = entry.getValue();
981             if (innerTypeImports != null) {
982                 String innerTypePackageName = innerTypeImports.get(typeName);
983                 if (innerTypePackageName != null) {
984                     if (innerTypePackageName.equals(packageName))
985                         continue;
986                 }
987             }
988             importLines.add("import " + packageName + "." + typeName + SC);
989         }
990         return importLines;
991     }
992
993     public static boolean isConstantInTO(String constName, GeneratedTransferObject genTO) {
994         if (constName == null || genTO == null)
995             throw new IllegalArgumentException();
996         List<Constant> consts = genTO.getConstantDefinitions();
997         for (Constant cons : consts) {
998             if (cons.getName().equals(constName)) {
999                 return true;
1000             }
1001
1002         }
1003         return false;
1004     }
1005
1006     /**
1007      * The method returns reference to highest (top parent) Generated Transfer
1008      * Object.
1009      * 
1010      * @param childTransportObject
1011      *            is generated transfer object which can be extended by other
1012      *            generated transfer object
1013      * @return in first case that <code>childTransportObject</code> isn't
1014      *         extended then <code>childTransportObject</code> is returned. In
1015      *         second case the method is recursive called until first case.
1016      */
1017     private static GeneratedTransferObject getTopParrentTransportObject(GeneratedTransferObject childTransportObject) {
1018         if (childTransportObject == null) {
1019             throw new IllegalArgumentException("Parameter childTransportObject can't be null.");
1020         }
1021         if (childTransportObject.getExtends() == null) {
1022             return childTransportObject;
1023         } else {
1024             return getTopParrentTransportObject(childTransportObject.getExtends());
1025         }
1026     }
1027
1028     /**
1029      * The method returns the list of the properties of all extending generated
1030      * transfer object from <code>genTO</code> to highest parent generated
1031      * transfer object
1032      * 
1033      * @param genTO
1034      * @return the list of all properties from actual to highest parent
1035      *         generated transfer object. In case when extension exists the
1036      *         method is recursive called.
1037      */
1038     private static List<GeneratedProperty> getPropertiesOfAllParents(GeneratedTransferObject genTO) {
1039         List<GeneratedProperty> propertiesOfAllParents = new ArrayList<GeneratedProperty>();
1040         if (genTO != null) {
1041             final List<GeneratedProperty> allPropertiesOfTO = genTO.getProperties();
1042             List<GeneratedProperty> readOnlyPropertiesOfTO = resolveReadOnlyPropertiesFromTO(allPropertiesOfTO);
1043             propertiesOfAllParents.addAll(readOnlyPropertiesOfTO);
1044             if (genTO.getExtends() != null) {
1045                 propertiesOfAllParents.addAll(getPropertiesOfAllParents(genTO.getExtends()));
1046             }
1047         }
1048         return propertiesOfAllParents;
1049     }
1050
1051     public static String createStaticInicializationBlock(GeneratedTransferObject genTransferObject, String indent) {
1052
1053         final StringBuilder builder = new StringBuilder();
1054
1055         List<Constant> constants = genTransferObject.getConstantDefinitions();
1056         for (Constant constant : constants) {
1057             if (constant.getName() == null || constant.getType() == null || constant.getValue() == null) {
1058                 continue;
1059             }
1060             if (constant.getName().equals(TypeConstants.PATTERN_CONSTANT_NAME)) {
1061                 final Object constValue = constant.getValue();
1062                 List<String> regularExpressions = new ArrayList<>();
1063                 if (constValue instanceof List) {
1064                     builder.append(indent + PUBLIC + GAP + STATIC + GAP + FINAL + GAP + "List<String>" + GAP
1065                             + TypeConstants.PATTERN_CONSTANT_NAME + GAP + "=" + GAP + "Arrays.asList" + LB);
1066                     final List<?> constantValues = (List<?>) constValue;
1067                     int stringsCount = 0;
1068                     for (Object value : constantValues) {
1069                         if (value instanceof String) {
1070                             if (stringsCount > 0) {
1071                                 builder.append(COMMA);
1072                             }
1073                             stringsCount++;
1074                             regularExpressions.add((String) value);
1075                             builder.append(DOUBLE_QUOTE + (String) value + DOUBLE_QUOTE);
1076                         }
1077                     }
1078                     builder.append(RB + SC + NL);
1079                 }
1080                 builder.append(indent + PRIVATE + GAP + STATIC + GAP + FINAL + GAP + "List<Pattern>" + GAP
1081                         + MEMBER_PATTERN_LIST + GAP + ASSIGN + GAP + "new ArrayList<Pattern>()" + GAP + SC + NL + NL);
1082
1083                 if (!regularExpressions.isEmpty()) {
1084                     builder.append(indent + STATIC + LCB + NL);
1085                     builder.append(indent + TAB + "for (String regEx : " + TypeConstants.PATTERN_CONSTANT_NAME + ") {"
1086                             + NL);
1087                     builder.append(indent + TAB + TAB + MEMBER_PATTERN_LIST + ".add(Pattern.compile(regEx))" + SC + NL);
1088                     builder.append(indent + TAB + RCB + NL);
1089                     builder.append(indent + RCB + NL + NL);
1090                 }
1091
1092             }
1093         }
1094         return builder.toString();
1095     }
1096 }