package org.opendaylight.mdsal.binding.model.util;
import com.google.common.base.CharMatcher;
+import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.google.common.collect.Iterables;
import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilderBase;
import org.opendaylight.mdsal.binding.model.api.type.builder.MethodSignatureBuilder;
import org.opendaylight.mdsal.binding.model.api.type.builder.TypeMemberBuilder;
-import org.opendaylight.yangtools.yang.binding.BindingMapping;
+import org.opendaylight.mdsal.binding.spec.naming.BindingMapping;
import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.QNameModule;
-import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.SchemaPath;
import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
public final class BindingGeneratorUtil {
/**
- * Impossible to instantiate this class. All of the methods or attributes
- * are static.
+ * Impossible to instantiate this class. All of the methods or attributes are static.
*/
private BindingGeneratorUtil() {
+
}
/**
* Pre-compiled replacement pattern.
*/
- private static final CharMatcher DOT_MATCHER = CharMatcher.is('.');
private static final CharMatcher DASH_COLON_MATCHER = CharMatcher.anyOf("-:");
private static final CharMatcher GT_MATCHER = CharMatcher.is('>');
private static final CharMatcher LT_MATCHER = CharMatcher.is('<');
};
private static final Comparator<TypeMemberBuilder<?>> SUID_MEMBER_COMPARATOR =
- (o1, o2) -> o1.getName().compareTo(o2.getName());
+ Comparator.comparing(TypeMemberBuilder::getName);
- private static final Comparator<Type> SUID_NAME_COMPARATOR =
- (o1, o2) -> o1.getFullyQualifiedName().compareTo(o2.getFullyQualifiedName());
+ private static final Comparator<Type> SUID_NAME_COMPARATOR = Comparator.comparing(Type::getFullyQualifiedName);
/**
- * Converts <code>parameterName</code> to valid JAVA parameter name.
- *
- * If the <code>parameterName</code> is one of the JAVA reserved words then
- * it is prefixed with underscore character.
+ * Converts <code>parameterName</code> to valid JAVA parameter name. If the <code>parameterName</code> is one
+ * of the JAVA reserved words then it is prefixed with underscore character.
*
- * @param parameterName
- * string with the parameter name
+ * @param parameterName string with the parameter name
* @return string with the admissible parameter name
*/
public static String resolveJavaReservedWordEquivalency(final String parameterName) {
}
/**
- * Converts module name to valid JAVA package name.
- *
- * The package name consists of:
- * <ul>
- * <li>prefix - <i>org.opendaylight.yang.gen.v</i></li>
- * <li>module YANG version - <i>org.opendaylight.yang.gen.v</i></li>
- * <li>module namespace - invalid characters are replaced with dots</li>
- * <li>revision prefix - <i>.rev</i></li>
- * <li>revision - YYYYMMDD (MM and DD aren't spread to the whole length)</li>
- * </ul>
- *
- * @param module
- * module which contains data about namespace and revision date
- * @return string with the valid JAVA package name
- * @throws IllegalArgumentException
- * if the revision date of the <code>module</code> equals
- * <code>null</code>
- * @deprecated USe {@link BindingMapping#getRootPackageName(QNameModule)} with {@link Module#getQNameModule()}.
- */
- @Deprecated
- public static String moduleNamespaceToPackageName(final Module module) {
- return BindingMapping.getRootPackageName(module.getQNameModule());
- }
-
- /**
- * Creates package name from specified <code>basePackageName</code> (package
- * name for module) and <code>schemaPath</code>.
+ * Creates package name from specified <code>basePackageName</code> (package name for module)
+ * and <code>schemaPath</code>. Resulting package name is concatenation of <code>basePackageName</code>
+ * and all local names of YANG nodes which are parents of some node for which <code>schemaPath</code> is specified.
*
- * Resulting package name is concatenation of <code>basePackageName</code>
- * and all local names of YANG nodes which are parents of some node for
- * which <code>schemaPath</code> is specified.
- *
- * @param basePackageName
- * string with package name of the module, MUST be normalized,
- * otherwise this method may return an invalid string.
- * @param schemaPath
- * list of names of YANG nodes which are parents of some node +
- * name of this node
+ * @param basePackageName string with package name of the module, MUST be normalized, otherwise this method may
+ * return an invalid string.
+ * @param schemaPath list of names of YANG nodes which are parents of some node + name of this node
* @return string with valid JAVA package name
* @throws NullPointerException if any of the arguments are null
*/
}
/**
- * Creates package name from specified <code>basePackageName</code> (package
- * name for module) and <code>schemaPath</code> which crosses an augmentation.
- *
- * Resulting package name is concatenation of <code>basePackageName</code>
- * and all local names of YANG nodes which are parents of some node for
- * which <code>schemaPath</code> is specified.
+ * Creates package name from specified <code>basePackageName</code> (package name for module)
+ * and <code>schemaPath</code> which crosses an augmentation. Resulting package name is concatenation
+ * of <code>basePackageName</code> and all local names of YANG nodes which are parents of some node for which
+ * <code>schemaPath</code> is specified.
*
- * @param basePackageName
- * string with package name of the module, MUST be normalized,
- * otherwise this method may return an invalid string.
- * @param schemaPath
- * list of names of YANG nodes which are parents of some node +
- * name of this node
+ * @param basePackageName string with package name of the module, MUST be normalized, otherwise this method may
+ * return an invalid string.
+ * @param schemaPath list of names of YANG nodes which are parents of some node + name of this node
* @return string with valid JAVA package name
* @throws NullPointerException if any of the arguments are null
*/
- public static String packageNameForAugmentedGeneratedType(final String basePackageName, final SchemaPath schemaPath) {
+ public static String packageNameForAugmentedGeneratedType(final String basePackageName,
+ final SchemaPath schemaPath) {
final int size = Iterables.size(schemaPath.getPathTowardsRoot());
if (size == 0) {
return basePackageName;
return BindingMapping.normalizePackageName(builder.toString());
}
- /**
- * Creates package name from specified <code>basePackageName</code> (package
- * name for module) and <code>schemaPath</code>.
- *
- * Resulting package name is concatenation of <code>basePackageName</code>
- * and all local names of YANG nodes which are parents of some node for
- * which <code>schemaPath</code> is specified.
- *
- * @param basePackageName
- * string with package name of the module
- * @param schemaPath
- * list of names of YANG nodes which are parents of some node +
- * name of this node
- * @param isUsesAugment
- * boolean true if using augment
- * @return string with valid JAVA package name
- *
- * @deprecated Use {@link #packageNameForGeneratedType(String, SchemaPath)} or
- * {@link #packageNameForAugmentedGeneratedType(String, SchemaPath)} instead.
- */
- @Deprecated
- public static String packageNameForGeneratedType(final String basePackageName, final SchemaPath schemaPath,
- final boolean isUsesAugment) {
- if (basePackageName == null) {
- throw new IllegalArgumentException("Base Package Name cannot be NULL!");
- }
- if (schemaPath == null) {
- throw new IllegalArgumentException("Schema Path cannot be NULL!");
- }
-
- final Iterable<QName> iterable = schemaPath.getPathFromRoot();
- final int size = Iterables.size(iterable);
- final int traversalSteps;
- if (isUsesAugment) {
- traversalSteps = size;
- } else {
- traversalSteps = size - 1;
- }
-
- if (traversalSteps == 0) {
- return BindingMapping.normalizePackageName(basePackageName);
- }
-
- return generateNormalizedPackageName(basePackageName, iterable, traversalSteps);
- }
-
- /**
- * Generates the package name for type definition from
- * <code>typeDefinition</code> and <code>basePackageName</code>.
- *
- * @param basePackageName
- * string with the package name of the module
- * @param typeDefinition
- * type definition for which the package name will be generated *
- * @return string with valid JAVA package name
- * @throws IllegalArgumentException
- * <ul>
- * <li>if <code>basePackageName</code> equals <code>null</code></li>
- * <li>if <code>typeDefinition</code> equals <code>null</code></li>
- * </ul>
- * @deprecated This method ignores typeDefinition argument and its result is only
- * <code>BindingMapping.normalizePackageName(basePackageName)</code>.
- * Aside from tests, there is not a single user in OpenDaylight codebase,
- * hence it can be considered buggy and defunct. It is scheduled for removal
- * in Boron release.
- */
- @Deprecated
- public static String packageNameForTypeDefinition(final String basePackageName,
- final TypeDefinition<?> typeDefinition) {
- if (basePackageName == null) {
- throw new IllegalArgumentException("Base Package Name cannot be NULL!");
- }
- if (typeDefinition == null) {
- throw new IllegalArgumentException("Type Definition reference cannot be NULL!");
- }
-
- return BindingMapping.normalizePackageName(basePackageName);
- }
-
- /**
- * Converts <code>token</code> to string which is in accordance with best
- * practices for JAVA class names.
- *
- * @param token
- * string which contains characters which should be converted to
- * JAVA class name
- * @return string which is in accordance with best practices for JAVA class
- * name.
- *
- * @deprecated Use {@link BindingMapping#getClassName(QName)} instead.
- */
- @Deprecated
- public static String parseToClassName(final String token) {
- return parseToCamelCase(token, true);
- }
-
- /**
- * Converts <code>token</code> to string which is in accordance with best
- * practices for JAVA parameter names.
- *
- * @param token
- * string which contains characters which should be converted to
- * JAVA parameter name
- * @return string which is in accordance with best practices for JAVA
- * parameter name.
- *
- * @deprecated Use {@link BindingMapping#getPropertyName(String)} instead.
- */
- @Deprecated public static String parseToValidParamName(final String token) {
- return resolveJavaReservedWordEquivalency(parseToCamelCase(token, false));
- }
-
- /**
- *
- * Converts string <code>token</code> to the cammel case format.
- *
- * @param token
- * string which should be converted to the cammel case format
- * @param uppercase
- * boolean value which says whether the first character of the
- * <code>token</code> should|shuldn't be uppercased
- * @return string in the cammel case format
- * @throws IllegalArgumentException
- * <ul>
- * <li>if <code>token</code> without white spaces is empty</li>
- * <li>if <code>token</code> equals null</li>
- * </ul>
- */
- private static String parseToCamelCase(final String token, final boolean uppercase) {
- if (token == null) {
- throw new IllegalArgumentException("Name can not be null");
- }
-
- String correctStr = DOT_MATCHER.removeFrom(token.trim());
- if (correctStr.isEmpty()) {
- throw new IllegalArgumentException("Name can not be empty");
- }
-
- correctStr = replaceWithCamelCase(correctStr, ' ');
- correctStr = replaceWithCamelCase(correctStr, '-');
- correctStr = replaceWithCamelCase(correctStr, '_');
-
- char firstChar = correctStr.charAt(0);
- firstChar = uppercase ? Character.toUpperCase(firstChar) : Character.toLowerCase(firstChar);
-
- if (firstChar >= '0' && firstChar <= '9') {
- return '_' + correctStr;
- } else {
- return firstChar + correctStr.substring(1);
- }
- }
-
- /**
- * Replaces all the occurrences of the <code>removalChar</code> in the
- * <code>text</code> with empty string and converts following character to
- * upper case.
- *
- * @param text
- * string with source text which should be converted
- * @param removalChar
- * character which is sought in the <code>text</code>
- * @return string which doesn't contain <code>removalChar</code> and has
- * following characters converted to upper case
- * @throws IllegalArgumentException
- * if the length of the returning string has length 0
- */
- private static String replaceWithCamelCase(final String text, final char removalChar) {
- int toBeRemovedPos = text.indexOf(removalChar);
- if (toBeRemovedPos == -1) {
- return text;
- }
-
- final StringBuilder sb = new StringBuilder(text);
- final String toBeRemoved = String.valueOf(removalChar);
- do {
- sb.replace(toBeRemovedPos, toBeRemovedPos + 1, "");
- // check if 'toBeRemoved' character is not the only character in
- // 'text'
- if (sb.length() == 0) {
- throw new IllegalArgumentException("The resulting string can not be empty");
- }
- final char replacement = Character.toUpperCase(sb.charAt(toBeRemovedPos));
- sb.setCharAt(toBeRemovedPos, replacement);
- toBeRemovedPos = sb.indexOf(toBeRemoved);
- } while (toBeRemovedPos != -1);
-
- return sb.toString();
- }
-
private static <T> Iterable<T> sortedCollection(final Comparator<? super T> comparator, final Collection<T> input) {
- if (input.size() > 1) {
- final List<T> ret = new ArrayList<>(input);
- Collections.sort(ret, comparator);
- return ret;
- } else {
+ if (input.size() <= 1) {
return input;
}
+
+ final List<T> ret = new ArrayList<>(input);
+ ret.sort(comparator);
+ return ret;
}
- private static final ThreadLocal<MessageDigest> SHA1_MD = new ThreadLocal<MessageDigest>() {
- @Override
- protected MessageDigest initialValue() {
- try {
- return MessageDigest.getInstance("SHA");
- } catch (final NoSuchAlgorithmException e) {
- throw new IllegalStateException("Failed to get a SHA digest provider", e);
- }
+ private static final ThreadLocal<MessageDigest> SHA1_MD = ThreadLocal.withInitial(() -> {
+ try {
+ return MessageDigest.getInstance("SHA");
+ } catch (final NoSuchAlgorithmException e) {
+ throw new IllegalStateException("Failed to get a SHA digest provider", e);
}
- };
+ });
public static long computeDefaultSUID(final GeneratedTypeBuilderBase<?> to) {
final ByteArrayOutputStream bout = new ByteArrayOutputStream();
- try (final DataOutputStream dout = new DataOutputStream(bout)) {
+ try (DataOutputStream dout = new DataOutputStream(bout)) {
dout.writeUTF(to.getName());
dout.writeInt(to.isAbstract() ? 3 : 7);
- for (final Type ifc : sortedCollection(SUID_NAME_COMPARATOR, to.getImplementsTypes())) {
+ for (final Type ifc : sortedCollection(SUID_NAME_COMPARATOR, filteredImplementsTypes(to))) {
dout.writeUTF(ifc.getFullyQualifiedName());
}
return hash;
}
+ private static Collection<Type> filteredImplementsTypes(final GeneratedTypeBuilderBase<?> to) {
+ return Collections2.filter(to.getImplementsTypes(), item -> !BindingTypes.TYPE_OBJECT.equals(item));
+ }
+
private static <T extends Optional<?>> T currentOrEmpty(final T current, final T base) {
return current.equals(base) ? (T)Optional.empty() : current;
}
public Optional<? extends RangeConstraint<?>> getRangeConstraint() {
return range;
}
+
@Override
public List<PatternConstraint> getPatternConstraints() {
return pattern;
}
+
@Override
public Optional<LengthConstraint> getLengthConstraint() {
return length;
}
+
@Override
public boolean isEmpty() {
return false;
}
/**
- * Encodes angle brackets in yang statement description
+ * Encodes angle brackets in yang statement description.
+ *
* @param description description of a yang statement which is used to generate javadoc comments
* @return string with encoded angle brackets
*/
return description;
}
- public static String replaceAllIllegalChars(final CharSequence stringBuilder){
+ @Deprecated
+ public static String replaceAllIllegalChars(final CharSequence stringBuilder) {
+ return defangUnicodeEscapes(stringBuilder);
+ }
+
+ /**
+ * Escape potential unicode references so that the resulting string is safe to put into a {@code .java} file. This
+ * processing is required to ensure this text we want to append does not end up with eligible backslashes. See
+ * <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.3">Java Language Specification</a>
+ * for more information.
+ *
+ * @param str Input string
+ * @return A string with all backslashes made ineligible
+ */
+ public static String replaceAllIllegalChars(final String str) {
+ final int backslash = str.indexOf('\\');
+ return backslash == -1 ? str : defangUnicodeEscapes(str);
+ }
+
+ private static String defangUnicodeEscapes(final CharSequence stringBuilder) {
+ // TODO: we should be able to receive the first offset from the non-deprecated method and perform a manual
+ // check for eligibility and escape -- that would be faster I think.
final String ret = UNICODE_CHAR_PATTERN.matcher(stringBuilder).replaceAll("\\\\\\\\u");
return ret.isEmpty() ? "" : ret;
}