adc4636f5a226697387bfa16a6c921d76e0b54d3
[mdsal.git] / binding / mdsal-binding-dom-adapter / src / main / java / org / opendaylight / mdsal / binding / dom / adapter / LazyDataTreeModification.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.mdsal.binding.dom.adapter;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.base.MoreObjects;
13 import java.util.ArrayList;
14 import java.util.List;
15 import org.eclipse.jdt.annotation.NonNull;
16 import org.eclipse.jdt.annotation.Nullable;
17 import org.opendaylight.mdsal.binding.api.DataObjectModification;
18 import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
19 import org.opendaylight.mdsal.binding.api.DataTreeModification;
20 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
21 import org.opendaylight.mdsal.dom.api.DOMDataTreeCandidate;
22 import org.opendaylight.yangtools.yang.binding.Augmentation;
23 import org.opendaylight.yangtools.yang.binding.DataObject;
24 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
25 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
26 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeCandidate;
27
28 /**
29  * Lazily translated {@link DataTreeModification} based on {@link DataTreeCandidate}.
30  *
31  * <p>
32  * {@link DataTreeModification} represents Data tree change event, but whole tree is not translated or resolved eagerly,
33  * but only child nodes which are directly accessed by user of data object modification.
34  */
35 final class LazyDataTreeModification<T extends DataObject> implements DataTreeModification<T> {
36     private final @NonNull DataTreeIdentifier<T> path;
37     private final @NonNull DataObjectModification<T> rootNode;
38
39     private LazyDataTreeModification(final DataTreeIdentifier<T> path, final DataObjectModification<T> modification) {
40         this.path = requireNonNull(path);
41         rootNode = requireNonNull(modification);
42     }
43
44     @SuppressWarnings({"unchecked", "rawtypes"})
45     static <T extends DataObject> @Nullable DataTreeModification<T> from(final CurrentAdapterSerializer serializer,
46             final DataTreeCandidate domChange, final LogicalDatastoreType datastoreType, final Class<T> augment) {
47         final var bindingPath = createBindingPath(serializer, domChange.getRootPath(), augment);
48         final var codec = serializer.getSubtreeCodec(bindingPath);
49         final var modification = LazyDataObjectModification.from(codec, domChange.getRootNode());
50         return modification == null ? null
51             : new LazyDataTreeModification(DataTreeIdentifier.of(datastoreType, bindingPath), modification);
52     }
53
54     @SuppressWarnings({"unchecked", "rawtypes"})
55     static <T extends DataObject> @Nullable DataTreeModification<T> from(final CurrentAdapterSerializer serializer,
56             final DOMDataTreeCandidate candidate, final Class<T> augment) {
57         final var domRootPath = candidate.getRootPath();
58         final var bindingPath = createBindingPath(serializer, domRootPath.path(), augment);
59         final var codec = serializer.getSubtreeCodec(bindingPath);
60         final var modification = LazyDataObjectModification.from(codec, candidate.getRootNode());
61         return modification == null ? null
62             : new LazyDataTreeModification(DataTreeIdentifier.of(domRootPath.datastore(), bindingPath), modification);
63     }
64
65     static <T extends DataObject> @NonNull List<DataTreeModification<T>> from(final CurrentAdapterSerializer codec,
66             final List<DataTreeCandidate> domChanges, final LogicalDatastoreType datastoreType,
67             final Class<T> augment) {
68         final var result = new ArrayList<DataTreeModification<T>>(domChanges.size());
69         for (var domChange : domChanges) {
70             final var bindingChange = from(codec, domChange, datastoreType, augment);
71             if (bindingChange != null) {
72                 result.add(bindingChange);
73             }
74         }
75         return result;
76     }
77
78     // We are given a DOM path, which does not reflect augmentations, as those are not representable in NormalizedNode
79     // world. This method takes care of reconstructing the InstanceIdentifier, appending the missing Augmentation. This
80     // important to get the correct codec into the mix -- otherwise we would be operating on the parent container's
81     // codec and mis-report what is actually going on.
82     @SuppressWarnings({"unchecked", "rawtypes"})
83     private static @NonNull InstanceIdentifier<?> createBindingPath(final CurrentAdapterSerializer serializer,
84             final YangInstanceIdentifier domPath, final Class<?> augment) {
85         final var bindingPath = serializer.coerceInstanceIdentifier(domPath);
86         return augment == null ? bindingPath : bindingPath.augmentation((Class) augment.asSubclass(Augmentation.class));
87     }
88
89     @Override
90     public DataObjectModification<T> getRootNode() {
91         return rootNode;
92     }
93
94     @Override
95     public DataTreeIdentifier<T> getRootPath() {
96         return path;
97     }
98
99     @Override
100     public String toString() {
101         return MoreObjects.toStringHelper(this).add("path", path).add("rootNode", rootNode).toString();
102     }
103 }