package org.opendaylight.yangtools.binding.generator.util;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import org.opendaylight.yangtools.binding.generator.util.generated.type.builder.GeneratedTOBuilderImpl;
+import org.opendaylight.yangtools.sal.binding.model.api.AccessModifier;
+import org.opendaylight.yangtools.sal.binding.model.api.Restrictions;
+import org.opendaylight.yangtools.sal.binding.model.api.Type;
+import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedPropertyBuilder;
+import org.opendaylight.yangtools.sal.binding.model.api.type.builder.MethodSignatureBuilder;
+import org.opendaylight.yangtools.sal.binding.model.api.type.builder.TypeMemberBuilder;
import org.opendaylight.yangtools.yang.common.QName;
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.LengthConstraint;
+import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
+import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
+import org.opendaylight.yangtools.yang.model.util.ExtendedType;
/**
* Contains the methods for converting strings to valid JAVA language strings
* (package names, class names, attribute names).
- *
- *
+ *
+ *
*/
public final class BindingGeneratorUtil {
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyMMdd");
-
+
/**
* Array of strings values which represents JAVA reserved words.
*/
/**
* Converts string <code>packageName</code> to valid JAVA package name.
- *
+ *
* If some words of package name are digits of JAVA reserved words they are
* prefixed with underscore character.
- *
+ *
* @param packageName
* string which contains words separated by point.
* @return package name which contains words separated by point.
*/
private static String validateJavaPackage(final String packageName) {
if (packageName != null) {
- final String[] packNameParts = packageName.split("\\.");
+ final String[] packNameParts = packageName.toLowerCase().split("\\.");
if (packNameParts != null) {
final StringBuilder builder = new StringBuilder();
for (int i = 0; i < packNameParts.length; ++i) {
/**
* 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
* @return string with the admissible parameter name
*/
- public static String validateParameterName(final String parameterName) {
+ public static String resolveJavaReservedWordEquivalency(final String parameterName) {
if (parameterName != null && JAVA_RESERVED_WORDS.contains(parameterName)) {
return "_" + 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>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
packageNameBuilder.append(namespace);
packageNameBuilder.append(".rev");
packageNameBuilder.append(DATE_FORMAT.format(module.getRevision()));
-
+
return validateJavaPackage(packageNameBuilder.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
/**
* 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
/**
* 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
* name.
*/
public static String parseToClassName(String token) {
- String correctStr = token.replace(".", "");
- correctStr = parseToCamelCase(correctStr);
-
- // make first char upper-case
- char first = Character.toUpperCase(correctStr.charAt(0));
- if (first >= '0' && first <= '9') {
-
- correctStr = "_" + correctStr;
- } else {
- correctStr = first + correctStr.substring(1);
- }
- return correctStr;
+ 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
* parameter name.
*/
public static String parseToValidParamName(final String token) {
- final String validToken = token.replace(".", "");
- String correctStr = parseToCamelCase(validToken);
-
- // make first char lower-case
- char first = Character.toLowerCase(correctStr.charAt(0));
- correctStr = first + correctStr.substring(1);
- return validateParameterName(correctStr);
+ return resolveJavaReservedWordEquivalency(parseToCamelCase(token, false));
}
/**
- * Converts <code>token</code> to capital letters and removes invalid
- * characters.
- *
- * @param token
- * string with characters which should be conversed to capital
- * @return string with capital letters
- */
- public static String convertToCapitalLetters(final String token) {
- String convertedStr = token.replace(" ", "_");
- convertedStr = convertedStr.replace(".", "_");
- convertedStr = convertedStr.toUpperCase();
- return convertedStr;
- }
-
- /**
- *
+ *
* 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> equals null</li>
* </ul>
*/
- private static String parseToCamelCase(String token) {
+
+ private static String parseToCamelCase(final String token, final boolean uppercase) {
if (token == null) {
throw new IllegalArgumentException("Name can not be null");
}
String correctStr = token.trim();
+ correctStr = correctStr.replace(".", "");
+
if (correctStr.isEmpty()) {
throw new IllegalArgumentException("Name can not be emty");
}
correctStr = replaceWithCamelCase(correctStr, ' ');
correctStr = replaceWithCamelCase(correctStr, '-');
correctStr = replaceWithCamelCase(correctStr, '_');
+
+ String firstChar = correctStr.substring(0, 1);
+ if (uppercase) {
+ firstChar = firstChar.toUpperCase();
+ } else {
+ firstChar = firstChar.toLowerCase();
+ }
+
+ if (firstChar.matches("[0-9]")) {
+ correctStr = "_" + correctStr;
+ } else {
+ correctStr = firstChar + correctStr.substring(1);
+ }
return correctStr;
}
* Replaces all the occurances 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
}
return sb.toString();
}
+
+ public static long computeDefaultSUID(GeneratedTOBuilderImpl to) {
+ try {
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ DataOutputStream dout = new DataOutputStream(bout);
+
+ dout.writeUTF(to.getName());
+ dout.writeInt(to.isAbstract() ? 3 : 7);
+
+ List<Type> impl = to.getImplementsTypes();
+ Collections.sort(impl, new Comparator<Type>() {
+ @Override
+ public int compare(Type o1, Type o2) {
+ return o1.getFullyQualifiedName().compareTo(o2.getFullyQualifiedName());
+ }
+ });
+ for (Type ifc : impl) {
+ dout.writeUTF(ifc.getFullyQualifiedName());
+ }
+
+ Comparator<TypeMemberBuilder<?>> comparator = new Comparator<TypeMemberBuilder<?>>() {
+ @Override
+ public int compare(TypeMemberBuilder<?> o1, TypeMemberBuilder<?> o2) {
+ return o1.getName().compareTo(o2.getName());
+ }
+ };
+
+ List<GeneratedPropertyBuilder> props = to.getProperties();
+ Collections.sort(props, comparator);
+ for (GeneratedPropertyBuilder gp : props) {
+ dout.writeUTF(gp.getName());
+ }
+
+ List<MethodSignatureBuilder> methods = to.getMethodDefinitions();
+ Collections.sort(methods, comparator);
+ for (MethodSignatureBuilder m : methods) {
+ if (!(m.getAccessModifier().equals(AccessModifier.PRIVATE))) {
+ dout.writeUTF(m.getName());
+ dout.write(m.getAccessModifier().ordinal());
+ }
+ }
+
+ dout.flush();
+
+ MessageDigest md = MessageDigest.getInstance("SHA");
+ byte[] hashBytes = md.digest(bout.toByteArray());
+ long hash = 0;
+ for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) {
+ hash = (hash << 8) | (hashBytes[i] & 0xFF);
+ }
+ return hash;
+ } catch (IOException ex) {
+ throw new InternalError();
+ } catch (NoSuchAlgorithmException ex) {
+ throw new SecurityException(ex.getMessage());
+ }
+ }
+
+ public static Restrictions getRestrictions(TypeDefinition<?> type) {
+ final List<LengthConstraint> length = new ArrayList<>();
+ final List<PatternConstraint> pattern = new ArrayList<>();
+ final List<RangeConstraint> range = new ArrayList<>();
+
+ if (type instanceof ExtendedType) {
+ ExtendedType ext = (ExtendedType)type;
+ length.addAll(ext.getLengthConstraints());
+ pattern.addAll(ext.getPatternConstraints());
+ range.addAll(ext.getRangeConstraints());
+ }
+
+ return new Restrictions() {
+ @Override
+ public List<RangeConstraint> getRangeConstraints() {
+ return range;
+ }
+ @Override
+ public List<PatternConstraint> getPatternConstraints() {
+ return pattern;
+ }
+ @Override
+ public List<LengthConstraint> getLengthConstraints() {
+ return length;
+ }
+ @Override
+ public boolean isEmpty() {
+ return range.isEmpty() && pattern.isEmpty() && length.isEmpty();
+ }
+ };
+ }
+
}