2 * Copyright (c) 2017 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.binding.javav2.generator.impl.util;
10 import com.google.common.annotations.Beta;
11 import com.google.common.base.CharMatcher;
12 import com.google.common.base.Preconditions;
13 import com.google.common.base.Splitter;
14 import com.google.common.base.Strings;
15 import com.google.common.collect.Iterables;
17 import java.util.StringTokenizer;
18 import org.opendaylight.mdsal.binding2.generator.util.Types;
19 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedType;
20 import org.opendaylight.mdsal.binding.javav2.model.api.ParameterizedType;
21 import org.opendaylight.mdsal.binding.javav2.model.api.Type;
22 import org.opendaylight.mdsal.binding.javav2.model.api.WildcardType;
23 import org.opendaylight.yangtools.yang.common.QName;
29 public final class YangTextTemplate {
30 private static final CharMatcher NEWLINE_OR_TAB = CharMatcher.anyOf("\n\t");
31 private static final String DOT = ".";
32 private static final String COMMA = ",";
33 private static final char NEW_LINE = '\n';
34 private static final CharMatcher NL_MATCHER = CharMatcher.is(NEW_LINE);
35 private static final CharMatcher AMP_MATCHER = CharMatcher.is('&');
36 private static final Splitter NL_SPLITTER = Splitter.on(NL_MATCHER);
38 private YangTextTemplate() {
39 throw new UnsupportedOperationException("Util class");
42 public static String formatSchemaPath(final String moduleName, final Iterable<QName> schemaPath) {
43 final StringBuilder sb = new StringBuilder();
44 sb.append(moduleName);
46 QName currentElement = Iterables.getFirst(schemaPath, null);
47 for (QName pathElement : schemaPath) {
49 if (!currentElement.getNamespace().equals(pathElement.getNamespace())) {
50 currentElement = pathElement;
51 sb.append(pathElement);
53 sb.append(pathElement.getLocalName());
60 * Used in #yangtemplateformodule.scala.txt for formating revision description
62 * @param text Content of tag description
63 * @param nextLineIndent Number of spaces from left side default is 12
64 * @return formatted description
66 public static String formatToParagraph(final String text, final int nextLineIndent) {
67 if (Strings.isNullOrEmpty(text)) {
70 boolean isFirstElementOnNewLineEmptyChar = false;
71 final StringBuilder sb = new StringBuilder();
72 final StringBuilder lineBuilder = new StringBuilder();
73 final String lineIndent = Strings.repeat(" ", nextLineIndent);
74 final String textToFormat = NEWLINE_OR_TAB.removeFrom(text);
75 final String formattedText = textToFormat.replaceAll(" +", " ");
76 final StringTokenizer tokenizer = new StringTokenizer(formattedText, " ", true);
78 while (tokenizer.hasMoreElements()) {
79 final String nextElement = tokenizer.nextElement().toString();
81 if (lineBuilder.length() + nextElement.length() > 80) {
82 // Trim trailing whitespace
83 for (int i = lineBuilder.length() - 1; i >= 0 && lineBuilder.charAt(i) != ' '; --i) {
84 lineBuilder.setLength(i);
86 // Trim leading whitespace
87 while (lineBuilder.charAt(0) == ' ') {
88 lineBuilder.deleteCharAt(0);
90 sb.append(lineBuilder).append('\n');
91 lineBuilder.setLength(0);
93 if (nextLineIndent > 0) {
94 sb.append(lineIndent);
97 if (" ".equals(nextElement)) {
98 isFirstElementOnNewLineEmptyChar = true;
101 if (isFirstElementOnNewLineEmptyChar) {
102 isFirstElementOnNewLineEmptyChar = false;
104 lineBuilder.append(nextElement);
107 return sb.append(lineBuilder).append('\n').toString();
111 * Used in all yangtemplates for formating augmentation target
113 * @param schemaPath path to augmented node
114 * @return path in string format
116 public static String formatToAugmentPath(final Iterable<QName> schemaPath) {
117 final StringBuilder sb = new StringBuilder();
118 for (QName pathElement : schemaPath) {
120 .append(pathElement.getNamespace())
122 .append(pathElement.getLocalName());
124 return sb.toString();
128 * Evaluates if it is necessary to add the package name for type to the map of imports for parentGenType
129 * If it is so the package name is saved to the map imports.
131 * @param parentGenType generated type for which is the map of necessary imports build
132 * @param type JAVA type for which is the necessary of the package import evaluated
133 * @param imports map of the imports for parentGenType
135 public static void putTypeIntoImports(final GeneratedType parentGenType, final Type type,
136 final Map<String, String> imports) {
137 Preconditions.checkArgument(parentGenType != null,
138 "Parent Generated Type parameter MUST be specified and cannot be NULL!");
139 Preconditions.checkArgument(type != null, "Type parameter MUST be specified and cannot be NULL!");
140 Preconditions.checkArgument(parentGenType.getPackageName() != null,
141 "Parent Generated Type cannot have Package Name referenced as NULL!");
143 final String typeName = Preconditions.checkNotNull(type.getName());
144 final String typePackageName = Preconditions.checkNotNull(type.getPackageName());
145 final String parentTypeName = Preconditions.checkNotNull(parentGenType.getName());
146 if (typeName.equals(parentTypeName) || typePackageName.startsWith("java.lang") || typePackageName.isEmpty()) {
149 if (!imports.containsKey(typeName)) {
150 imports.put(typeName, typePackageName);
152 if (type instanceof ParameterizedType) {
153 final ParameterizedType paramType = (ParameterizedType) type;
154 final Type[] params = paramType.getActualTypeArguments();
155 if (params != null) {
156 for (Type param : params) {
157 putTypeIntoImports(parentGenType, param, imports);
164 * Builds the string which contains either the full path to the type (package name with type) or only type name
165 * if the package is among imports.
167 * @param parentGenType generated type which contains type
168 * @param type JAVA type for which is the string with type info generated
169 * @param imports map of necessary imports for parentGenType
170 * @return string with type name for type in the full format or in the short format
172 public static String getExplicitType(final GeneratedType parentGenType, final Type type,
173 final Map<String, String> imports) {
174 Preconditions.checkArgument(type != null, "Type parameter MUST be specified and cannot be NULL!");
175 Preconditions.checkArgument(imports != null, "Imports Map cannot be NULL!");
177 final String typePackageName = Preconditions.checkNotNull(type.getPackageName());
178 final String typeName = Preconditions.checkNotNull(type.getName());
179 final String importedPackageName = imports.get(typeName);
180 final StringBuilder builder;
181 if (typePackageName.equals(importedPackageName)) {
182 builder = new StringBuilder(typeName);
183 addActualTypeParameters(builder, type, parentGenType, imports);
184 if ("Void".equals(builder.toString())) {
188 builder = new StringBuilder();
189 if (!typePackageName.isEmpty()) {
190 builder.append(typePackageName + DOT + typeName);
192 builder.append(type.getName());
194 if (type.equals(Types.voidType())) {
197 addActualTypeParameters(builder, type, parentGenType, imports);
199 return builder.toString();
203 * Adds actual type parameters from type to builder if type is ParametrizedType.
205 * @param builder string builder which contains type name
206 * @param type JAVA Type for which is the string with type info generated
207 * @param parentGenType generated type which contains type
208 * @param imports map of necessary imports for parentGenType
209 * @return adds actual type parameters to builder
211 private static StringBuilder addActualTypeParameters(final StringBuilder builder, final Type type,
212 final GeneratedType parentGenType, final Map<String, String> imports) {
213 if (type instanceof ParameterizedType) {
214 final ParameterizedType pType = (ParameterizedType) type;
215 final Type[] pTypes = pType.getActualTypeArguments();
217 builder.append(getParameters(parentGenType, pTypes, imports));
224 * Generates the string with all actual type parameters from
226 * @param parentGenType generated type for which is the JAVA code generated
227 * @param pTypes array of Type instances = actual type parameters
228 * @param availableImports map of imports for parentGenType
229 * @return string with all actual type parameters from pTypes
231 private static String getParameters(final GeneratedType parentGenType, final Type[] pTypes,
232 final Map<String, String> availableImports) {
233 if (pTypes == null || pTypes.length == 0) {
236 final StringBuilder builder = new StringBuilder();
237 for (int i = 0; i < pTypes.length; i++) {
238 final Type t = pTypes[i];
240 String separator = COMMA;
241 if (i == (pTypes.length - 1)) {
245 String wildcardParam = "";
246 if (t.equals(Types.voidType())) {
247 builder.append("java.lang.Void")
252 if (t instanceof WildcardType) {
253 wildcardParam = "? extends ";
256 builder.append(wildcardParam)
257 .append(getExplicitType(parentGenType, t, availableImports) + separator);
260 return builder.toString();
264 * Wraps text as documentation
266 * @param text text for wrapping
267 * @return wrapped text
269 public static String wrapToDocumentation(String text) {
270 if (text.isEmpty()) {
273 final StringBuilder sb = new StringBuilder("/**");
275 Iterable<String> lineSplitText = NL_SPLITTER.split(text);
276 for (final String t : lineSplitText) {
285 return sb.toString();
288 public static String encodeJavadocSymbols(String description) {
289 if (description == null || description.isEmpty()) {
292 String ret = description.replace("*/", "*/");
293 return AMP_MATCHER.replaceFrom(ret, "&");