Fixed resolution problems in Code Generator
[yangtools.git] / code-generator / binding-generator-util / src / main / java / org / opendaylight / yangtools / binding / generator / util / BindingGeneratorUtil.java
1 package org.opendaylight.yangtools.binding.generator.util;\r
2 \r
3 import java.text.DateFormat;\r
4 import java.text.SimpleDateFormat;\r
5 import java.util.Arrays;\r
6 import java.util.Calendar;\r
7 import java.util.HashSet;\r
8 import java.util.List;\r
9 import java.util.Set;\r
10 \r
11 import org.opendaylight.yangtools.binding.generator.util.generated.type.builder.GeneratedTOBuilderImpl;\r
12 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTOBuilder;\r
13 import org.opendaylight.yangtools.yang.common.QName;\r
14 import org.opendaylight.yangtools.yang.model.api.Module;\r
15 import org.opendaylight.yangtools.yang.model.api.SchemaPath;\r
16 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;\r
17 \r
18 /**\r
19  * Contains the methods for converting strings to valid JAVA language strings\r
20  * (package names, class names, attribute names).\r
21  * \r
22  * \r
23  */\r
24 public final class BindingGeneratorUtil {\r
25 \r
26     private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyMMdd");\r
27     \r
28     /**\r
29      * Array of strings values which represents JAVA reserved words.\r
30      */\r
31     private static final String[] SET_VALUES = new String[] { "abstract", "assert", "boolean", "break", "byte", "case",\r
32             "catch", "char", "class", "const", "continue", "default", "double", "do", "else", "enum", "extends",\r
33             "false", "final", "finally", "float", "for", "goto", "if", "implements", "import", "instanceof", "int",\r
34             "interface", "long", "native", "new", "null", "package", "private", "protected", "public", "return",\r
35             "short", "static", "strictfp", "super", "switch", "synchronized", "this", "throw", "throws", "transient",\r
36             "true", "try", "void", "volatile", "while" };\r
37 \r
38     /**\r
39      * Impossible to instantiate this class. All of the methods or attributes\r
40      * are static.\r
41      */\r
42     private BindingGeneratorUtil() {\r
43     }\r
44 \r
45     /**\r
46      * Hash set of words which are reserved in JAVA language.\r
47      */\r
48     private static final Set<String> JAVA_RESERVED_WORDS = new HashSet<String>(Arrays.asList(SET_VALUES));\r
49 \r
50     /**\r
51      * Converts string <code>packageName</code> to valid JAVA package name.\r
52      * \r
53      * If some words of package name are digits of JAVA reserved words they are\r
54      * prefixed with underscore character.\r
55      * \r
56      * @param packageName\r
57      *            string which contains words separated by point.\r
58      * @return package name which contains words separated by point.\r
59      */\r
60     private static String validateJavaPackage(final String packageName) {\r
61         if (packageName != null) {\r
62             final String[] packNameParts = packageName.split("\\.");\r
63             if (packNameParts != null) {\r
64                 final StringBuilder builder = new StringBuilder();\r
65                 for (int i = 0; i < packNameParts.length; ++i) {\r
66                     final String packNamePart = packNameParts[i];\r
67                     if (Character.isDigit(packNamePart.charAt(0))) {\r
68                         packNameParts[i] = "_" + packNamePart;\r
69                     } else if (JAVA_RESERVED_WORDS.contains(packNamePart)) {\r
70                         packNameParts[i] = "_" + packNamePart;\r
71                     }\r
72                     if (i > 0) {\r
73                         builder.append(".");\r
74                     }\r
75                     builder.append(packNameParts[i]);\r
76                 }\r
77                 return builder.toString();\r
78             }\r
79         }\r
80         return packageName;\r
81     }\r
82 \r
83     /**\r
84      * Converts <code>parameterName</code> to valid JAVA parameter name.\r
85      * \r
86      * If the <code>parameterName</code> is one of the JAVA reserved words then\r
87      * it is prefixed with underscore character.\r
88      * \r
89      * @param parameterName\r
90      *            string with the parameter name\r
91      * @return string with the admissible parameter name\r
92      */\r
93     public static String validateParameterName(final String parameterName) {\r
94         if (parameterName != null) {\r
95             if (JAVA_RESERVED_WORDS.contains(parameterName)) {\r
96                 return "_" + parameterName;\r
97             }\r
98         }\r
99         return parameterName;\r
100     }\r
101 \r
102     /**\r
103      * Creates generated TO builder from <code>packageName</code> and\r
104      * <code>transObjectName</code>.\r
105      * \r
106      * @param packageName\r
107      *            string with name of package to which the returned object\r
108      *            belongs\r
109      * @param transObjectName\r
110      *            string with name which the returned object has\r
111      * @return generated TO builder or <code>null</code> value if\r
112      *         <code>packageName</code> or <code>transObjectName</code> equal\r
113      *         <code>null</code>\r
114      */\r
115     public static GeneratedTOBuilder schemaNodeToTransferObjectBuilder(final String packageName,\r
116             final String transObjectName) {\r
117         if (packageName != null && transObjectName != null) {\r
118 \r
119             final String genTOName = BindingGeneratorUtil.parseToClassName(transObjectName);\r
120             final GeneratedTOBuilder newType = new GeneratedTOBuilderImpl(packageName, genTOName);\r
121 \r
122             return newType;\r
123 \r
124         }\r
125         return null;\r
126     }\r
127 \r
128     /**\r
129      * Converts module name to valid JAVA package name.\r
130      * \r
131      * The package name consists of:\r
132      * <ul>\r
133      * <li>prefix - <i>org.opendaylight.yang.gen.v</i></li>\r
134      * <li>module YANG version - <i>org.opendaylight.yang.gen.v</i></li>\r
135      * <li>module namespace - invalid characters are replaced with dots</li>\r
136      * <li>revision prefix - <i>.rev</i></li>\r
137      * <li>revision - YYYYMMDD (MM and DD aren't spread to the whole length)</li>\r
138      * </ul>\r
139      * \r
140      * @param module\r
141      *            module which contains data about namespace and revision date\r
142      * @return string with the valid JAVA package name\r
143      * @throws IllegalArgumentException\r
144      *             if the revision date of the <code>module</code> equals\r
145      *             <code>null</code>\r
146      */\r
147     public static String moduleNamespaceToPackageName(final Module module) {\r
148         final StringBuilder packageNameBuilder = new StringBuilder();\r
149 \r
150         if (module.getRevision() == null) {\r
151             throw new IllegalArgumentException("Module " + module.getName() + " does not specify revision date!");\r
152         }\r
153         packageNameBuilder.append("org.opendaylight.yang.gen.v");\r
154         packageNameBuilder.append(module.getYangVersion());\r
155         packageNameBuilder.append(".");\r
156 \r
157         String namespace = module.getNamespace().toString();\r
158         namespace = namespace.replace("://", ".");\r
159         namespace = namespace.replace("/", ".");\r
160         namespace = namespace.replace(":", ".");\r
161         namespace = namespace.replace("-", ".");\r
162         namespace = namespace.replace("@", ".");\r
163         namespace = namespace.replace("$", ".");\r
164         namespace = namespace.replace("#", ".");\r
165         namespace = namespace.replace("'", ".");\r
166         namespace = namespace.replace("*", ".");\r
167         namespace = namespace.replace("+", ".");\r
168         namespace = namespace.replace(",", ".");\r
169         namespace = namespace.replace(";", ".");\r
170         namespace = namespace.replace("=", ".");\r
171 \r
172         packageNameBuilder.append(namespace);\r
173         packageNameBuilder.append(".rev");\r
174         packageNameBuilder.append(DATE_FORMAT.format(module.getRevision()));\r
175         \r
176         return validateJavaPackage(packageNameBuilder.toString());\r
177     }\r
178 \r
179     /**\r
180      * Creates package name from specified <code>basePackageName</code> (package\r
181      * name for module) and <code>schemaPath</code>.\r
182      * \r
183      * Resulting package name is concatenation of <code>basePackageName</code>\r
184      * and all local names of YANG nodes which are parents of some node for\r
185      * which <code>schemaPath</code> is specified.\r
186      * \r
187      * @param basePackageName\r
188      *            string with package name of the module\r
189      * @param schemaPath\r
190      *            list of names of YANG nodes which are parents of some node +\r
191      *            name of this node\r
192      * @return string with valid JAVA package name\r
193      */\r
194     public static String packageNameForGeneratedType(final String basePackageName, final SchemaPath schemaPath) {\r
195         if (basePackageName == null) {\r
196             throw new IllegalArgumentException("Base Package Name cannot be NULL!");\r
197         }\r
198         if (schemaPath == null) {\r
199             throw new IllegalArgumentException("Schema Path cannot be NULL!");\r
200         }\r
201 \r
202         final StringBuilder builder = new StringBuilder();\r
203         builder.append(basePackageName);\r
204         final List<QName> pathToNode = schemaPath.getPath();\r
205         final int traversalSteps = (pathToNode.size() - 1);\r
206         for (int i = 0; i < traversalSteps; ++i) {\r
207             builder.append(".");\r
208             String nodeLocalName = pathToNode.get(i).getLocalName();\r
209 \r
210             nodeLocalName = nodeLocalName.replace(":", ".");\r
211             nodeLocalName = nodeLocalName.replace("-", ".");\r
212             builder.append(nodeLocalName);\r
213         }\r
214         return validateJavaPackage(builder.toString());\r
215     }\r
216 \r
217     /**\r
218      * Generates the package name for type definition from\r
219      * <code>typeDefinition</code> and <code>basePackageName</code>.\r
220      * \r
221      * @param basePackageName\r
222      *            string with the package name of the module\r
223      * @param typeDefinition\r
224      *            type definition for which the package name will be generated *\r
225      * @return string with valid JAVA package name\r
226      * @throws IllegalArgumentException\r
227      *             <ul>\r
228      *             <li>if <code>basePackageName</code> equals <code>null</code></li>\r
229      *             <li>if <code>typeDefinition</code> equals <code>null</code></li>\r
230      *             </ul>\r
231      */\r
232     public static String packageNameForTypeDefinition(final String basePackageName,\r
233             final TypeDefinition<?> typeDefinition) {\r
234         if (basePackageName == null) {\r
235             throw new IllegalArgumentException("Base Package Name cannot be NULL!");\r
236         }\r
237         if (typeDefinition == null) {\r
238             throw new IllegalArgumentException("Type Definition reference cannot be NULL!");\r
239         }\r
240 \r
241         final StringBuilder builder = new StringBuilder();\r
242         builder.append(basePackageName);\r
243         return validateJavaPackage(builder.toString());\r
244     }\r
245 \r
246     /**\r
247      * Converts <code>token</code> to string which is in accordance with best\r
248      * practices for JAVA class names.\r
249      * \r
250      * @param token\r
251      *            string which contains characters which should be converted to\r
252      *            JAVA class name\r
253      * @return string which is in accordance with best practices for JAVA class\r
254      *         name.\r
255      */\r
256     public static String parseToClassName(String token) {\r
257         token = token.replace(".", "");\r
258         String correctStr = parseToCamelCase(token);\r
259 \r
260         // make first char upper-case\r
261         char first = Character.toUpperCase(correctStr.charAt(0));\r
262         if(first >= '0' && first <= '9') {\r
263             \r
264             correctStr = "_" + correctStr;\r
265         } else {\r
266             correctStr = first + correctStr.substring(1);\r
267         }\r
268         return correctStr;\r
269     }\r
270 \r
271     /**\r
272      * Converts <code>token</code> to string which is in accordance with best\r
273      * practices for JAVA parameter names.\r
274      * \r
275      * @param token\r
276      *            string which contains characters which should be converted to\r
277      *            JAVA parameter name\r
278      * @return string which is in accordance with best practices for JAVA\r
279      *         parameter name.\r
280      */\r
281     public static String parseToValidParamName(final String token) {\r
282         final String validToken = token.replace(".", "");\r
283         String correctStr = parseToCamelCase(validToken);\r
284 \r
285         // make first char lower-case\r
286         char first = Character.toLowerCase(correctStr.charAt(0));\r
287         correctStr = first + correctStr.substring(1);\r
288         return validateParameterName(correctStr);\r
289     }\r
290 \r
291     /**\r
292      * Converts <code>token</code> to capital letters and removes invalid\r
293      * characters.\r
294      * \r
295      * @param token\r
296      *            string with characters which should be conversed to capital\r
297      * @return string with capital letters\r
298      */\r
299     public static String convertToCapitalLetters(final String token) {\r
300         String convertedStr = token.replace(" ", "_");\r
301         convertedStr = convertedStr.replace(".", "_");\r
302         convertedStr = convertedStr.toUpperCase();\r
303         return convertedStr;\r
304     }\r
305 \r
306     /**\r
307      * \r
308      * Converts string <code>token</code> to the cammel case format.\r
309      * \r
310      * @param token\r
311      *            string which should be converted to the cammel case format\r
312      * @return string in the cammel case format\r
313      * @throws NullPointerException\r
314      *             - if <code>token</code> equals null\r
315      * @throws IllegalArgumentException\r
316      *             - if <code>token</code> without white spaces is empty\r
317      */\r
318     private static String parseToCamelCase(String token) {\r
319         if (token == null) {\r
320             throw new NullPointerException("Name can not be null");\r
321         }\r
322 \r
323         String correctStr = token.trim();\r
324         if (correctStr.isEmpty()) {\r
325             throw new IllegalArgumentException("Name can not be emty");\r
326         }\r
327 \r
328         correctStr = replaceWithCamelCase(correctStr, ' ');\r
329         correctStr = replaceWithCamelCase(correctStr, '-');\r
330         correctStr = replaceWithCamelCase(correctStr, '_');\r
331         return correctStr;\r
332     }\r
333 \r
334     /**\r
335      * Replaces all the occurances of the <code>removalChar</code> in the\r
336      * <code>text</code> with empty string and converts following character to\r
337      * upper case.\r
338      * \r
339      * @param text\r
340      *            string with source text which should be converted\r
341      * @param removalChar\r
342      *            character which is sought in the <code>text</code>\r
343      * @return string which doesn't contain <code>removalChar</code> and has\r
344      *         following characters converted to upper case\r
345      * @throws IllegalArgumentException\r
346      *             if the length of the returning string has length 0\r
347      */\r
348     private static String replaceWithCamelCase(String text, char removalChar) {\r
349         StringBuilder sb = new StringBuilder(text);\r
350         String toBeRemoved = String.valueOf(removalChar);\r
351 \r
352         int toBeRemovedPos = sb.indexOf(toBeRemoved);\r
353         while (toBeRemovedPos != -1) {\r
354             sb.replace(toBeRemovedPos, toBeRemovedPos + 1, "");\r
355             // check if 'toBeRemoved' character is not the only character in\r
356             // 'text'\r
357             if (sb.length() == 0) {\r
358                 throw new IllegalArgumentException("The resulting string can not be empty");\r
359             }\r
360             String replacement = String.valueOf(sb.charAt(toBeRemovedPos)).toUpperCase();\r
361             sb.setCharAt(toBeRemovedPos, replacement.charAt(0));\r
362             toBeRemovedPos = sb.indexOf(toBeRemoved);\r
363         }\r
364         return sb.toString();\r
365     }\r
366 }\r