2 * Copyright (c) 2017 Pantheon Technologies s.r.o. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.mdsal.binding.javav2.dom.codec.modification;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.annotations.Beta;
13 import java.util.ArrayList;
14 import java.util.Collection;
15 import java.util.Iterator;
16 import java.util.List;
17 import java.util.Optional;
18 import javax.annotation.Nonnull;
19 import javax.annotation.Nullable;
20 import org.opendaylight.mdsal.binding.javav2.api.TreeNodeModification;
21 import org.opendaylight.mdsal.binding.javav2.dom.codec.api.BindingTreeNodeCodec;
22 import org.opendaylight.mdsal.binding.javav2.spec.base.IdentifiableItem;
23 import org.opendaylight.mdsal.binding.javav2.spec.base.Item;
24 import org.opendaylight.mdsal.binding.javav2.spec.base.TreeArgument;
25 import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
26 import org.opendaylight.mdsal.binding.javav2.spec.structural.Augmentation;
27 import org.opendaylight.mdsal.binding.javav2.spec.structural.TreeChildNode;
28 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
29 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
30 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
35 * Lazily translated {@link TreeNodeModification} based on {@link DataTreeCandidateNode}.
38 * {@link LazyTreeNodeModification} represents Data tree change event, but whole tree is not translated or
39 * resolved eagerly, but only child nodes which are directly accessed by user of tree node modification.
42 * Type of Binding Tree Node
45 final class LazyTreeNodeModification<T extends TreeNode> implements TreeNodeModification<T> {
47 private static final Logger LOG = LoggerFactory.getLogger(LazyTreeNodeModification.class);
49 private final BindingTreeNodeCodec<T> codec;
50 private final DataTreeCandidateNode domData;
51 private final TreeArgument<?> identifier;
52 private Collection<TreeNodeModification<? extends TreeNode>> childNodesCache;
54 private LazyTreeNodeModification(final BindingTreeNodeCodec<T> codec, final DataTreeCandidateNode domData) {
55 this.codec = requireNonNull(codec);
56 this.domData = requireNonNull(domData);
57 this.identifier = codec.deserializePathArgument(domData.getIdentifier());
60 static <T extends TreeNode> TreeNodeModification<T> create(final BindingTreeNodeCodec<T> codec,
61 final DataTreeCandidateNode domData) {
62 return new LazyTreeNodeModification<>(codec, domData);
65 private static Collection<TreeNodeModification<? extends TreeNode>> from(final BindingTreeNodeCodec<?> parentCodec,
66 final Collection<DataTreeCandidateNode> domChildNodes) {
67 final List<TreeNodeModification<? extends TreeNode>> result = new ArrayList<>(domChildNodes.size());
68 populateList(result, parentCodec, domChildNodes);
72 private static void populateList(final List<TreeNodeModification<? extends TreeNode>> result,
73 final BindingTreeNodeCodec<?> parentCodec, final Collection<DataTreeCandidateNode> domChildNodes) {
74 for (final DataTreeCandidateNode domChildNode : domChildNodes) {
75 final BindingStructuralType type = BindingStructuralType.from(domChildNode);
76 if (type != BindingStructuralType.NOT_ADDRESSABLE) {
78 * Even if type is UNKNOWN, from perspective of BindingStructuralType we try to load codec for
79 * it. We will use that type to further specify debug log.
82 final BindingTreeNodeCodec<?> childCodec =
83 parentCodec.yangPathArgumentChild(domChildNode.getIdentifier());
84 populateList(result, type, childCodec, domChildNode);
85 } catch (final IllegalArgumentException e) {
86 if (type == BindingStructuralType.UNKNOWN) {
87 LOG.debug("Unable to deserialize unknown DOM node {}", domChildNode, e);
89 LOG.debug("Binding representation for DOM node {} was not found", domChildNode, e);
96 private static void populateList(final List<TreeNodeModification<? extends TreeNode>> result,
97 final BindingStructuralType type, final BindingTreeNodeCodec<?> childCodec,
98 final DataTreeCandidateNode domChildNode) {
101 // We use parent codec intentionally.
102 populateListWithSingleCodec(result, childCodec, domChildNode.getChildNodes());
104 case INVISIBLE_CONTAINER:
105 populateList(result, childCodec, domChildNode.getChildNodes());
108 case VISIBLE_CONTAINER:
109 result.add(create(childCodec, domChildNode));
115 private static void populateListWithSingleCodec(final List<TreeNodeModification<? extends TreeNode>> result,
116 final BindingTreeNodeCodec<?> codec, final Collection<DataTreeCandidateNode> childNodes) {
117 for (final DataTreeCandidateNode child : childNodes) {
118 result.add(create(codec, child));
124 public T getDataBefore() {
125 return deserialize(domData.getDataBefore());
130 public T getDataAfter() {
131 return deserialize(domData.getDataAfter());
136 public Class<T> getDataType() {
137 return codec.getBindingClass();
142 public TreeArgument<?> getIdentifier() {
148 public TreeNodeModification.ModificationType getModificationType() {
149 switch (domData.getModificationType()) {
152 return TreeNodeModification.ModificationType.WRITE;
153 case SUBTREE_MODIFIED:
154 return TreeNodeModification.ModificationType.SUBTREE_MODIFIED;
157 return TreeNodeModification.ModificationType.DELETE;
160 // TODO: Should we lie about modification type instead of exception?
161 throw new IllegalStateException("Unsupported DOM Modification type " + domData.getModificationType());
167 public Collection<TreeNodeModification<? extends TreeNode>> getModifiedChildren() {
168 if (childNodesCache == null) {
169 childNodesCache = from(codec, domData.getChildNodes());
171 return childNodesCache;
174 @SuppressWarnings("unchecked")
176 public <C extends TreeChildNode<? super T, ?>> Collection<TreeNodeModification<C>>
177 getModifiedChildren(@Nonnull final Class<C> childType) {
178 final List<TreeNodeModification<C>> children = new ArrayList<>();
179 for (final TreeNodeModification<? extends TreeNode> potential : getModifiedChildren()) {
180 if (childType.isAssignableFrom(potential.getDataType())) {
181 children.add((TreeNodeModification<C>) potential);
187 @SuppressWarnings("rawtypes")
190 public TreeNodeModification<? extends TreeNode> getModifiedChild(final TreeArgument childArgument) {
191 final List<YangInstanceIdentifier.PathArgument> domArgumentList = new ArrayList<>();
192 final BindingTreeNodeCodec<?> childCodec = codec.bindingPathArgumentChild(childArgument, domArgumentList);
193 final Iterator<YangInstanceIdentifier.PathArgument> toEnter = domArgumentList.iterator();
194 DataTreeCandidateNode current = domData;
195 while (toEnter.hasNext() && current != null) {
196 current = current.getModifiedChild(toEnter.next());
198 if (current != null) {
199 return create(childCodec, current);
204 @SuppressWarnings({ "unchecked", "rawtypes" })
206 public <C extends IdentifiableItem<T, K> & TreeChildNode<? super T, ?>, K extends IdentifiableItem<T, K>>
207 TreeNodeModification<C>
208 getModifiedChildListItem(@Nonnull final Class<C> listItem, @Nonnull final K listKey) {
209 return (TreeNodeModification) getModifiedChild(new IdentifiableItem(listItem, listKey));
212 @SuppressWarnings({ "unchecked", "rawtypes" })
215 public <C extends TreeChildNode<? super T, ?>> TreeNodeModification<C>
216 getModifiedChildContainer(@Nonnull final Class<C> child) {
217 return (TreeNodeModification<C>) getModifiedChild(new Item(child));
220 @SuppressWarnings({ "unchecked", "rawtypes" })
223 public <C extends Augmentation<T> & TreeNode> TreeNodeModification<C>
224 getModifiedAugmentation(@Nonnull final Class<C> augmentation) {
225 return (TreeNodeModification<C>) getModifiedChild(new Item(augmentation));
228 private T deserialize(final Optional<NormalizedNode<?, ?>> dataAfter) {
229 if (dataAfter.isPresent()) {
230 return codec.deserialize(dataAfter.get());