Fix for resolving leafSchemaNode asProperty in BindingGeneratorImpl
[yangtools.git] / code-generator / binding-generator-util / src / main / java / org / opendaylight / yangtools / binding / generator / util / BindingGeneratorUtil.java
index 507cb60c2d99c671779508bf0f3e4c62edca479c..41bcb83c71d01d33513d1c26f04602813c31d08f 100644 (file)
@@ -8,34 +8,28 @@
 package org.opendaylight.yangtools.binding.generator.util;
 
 import com.google.common.base.CharMatcher;
-import com.google.common.base.Splitter;
 import com.google.common.collect.Iterables;
-
 import java.io.ByteArrayOutputStream;
 import java.io.DataOutputStream;
 import java.io.IOException;
-import java.io.Serializable;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
-import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Iterator;
 import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.opendaylight.yangtools.binding.generator.util.generated.type.builder.GeneratedPropertyBuilderImpl;
-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.GeneratedTypeBuilderBase;
 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.binding.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;
@@ -55,19 +49,6 @@ import org.opendaylight.yangtools.yang.model.util.ExtendedType;
  */
 public final class BindingGeneratorUtil {
 
-    private static final ThreadLocal<SimpleDateFormat> DATE_FORMAT = new ThreadLocal<SimpleDateFormat>() {
-
-        @Override
-        protected SimpleDateFormat initialValue() {
-            return new SimpleDateFormat("yyMMdd");
-        }
-
-        @Override
-        public void set(final SimpleDateFormat value) {
-            throw new UnsupportedOperationException();
-        }
-    };
-
     /**
      * Impossible to instantiate this class. All of the methods or attributes
      * are static.
@@ -78,44 +59,44 @@ public final class BindingGeneratorUtil {
     /**
      * Pre-compiled replacement pattern.
      */
-    private static final Pattern COLON_SLASH_SLASH = Pattern.compile("://", Pattern.LITERAL);
-    private static final String QUOTED_DOT = Matcher.quoteReplacement(".");
-    private static final Splitter DOT = Splitter.on('.');
     private static final CharMatcher DOT_MATCHER = CharMatcher.is('.');
+    private static final CharMatcher DASH_COLON_MATCHER = CharMatcher.anyOf("-:");
 
-    /**
-     * 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) {
-            return null;
+    private static final Restrictions EMPTY_RESTRICTIONS = new Restrictions() {
+        @Override
+        public List<LengthConstraint> getLengthConstraints() {
+            return Collections.emptyList();
         }
 
-        final StringBuilder builder = new StringBuilder();
-        boolean first = true;
+        @Override
+        public List<PatternConstraint> getPatternConstraints() {
+            return Collections.emptyList();
+        }
 
-        for (String p : DOT.split(packageName.toLowerCase())) {
-            if (first) {
-                first = false;
-            } else {
-                builder.append('.');
-            }
+        @Override
+        public List<RangeConstraint> getRangeConstraints() {
+            return Collections.emptyList();
+        }
 
-            if (Character.isDigit(p.charAt(0)) || BindingMapping.JAVA_RESERVED_WORDS.contains(p)) {
-                builder.append('_');
-            }
-            builder.append(p);
+        @Override
+        public boolean isEmpty() {
+            return true;
         }
+    };
 
-        return builder.toString();
-    }
+    private static final Comparator<TypeMemberBuilder<?>> SUID_MEMBER_COMPARATOR = new Comparator<TypeMemberBuilder<?>>() {
+        @Override
+        public int compare(final TypeMemberBuilder<?> o1, final TypeMemberBuilder<?> o2) {
+            return o1.getName().compareTo(o2.getName());
+        }
+    };
+
+    private static final Comparator<Type> SUID_NAME_COMPARATOR = new Comparator<Type>() {
+        @Override
+        public int compare(final Type o1, final Type o2) {
+            return o1.getFullyQualifiedName().compareTo(o2.getFullyQualifiedName());
+        }
+    };
 
     /**
      * Converts <code>parameterName</code> to valid JAVA parameter name.
@@ -152,43 +133,11 @@ public final class BindingGeneratorUtil {
      * @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) {
-        final StringBuilder packageNameBuilder = new StringBuilder();
-
-        if (module.getRevision() == null) {
-            throw new IllegalArgumentException("Module " + module.getName() + " does not specify revision date!");
-        }
-        packageNameBuilder.append(BindingMapping.PACKAGE_PREFIX);
-        packageNameBuilder.append('.');
-
-        String namespace = module.getNamespace().toString();
-        namespace = COLON_SLASH_SLASH.matcher(namespace).replaceAll(QUOTED_DOT);
-
-        final char[] chars = namespace.toCharArray();
-        for (int i = 0; i < chars.length; ++i) {
-            switch (chars[i]) {
-            case '/':
-            case ':':
-            case '-':
-            case '@':
-            case '$':
-            case '#':
-            case '\'':
-            case '*':
-            case '+':
-            case ',':
-            case ';':
-            case '=':
-                chars[i] = '.';
-            }
-        }
-
-        packageNameBuilder.append(chars);
-        packageNameBuilder.append(".rev");
-        packageNameBuilder.append(DATE_FORMAT.get().format(module.getRevision()));
-
-        return validateJavaPackage(packageNameBuilder.toString());
+        return BindingMapping.getRootPackageName(module.getQNameModule());
     }
 
     public static String packageNameForGeneratedType(final String basePackageName, final SchemaPath schemaPath) {
@@ -233,12 +182,10 @@ public final class BindingGeneratorUtil {
         for (int i = 0; i < traversalSteps; ++i) {
             builder.append('.');
             String nodeLocalName = iterator.next().getLocalName();
-
-            nodeLocalName = nodeLocalName.replace(':', '.');
-            nodeLocalName = nodeLocalName.replace('-', '.');
-            builder.append(nodeLocalName);
+            // FIXME: Collon ":" is invalid in node local name as per RFC6020, identifier statement.
+            builder.append(DASH_COLON_MATCHER.replaceFrom(nodeLocalName, '.'));
         }
-        return validateJavaPackage(builder.toString());
+        return BindingMapping.normalizePackageName(builder.toString());
     }
 
     /**
@@ -267,7 +214,7 @@ public final class BindingGeneratorUtil {
 
         final StringBuilder builder = new StringBuilder();
         builder.append(basePackageName);
-        return validateJavaPackage(builder.toString());
+        return BindingMapping.normalizePackageName(builder.toString());
     }
 
     /**
@@ -296,8 +243,10 @@ public final class BindingGeneratorUtil {
      *            JAVA parameter name
      * @return string which is in accordance with best practices for JAVA
      *         parameter name.
+     *
+     * @deprecated Use {@link BindingMapping#getPropertyName(String)} instead.
      */
-    public static String parseToValidParamName(final String token) {
+    @Deprecated public static String parseToValidParamName(final String token) {
         return resolveJavaReservedWordEquivalency(parseToCamelCase(token, false));
     }
 
@@ -325,7 +274,7 @@ public final class BindingGeneratorUtil {
 
         String correctStr = DOT_MATCHER.removeFrom(token.trim());
         if (correctStr.isEmpty()) {
-            throw new IllegalArgumentException("Name can not be emty");
+            throw new IllegalArgumentException("Name can not be empty");
         }
 
         correctStr = replaceWithCamelCase(correctStr, ' ');
@@ -379,21 +328,17 @@ public final class BindingGeneratorUtil {
         return sb.toString();
     }
 
-    /**
-     * Add {@link Serializable} to implemented interfaces of this TO. Also
-     * compute and add serialVersionUID property.
-     *
-     * @param gto
-     *            transfer object which needs to be serializable
-     */
-    public static void makeSerializable(final GeneratedTOBuilderImpl gto) {
-        gto.addImplementsType(Types.typeForClass(Serializable.class));
-        GeneratedPropertyBuilder prop = new GeneratedPropertyBuilderImpl("serialVersionUID");
-        prop.setValue(Long.toString(computeDefaultSUID(gto)));
-        gto.setSUID(prop);
+    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 {
+            return input;
+        }
     }
 
-    public static long computeDefaultSUID(final GeneratedTOBuilderImpl to) {
+    public static long computeDefaultSUID(final GeneratedTypeBuilderBase<?> to) {
         try {
             ByteArrayOutputStream bout = new ByteArrayOutputStream();
             DataOutputStream dout = new DataOutputStream(bout);
@@ -401,33 +346,15 @@ public final class BindingGeneratorUtil {
             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(final Type o1, final Type o2) {
-                    return o1.getFullyQualifiedName().compareTo(o2.getFullyQualifiedName());
-                }
-            });
-            for (Type ifc : impl) {
+            for (Type ifc : sortedCollection(SUID_NAME_COMPARATOR, to.getImplementsTypes())) {
                 dout.writeUTF(ifc.getFullyQualifiedName());
             }
 
-            Comparator<TypeMemberBuilder<?>> comparator = new Comparator<TypeMemberBuilder<?>>() {
-                @Override
-                public int compare(final TypeMemberBuilder<?> o1, final TypeMemberBuilder<?> o2) {
-                    return o1.getName().compareTo(o2.getName());
-                }
-            };
-
-            List<GeneratedPropertyBuilder> props = to.getProperties();
-            Collections.sort(props, comparator);
-            for (GeneratedPropertyBuilder gp : props) {
+            for (GeneratedPropertyBuilder gp : sortedCollection(SUID_MEMBER_COMPARATOR, to.getProperties())) {
                 dout.writeUTF(gp.getName());
             }
 
-            List<MethodSignatureBuilder> methods = to.getMethodDefinitions();
-            Collections.sort(methods, comparator);
-            for (MethodSignatureBuilder m : methods) {
+            for (MethodSignatureBuilder m : sortedCollection(SUID_MEMBER_COMPARATOR, to.getMethodDefinitions())) {
                 if (!(m.getAccessModifier().equals(AccessModifier.PRIVATE))) {
                     dout.writeUTF(m.getName());
                     dout.write(m.getAccessModifier().ordinal());
@@ -436,42 +363,52 @@ public final class BindingGeneratorUtil {
 
             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);
+            try {
+                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 (NoSuchAlgorithmException ex) {
+                throw new SecurityException(ex.getMessage());
             }
-            return hash;
         } catch (IOException ex) {
             throw new InternalError();
-        } catch (NoSuchAlgorithmException ex) {
-            throw new SecurityException(ex.getMessage());
         }
     }
 
     public static Restrictions getRestrictions(final 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;
-            TypeDefinition<?> base = ext.getBaseType();
-            length.addAll(ext.getLengthConstraints());
-            pattern.addAll(ext.getPatternConstraints());
-            range.addAll(ext.getRangeConstraints());
-
-            if (base instanceof IntegerTypeDefinition && range.isEmpty()) {
-                range.addAll(((IntegerTypeDefinition)base).getRangeConstraints());
-            } else if (base instanceof UnsignedIntegerTypeDefinition && range.isEmpty()) {
-                range.addAll(((UnsignedIntegerTypeDefinition)base).getRangeConstraints());
-            } else if (base instanceof DecimalTypeDefinition && range.isEmpty()) {
-                range.addAll(((DecimalTypeDefinition)base).getRangeConstraints());
+        // Base types have no constraints, so get over it quickly
+        if (!(type instanceof ExtendedType)) {
+            return EMPTY_RESTRICTIONS;
+        }
+
+        // Take care of the extended types ...
+        final ExtendedType ext = (ExtendedType)type;
+        final List<LengthConstraint> length = ext.getLengthConstraints();
+        final List<PatternConstraint> pattern = ext.getPatternConstraints();
+
+        List<RangeConstraint> tmp = ext.getRangeConstraints();
+        if (tmp.isEmpty()) {
+            final TypeDefinition<?> base = ext.getBaseType();
+            if (base instanceof IntegerTypeDefinition) {
+                tmp = ((IntegerTypeDefinition)base).getRangeConstraints();
+            } else if (base instanceof UnsignedIntegerTypeDefinition) {
+                tmp = ((UnsignedIntegerTypeDefinition)base).getRangeConstraints();
+            } else if (base instanceof DecimalTypeDefinition) {
+                tmp = ((DecimalTypeDefinition)base).getRangeConstraints();
             }
+        }
 
+        // Now, this may have ended up being empty, too...
+        if (length.isEmpty() && pattern.isEmpty() && tmp.isEmpty()) {
+            return EMPTY_RESTRICTIONS;
         }
 
+        // Nope, not empty allocate a holder
+        final List<RangeConstraint> range = tmp;
         return new Restrictions() {
             @Override
             public List<RangeConstraint> getRangeConstraints() {
@@ -487,7 +424,7 @@ public final class BindingGeneratorUtil {
             }
             @Override
             public boolean isEmpty() {
-                return range.isEmpty() && pattern.isEmpty() && length.isEmpty();
+                return false;
             }
         };
     }