/** * Copyright (c) 2015 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.yangtools.yang.data.impl.leafref; import java.io.ByteArrayInputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.Collection; import java.util.LinkedList; import java.util.List; import java.util.Set; import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode; import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode; import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.api.TypeDefinition; import org.opendaylight.yangtools.yang.model.api.TypedSchemaNode; import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition; class LeafRefContextTreeBuilder { private final SchemaContext schemaContext; private final List<LeafRefContext> leafRefs; public LeafRefContextTreeBuilder(final SchemaContext schemaContext) { this.schemaContext = schemaContext; this.leafRefs = new LinkedList<>(); } public LeafRefContext buildLeafRefContextTree() throws IOException, LeafRefYangSyntaxErrorException { final LeafRefContextBuilder rootBuilder = new LeafRefContextBuilder( schemaContext.getQName(), schemaContext.getPath(), schemaContext); final Set<Module> modules = schemaContext.getModules(); for (final Module module : modules) { final Collection<DataSchemaNode> childNodes = module.getChildNodes(); for (final DataSchemaNode childNode : childNodes) { final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree( childNode, module); if (childLeafRefContext.hasReferencingChild() || childLeafRefContext.isReferencing()) { rootBuilder.addReferencingChild(childLeafRefContext, childLeafRefContext.getNodeName()); } } } for (final Module module : modules) { final Collection<DataSchemaNode> childNodes = module.getChildNodes(); for (final DataSchemaNode childNode : childNodes) { final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree( childNode, module); if (childLeafRefContext.hasReferencedChild() || childLeafRefContext.isReferenced()) { rootBuilder.addReferencedByChild(childLeafRefContext, childLeafRefContext.getNodeName()); } } } // FIXME: it might be useful to merge these subtrees (i.e. referencing // and referencedBy subtree) return rootBuilder.build(); } private LeafRefContext buildLeafRefContextReferencingTree( final DataSchemaNode node, final Module currentModule) throws IOException, LeafRefYangSyntaxErrorException { final LeafRefContextBuilder currentLeafRefContextBuilder = new LeafRefContextBuilder( node.getQName(), node.getPath(), schemaContext); if (node instanceof DataNodeContainer) { final DataNodeContainer dataNodeContainer = (DataNodeContainer) node; final Collection<DataSchemaNode> childNodes = dataNodeContainer .getChildNodes(); for (final DataSchemaNode childNode : childNodes) { final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree( childNode, currentModule); if (childLeafRefContext.hasReferencingChild() || childLeafRefContext.isReferencing()) { currentLeafRefContextBuilder.addReferencingChild( childLeafRefContext, childLeafRefContext.getNodeName()); } } } else if (node instanceof ChoiceSchemaNode) { final ChoiceSchemaNode choice = (ChoiceSchemaNode) node; final Set<ChoiceCaseNode> cases = choice.getCases(); // :FIXME choice without case for (final ChoiceCaseNode caseNode : cases) { final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree( caseNode, currentModule); if (childLeafRefContext.hasReferencingChild() || childLeafRefContext.isReferencing()) { currentLeafRefContextBuilder.addReferencingChild( childLeafRefContext, childLeafRefContext.getNodeName()); } } } else if (node instanceof TypedSchemaNode) { final TypeDefinition<?> type = ((TypedSchemaNode) node).getType(); // FIXME: fix case when type is e.g. typedef -> typedef -> leafref if (type instanceof LeafrefTypeDefinition) { final LeafrefTypeDefinition leafrefType = (LeafrefTypeDefinition) type; final String leafRefPathString = leafrefType.getPathStatement().toString(); currentLeafRefContextBuilder.setLeafRefTargetPathString(leafRefPathString); currentLeafRefContextBuilder.setReferencing(true); final LeafRefPathParserImpl leafRefPathParser = new LeafRefPathParserImpl( schemaContext, currentModule, node); final LeafRefPath leafRefPath = leafRefPathParser.parseLeafRefPathSourceToSchemaPath( new ByteArrayInputStream(leafRefPathString.getBytes(StandardCharsets.UTF_8))); currentLeafRefContextBuilder.setLeafRefTargetPath(leafRefPath); final LeafRefContext currentLeafRefContext = currentLeafRefContextBuilder.build(); leafRefs.add(currentLeafRefContext); return currentLeafRefContext; } } return currentLeafRefContextBuilder.build(); } private LeafRefContext buildLeafRefContextReferencedByTree( final DataSchemaNode node, final Module currentModule) throws IOException, LeafRefYangSyntaxErrorException { final LeafRefContextBuilder currentLeafRefContextBuilder = new LeafRefContextBuilder( node.getQName(), node.getPath(), schemaContext); if (node instanceof DataNodeContainer) { final DataNodeContainer dataNodeContainer = (DataNodeContainer) node; final Collection<DataSchemaNode> childNodes = dataNodeContainer .getChildNodes(); for (final DataSchemaNode childNode : childNodes) { final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree( childNode, currentModule); if (childLeafRefContext.hasReferencedChild() || childLeafRefContext.isReferenced()) { currentLeafRefContextBuilder.addReferencedByChild( childLeafRefContext, childLeafRefContext.getNodeName()); } } } else if (node instanceof ChoiceSchemaNode) { final ChoiceSchemaNode choice = (ChoiceSchemaNode) node; final Set<ChoiceCaseNode> cases = choice.getCases(); for (final ChoiceCaseNode caseNode : cases) { final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree( caseNode, currentModule); if (childLeafRefContext.hasReferencedChild() || childLeafRefContext.isReferenced()) { currentLeafRefContextBuilder.addReferencedByChild( childLeafRefContext, childLeafRefContext.getNodeName()); } } } else if (node instanceof LeafSchemaNode || node instanceof LeafListSchemaNode) { final List<LeafRefContext> foundLeafRefs = getLeafRefsFor(node, currentModule); if (!foundLeafRefs.isEmpty()) { currentLeafRefContextBuilder.setReferencedBy(true); for (final LeafRefContext leafRef : foundLeafRefs) { currentLeafRefContextBuilder.addReferencedByLeafRefCtx( leafRef.getNodeName(), leafRef); } } } return currentLeafRefContextBuilder.build(); } private List<LeafRefContext> getLeafRefsFor(final DataSchemaNode node, final Module module) { final LeafRefPath nodeXPath = LeafRefUtils.schemaPathToLeafRefPath( node.getPath(), module); final List<LeafRefContext> foundLeafRefs = new LinkedList<>(); for (final LeafRefContext leafref : leafRefs) { final LeafRefPath leafRefTargetPath = leafref .getAbsoluteLeafRefTargetPath(); if (leafRefTargetPath.equals(nodeXPath)) { foundLeafRefs.add(leafref); } } return foundLeafRefs; } }