/* * 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.util; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableSet; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.annotation.Nullable; import org.opendaylight.yangtools.concepts.Identifiable; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode; import org.opendaylight.yangtools.yang.model.api.AugmentationSchema; import org.opendaylight.yangtools.yang.model.api.AugmentationTarget; import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode; import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode; import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; 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.ListSchemaNode; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.api.SchemaNode; import org.opendaylight.yangtools.yang.model.util.EffectiveAugmentationSchema; /** * Schema derived data providing necessary information for mapping * between {@link org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode} * and serialization format defined in RFC6020, since the mapping * is not one-to-one. * * @param <T> Path Argument type * */ public abstract class DataSchemaContextNode<T extends PathArgument> implements Identifiable<T> { private final T identifier; private final DataSchemaNode dataSchemaNode; @Override public T getIdentifier() { return identifier; } protected DataSchemaContextNode(final T identifier, final SchemaNode schema) { super(); this.identifier = identifier; if (schema instanceof DataSchemaNode) { this.dataSchemaNode = (DataSchemaNode) schema; } else { this.dataSchemaNode = null; } } public boolean isMixin() { return false; } public boolean isKeyedEntry() { return false; } protected Set<QName> getQNameIdentifiers() { return Collections.singleton(identifier.getNodeType()); } @Nullable public abstract DataSchemaContextNode<?> getChild(final PathArgument child); @Nullable public abstract DataSchemaContextNode<?> getChild(QName child); public abstract boolean isLeaf(); @Nullable public DataSchemaNode getDataSchemaNode() { return dataSchemaNode; } static DataSchemaNode findChildSchemaNode(final DataNodeContainer parent, final QName child) { DataSchemaNode potential = parent.getDataChildByName(child); if (potential == null) { Iterable<ChoiceSchemaNode> choices = FluentIterable.from( parent.getChildNodes()).filter(ChoiceSchemaNode.class); potential = findChoice(choices, child); } return potential; } static DataSchemaContextNode<?> fromSchemaAndQNameChecked(final DataNodeContainer schema, final QName child) { DataSchemaNode result = findChildSchemaNode(schema, child); // We try to look up if this node was added by augmentation if (result != null && (schema instanceof DataSchemaNode) && result.isAugmenting()) { return fromAugmentation(schema, (AugmentationTarget) schema, result); } return fromDataSchemaNode(result); } private static ChoiceSchemaNode findChoice(final Iterable<ChoiceSchemaNode> choices, final QName child) { ChoiceSchemaNode foundChoice = null; choiceLoop: for (ChoiceSchemaNode choice : choices) { for (ChoiceCaseNode caze : choice.getCases()) { if (findChildSchemaNode(caze, child) != null) { foundChoice = choice; break choiceLoop; } } } return foundChoice; } public static AugmentationIdentifier augmentationIdentifierFrom(final AugmentationSchema augmentation) { ImmutableSet.Builder<QName> potentialChildren = ImmutableSet.builder(); for (DataSchemaNode child : augmentation.getChildNodes()) { potentialChildren.add(child.getQName()); } return new AugmentationIdentifier(potentialChildren.build()); } static DataNodeContainer augmentationProxy(final AugmentationSchema augmentation, final DataNodeContainer schema) { Set<DataSchemaNode> children = new HashSet<>(); for (DataSchemaNode augNode : augmentation.getChildNodes()) { children.add(schema.getDataChildByName(augNode.getQName())); } return new EffectiveAugmentationSchema(augmentation, children); } /** * Returns a DataContextNodeOperation for provided child node * * If supplied child is added by Augmentation this operation returns a * DataContextNodeOperation for augmentation, otherwise returns a * DataContextNodeOperation for child as call for * {@link #fromDataSchemaNode(DataSchemaNode)}. * * * @param parent * @param parentAug * @param child * @return */ @Nullable static DataSchemaContextNode<?> fromAugmentation(final DataNodeContainer parent, final AugmentationTarget parentAug, final DataSchemaNode child) { AugmentationSchema augmentation = null; for (AugmentationSchema aug : parentAug.getAvailableAugmentations()) { DataSchemaNode potential = aug.getDataChildByName(child.getQName()); if (potential != null) { augmentation = aug; break; } } if (augmentation != null) { return new AugmentationContextNode(augmentation, parent); } return fromDataSchemaNode(child); } @Nullable public static DataSchemaContextNode<?> fromDataSchemaNode(final DataSchemaNode potential) { if (potential instanceof ContainerSchemaNode) { return new ContainerContextNode((ContainerSchemaNode) potential); } else if (potential instanceof ListSchemaNode) { return fromListSchemaNode((ListSchemaNode) potential); } else if (potential instanceof LeafSchemaNode) { return new LeafContextNode((LeafSchemaNode) potential); } else if (potential instanceof ChoiceSchemaNode) { return new ChoiceNodeContextNode((ChoiceSchemaNode) potential); } else if (potential instanceof LeafListSchemaNode) { return fromLeafListSchemaNode((LeafListSchemaNode) potential); } else if (potential instanceof AnyXmlSchemaNode) { return new AnyXmlContextNode((AnyXmlSchemaNode) potential); } return null; } private static DataSchemaContextNode<?> fromListSchemaNode(final ListSchemaNode potential) { List<QName> keyDefinition = potential.getKeyDefinition(); if (keyDefinition == null || keyDefinition.isEmpty()) { return new UnkeyedListMixinContextNode(potential); } if (potential.isUserOrdered()) { return new OrderedMapMixinContextNode(potential); } return new UnorderedMapMixinContextNode(potential); } private static DataSchemaContextNode<?> fromLeafListSchemaNode(final LeafListSchemaNode potential) { if (potential.isUserOrdered()) { return new OrderedLeafListMixinContextNode(potential); } return new UnorderedLeafListMixinContextNode(potential); } public static DataSchemaContextNode<?> from(final SchemaContext ctx) { return new ContainerContextNode(ctx); } }