2 * Copyright (c) 2015 Cisco Systems, Inc. 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.dom.spi;
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;
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;
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
34 * @param <T> registration type
35 * @author Robert Varga
37 public final class RegistrationTreeNode<T> implements Identifiable<PathArgument> {
38 private static final Logger LOG = LoggerFactory.getLogger(RegistrationTreeNode.class);
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;
46 RegistrationTreeNode(final RegistrationTreeNode<T> parent, final PathArgument identifier) {
47 this.parent = new WeakReference<>(parent);
48 this.identifier = identifier;
52 public PathArgument getIdentifier() {
57 * Return the child matching a {@link PathArgument} specification.
59 * @param arg Child identifier
60 * @return Child matching exactly, or null.
62 public RegistrationTreeNode<T> getExactChild(@Nonnull final PathArgument arg) {
63 return children.get(Preconditions.checkNotNull(arg));
67 * Return a collection children which match a {@link PathArgument} specification inexactly.
68 * This explicitly excludes the child returned by {@link #getExactChild(PathArgument)}.
70 * @param arg Child identifier
71 * @return Collection of children, guaranteed to be non-null.
73 public @Nonnull Collection<RegistrationTreeNode<T>> getInexactChildren(@Nonnull final PathArgument arg) {
74 Preconditions.checkNotNull(arg);
75 if (arg instanceof NodeWithValue || arg instanceof NodeIdentifierWithPredicates) {
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
82 final RegistrationTreeNode<T> child = children.get(new NodeIdentifier(arg.getNodeType()));
84 return Collections.emptyList();
86 return Collections.singletonList(child);
89 return Collections.emptyList();
93 public Collection<T> getRegistrations() {
94 return publicRegistrations;
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<T>(this, child);
101 children.put(child, potential);
106 void addRegistration(@Nonnull final T registration) {
107 registrations.add(Preconditions.checkNotNull(registration));
108 LOG.debug("Registration {} added", registration);
111 void removeRegistration(@Nonnull final T registration) {
112 registrations.remove(Preconditions.checkNotNull(registration));
113 LOG.debug("Registration {} removed", registration);
115 // We have been called with the write-lock held, so we can perform some cleanup.
116 removeThisIfUnused();
119 private void removeThisIfUnused() {
120 final RegistrationTreeNode<T> p = parent.get();
121 if (p != null && registrations.isEmpty() && children.isEmpty()) {
122 p.removeChild(identifier);
126 private void removeChild(final PathArgument arg) {
127 children.remove(arg);
128 removeThisIfUnused();
132 public String toString() {
133 return MoreObjects.toStringHelper(this)
134 .add("identifier", identifier)
135 .add("registrations", registrations.size())
136 .add("children", children.size()).toString();