2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.mdsal.binding2.generator.impl.util;
10 import static com.google.common.base.Preconditions.checkArgument;
12 import com.google.common.annotations.Beta;
13 import com.google.common.base.CharMatcher;
14 import com.google.common.base.Preconditions;
15 import com.google.common.base.Splitter;
16 import com.google.common.base.Strings;
17 import com.google.common.collect.Iterables;
19 import java.util.StringTokenizer;
20 import java.util.regex.Pattern;
21 import org.opendaylight.mdsal.binding2.generator.util.Types;
22 import org.opendaylight.mdsal.binding2.model.api.GeneratedType;
23 import org.opendaylight.mdsal.binding2.model.api.ParameterizedType;
24 import org.opendaylight.mdsal.binding2.model.api.Type;
25 import org.opendaylight.mdsal.binding2.model.api.WildcardType;
26 import org.opendaylight.yangtools.yang.common.QName;
32 public final class YangTextTemplate {
33 private static final CharMatcher NEWLINE_OR_TAB = CharMatcher.anyOf("\n\t");
34 private static final String DOT = ".";
35 private static final String COMMA = ",";
36 private static final char NEW_LINE = '\n';
37 private static final CharMatcher NL_MATCHER = CharMatcher.is(NEW_LINE);
38 private static final CharMatcher AMP_MATCHER = CharMatcher.is('&');
39 private static final Splitter NL_SPLITTER = Splitter.on(NL_MATCHER);
40 private static final CharMatcher TAB_MATCHER = CharMatcher.is('\t');
41 private static final Pattern SPACES_PATTERN = Pattern.compile(" +");
43 private YangTextTemplate() {
44 throw new UnsupportedOperationException("Util class");
47 public static String formatSchemaPath(final String moduleName, final Iterable<QName> schemaPath) {
48 final StringBuilder sb = new StringBuilder();
49 sb.append(moduleName);
51 QName currentElement = Iterables.getFirst(schemaPath, null);
52 for (QName pathElement : schemaPath) {
54 if (!currentElement.getNamespace().equals(pathElement.getNamespace())) {
55 currentElement = pathElement;
56 sb.append(pathElement);
58 sb.append(pathElement.getLocalName());
65 * Used in #yangtemplateformodule.scala.txt for formating revision description
67 * @param text Content of tag description
68 * @param nextLineIndent Number of spaces from left side default is 12
69 * @return formatted description
71 public static String formatToParagraph(final String text, final int nextLineIndent) {
72 if (Strings.isNullOrEmpty(text)) {
75 boolean isFirstElementOnNewLineEmptyChar = false;
76 final StringBuilder sb = new StringBuilder();
77 final StringBuilder lineBuilder = new StringBuilder();
78 final String lineIndent = Strings.repeat(" ", nextLineIndent);
79 final String textToFormat = NEWLINE_OR_TAB.removeFrom(text);
80 final String formattedText = textToFormat.replaceAll(" +", " ");
81 final StringTokenizer tokenizer = new StringTokenizer(formattedText, " ", true);
83 while (tokenizer.hasMoreElements()) {
84 final String nextElement = tokenizer.nextElement().toString();
86 if (lineBuilder.length() + nextElement.length() > 80) {
87 // Trim trailing whitespace
88 for (int i = lineBuilder.length() - 1; i >= 0 && lineBuilder.charAt(i) != ' '; --i) {
89 lineBuilder.setLength(i);
91 // Trim leading whitespace
92 while (lineBuilder.charAt(0) == ' ') {
93 lineBuilder.deleteCharAt(0);
95 sb.append(lineBuilder).append('\n');
96 lineBuilder.setLength(0);
98 if (nextLineIndent > 0) {
99 sb.append(lineIndent);
102 if (" ".equals(nextElement)) {
103 isFirstElementOnNewLineEmptyChar = true;
106 if (isFirstElementOnNewLineEmptyChar) {
107 isFirstElementOnNewLineEmptyChar = false;
109 lineBuilder.append(nextElement);
112 return sb.append(lineBuilder).append('\n').toString();
116 * Used in all yangtemplates for formating augmentation target
118 * @param schemaPath path to augmented node
119 * @return path in string format
121 public static String formatToAugmentPath(final Iterable<QName> schemaPath) {
122 final StringBuilder sb = new StringBuilder();
123 for (QName pathElement : schemaPath) {
125 .append(pathElement.getNamespace())
127 .append(pathElement.getLocalName());
129 return sb.toString();
133 * Evaluates if it is necessary to add the package name for type to the map of imports for parentGenType
134 * If it is so the package name is saved to the map imports.
136 * @param parentGenType generated type for which is the map of necessary imports build
137 * @param type JAVA type for which is the necessary of the package import evaluated
138 * @param imports map of the imports for parentGenType
140 public static void putTypeIntoImports(final GeneratedType parentGenType, final Type type,
141 final Map<String, String> imports) {
142 checkArgument(parentGenType != null, "Parent Generated Type parameter MUST be specified and cannot be NULL!");
143 checkArgument(type != null, "Type parameter MUST be specified and cannot be NULL!");
144 checkArgument(parentGenType.getPackageName() != null,
145 "Parent Generated Type cannot have Package Name referenced as NULL!");
147 final String typeName = Preconditions.checkNotNull(type.getName());
148 final String typePackageName = Preconditions.checkNotNull(type.getPackageName());
149 final String parentTypeName = Preconditions.checkNotNull(parentGenType.getName());
150 if (typeName.equals(parentTypeName) || typePackageName.startsWith("java.lang") || typePackageName.isEmpty()) {
153 if (!imports.containsKey(typeName)) {
154 imports.put(typeName, typePackageName);
156 if (type instanceof ParameterizedType) {
157 final ParameterizedType paramType = (ParameterizedType) type;
158 final Type[] params = paramType.getActualTypeArguments();
159 if (params != null) {
160 for (Type param : params) {
161 putTypeIntoImports(parentGenType, param, imports);
168 * Builds the string which contains either the full path to the type (package name with type) or only type name
169 * if the package is among imports.
171 * @param parentGenType generated type which contains type
172 * @param type JAVA type for which is the string with type info generated
173 * @param imports map of necessary imports for parentGenType
174 * @return string with type name for type in the full format or in the short format
176 public static String getExplicitType(final GeneratedType parentGenType, final Type type,
177 final Map<String, String> imports) {
178 checkArgument(type != null, "Type parameter MUST be specified and cannot be NULL!");
179 checkArgument(imports != null, "Imports Map cannot be NULL!");
181 final String typePackageName = Preconditions.checkNotNull(type.getPackageName());
182 final String typeName = Preconditions.checkNotNull(type.getName());
183 final String importedPackageName = imports.get(typeName);
184 final StringBuilder builder;
185 if (typePackageName.equals(importedPackageName)) {
186 builder = new StringBuilder(typeName);
187 addActualTypeParameters(builder, type, parentGenType, imports);
188 if (builder.toString().equals("Void")) {
192 builder = new StringBuilder();
193 if (!typePackageName.isEmpty()) {
194 builder.append(typePackageName + DOT + typeName);
196 builder.append(type.getName());
198 if (type.equals(Types.voidType())) {
201 addActualTypeParameters(builder, type, parentGenType, imports);
203 return builder.toString();
207 * Adds actual type parameters from type to builder if type is ParametrizedType.
209 * @param builder string builder which contains type name
210 * @param type JAVA Type for which is the string with type info generated
211 * @param parentGenType generated type which contains type
212 * @param imports map of necessary imports for parentGenType
213 * @return adds actual type parameters to builder
215 private static StringBuilder addActualTypeParameters(final StringBuilder builder, final Type type,
216 final GeneratedType parentGenType, final Map<String, String> imports) {
217 if (type instanceof ParameterizedType) {
218 final ParameterizedType pType = (ParameterizedType) type;
219 final Type[] pTypes = pType.getActualTypeArguments();
221 builder.append(getParameters(parentGenType, pTypes, imports));
228 * Generates the string with all actual type parameters from
230 * @param parentGenType generated type for which is the JAVA code generated
231 * @param pTypes array of Type instances = actual type parameters
232 * @param availableImports map of imports for parentGenType
233 * @return string with all actual type parameters from pTypes
235 private static String getParameters(final GeneratedType parentGenType, final Type[] pTypes,
236 final Map<String, String> availableImports) {
237 if (pTypes == null || pTypes.length == 0) {
240 final StringBuilder builder = new StringBuilder();
241 for (int i = 0; i < pTypes.length; i++) {
242 final Type t = pTypes[i];
244 String separator = COMMA;
245 if (i == (pTypes.length - 1)) {
249 String wildcardParam = "";
250 if (t.equals(Types.voidType())) {
251 builder.append("java.lang.Void")
256 if (t instanceof WildcardType) {
257 wildcardParam = "? extends ";
260 builder.append(wildcardParam)
261 .append(getExplicitType(parentGenType, t, availableImports) + separator);
264 return builder.toString();
268 * Wraps text as documentation
270 * @param text text for wrapping
271 * @return wrapped text
273 public static String wrapToDocumentation(String text) {
274 if (text.isEmpty()) {
277 final StringBuilder sb = new StringBuilder("/**");
279 Iterable<String> lineSplitText = NL_SPLITTER.split(text);
280 for (final String t : lineSplitText) {
289 return sb.toString();
292 public static String encodeJavadocSymbols(String description) {
293 if (description == null || description.isEmpty()) {
296 String ret = description.replace("*/", "*/");
297 return AMP_MATCHER.replaceFrom(ret, "&");