import com.google.common.annotations.Beta;
import com.google.common.base.CharMatcher;
import com.google.common.base.Splitter;
-import com.google.common.collect.ArrayListMultimap;
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.regex.Pattern;
+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;
* </li>
* </ul>
*
+ * <p>
* There is special case in CLASS, INTERFACE, ENUM, ENUM VALUE, CONSTANT, METHOD
* and VARIABLE if identifier contains single dash - then the converter ignores
* the single dash in the way of the non-java chars. In other way, if dash is
* </li>
* </ul>
*
+ * <p>
* Next special case talks about normalizing class name which already exists in
* package - but with different camel cases (foo, Foo, fOo, ...). To every next
* classes with same names will by added their actual rank (serial number),
"java",
"com");
- private static final int FIRST_CHAR = 0;
- private static final int FIRST_INDEX = 1;
private static final char UNDERSCORE = '_';
private static final char DASH = '-';
private static final String RESERVED_KEYWORD = "reserved_keyword";
- private static final ListMultimap<String, String> PACKAGES_MAP = ArrayListMultimap.create();
private static final Set<String> PRIMITIVE_TYPES = ImmutableSet.of("char[]", "byte[]");
private static final CharMatcher DASH_MATCHER = CharMatcher.is(DASH);
private static final Splitter DOT_SPLITTER = Splitter.on('.');
private static final Splitter UNDERSCORE_SPLITTER = Splitter.on(UNDERSCORE);
+ private static final Pattern DOUBLE_UNDERSCORE_PATTERN = Pattern.compile("__", Pattern.LITERAL);
+
// Converted to lower case
private static final Set<String> WINDOWS_RESERVED_WORDS = BindingMapping.WINDOWS_RESERVED_WORDS.stream()
.map(String::toLowerCase).collect(ImmutableSet.toImmutableSet());
* }
* </pre>
*
+ * <p>
* YANG enum values will be mapped to 'FOO' and 'FOO_1' Java enum values.
*
* @param name
* @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);
}
/**
final StringBuilder sb = new StringBuilder(fullPackageName.length());
while (true) {
- sb.append(normalizePartialPackageName(it.next()));
+ String next = it.next();
+ sb.append(normalizePartialPackageName(next));
if (!it.hasNext()) {
return sb.toString();
}
- sb.append('.');
+
+ if (!next.isEmpty()) {
+ sb.append('.');
+ }
}
}
* - 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
final String lowerPart = packageNamePart.toLowerCase();
* - 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,
+ final ModuleContext context) {
if (packageName.isEmpty() && PRIMITIVE_TYPES.contains(className)) {
return className;
}
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(FIRST_CHAR, lastDot);
+ basePackageName = packageName.substring(0, lastDot);
} else {
basePackageName = packageName;
}
- return normalizeClassIdentifier(basePackageName, convertedClassName, convertedClassName, FIRST_INDEX);
+ return normalizeClassIdentifier(basePackageName, convertedClassName, convertedClassName, 1, context);
+ }
+
+ /**
+ * Checking while there doesn't exist any class name with the same name
+ * (regardless of camel cases) in package.
+ *
+ * @param packageName
+ * - package of class name
+ * @param origClassName
+ * - original class name
+ * @param actualClassName
+ * - actual class name with rank (serial number)
+ * @param rank
+ * - actual rank (serial number)
+ * @return converted identifier
+ */
+ private static String normalizeClassIdentifier(final String packageName, final String origClassName,
+ final String actualClassName, final int rank, final 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;
+ }
}
/**
// check and convert first char in identifier if there is non-java char
final StringBuilder sb = new StringBuilder();
- final char firstChar = identifier.charAt(FIRST_CHAR);
+ 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 (actualChar == DASH && existNext(identifier, i)) {
if (identifier.charAt(i - 1) != DASH && identifier.charAt(i + 1) != DASH) {
sb.append(UNDERSCORE);
continue;
sb.append(actualChar);
}
}
- // apply camel case in appropriate way
- return fixCasesByJavaType(sb.toString().replace("__", "_").toLowerCase(), javaIdentifier);
- }
-
- /**
- * Checking while there doesn't exist any class name with the same name
- * (regardless of camel cases) in package.
- *
- * @param packageName
- * - package of class name
- * @param origClassName
- * - original class name
- * @param actualClassName
- * - actual class name with rank (serial number)
- * @param rank
- * - actual rank (serial number)
- * @return converted identifier
- */
- private static String normalizeClassIdentifier(final String packageName, final String origClassName,
- final String actualClassName, final int rank) {
- // FIXME: this does not look thread-safe and seems to leak memory
- if (PACKAGES_MAP.containsKey(packageName)) {
- for (final String existingName : PACKAGES_MAP.get(packageName)) {
- if (actualClassName.equalsIgnoreCase(existingName)) {
- return normalizeClassIdentifier(packageName, origClassName, origClassName + rank, rank + 1);
- }
- }
- }
- PACKAGES_MAP.put(packageName, actualClassName);
- return actualClassName;
+ // apply camel case in appropriate way
+ return fixCasesByJavaType(DOUBLE_UNDERSCORE_PATTERN.matcher(sb).replaceAll("_").toLowerCase(), javaIdentifier);
}
/**
- * Fix cases of converted identifiers by Java type
+ * Fix cases of converted identifiers by Java type.
*
- * @param string
+ * @param convertedIdentifier
* - converted identifier
* @param javaIdentifier
* - java type of identifier
}
/**
- * Check if there exist next char in identifier behind actual char position
+ * Check if there exist next char in identifier behind actual char position.
*
* @param identifier
* - original identifier
/**
* Converting first char of identifier. This happen only if this char is
- * non-java char
+ * non-java char.
*
- * @param c
+ * @param firstChar
* - first char
* @param existNext
* - existing of next char behind actual char
* @return converted char
*/
- private static String convertFirst(final char c, final boolean existNext) {
- final String name = DASH_OR_SPACE_MATCHER.replaceFrom(Character.getName(c), UNDERSCORE);
+ private static String convertFirst(final char firstChar, final boolean existNext) {
+ final String name = DASH_OR_SPACE_MATCHER.replaceFrom(Character.getName(firstChar), UNDERSCORE);
return existNext ? name + '_' : name;
}
/**
* Converting any char in java identifier, This happen only if this char is
- * non-java char
+ * non-java char.
*
- * @param c
+ * @param actualChar
* - actual char
* @param existNext
* - existing of next char behind actual char
* - last char of partial converted identifier
* @return converted char
*/
- private static String convert(final char c, final boolean existNext, final char partialLastChar) {
- return partialLastChar == '_' ? convertFirst(c, existNext) : "_" + convertFirst(c, existNext);
+ private static String convert(final char actualChar, final boolean existNext, final char partialLastChar) {
+ return partialLastChar == '_' ? convertFirst(actualChar, existNext) : "_" + convertFirst(actualChar, existNext);
}
/**
- * Capitalize input string
+ * Capitalize input string.
*
* @param identifier
* - 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,