2 * Copyright (c) 2014 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.api;
10 import java.io.Serializable;
11 import java.util.List;
15 import org.opendaylight.yangtools.concepts.Builder;
16 import org.opendaylight.yangtools.concepts.Immutable;
17 import org.opendaylight.yangtools.concepts.Path;
18 import org.opendaylight.yangtools.yang.common.QName;
19 import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
20 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
21 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
22 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
23 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
25 import com.google.common.collect.ImmutableList;
26 import com.google.common.collect.ImmutableMap;
27 import com.google.common.collect.ImmutableSet;
29 public class InstanceIdentifier implements Path<InstanceIdentifier>, Immutable, Serializable {
31 private static final long serialVersionUID = 8467409862384206193L;
32 private final List<PathArgument> path;
34 private transient String toStringCache = null;
35 private transient Integer hashCodeCache = null;
37 public List<PathArgument> getPath() {
41 public InstanceIdentifier(final List<? extends PathArgument> path) {
42 this.path = ImmutableList.copyOf(path);
45 private InstanceIdentifier(NodeIdentifier nodeIdentifier) {
46 this.path = ImmutableList.<PathArgument> of(nodeIdentifier);
50 public int hashCode() {
52 * The hashCodeCache is safe, since the object contract requires
53 * immutability of the object and all objects referenced from this
56 * Used lists, maps are immutable. Path Arguments (elements) are also
57 * immutable, since the PathArgument contract requires immutability.
59 * The cache is thread-safe - if multiple computations occurs at the
60 * same time, cache will be overwritten with same result.
62 if (hashCodeCache == null) {
65 result = prime * result + ((path == null) ? 0 : path.hashCode());
66 hashCodeCache = result;
72 public boolean equals(Object obj) {
79 if (getClass() != obj.getClass()) {
82 InstanceIdentifier other = (InstanceIdentifier) obj;
83 if (this.hashCode() != obj.hashCode()) {
87 if (other.path != null) {
90 } else if (!path.equals(other.path)) {
96 // Static factories & helpers
98 public static InstanceIdentifier of(QName name) {
99 return new InstanceIdentifier(new NodeIdentifier(name));
102 static public InstanceIdentifierBuilder builder() {
103 return new BuilderImpl();
106 static public InstanceIdentifierBuilder builder(InstanceIdentifier origin) {
107 return new BuilderImpl(origin.getPath());
110 public interface PathArgument extends Immutable, Serializable {
113 * If applicable returns uniqee QName of data node as defined in YANG
116 * This method may return null, if the corresponding schema node, does
117 * not have QName associated, such as in cases of augmentations.
125 public interface InstanceIdentifierBuilder extends Builder<InstanceIdentifier> {
126 InstanceIdentifierBuilder node(QName nodeType);
128 InstanceIdentifierBuilder nodeWithKey(QName nodeType, Map<QName, Object> keyValues);
130 InstanceIdentifierBuilder nodeWithKey(QName nodeType, QName key, Object value);
133 InstanceIdentifier getIdentifier();
135 InstanceIdentifier build();
139 * Simple path argument identifying a {@link ContainerNode} or {@link LeafNode} leaf
143 public static final class NodeIdentifier implements PathArgument {
148 private static final long serialVersionUID = -2255888212390871347L;
150 private final QName nodeType;
152 public NodeIdentifier(QName node) {
153 this.nodeType = node;
157 public QName getNodeType() {
162 public int hashCode() {
163 final int prime = 31;
165 result = prime * result + ((nodeType == null) ? 0 : nodeType.hashCode());
170 public boolean equals(Object obj) {
175 if (getClass() != obj.getClass())
177 NodeIdentifier other = (NodeIdentifier) obj;
178 if (nodeType == null) {
179 if (other.nodeType != null)
181 } else if (!nodeType.equals(other.nodeType))
187 public String toString() {
188 return nodeType.toString();
194 * Composite path argument identifying a {@link MapEntryNode} leaf
198 public static final class NodeIdentifierWithPredicates implements PathArgument {
203 private static final long serialVersionUID = -4787195606494761540L;
205 private final QName nodeType;
206 private final Map<QName, Object> keyValues;
208 public NodeIdentifierWithPredicates(QName node, Map<QName, Object> keyValues) {
209 this.nodeType = node;
210 this.keyValues = ImmutableMap.copyOf(keyValues);
213 public NodeIdentifierWithPredicates(QName node, QName key, Object value) {
214 this.nodeType = node;
215 this.keyValues = ImmutableMap.of(key, value);
219 public QName getNodeType() {
223 public Map<QName, Object> getKeyValues() {
228 public int hashCode() {
229 final int prime = 31;
231 result = prime * result + ((keyValues == null) ? 0 : keyValues.hashCode());
232 result = prime * result + ((nodeType == null) ? 0 : nodeType.hashCode());
237 public boolean equals(Object obj) {
242 if (getClass() != obj.getClass())
244 NodeIdentifierWithPredicates other = (NodeIdentifierWithPredicates) obj;
245 if (keyValues == null) {
246 if (other.keyValues != null)
248 } else if (!keyValues.equals(other.keyValues))
250 if (nodeType == null) {
251 if (other.nodeType != null)
253 } else if (!nodeType.equals(other.nodeType))
259 public String toString() {
260 return nodeType + "[" + keyValues + "]";
265 * Simple path argument identifying a {@link LeafSetEntryNode} leaf
269 public static final class NodeWithValue implements PathArgument {
273 * Composite path argument identifying a {@link AugmentationNode} leaf
277 private static final long serialVersionUID = -3637456085341738431L;
279 private final QName nodeType;
280 private final Object value;
282 public NodeWithValue(QName node, Object value) {
283 this.nodeType = node;
288 public QName getNodeType() {
292 public Object getValue() {
297 public int hashCode() {
298 final int prime = 31;
300 result = prime * result + ((value == null) ? 0 : value.hashCode());
301 result = prime * result + ((nodeType == null) ? 0 : nodeType.hashCode());
306 public boolean equals(Object obj) {
311 if (getClass() != obj.getClass())
313 NodeWithValue other = (NodeWithValue) obj;
315 if (other.value != null)
317 } else if (!value.equals(other.value))
319 if (nodeType == null) {
320 if (other.nodeType != null)
322 } else if (!nodeType.equals(other.nodeType))
328 public String toString() {
329 return nodeType + "[" + value + "]";
335 public static final class AugmentationIdentifier implements PathArgument {
338 private static final long serialVersionUID = -8122335594681936939L;
339 private final QName nodeType;
340 private final ImmutableSet<QName> childNames;
343 public QName getNodeType() {
347 public AugmentationIdentifier(QName nodeType, Set<QName> childNames) {
349 this.nodeType = nodeType;
350 this.childNames = ImmutableSet.copyOf(childNames);
353 public Set<QName> getPossibleChildNames() {
359 private static class BuilderImpl implements InstanceIdentifierBuilder {
361 private final ImmutableList.Builder<PathArgument> path;
363 public BuilderImpl() {
364 path = ImmutableList.<PathArgument> builder();
367 public BuilderImpl(List<? extends PathArgument> prefix) {
368 path = ImmutableList.<PathArgument> builder();
373 public InstanceIdentifierBuilder node(QName nodeType) {
374 path.add(new NodeIdentifier(nodeType));
379 public InstanceIdentifierBuilder nodeWithKey(QName nodeType, QName key, Object value) {
380 path.add(new NodeIdentifierWithPredicates(nodeType, key, value));
385 public InstanceIdentifierBuilder nodeWithKey(QName nodeType, Map<QName, Object> keyValues) {
386 path.add(new NodeIdentifierWithPredicates(nodeType, keyValues));
392 public InstanceIdentifier toInstance() {
397 public InstanceIdentifier build() {
398 return new InstanceIdentifier(path.build());
403 public InstanceIdentifier getIdentifier() {
409 public boolean contains(final InstanceIdentifier other) {
411 throw new IllegalArgumentException("other should not be null");
413 final int localSize = this.path.size();
414 final List<PathArgument> otherPath = other.getPath();
415 if (localSize > other.path.size()) {
418 for (int i = 0; i < localSize; i++) {
419 if (!path.get(i).equals(otherPath.get(i))) {
427 public String toString() {
429 * The toStringCache is safe, since the object contract requires
430 * immutability of the object and all objects referenced from this
433 * Used lists, maps are immutable. Path Arguments (elements) are also
434 * immutable, since the PathArgument contract requires immutability.
436 * The cache is thread-safe - if multiple computations occurs at the
437 * same time, cache will be overwritten with same result.
439 if (toStringCache != null) {
440 return toStringCache;
442 StringBuilder builder = new StringBuilder();
443 for (PathArgument argument : path) {
445 builder.append(argument.toString());
447 toStringCache = builder.toString();
448 return toStringCache;
451 public static InstanceIdentifierBuilder builder(QName node) {
452 return builder().node(node);