+ final Iterable<QName> schemaNodePath = actualSchemaNode.getPath().getPathFromRoot();
+
+ if (Iterables.size(schemaNodePath) - colCount >= 0) {
+ return Iterables.concat(Iterables.limit(schemaNodePath, Iterables.size(schemaNodePath) - colCount),
+ Iterables.transform(Iterables.skip(xpaths, colCount), new Function<String, QName>() {
+ @Override
+ public QName apply(final String input) {
+ return stringPathPartToQName(context, module, input);
+ }
+ }));
+ }
+ return Iterables.concat(schemaNodePath,
+ Iterables.transform(Iterables.skip(xpaths, colCount), new Function<String, QName>() {
+ @Override
+ public QName apply(final String input) {
+ return stringPathPartToQName(context, module, input);
+ }
+ }));
+ }
+
+ /**
+ * Extracts the base type of node on which schema node points to. If target node is again of type LeafrefTypeDefinition, methods will be call recursively until it reach concrete
+ * type definition.
+ *
+ * @param typeDefinition
+ * type of node which will be extracted
+ * @param schemaContext
+ * Schema Context
+ * @param schema
+ * Schema Node
+ * @return recursively found type definition this leafref is pointing to or null if the xpath is incorrect (null is there to preserve backwards compatibility)
+ */
+ public static TypeDefinition<?> getBaseTypeForLeafRef(final LeafrefTypeDefinition typeDefinition, final SchemaContext schemaContext, final SchemaNode schema) {
+ RevisionAwareXPath pathStatement = typeDefinition.getPathStatement();
+ pathStatement = new RevisionAwareXPathImpl(stripConditionsFromXPathString(pathStatement), pathStatement.isAbsolute());
+
+ final DataSchemaNode dataSchemaNode;
+ if (pathStatement.isAbsolute()) {
+ SchemaNode baseSchema = schema;
+ while (baseSchema instanceof DerivableSchemaNode) {
+ final Optional<? extends SchemaNode> basePotential = ((DerivableSchemaNode) baseSchema).getOriginal();
+ if (basePotential.isPresent()) {
+ baseSchema = basePotential.get();
+ } else {
+ break;
+ }
+ }
+
+ Module parentModule = findParentModuleOfReferencingType(schemaContext, baseSchema);
+ dataSchemaNode = (DataSchemaNode) SchemaContextUtil.findDataSchemaNode(schemaContext, parentModule,
+ pathStatement);
+ } else {
+ Module parentModule = findParentModule(schemaContext, schema);
+ dataSchemaNode = (DataSchemaNode) SchemaContextUtil.findDataSchemaNodeForRelativeXPath(schemaContext,
+ parentModule, schema, pathStatement);
+ }
+
+ // FIXME this is just to preserve backwards compatibility since yangtools do not mind wrong leafref xpaths
+ // and current expected behaviour for such cases is to just use pure string
+ // This should throw an exception about incorrect XPath in leafref
+ if(dataSchemaNode == null) {
+ return null;
+ }
+
+ final TypeDefinition<?> targetTypeDefinition = typeDefinition(dataSchemaNode);
+
+ if(targetTypeDefinition instanceof LeafrefTypeDefinition) {
+ return getBaseTypeForLeafRef(((LeafrefTypeDefinition) targetTypeDefinition), schemaContext, dataSchemaNode);
+ } else {
+ return targetTypeDefinition;
+ }
+ }
+
+ private static Module findParentModuleOfReferencingType(final SchemaContext schemaContext,
+ final SchemaNode schemaNode) {
+ Preconditions.checkArgument(schemaContext != null, "Schema Context reference cannot be NULL!");
+ Preconditions.checkArgument(schemaNode != null, "Schema Node cannot be NULL!");
+ TypeDefinition<?> nodeType = null;
+
+ if (schemaNode instanceof LeafSchemaNode) {
+ nodeType = ((LeafSchemaNode) schemaNode).getType();
+ } else if (schemaNode instanceof LeafListSchemaNode) {
+ nodeType = ((LeafListSchemaNode) schemaNode).getType();
+ }
+
+ if (nodeType.getBaseType() != null) {
+ while (nodeType.getBaseType() != null) {
+ nodeType = nodeType.getBaseType();
+ }
+
+ final QNameModule typeDefModuleQname = nodeType.getQName().getModule();
+ return schemaContext.findModuleByNamespaceAndRevision(typeDefModuleQname.getNamespace(),
+ typeDefModuleQname.getRevision());
+ }
+
+ return SchemaContextUtil.findParentModule(schemaContext, schemaNode);
+ }
+
+ /**
+ * @deprecated due to expensive lookup
+ * Returns parent Yang Module for specified Schema Context in which Schema
+ * Node is declared. If Schema Node is of type 'ExtendedType' it tries to find parent module
+ * in which the type was originally declared (needed for correct leafref path resolution). <br>
+ * If the Schema Node is not present in Schema Context the
+ * operation will return <code>null</code>. <br>
+ * If Schema Context or Schema Node contains <code>null</code> references
+ * the method will throw IllegalArgumentException
+ *
+ * @throws IllegalArgumentException
+ *
+ * @param schemaContext
+ * Schema Context
+ * @param schemaNode
+ * Schema Node
+ * @return Yang Module for specified Schema Context and Schema Node, if
+ * Schema Node is NOT present, the method will returns
+ * <code>null</code>
+ */
+ @Deprecated
+ public static Module findParentModuleByType(final SchemaContext schemaContext, final SchemaNode schemaNode) {
+ Preconditions.checkArgument(schemaContext != null, "Schema Context reference cannot be NULL!");
+ Preconditions.checkArgument(schemaNode != null, "Schema Node cannot be NULL!");
+ TypeDefinition<?> nodeType = null;
+
+ if (schemaNode instanceof LeafSchemaNode) {
+ nodeType = ((LeafSchemaNode) schemaNode).getType();
+ } else if (schemaNode instanceof LeafListSchemaNode) {
+ nodeType = ((LeafListSchemaNode) schemaNode).getType();
+ }
+
+ if (!BaseTypes.isYangBuildInType(nodeType) && nodeType.getBaseType() != null) {
+ while (nodeType.getBaseType() != null && !BaseTypes.isYangBuildInType(nodeType.getBaseType())) {
+ nodeType = nodeType.getBaseType();