package org.opendaylight.mdsal.binding.javav2.generator.util;
import com.google.common.annotations.Beta;
-import com.google.common.collect.ArrayListMultimap;
+import com.google.common.base.CharMatcher;
+import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ListMultimap;
+import java.util.Iterator;
import java.util.List;
import java.util.Set;
+import java.util.stream.Collectors;
+import org.opendaylight.mdsal.binding.javav2.generator.context.ModuleContext;
import org.opendaylight.mdsal.binding.javav2.model.api.Enumeration;
import org.opendaylight.mdsal.binding.javav2.model.api.Enumeration.Pair;
import org.opendaylight.mdsal.binding.javav2.util.BindingMapping;
@Beta
public final class JavaIdentifierNormalizer {
- private static final int FIRST_CHAR = 0;
- private static final int FIRST_INDEX = 1;
+ public static final Set<String> SPECIAL_RESERVED_PATHS = ImmutableSet.of(
+ "org.opendaylight.yangtools.concepts",
+ "org.opendaylight.yangtools.yang.common",
+ "org.opendaylight.yangtools.yang.model",
+ "org.opendaylight.mdsal.binding.javav2.spec",
+ "java",
+ "com");
+
private static final char UNDERSCORE = '_';
private static final char DASH = '-';
- private static final String EMPTY_STRING = "";
private static final String RESERVED_KEYWORD = "reserved_keyword";
- private static final ListMultimap<String, String> PACKAGES_MAP = ArrayListMultimap.create();
- public static final Set<String> SPECIAL_RESERVED_PATHS =
- ImmutableSet.of("org.opendaylight.yangtools.yang.model","org.opendaylight.yangtools.concepts","org.opendaylight.yangtools.yang.common",
- "org.opendaylight.mdsal.binding.javav2.spec","java", "com");
+ private static final Set<String> PRIMITIVE_TYPES = ImmutableSet.of("char[]", "byte[]");
+
+ private static final CharMatcher DASH_MATCHER = CharMatcher.is(DASH);
+ private static final CharMatcher DASH_OR_SPACE_MATCHER = CharMatcher.anyOf(" -");
+ private static final CharMatcher UNDERSCORE_MATCHER = CharMatcher.is(UNDERSCORE);
+ private static final Splitter DOT_SPLITTER = Splitter.on('.');
+ private static final Splitter UNDERSCORE_SPLITTER = Splitter.on(UNDERSCORE);
+
+ // Converted to lower case
+ private static final Set<String> WINDOWS_RESERVED_WORDS = BindingMapping.WINDOWS_RESERVED_WORDS.stream()
+ .map(String::toLowerCase).collect(Collectors.collectingAndThen(Collectors.toSet(), ImmutableSet::copyOf));
private JavaIdentifierNormalizer() {
throw new UnsupportedOperationException("Util class");
* @return converted and fixed name of new enum value
*/
public static String normalizeEnumValueIdentifier(final String name, final List<Pair> values) {
- return convertIdentifierEnumValue(name, name, values, FIRST_INDEX);
+ return convertIdentifierEnumValue(name, name, values, 1);
}
/**
* @return normalized name
*/
public static String normalizeFullPackageName(final String fullPackageName) {
- final String[] packageNameParts = fullPackageName.split("\\.");
- final StringBuilder sb = new StringBuilder();
- for (int i = 0; i < packageNameParts.length; i++) {
- sb.append(normalizePartialPackageName(packageNameParts[i]));
- if (i != (packageNameParts.length - 1)) {
- sb.append(".");
+ final Iterator<String> it = DOT_SPLITTER.split(fullPackageName).iterator();
+ if (!it.hasNext()) {
+ return fullPackageName;
+ }
+
+ final StringBuilder sb = new StringBuilder(fullPackageName.length());
+ while (true) {
+ sb.append(normalizePartialPackageName(it.next()));
+ if (!it.hasNext()) {
+ return sb.toString();
}
+ sb.append('.');
}
- return sb.toString();
}
/**
* - part of package name
* @return normalized name
*/
- public static String normalizePartialPackageName(final String packageNamePart) {
+ static String normalizePartialPackageName(final String packageNamePart) {
// if part of package name consist from java or windows reserved word, return it with
// underscore at the end and in lower case
- if (BindingMapping.JAVA_RESERVED_WORDS.contains(packageNamePart.toLowerCase())
- || BindingMapping.WINDOWS_RESERVED_WORDS.contains(packageNamePart.toUpperCase())) {
- return new StringBuilder(packageNamePart).append(UNDERSCORE).toString().toLowerCase();
- }
- String normalizedPackageNamePart = packageNamePart;
- if (packageNamePart.contains(String.valueOf(DASH))) {
- normalizedPackageNamePart = packageNamePart.replaceAll(String.valueOf(DASH), String.valueOf(UNDERSCORE));
+ final String lowerPart = packageNamePart.toLowerCase();
+ if (BindingMapping.JAVA_RESERVED_WORDS.contains(lowerPart) || WINDOWS_RESERVED_WORDS.contains(lowerPart)) {
+ return lowerPart + UNDERSCORE;
}
+
+ final String normalizedPart = DASH_MATCHER.replaceFrom(packageNamePart, UNDERSCORE);
+
final StringBuilder sb = new StringBuilder();
- StringBuilder innserSb = new StringBuilder();
- for (int i = 0; i < normalizedPackageNamePart.length(); i++) {
- if (normalizedPackageNamePart.charAt(i) == UNDERSCORE) {
- if (!innserSb.toString().isEmpty()) {
- sb.append(normalizeSpecificIdentifier(innserSb.toString(), JavaIdentifier.PACKAGE));
- innserSb = new StringBuilder();
+ final StringBuilder innerSb = new StringBuilder();
+ for (int i = 0; i < normalizedPart.length(); i++) {
+ final char c = normalizedPart.charAt(i);
+ if (c == UNDERSCORE) {
+ if (innerSb.length() != 0) {
+ sb.append(normalizeSpecificIdentifier(innerSb.toString(), JavaIdentifier.PACKAGE));
+ innerSb.setLength(0);
}
sb.append(UNDERSCORE);
} else {
- innserSb.append(normalizedPackageNamePart.charAt(i));
+ innerSb.append(c);
}
}
- if (!innserSb.toString().isEmpty()) {
- sb.append(normalizeSpecificIdentifier(innserSb.toString(), JavaIdentifier.PACKAGE));
+ if (innerSb.length() != 0) {
+ sb.append(normalizeSpecificIdentifier(innerSb.toString(), JavaIdentifier.PACKAGE));
}
// returned normalized part of package name
return sb.toString();
* - name of identifier
* @return - java acceptable identifier
*/
- public static String normalizeClassIdentifier(final String packageName, final String className) {
+ static String normalizeClassIdentifier(final String packageName, final String className,
+ ModuleContext context) {
+ if (packageName.isEmpty() && PRIMITIVE_TYPES.contains(className)) {
+ return className;
+ }
for (final String reservedPath : SPECIAL_RESERVED_PATHS) {
if (packageName.startsWith(reservedPath)) {
return className;
}
}
final String convertedClassName = normalizeSpecificIdentifier(className, JavaIdentifier.CLASS);
- return normalizeClassIdentifier(packageName, convertedClassName, convertedClassName, FIRST_INDEX);
+
+ // if packageName contains class name at the end, then the className is name of inner class
+ final String basePackageName;
+ final int lastDot = packageName.lastIndexOf('.');
+ if (lastDot != -1 && Character.isUpperCase(packageName.charAt(lastDot + 1))) {
+ // ignore class name in package name - inner class name has to be normalized according to original package
+ // of parent class
+ basePackageName = packageName.substring(0, lastDot);
+ } else {
+ basePackageName = packageName;
+ }
+
+ return normalizeClassIdentifier(basePackageName, convertedClassName, convertedClassName, 1, context);
}
/**
* @return - java acceptable identifier
*/
public static String normalizeSpecificIdentifier(final String identifier, final JavaIdentifier javaIdentifier) {
- final StringBuilder sb = new StringBuilder();
-
// if identifier isn't PACKAGE type then check it by reserved keywords
- if(javaIdentifier != JavaIdentifier.PACKAGE) {
- if (BindingMapping.JAVA_RESERVED_WORDS.contains(identifier.toLowerCase())
- || BindingMapping.WINDOWS_RESERVED_WORDS.contains(identifier.toUpperCase())) {
- return fixCasesByJavaType(
- sb.append(identifier).append(UNDERSCORE).append(RESERVED_KEYWORD).toString().toLowerCase(),
- javaIdentifier);
+ if (javaIdentifier != JavaIdentifier.PACKAGE) {
+ final String lower = identifier.toLowerCase();
+ if (BindingMapping.JAVA_RESERVED_WORDS.contains(lower) || WINDOWS_RESERVED_WORDS.contains(lower)) {
+ return fixCasesByJavaType(lower + UNDERSCORE + RESERVED_KEYWORD, javaIdentifier);
}
}
// check and convert first char in identifier if there is non-java char
- final char firstChar = identifier.charAt(FIRST_CHAR);
+ final StringBuilder sb = new StringBuilder();
+ final char firstChar = identifier.charAt(0);
if (!Character.isJavaIdentifierStart(firstChar)) {
// converting first char of identifier
- sb.append(convertFirst(firstChar, existNext(identifier, FIRST_CHAR)));
+ sb.append(convertFirst(firstChar, existNext(identifier, 0)));
} else {
sb.append(firstChar);
}
final char actualChar = identifier.charAt(i);
// ignore single dash as non java char - if there is more dashes in a row or dash is as
// the last char in identifier then parse these dashes as non java chars
- if ((actualChar == '-') && existNext(identifier, i)) {
- if ((identifier.charAt(i - 1) != DASH) && (identifier.charAt(i + 1) != DASH)) {
+ if (actualChar == DASH && existNext(identifier, i)) {
+ if (identifier.charAt(i - 1) != DASH && identifier.charAt(i + 1) != DASH) {
sb.append(UNDERSCORE);
continue;
}
}
if (!Character.isJavaIdentifierPart(actualChar)) {
- // prepare actual string of sb for checking if underscore exist on position of the
- // last char
- final String partialConvertedIdentifier = sb.toString();
- sb.append(convert(actualChar, existNext(identifier, i),
- partialConvertedIdentifier.charAt(partialConvertedIdentifier.length() - 1)));
+ // prepare actual string of sb for checking if underscore exist on position of the last char
+ sb.append(convert(actualChar, existNext(identifier, i), sb.charAt(sb.length() - 1)));
} else {
sb.append(actualChar);
}
* @return converted identifier
*/
private static String normalizeClassIdentifier(final String packageName, final String origClassName,
- final String actualClassName, final int rank) {
- if (PACKAGES_MAP.containsKey(packageName)) {
- for (final String existingName : PACKAGES_MAP.get(packageName)) {
- if (existingName.toLowerCase().equals(actualClassName.toLowerCase())) {
- final int nextRank = rank + 1;
- return normalizeClassIdentifier(packageName, origClassName,
- new StringBuilder(origClassName).append(rank).toString(), nextRank);
+ final String actualClassName, final int rank, ModuleContext context) {
+
+ final ListMultimap<String, String> packagesMap = context.getPackagesMap();
+
+ synchronized (packagesMap) {
+ if (packagesMap.containsKey(packageName)) {
+ for (final String existingName : packagesMap.get(packageName)) {
+ if (actualClassName.equalsIgnoreCase(existingName)) {
+ return normalizeClassIdentifier(packageName, origClassName, origClassName + rank,
+ rank + 1, context);
+ }
}
}
+ context.putToPackagesMap(packageName, actualClassName);
+ return actualClassName;
}
- PACKAGES_MAP.put(packageName, actualClassName);
- return actualClassName;
}
/**
* Fix cases of converted identifiers by Java type
*
- * @param string
+ * @param convertedIdentifier
* - converted identifier
* @param javaIdentifier
* - java type of identifier
case VARIABLE:
return fixCases(convertedIdentifier);
case PACKAGE:
- return convertedIdentifier.replaceAll(String.valueOf(UNDERSCORE), EMPTY_STRING);
+ return UNDERSCORE_MATCHER.removeFrom(convertedIdentifier);
default:
throw new IllegalArgumentException("Unknown java type of identifier : " + javaIdentifier.toString());
}
* @return resolved identifier
*/
private static String fixCases(final String convertedIdentifier) {
- final StringBuilder sb = new StringBuilder();
- if (convertedIdentifier.contains(String.valueOf(UNDERSCORE))) {
- boolean isFirst = true;
- for (final String part : convertedIdentifier.split(String.valueOf(UNDERSCORE))) {
- if (isFirst) {
- isFirst = false;
- sb.append(part);
- } else {
- sb.append(capitalize(part));
- }
- }
- } else {
- sb.append(convertedIdentifier);
+ if (convertedIdentifier.indexOf(UNDERSCORE) == -1) {
+ return convertedIdentifier;
+ }
+
+ final StringBuilder sb = new StringBuilder(convertedIdentifier.length());
+ final Iterator<String> it = UNDERSCORE_SPLITTER.split(convertedIdentifier).iterator();
+ sb.append(it.next());
+ while (it.hasNext()) {
+ sb.append(capitalize(it.next()));
}
return sb.toString();
}
* @return true if there is another char, false otherwise
*/
private static boolean existNext(final String identifier, final int actual) {
- return (identifier.length() - 1) < (actual + 1) ? false : true;
+ return identifier.length() > actual + 1;
}
/**
* @return converted char
*/
private static String convertFirst(final char c, final boolean existNext) {
- String name = Character.getName(c);
- if (name.contains(String.valueOf(DASH))) {
- name = name.replaceAll(String.valueOf(DASH), String.valueOf(UNDERSCORE));
- }
- name = existNext ? (name + "_") : name;
- return name.contains(" ") ? name.replaceAll(" ", "_") : name;
+ final String name = DASH_OR_SPACE_MATCHER.replaceFrom(Character.getName(c), UNDERSCORE);
+ return existNext ? name + '_' : name;
}
/**
* - string to be capitalized
*/
private static String capitalize(final String identifier) {
- return identifier.substring(FIRST_CHAR, FIRST_CHAR + 1).toUpperCase() + identifier.substring(1);
+ return identifier.substring(0, 1).toUpperCase() + identifier.substring(1);
}
private static String convertIdentifierEnumValue(final String name, final String origName, final List<Pair> values,
final int rank) {
String newName = name;
for (final Pair pair : values) {
- if (pair.getName().toLowerCase().equals(name.toLowerCase())
- || pair.getMappedName().toLowerCase().equals(name.toLowerCase())) {
+ if (name.equalsIgnoreCase(pair.getName()) || name.equalsIgnoreCase(pair.getMappedName())) {
int actualRank = rank;
- final StringBuilder actualNameBuilder =
- new StringBuilder(origName).append(UNDERSCORE).append(actualRank);
- newName = convertIdentifierEnumValue(actualNameBuilder.toString(), origName, values, ++actualRank);
+ final String actualName = origName + UNDERSCORE + actualRank;
+ newName = convertIdentifierEnumValue(actualName, origName, values, ++actualRank);
}
}
return normalizeSpecificIdentifier(newName, JavaIdentifier.ENUM_VALUE);