Cleanup use of Guava library
[yangtools.git] / yang / yang-data-impl / src / main / java / org / opendaylight / yangtools / yang / data / impl / schema / tree / AbstractDataTreeCandidateNode.java
1 /*
2  * Copyright (c) 2015, 2016 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.yangtools.yang.data.impl.schema.tree;
9
10 import com.google.common.base.Preconditions;
11 import com.google.common.collect.Collections2;
12 import java.util.ArrayList;
13 import java.util.Collection;
14 import java.util.Optional;
15 import javax.annotation.Nonnull;
16 import javax.annotation.Nullable;
17 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
18 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
19 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
20 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
21
22 abstract class AbstractDataTreeCandidateNode implements DataTreeCandidateNode {
23     private static Optional<NormalizedNode<?, ?>> getChild(
24             final NormalizedNodeContainer<?, PathArgument, NormalizedNode<?, ?>> container,
25                     final PathArgument identifier) {
26         return container == null ? Optional.empty() : container.getChild(identifier);
27     }
28
29     static DataTreeCandidateNode deltaChild(
30             final NormalizedNodeContainer<?, PathArgument, NormalizedNode<?, ?>> oldData,
31             final NormalizedNodeContainer<?, PathArgument, NormalizedNode<?, ?>> newData,
32             final PathArgument identifier) {
33
34         final Optional<NormalizedNode<?, ?>> maybeNewChild = getChild(newData, identifier);
35         final Optional<NormalizedNode<?, ?>> maybeOldChild = getChild(oldData, identifier);
36         if (maybeOldChild.isPresent()) {
37             final NormalizedNode<?, ?> oldChild = maybeOldChild.get();
38             if (maybeNewChild.isPresent()) {
39                 return AbstractRecursiveCandidateNode.replaceNode(oldChild, maybeNewChild.get());
40             }
41             return AbstractRecursiveCandidateNode.deleteNode(oldChild);
42         }
43
44         return maybeNewChild.isPresent() ? AbstractRecursiveCandidateNode.writeNode(maybeNewChild.get()) : null;
45     }
46
47     static Collection<DataTreeCandidateNode> deltaChildren(
48             @Nullable final NormalizedNodeContainer<?, PathArgument, NormalizedNode<?, ?>> oldData,
49             @Nullable final NormalizedNodeContainer<?, PathArgument, NormalizedNode<?, ?>> newData) {
50         Preconditions.checkArgument(newData != null || oldData != null,
51                 "No old or new data, modification type should be NONE and deltaChildren() mustn't be called.");
52         if (newData == null) {
53             return Collections2.transform(oldData.getValue(), AbstractRecursiveCandidateNode::deleteNode);
54         }
55         if (oldData == null) {
56             return Collections2.transform(newData.getValue(), AbstractRecursiveCandidateNode::writeNode);
57         }
58
59         /*
60          * This is slightly inefficient, as it requires N*F(M)+M*F(N) lookup operations, where
61          * F is dependent on the implementation of NormalizedNodeContainer.getChild().
62          *
63          * We build the return collection by iterating over new data and looking each child up
64          * in old data. Based on that we construct replaced/written nodes. We then proceed to
65          * iterate over old data and looking up each child in new data.
66          */
67         final Collection<DataTreeCandidateNode> result = new ArrayList<>();
68         for (NormalizedNode<?, ?> child : newData.getValue()) {
69             final DataTreeCandidateNode node;
70             final Optional<NormalizedNode<?, ?>> maybeOldChild = oldData.getChild(child.getIdentifier());
71
72             if (maybeOldChild.isPresent()) {
73                 // This does not find children which have not in fact been modified, as doing that
74                 // reliably would require us running a full equals() on the two nodes.
75                 node = AbstractRecursiveCandidateNode.replaceNode(maybeOldChild.get(), child);
76             } else {
77                 node = AbstractRecursiveCandidateNode.writeNode(child);
78             }
79
80             result.add(node);
81         }
82
83         // Process removals next, looking into new data to see if we processed it
84         for (NormalizedNode<?, ?> child : oldData.getValue()) {
85             if (!newData.getChild(child.getIdentifier()).isPresent()) {
86                 result.add(AbstractRecursiveCandidateNode.deleteNode(child));
87             }
88         }
89
90         return result;
91     }
92
93     private final NormalizedNodeContainer<?, PathArgument, NormalizedNode<?,?>> data;
94
95     protected AbstractDataTreeCandidateNode(final NormalizedNodeContainer<?, PathArgument, NormalizedNode<?, ?>> data) {
96         this.data = Preconditions.checkNotNull(data);
97     }
98
99     protected final Optional<NormalizedNode<?, ?>> dataOptional() {
100         return Optional.of(data);
101     }
102
103     @Override
104     @Nonnull
105     public final PathArgument getIdentifier() {
106         return data.getIdentifier();
107     }
108
109     protected final NormalizedNodeContainer<?, PathArgument, NormalizedNode<?, ?>> getData() {
110         return data;
111     }
112
113     @Override
114     public String toString() {
115         return this.getClass().getSimpleName() + "{data = " + this.data + "}";
116     }
117 }