Bug 1027: Fixed generation of static QNAME field 30/7330/3
authorTony Tkacik <ttkacik@cisco.com>
Thu, 22 May 2014 11:10:55 +0000 (13:10 +0200)
committerTony Tkacik <ttkacik@cisco.com>
Mon, 2 Jun 2014 14:27:16 +0000 (16:27 +0200)
All YANG modeled entities such as containers, lists
which have Binding-aware interface associated with
it should have static field QNAME with their respective
from YANG models. Only exception are augmentations
which do not have explicit name.

Instance Identifier codec relies on this existence
of QName which was not true for classes derived from
RPC Input and RPC Output

The code was changed to fix this issue:

BindingGeneratorImpl:
  Updated to include QName for all YANG modeled
  data container.

BindingReflections:
  ClassToQNameLoader was updated to derive correct
  qname for RPC inputs and RPC outputs for models
  which was compiled with missing QName field.

Change-Id: I190f569037cb4e88cf2edc7f18c436cf3eb86aeb
Signed-off-by: Tony Tkacik <ttkacik@cisco.com>
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingGeneratorImpl.xtend
yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/util/BindingReflections.java

index ec1ec8fc6af0bed3c0ffb33ddae6fad66656ac92..e462fbaf23b156a6907972aa62dbb1d348d62028 100644 (file)
@@ -1544,7 +1544,6 @@ public class BindingGeneratorImpl implements BindingGenerator {
     private def GeneratedTypeBuilder addDefaultInterfaceDefinition(String packageName, SchemaNode schemaNode,
         Type parent) {
         val it = addRawInterfaceDefinition(packageName, schemaNode, "");
-        qnameConstant(BindingMapping.QNAME_STATIC_FIELD_NAME,schemaNode.QName);
         if (parent === null) {
             addImplementsType(DATA_OBJECT);
         } else {
@@ -1616,6 +1615,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
 
         //FIXME: Validation of name conflict
         val newType = new GeneratedTypeBuilderImpl(packageName, genTypeName);
+        qnameConstant(newType,BindingMapping.QNAME_STATIC_FIELD_NAME,schemaNode.QName);
         newType.addComment(schemaNode.getDescription());
         if (!genTypeBuilders.containsKey(packageName)) {
             val Map<String, GeneratedTypeBuilder> builders = new HashMap();
index 0b057a194bc86b1d79a8218b67e820eb88dee819..d6c1d7b75138ab6da9ad5290cc83f4714459b7a3 100644 (file)
@@ -441,29 +441,103 @@ public class BindingReflections {
 
         @Override
         public Optional<QName> load(final Class<?> key) throws Exception {
+            return resolveQNameNoCache(key);
+        }
+    }
+
+    /**
+     *
+     * Tries to resolve QName for supplied class.
+     *
+     * Looks up for static field with name from constant {@link BindingMapping#QNAME_STATIC_FIELD_NAME}
+     * and returns value if present.
+     *
+     * If field is not present uses {@link #computeQName(Class)} to compute QName for missing types.
+     *
+     * @param key
+     * @return
+     */
+    private static Optional<QName> resolveQNameNoCache(final Class<?> key) {
+        try {
+            Field field = key.getField(BindingMapping.QNAME_STATIC_FIELD_NAME);
+            Object obj = field.get(null);
+            if (obj instanceof QName) {
+                return Optional.of((QName) obj);
+            }
+
+        } catch (NoSuchFieldException e) {
+            return Optional.of(computeQName(key));
+
+        } catch (SecurityException | IllegalArgumentException | IllegalAccessException e) {
+            /*
+             *
+             * It is safe to log this this exception on debug, since
+             * this method should not fail. Only failures are possible if
+             * the runtime / backing.
+             *
+             */
+            LOG.debug("Unexpected exception during extracting QName for {}",key,e);
+        }
+        return Optional.absent();
+    }
+
+    /**
+     * Computes QName for supplied class
+     *
+     * Namespace and revision are same as {@link YangModuleInfo}
+     * associated with supplied class.
+     * <p>
+     * If class is
+     * <ul>
+     *  <li>rpc input: local name is "input".
+     *  <li>rpc output: local name is "output".
+     *  <li>augmentation: local name is "module name".
+     * </ul>
+     *
+     * There is also fallback, if it is not possible to compute QName
+     * using following algorithm returns module QName.
+     *
+     * FIXME: Extend this algorithm to also provide QName for YANG modeled simple types.
+     *
+     * @throws IllegalStateException If YangModuleInfo could not be resolved
+     * @throws IllegalArgumentException If supplied class was not derived from YANG model.
+     *
+     */
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    private static QName computeQName(final Class key) {
+        if(isBindingClass(key)) {
+            YangModuleInfo moduleInfo;
             try {
-                Field field = key.getField(BindingMapping.QNAME_STATIC_FIELD_NAME);
-                Object obj = field.get(null);
-                if (obj instanceof QName) {
-                    return Optional.of((QName) obj);
-                }
-            } catch (NoSuchFieldException e) {
-                if (Augmentation.class.isAssignableFrom(key)) {
-                    YangModuleInfo moduleInfo = getModuleInfo(key);
-                    return Optional.of(QName.create(moduleInfo.getNamespace(), moduleInfo.getRevision(),
-                            moduleInfo.getName()));
+                moduleInfo = getModuleInfo(key);
+            } catch (Exception e) {
+                throw new IllegalStateException("Unable to get QName for " + key + ". YangModuleInfo was not found.",e);
+            }
+            final QName module = getModuleQName(moduleInfo);
+            if (Augmentation.class.isAssignableFrom(key)) {
+                return module;
+            } else if(isRpcType(key)) {
+                final String className = key.getSimpleName();
+                if(className.endsWith(BindingMapping.RPC_OUTPUT_SUFFIX)) {
+                    return QName.create(module,"output");
+                } else {
+                    return QName.create(module,"input");
                 }
-            } catch (SecurityException | IllegalArgumentException | IllegalAccessException e) {
-                /*
-                 *
-                 * It is safe to log this this exception on debug, since
-                 * this method should not fail. Only failures are possible if
-                 * the runtime / backing.
-                 *
-                 */
-                LOG.debug("Unexpected exception during extracting QName for {}",key,e);
             }
-            return Optional.absent();
+            /*
+             *  Fallback for Binding types which fo not have QNAME
+             *  field
+             */
+            return module;
+        } else {
+            throw new IllegalArgumentException("Supplied class "+key+"is not derived from YANG.");
         }
     }
+
+    public static QName getModuleQName(final YangModuleInfo moduleInfo) {
+        checkArgument(moduleInfo != null, "moduleInfo must not be null.");
+        return QName.create(moduleInfo.getNamespace(), moduleInfo.getRevision(),
+                moduleInfo.getName());
+    }
+
+
 }