Fixed implementation of TypeProviderImpl for Leafref resolving.
[controller.git] / opendaylight / sal / yang-prototype / code-generator / binding-generator-impl / src / main / java / org / opendaylight / controller / sal / binding / yang / types / TypeProviderImpl.java
index 2cc774ac83f3e1b94bfca4417031ecde18f8e692..bb5e80a5257e0153d9ccc24384f319381744eb50 100644 (file)
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.\r
- *\r
- * This program and the accompanying materials are made available under the\r
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
- * and is available at http://www.eclipse.org/legal/epl-v10.html\r
- */\r
-package org.opendaylight.controller.sal.binding.yang.types;\r
-\r
-import org.opendaylight.controller.sal.binding.generator.spi.TypeProvider;\r
-import org.opendaylight.controller.sal.binding.model.api.Type;\r
-import org.opendaylight.controller.yang.model.api.TypeDefinition;\r
-\r
-public class TypeProviderImpl implements TypeProvider {\r
-\r
-    /*\r
-     * (non-Javadoc)\r
-     * \r
-     * @see org.opendaylight.controller.yang.model.type.provider.TypeProvider#\r
-     * javaTypeForYangType(java.lang.String)\r
-     */\r
-    @Override\r
-    public Type javaTypeForYangType(String type) {\r
-        Type t = BaseYangTypes.BASE_YANG_TYPES_PROVIDER\r
-                .javaTypeForYangType(type);\r
-        // TODO: this needs to be implemented in better way\r
-        // if(t == null) {\r
-        // t = BaseYangTypes.IETF_INET_TYPES_PROVIDER.javaTypeForYangType(type);\r
-        // }\r
-        return t;\r
-    }\r
-\r
-    @Override\r
-    public Type javaTypeForSchemaDefinitionType(final TypeDefinition<?> type) {\r
-        if (type != null) {\r
-            Type t = BaseYangTypes.BASE_YANG_TYPES_PROVIDER\r
-                    .javaTypeForSchemaDefinitionType(type);\r
-\r
-            if (t != null) {\r
-                return t;\r
-            }\r
-        }\r
-        return null;\r
-    }\r
-}\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.binding.yang.types;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+import java.util.Set;
+
+import org.opendaylight.controller.binding.generator.util.Types;
+import org.opendaylight.controller.sal.binding.generator.spi.TypeProvider;
+import org.opendaylight.controller.sal.binding.model.api.Type;
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.controller.yang.model.api.DataNodeContainer;
+import org.opendaylight.controller.yang.model.api.DataSchemaNode;
+import org.opendaylight.controller.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.controller.yang.model.api.LeafSchemaNode;
+import org.opendaylight.controller.yang.model.api.ListSchemaNode;
+import org.opendaylight.controller.yang.model.api.Module;
+import org.opendaylight.controller.yang.model.api.ModuleImport;
+import org.opendaylight.controller.yang.model.api.RevisionAwareXPath;
+import org.opendaylight.controller.yang.model.api.SchemaContext;
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.TypeDefinition;
+import org.opendaylight.controller.yang.model.api.type.IdentityrefTypeDefinition;
+import org.opendaylight.controller.yang.model.api.type.LeafrefTypeDefinition;
+import org.opendaylight.controller.yang.model.util.ExtendedType;
+import org.opendaylight.controller.yang.model.util.Leafref;
+
+public class TypeProviderImpl implements TypeProvider {
+
+    private SchemaContext schemaContext;
+
+    public TypeProviderImpl(SchemaContext schemaContext) {
+        this.schemaContext = schemaContext;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.opendaylight.controller.yang.model.type.provider.TypeProvider#
+     * javaTypeForYangType(java.lang.String)
+     */
+    @Override
+    public Type javaTypeForYangType(String type) {
+        Type t = BaseYangTypes.BASE_YANG_TYPES_PROVIDER
+                .javaTypeForYangType(type);
+        return t;
+    }
+
+    @Override
+    public Type javaTypeForSchemaDefinitionType(final TypeDefinition<?> typeDefinition) {
+        Type returnType = null;
+        if (typeDefinition != null) {
+            if (typeDefinition instanceof Leafref) {
+                final LeafrefTypeDefinition leafref = (LeafrefTypeDefinition) typeDefinition;
+                returnType = provideTypeForLeafref(leafref);
+            } else if (typeDefinition instanceof IdentityrefTypeDefinition) {
+
+            } else if (typeDefinition instanceof ExtendedType) {
+                final TypeDefinition<?> baseType = typeDefinition.getBaseType(); 
+                return javaTypeForSchemaDefinitionType(baseType);
+            }
+            else {
+                returnType = baseTypeForExtendedType(typeDefinition);
+            }
+        }
+        return returnType;
+    }
+    
+    public Type baseTypeForExtendedType(final TypeDefinition<?> typeDefinition) {
+        Type returnType = null;
+        if (typeDefinition != null) {
+            if (typeDefinition instanceof ExtendedType) {
+                final TypeDefinition<?> extType = typeDefinition.getBaseType(); 
+                return baseTypeForExtendedType(extType);
+            } else {
+                returnType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER
+                        .javaTypeForSchemaDefinitionType(typeDefinition);
+            }
+        }
+        return returnType;
+    }
+    
+    public Type provideTypeForLeafref(final LeafrefTypeDefinition leafrefType) {
+        Type returnType = null;
+        if ((leafrefType != null) && (leafrefType.getPathStatement() != null)
+                && (leafrefType.getPath() != null)) {
+
+            final RevisionAwareXPath xpath = leafrefType.getPathStatement();
+            final String strXPath = xpath.toString();
+
+            if (strXPath != null) {
+                if (strXPath.matches(".*//[.* | .*//].*")) {
+                    returnType = Types.typeForClass(Object.class);
+                } else {
+                    final Module module = resolveModuleFromSchemaPath(leafrefType
+                            .getPath());
+                    if (module != null) {
+                        Queue<String> leafrefPath;
+                        if (!xpath.isAbsolute()) {
+                            leafrefPath = resolveRelativeXPath(xpath,
+                                    leafrefType.getPath());
+                        } else {
+                            leafrefPath = xpathToPrefixedPath(strXPath,
+                                    module.getName());
+                        }
+                        if (leafrefPath != null) {
+                            final DataSchemaNode dataNode = findSchemaNodeForGivenPath(
+                                    module, leafrefPath);
+                            returnType = resolveTypeFromDataSchemaNode(dataNode);
+                        }
+                    }
+                }
+            }
+        }
+        return returnType;
+    }
+
+    private Type resolveTypeFromDataSchemaNode(final DataSchemaNode dataNode) {
+        Type returnType = null;
+        if (dataNode != null) {
+            if (dataNode instanceof LeafSchemaNode) {
+                final LeafSchemaNode leaf = (LeafSchemaNode) dataNode;
+                returnType = javaTypeForSchemaDefinitionType(leaf.getType());
+            } else if (dataNode instanceof LeafListSchemaNode) {
+                final LeafListSchemaNode leafList = (LeafListSchemaNode) dataNode;
+                returnType = javaTypeForSchemaDefinitionType(leafList.getType());
+            }
+        }
+        return returnType;
+    }
+
+    /**
+     * Search which starts from root of Module.
+     * 
+     * @param module
+     * @param prefixedPath
+     * @return
+     */
+    private DataSchemaNode findSchemaNodeForGivenPath(final Module module,
+            final Queue<String> prefixedPath) {
+        if ((module != null) && (prefixedPath != null)) {
+            DataNodeContainer nextContainer = module;
+            final String modulePrefix = module.getPrefix();
+            
+            String childNodeName = null;
+            DataSchemaNode schemaNode = null;
+            while ((nextContainer != null) && (prefixedPath.size() > 0)) {
+                childNodeName = prefixedPath.poll();
+                if (childNodeName.contains(":")) {
+                    final String[] prefixedChildNode = childNodeName.split(":");
+                    if ((modulePrefix != null)
+                            && modulePrefix.equals(prefixedChildNode[0])) {
+
+                        childNodeName = prefixedChildNode[1];
+                    } else {
+                        final Module nextModule = resolveModuleForPrefix(
+                                prefixedChildNode[0], module);
+                        final Queue<String> nextModulePrefixedPath = new LinkedList<String>();
+                        nextModulePrefixedPath.add(childNodeName);
+                        nextModulePrefixedPath.addAll(prefixedPath);
+                        prefixedPath.clear();
+
+                        schemaNode = findSchemaNodeForGivenPath(nextModule,
+                                nextModulePrefixedPath);
+
+                        return schemaNode;
+                    }
+                }
+
+                schemaNode = nextContainer.getDataChildByName(childNodeName);
+                if (schemaNode instanceof ContainerSchemaNode) {
+                    nextContainer = (ContainerSchemaNode) schemaNode;
+                } else if (schemaNode instanceof ListSchemaNode) {
+                    nextContainer = (ListSchemaNode) schemaNode;
+                } else {
+                    return schemaNode;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    private Module resolveModuleFromSchemaPath(final SchemaPath schemaPath) {
+        if ((schemaPath != null) && (schemaPath.getPath() != null)) {
+            final QName qname = schemaPath.getPath().get(0);
+
+            if ((qname != null) && (qname.getNamespace() != null)) {
+                return schemaContext
+                        .findModuleByNamespace(qname.getNamespace());
+            }
+        }
+        return null;
+    }
+
+    private Queue<String> xpathToPrefixedPath(final String xpath,
+            final String moduleName) {
+        final Queue<String> retQueue = new LinkedList<String>();
+        if ((xpath != null) && (moduleName != null)) {
+            final String[] prefixedPath = xpath.split("/");
+
+            if (prefixedPath != null) {
+                for (int i = 0; i < prefixedPath.length; ++i) {
+                    if (!prefixedPath[i].isEmpty()) {
+                        retQueue.add(prefixedPath[i]);
+                    }
+                }
+            }
+        }
+        return retQueue;
+    }
+
+    private Module resolveModuleForPrefix(final String prefix,
+            final Module parent) {
+        if ((prefix != null) && (parent != null)) {
+            final Set<ModuleImport> imports = parent.getImports();
+
+            if (imports != null) {
+                for (final ModuleImport impModule : imports) {
+                    final String impModPrefix = impModule.getPrefix();
+                    if ((impModPrefix != null) && prefix.equals(impModPrefix)) {
+                        return resolveModuleFromContext(prefix,
+                                impModule.getModuleName());
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    private Module resolveModuleFromContext(final String prefix,
+            final String moduleName) {
+        final Set<Module> modules = schemaContext.getModules();
+
+        if ((prefix != null) && (moduleName != null) && (modules != null)) {
+            for (Module module : modules) {
+                if ((module != null) && prefix.equals(module.getPrefix())
+                        && moduleName.equals(module.getName())) {
+                    return module;
+                }
+            }
+        }
+        return null;
+    }
+
+    private Queue<String> resolveRelativeXPath(
+            final RevisionAwareXPath relativeXPath,
+            final SchemaPath leafrefSchemaPath) {
+        final Queue<String> absolutePath = new LinkedList<String>();
+
+        if ((relativeXPath != null) && !relativeXPath.isAbsolute()
+                && (leafrefSchemaPath != null)) {
+            final String strXPath = relativeXPath.toString();
+            if (strXPath != null) {
+                final String[] xpaths = strXPath.split("/");
+
+                if (xpaths != null) {
+                    int colCount = 0;
+                    while (xpaths[colCount].contains("..")) {
+                        ++colCount;
+                    }
+                    final List<QName> path = leafrefSchemaPath.getPath();
+                    if (path != null) {
+                        int lenght = path.size() - colCount;
+                        for (int i = 0; i < lenght; ++i) {
+                            absolutePath.add(path.get(i).getLocalName());
+                        }
+                        for (int i = colCount; i < xpaths.length; ++i) {
+                            absolutePath.add(xpaths[i]);
+                        }
+                    }
+                }
+            }
+        }
+        return absolutePath;
+    }
+}