3a0d74c8c4d3887f8a7ce62736d791d2cbe9bec8
[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.util.Arrays;\r
4 import java.util.Calendar;\r
5 import java.util.HashSet;\r
6 import java.util.List;\r
7 import java.util.Set;\r
8 \r
9 import org.opendaylight.yangtools.binding.generator.util.generated.type.builder.GeneratedTOBuilderImpl;\r
10 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTOBuilder;\r
11 import org.opendaylight.yangtools.yang.common.QName;\r
12 import org.opendaylight.yangtools.yang.model.api.Module;\r
13 import org.opendaylight.yangtools.yang.model.api.SchemaPath;\r
14 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;\r
15 \r
16 /**\r
17  * Contains the methods for converting strings to valid JAVA language strings\r
18  * (package names, class names, attribute names).\r
19  * \r
20  * \r
21  */\r
22 public final class BindingGeneratorUtil {\r
23 \r
24     /**\r
25      * Array of strings values which represents JAVA reserved words.\r
26      */\r
27     private static final String[] SET_VALUES = new String[] { "abstract", "assert", "boolean", "break", "byte", "case",\r
28             "catch", "char", "class", "const", "continue", "default", "double", "do", "else", "enum", "extends",\r
29             "false", "final", "finally", "float", "for", "goto", "if", "implements", "import", "instanceof", "int",\r
30             "interface", "long", "native", "new", "null", "package", "private", "protected", "public", "return",\r
31             "short", "static", "strictfp", "super", "switch", "synchronized", "this", "throw", "throws", "transient",\r
32             "true", "try", "void", "volatile", "while" };\r
33 \r
34     /**\r
35      * Impossible to instantiate this class. All of the methods or attributes\r
36      * are static.\r
37      */\r
38     private BindingGeneratorUtil() {\r
39     }\r
40 \r
41     /**\r
42      * Hash set of words which are reserved in JAVA language.\r
43      */\r
44     private static final Set<String> JAVA_RESERVED_WORDS = new HashSet<String>(Arrays.asList(SET_VALUES));\r
45 \r
46     /**\r
47      * Converts string <code>packageName</code> to valid JAVA package name.\r
48      * \r
49      * If some words of package name are digits of JAVA reserved words they are\r
50      * prefixed with underscore character.\r
51      * \r
52      * @param packageName\r
53      *            string which contains words separated by point.\r
54      * @return package name which contains words separated by point.\r
55      */\r
56     private static String validateJavaPackage(final String packageName) {\r
57         if (packageName != null) {\r
58             final String[] packNameParts = packageName.split("\\.");\r
59             if (packNameParts != null) {\r
60                 final StringBuilder builder = new StringBuilder();\r
61                 for (int i = 0; i < packNameParts.length; ++i) {\r
62                     final String packNamePart = packNameParts[i];\r
63                     if (Character.isDigit(packNamePart.charAt(0))) {\r
64                         packNameParts[i] = "_" + packNamePart;\r
65                     } else if (JAVA_RESERVED_WORDS.contains(packNamePart)) {\r
66                         packNameParts[i] = "_" + packNamePart;\r
67                     }\r
68                     if (i > 0) {\r
69                         builder.append(".");\r
70                     }\r
71                     builder.append(packNameParts[i]);\r
72                 }\r
73                 return builder.toString();\r
74             }\r
75         }\r
76         return packageName;\r
77     }\r
78 \r
79     /**\r
80      * Converts <code>parameterName</code> to valid JAVA parameter name.\r
81      * \r
82      * If the <code>parameterName</code> is one of the JAVA reserved words then\r
83      * it is prefixed with underscore character.\r
84      * \r
85      * @param parameterName\r
86      *            string with the parameter name\r
87      * @return string with the admissible parameter name\r
88      */\r
89     public static String validateParameterName(final String parameterName) {\r
90         if (parameterName != null) {\r
91             if (JAVA_RESERVED_WORDS.contains(parameterName)) {\r
92                 return "_" + parameterName;\r
93             }\r
94         }\r
95         return parameterName;\r
96     }\r
97 \r
98     /**\r
99      * Creates generated TO builder from <code>packageName</code> and\r
100      * <code>transObjectName</code>.\r
101      * \r
102      * @param packageName\r
103      *            string with name of package to which the returned object\r
104      *            belongs\r
105      * @param transObjectName\r
106      *            string with name which the returned object has\r
107      * @return generated TO builder or <code>null</code> value if\r
108      *         <code>packageName</code> or <code>transObjectName</code> equal\r
109      *         <code>null</code>\r
110      */\r
111     public static GeneratedTOBuilder schemaNodeToTransferObjectBuilder(final String packageName,\r
112             final String transObjectName) {\r
113         if (packageName != null && transObjectName != null) {\r
114 \r
115             final String genTOName = BindingGeneratorUtil.parseToClassName(transObjectName);\r
116             final GeneratedTOBuilder newType = new GeneratedTOBuilderImpl(packageName, genTOName);\r
117 \r
118             return newType;\r
119 \r
120         }\r
121         return null;\r
122     }\r
123 \r
124     /**\r
125      * Converts module name to valid JAVA package name.\r
126      * \r
127      * The package name consists of:\r
128      * <ul>\r
129      * <li>prefix - <i>org.opendaylight.yang.gen.v</i></li>\r
130      * <li>module YANG version - <i>org.opendaylight.yang.gen.v</i></li>\r
131      * <li>module namespace - invalid characters are replaced with dots</li>\r
132      * <li>revision prefix - <i>.rev</i></li>\r
133      * <li>revision - YYYYMMDD (MM and DD aren't spread to the whole length)</li>\r
134      * </ul>\r
135      * \r
136      * @param module\r
137      *            module which contains data about namespace and revision date\r
138      * @return string with the valid JAVA package name\r
139      * @throws IllegalArgumentException\r
140      *             if the revision date of the <code>module</code> equals\r
141      *             <code>null</code>\r
142      */\r
143     public static String moduleNamespaceToPackageName(final Module module) {\r
144         final StringBuilder packageNameBuilder = new StringBuilder();\r
145 \r
146         final Calendar calendar = Calendar.getInstance();\r
147         if (module.getRevision() == null) {\r
148             throw new IllegalArgumentException("Module " + module.getName() + " does not specify revision date!");\r
149         }\r
150         packageNameBuilder.append("org.opendaylight.yang.gen.v");\r
151         packageNameBuilder.append(module.getYangVersion());\r
152         packageNameBuilder.append(".");\r
153 \r
154         String namespace = module.getNamespace().toString();\r
155         namespace = namespace.replace("://", ".");\r
156         namespace = namespace.replace("/", ".");\r
157         namespace = namespace.replace(":", ".");\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 \r
169         packageNameBuilder.append(namespace);\r
170         calendar.setTime(module.getRevision());\r
171         packageNameBuilder.append(".rev");\r
172         packageNameBuilder.append(calendar.get(Calendar.YEAR));\r
173         packageNameBuilder.append((calendar.get(Calendar.MONTH) + 1));\r
174         packageNameBuilder.append(calendar.get(Calendar.DAY_OF_MONTH));\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