Remove @(Not)ThreadSafe annotation
[mdsal.git] / dom / mdsal-dom-spi / src / main / java / org / opendaylight / mdsal / dom / spi / DOMDataTreePrefixTableEntry.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.dom.spi;
9
10 import static com.google.common.base.Preconditions.checkState;
11 import static java.util.Objects.requireNonNull;
12
13 import com.google.common.annotations.Beta;
14 import java.util.HashMap;
15 import java.util.Iterator;
16 import java.util.Map;
17 import org.opendaylight.yangtools.concepts.Identifiable;
18 import org.opendaylight.yangtools.concepts.Mutable;
19 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
20 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
23
24 /**
25  * An entry in DOMDataTreePrefixTable. This class is not thread-safe.
26  */
27 @Beta
28 public final class DOMDataTreePrefixTableEntry<V> implements Identifiable<PathArgument>, Mutable {
29     private static final Logger LOG = LoggerFactory.getLogger(DOMDataTreePrefixTableEntry.class);
30     // FIXME: We do probably want to adapt map
31     private final Map<PathArgument, DOMDataTreePrefixTableEntry<V>> children = new HashMap<>();
32     private final PathArgument identifier;
33     private V value;
34
35     DOMDataTreePrefixTableEntry() {
36         identifier = null;
37     }
38
39     DOMDataTreePrefixTableEntry(final PathArgument identifier) {
40         this.identifier = requireNonNull(identifier);
41     }
42
43     @Override
44     public PathArgument getIdentifier() {
45         return identifier;
46     }
47
48     public V getValue() {
49         return value;
50     }
51
52     DOMDataTreePrefixTableEntry<V> lookup(final YangInstanceIdentifier id) {
53         final Iterator<PathArgument> it = id.getPathArguments().iterator();
54         DOMDataTreePrefixTableEntry<V> entry = this;
55         DOMDataTreePrefixTableEntry<V> lastPresentEntry = entry.getValue() != null ? entry : null;
56
57         while (it.hasNext()) {
58             final PathArgument a = it.next();
59             final DOMDataTreePrefixTableEntry<V> child = entry.children.get(a);
60             if (child == null) {
61                 LOG.debug("Lookup of {} stopped at {}", id, a);
62                 break;
63             }
64
65             entry = child;
66
67             if (child.getValue() != null) {
68                 lastPresentEntry = child;
69             }
70         }
71
72         return lastPresentEntry;
73     }
74
75     void store(final YangInstanceIdentifier id, final V reg) {
76         final Iterator<PathArgument> it = id.getPathArguments().iterator();
77         DOMDataTreePrefixTableEntry<V> entry = this;
78
79         while (it.hasNext()) {
80             final PathArgument a = it.next();
81             DOMDataTreePrefixTableEntry<V> child = entry.children.get(a);
82             if (child == null) {
83                 child = new DOMDataTreePrefixTableEntry<>(a);
84                 entry.children.put(a, child);
85             }
86             // TODO: Is this correct? We want to enter child
87             entry = child;
88         }
89
90         checkState(entry.value == null);
91         entry.value = reg;
92     }
93
94     private boolean remove(final Iterator<PathArgument> it) {
95         if (it.hasNext()) {
96             final PathArgument arg = it.next();
97             final DOMDataTreePrefixTableEntry<V> child = children.get(arg);
98             if (child != null) {
99                 if (child.remove(it)) {
100                     children.remove(arg);
101                 }
102             } else {
103                 LOG.warn("Cannot remove non-existent child {}", arg);
104             }
105         } else {
106             /*
107              * Iterator is empty, this effectively means is table entry to remove registration.
108              * FIXME: We probably want to compare value to make sure we are removing correct value.
109              */
110             value = null;
111         }
112         return value == null && children.isEmpty();
113     }
114
115     void remove(final YangInstanceIdentifier id) {
116         this.remove(id.getPathArguments().iterator());
117     }
118 }