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.yangtools.yang.data.tree.leafref;
10 import static com.google.common.base.Preconditions.checkArgument;
12 import com.google.common.annotations.Beta;
13 import com.google.common.collect.ImmutableMap;
14 import java.util.ArrayList;
15 import java.util.Iterator;
16 import java.util.List;
18 import java.util.Map.Entry;
19 import org.opendaylight.yangtools.yang.common.QName;
20 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
21 import org.opendaylight.yangtools.yang.model.api.Module;
22 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
23 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
24 import org.opendaylight.yangtools.yang.model.spi.AbstractEffectiveModelContextProvider;
26 public final class LeafRefContext extends AbstractEffectiveModelContextProvider {
28 private final QName currentNodeQName;
29 private final SchemaPath currentNodePath;
30 private final Module module;
32 private final LeafRefPath leafRefTargetPath;
33 private final LeafRefPath absoluteLeafRefTargetPath;
34 private final String leafRefTargetPathString;
36 private final boolean isReferencedBy;
37 private final boolean isReferencing;
39 private final ImmutableMap<QName, LeafRefContext> referencingChilds;
40 private final ImmutableMap<QName, LeafRefContext> referencedByChilds;
41 private final ImmutableMap<QName, LeafRefContext> referencedByLeafRefCtx;
43 // FIXME: this looks like it's related to absoluteLeafRefTargetPath, but the original use in LeafRefValidation
44 // fast path did not make it clear. Analyze the relationship between this field and
45 // absoluteLeafRefTargetPath.
46 private volatile LeafRefPath leafRefNodePath = null;
48 LeafRefContext(final LeafRefContextBuilder leafRefContextBuilder) {
49 super(leafRefContextBuilder.getSchemaContext());
50 this.currentNodeQName = leafRefContextBuilder.getCurrentNodeQName();
51 this.currentNodePath = leafRefContextBuilder.getCurrentNodePath();
52 this.leafRefTargetPath = leafRefContextBuilder.getLeafRefTargetPath();
53 this.absoluteLeafRefTargetPath = leafRefContextBuilder.getAbsoluteLeafRefTargetPath();
54 this.leafRefTargetPathString = leafRefContextBuilder.getLeafRefTargetPathString();
55 this.isReferencedBy = leafRefContextBuilder.isReferencedBy();
56 this.isReferencing = leafRefContextBuilder.isReferencing();
57 this.referencingChilds = ImmutableMap.copyOf(leafRefContextBuilder.getReferencingChilds());
58 this.referencedByChilds = ImmutableMap.copyOf(leafRefContextBuilder.getReferencedByChilds());
59 this.referencedByLeafRefCtx = ImmutableMap.copyOf(leafRefContextBuilder.getAllReferencedByLeafRefCtxs());
60 this.module = leafRefContextBuilder.getLeafRefContextModule();
63 public static LeafRefContext create(final EffectiveModelContext ctx) {
65 return new LeafRefContextTreeBuilder(ctx).buildLeafRefContextTree();
66 } catch (LeafRefYangSyntaxErrorException e) {
67 throw new IllegalArgumentException(e);
71 public boolean hasLeafRefContextChild() {
72 return hasReferencedChild() || hasReferencingChild();
75 public boolean hasReferencedChild() {
76 return !referencedByChilds.isEmpty();
79 public boolean hasReferencingChild() {
80 return !referencingChilds.isEmpty();
83 public boolean isReferenced() {
84 return isReferencedBy;
87 public boolean isReferencing() {
91 public LeafRefContext getReferencingChildByName(final QName name) {
92 return referencingChilds.get(name);
95 public Map<QName, LeafRefContext> getReferencingChilds() {
96 return referencingChilds;
99 public LeafRefContext getReferencedChildByName(final QName name) {
100 return referencedByChilds.get(name);
103 public Map<QName, LeafRefContext> getReferencedByChilds() {
104 return referencedByChilds;
107 public SchemaPath getCurrentNodePath() {
108 return currentNodePath;
111 public LeafRefPath getLeafRefTargetPath() {
112 return leafRefTargetPath;
115 public String getLeafRefTargetPathString() {
116 return leafRefTargetPathString;
119 public QName getNodeName() {
120 return currentNodeQName;
123 public LeafRefPath getAbsoluteLeafRefTargetPath() {
124 return absoluteLeafRefTargetPath;
127 public Module getLeafRefContextModule() {
131 public LeafRefContext getReferencedByLeafRefCtxByName(final QName qname) {
132 return referencedByLeafRefCtx.get(qname);
135 public Map<QName, LeafRefContext> getAllReferencedByLeafRefCtxs() {
136 return referencedByLeafRefCtx;
140 public LeafRefContext getLeafRefReferencingContext(final SchemaNodeIdentifier node) {
141 final Iterator<QName> iterator = descendantIterator(node);
142 LeafRefContext leafRefCtx = null;
143 LeafRefContext current = this;
144 while (iterator.hasNext() && current != null) {
145 final QName qname = iterator.next();
146 leafRefCtx = current.getReferencingChildByName(qname);
147 if (iterator.hasNext()) {
148 current = leafRefCtx;
156 public LeafRefContext getLeafRefReferencedByContext(final SchemaNodeIdentifier node) {
157 final Iterator<QName> iterator = descendantIterator(node);
158 LeafRefContext leafRefCtx = null;
159 LeafRefContext current = this;
160 while (iterator.hasNext() && current != null) {
161 final QName qname = iterator.next();
162 leafRefCtx = current.getReferencedChildByName(qname);
163 if (iterator.hasNext()) {
164 current = leafRefCtx;
171 private Iterator<QName> descendantIterator(final SchemaNodeIdentifier node) {
172 final Iterator<QName> nodeSteps = node.getNodeIdentifiers().iterator();
173 if (node instanceof SchemaNodeIdentifier.Absolute) {
174 final Iterator<QName> mySteps = currentNodePath.getPathFromRoot().iterator();
175 while (mySteps.hasNext()) {
176 final QName myNext = mySteps.next();
177 checkArgument(nodeSteps.hasNext(), "Node %s is an ancestor of %s", node, currentNodePath);
178 final QName nodeNext = nodeSteps.next();
179 checkArgument(myNext.equals(nodeNext), "Node %s is not a descendant of %s", node, currentNodePath);
186 public boolean isLeafRef(final SchemaNodeIdentifier node) {
187 final LeafRefContext leafRefReferencingContext = getLeafRefReferencingContext(node);
188 return leafRefReferencingContext != null && leafRefReferencingContext.isReferencing();
192 public boolean hasLeafRefChild(final SchemaNodeIdentifier node) {
193 final LeafRefContext leafRefReferencingContext = getLeafRefReferencingContext(node);
194 return leafRefReferencingContext != null && leafRefReferencingContext.hasReferencingChild();
198 public boolean isReferencedByLeafRef(final SchemaNodeIdentifier node) {
199 final LeafRefContext leafRefReferencedByContext = getLeafRefReferencedByContext(node);
200 return leafRefReferencedByContext != null && leafRefReferencedByContext.isReferenced();
204 public boolean hasChildReferencedByLeafRef(final SchemaNodeIdentifier node) {
205 final LeafRefContext leafRefReferencedByContext = getLeafRefReferencedByContext(node);
206 return leafRefReferencedByContext != null && leafRefReferencedByContext.hasReferencedChild();
210 public List<LeafRefContext> findAllLeafRefChilds(final SchemaNodeIdentifier node) {
211 final LeafRefContext ctx = getLeafRefReferencingContext(node);
212 return ctx == null ? List.of() : ctx.findAllLeafRefChilds();
215 private List<LeafRefContext> findAllLeafRefChilds() {
216 if (isReferencing()) {
217 return List.of(this);
220 final List<LeafRefContext> leafRefChilds = new ArrayList<>();
221 for (final Entry<QName, LeafRefContext> child : getReferencingChilds().entrySet()) {
222 leafRefChilds.addAll(child.getValue().findAllLeafRefChilds());
224 return leafRefChilds;
228 public List<LeafRefContext> findAllChildsReferencedByLeafRef(final SchemaNodeIdentifier node) {
229 final LeafRefContext ctx = getLeafRefReferencedByContext(node);
230 return ctx == null ? List.of() : ctx.findAllChildsReferencedByLeafRef();
233 private List<LeafRefContext> findAllChildsReferencedByLeafRef() {
234 if (isReferenced()) {
235 return List.of(this);
238 final List<LeafRefContext> childsReferencedByLeafRef = new ArrayList<>();
239 for (final Entry<QName, LeafRefContext> child : getReferencedByChilds().entrySet()) {
240 childsReferencedByLeafRef.addAll(child.getValue().findAllChildsReferencedByLeafRef());
242 return childsReferencedByLeafRef;
246 public Map<QName, LeafRefContext> getAllLeafRefsReferencingThisNode(final SchemaNodeIdentifier node) {
247 final LeafRefContext referencedByContext = getLeafRefReferencedByContext(node);
248 return referencedByContext == null ? Map.of() : referencedByContext.getAllReferencedByLeafRefCtxs();
251 LeafRefPath getLeafRefNodePath() {
252 LeafRefPath ret = leafRefNodePath;
254 synchronized (this) {
255 ret = leafRefNodePath;
257 ret = leafRefNodePath = LeafRefUtils.schemaPathToLeafRefPath(currentNodePath, module);