Mechanical code cleanup (sal-dom-spi)
[controller.git] / opendaylight / md-sal / sal-dom-spi / src / main / java / org / opendaylight / controller / md / sal / dom / spi / RegistrationTreeNode.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.controller.md.sal.dom.spi;
9
10 import com.google.common.base.MoreObjects;
11 import com.google.common.base.Preconditions;
12 import java.lang.ref.Reference;
13 import java.lang.ref.WeakReference;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.Collections;
17 import java.util.HashMap;
18 import java.util.Map;
19 import javax.annotation.Nonnull;
20 import org.opendaylight.yangtools.concepts.Identifiable;
21 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
22 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
23 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
24 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
27
28 /**
29  * This is a single node within the registration tree. Note that the data returned from
30  * and instance of this class is guaranteed to have any relevance or consistency
31  * only as long as the {@link RegistrationTreeSnapshot} instance through which it is reached
32  * remains unclosed.
33  *
34  * @param <T> registration type
35  * @author Robert Varga
36  */
37 public final class RegistrationTreeNode<T> implements Identifiable<PathArgument> {
38     private static final Logger LOG = LoggerFactory.getLogger(RegistrationTreeNode.class);
39
40     private final Map<PathArgument, RegistrationTreeNode<T>> children = new HashMap<>();
41     private final Collection<T> registrations = new ArrayList<>(2);
42     private final Collection<T> publicRegistrations = Collections.unmodifiableCollection(registrations);
43     private final Reference<RegistrationTreeNode<T>> parent;
44     private final PathArgument identifier;
45
46     RegistrationTreeNode(final RegistrationTreeNode<T> parent, final PathArgument identifier) {
47         this.parent = new WeakReference<>(parent);
48         this.identifier = identifier;
49     }
50
51     @Override
52     public PathArgument getIdentifier() {
53         return identifier;
54     }
55
56     /**
57      * Return the child matching a {@link PathArgument} specification.
58      *
59      * @param arg Child identifier
60      * @return Child matching exactly, or null.
61      */
62     public RegistrationTreeNode<T> getExactChild(@Nonnull final PathArgument arg) {
63         return children.get(Preconditions.checkNotNull(arg));
64     }
65
66     /**
67      * Return a collection children which match a {@link PathArgument} specification inexactly.
68      * This explicitly excludes the child returned by {@link #getExactChild(PathArgument)}.
69      *
70      * @param arg Child identifier
71      * @return Collection of children, guaranteed to be non-null.
72      */
73     public @Nonnull Collection<RegistrationTreeNode<T>> getInexactChildren(@Nonnull final PathArgument arg) {
74         Preconditions.checkNotNull(arg);
75         if (arg instanceof NodeWithValue || arg instanceof NodeIdentifierWithPredicates) {
76             /*
77              * TODO: This just all-or-nothing wildcards, which we have historically supported. Given
78              *       that the argument is supposed to have all the elements filled out, we could support
79              *       partial wildcards by iterating over the registrations and matching the maps for
80              *       partial matches.
81              */
82             final RegistrationTreeNode<T> child = children.get(new NodeIdentifier(arg.getNodeType()));
83             if (child == null) {
84                 return Collections.emptyList();
85             } else {
86                 return Collections.singletonList(child);
87             }
88         } else {
89             return Collections.emptyList();
90         }
91     }
92
93     public Collection<T> getRegistrations() {
94         return publicRegistrations;
95     }
96
97     RegistrationTreeNode<T> ensureChild(@Nonnull final PathArgument child) {
98         RegistrationTreeNode<T> potential = children.get(Preconditions.checkNotNull(child));
99         if (potential == null) {
100             potential = new RegistrationTreeNode<>(this, child);
101             children.put(child, potential);
102         }
103         return potential;
104     }
105
106     void addRegistration(@Nonnull final T registration) {
107         registrations.add(Preconditions.checkNotNull(registration));
108         LOG.debug("Registration {} added", registration);
109     }
110
111     void removeRegistration(@Nonnull final T registration) {
112         registrations.remove(Preconditions.checkNotNull(registration));
113         LOG.debug("Registration {} removed", registration);
114
115         // We have been called with the write-lock held, so we can perform some cleanup.
116         removeThisIfUnused();
117     }
118
119     private void removeThisIfUnused() {
120         final RegistrationTreeNode<T> p = parent.get();
121         if (p != null && registrations.isEmpty() && children.isEmpty()) {
122             p.removeChild(identifier);
123         }
124     }
125
126     private void removeChild(final PathArgument arg) {
127         children.remove(arg);
128         removeThisIfUnused();
129     }
130
131     @Override
132     public String toString() {
133         return MoreObjects.toStringHelper(this)
134                 .add("identifier", identifier)
135                 .add("registrations", registrations.size())
136                 .add("children", children.size()).toString();
137     }
138 }