Merge "Bug 735 - Part 1: Update ietf-restconf and ietf-yangtypes to newer versions"
[yangtools.git] / yang / yang-data-api / src / main / java / org / opendaylight / yangtools / yang / data / api / InstanceIdentifier.java
index f954256611f99050855819326bb4e14f3cee9b9a..951e27f743dfb7d16883b6255da1f7116e6b7c59 100644 (file)
-package org.opendaylight.yangtools.yang.data.api;\r
-\r
-import java.io.Serializable;\r
-import java.util.ArrayList;\r
-import java.util.Collections;\r
-import java.util.HashMap;\r
-import java.util.List;\r
-import java.util.Map;\r
-\r
-import org.opendaylight.yangtools.concepts.Builder;\r
-import org.opendaylight.yangtools.concepts.Immutable;\r
-import org.opendaylight.yangtools.concepts.Path;\r
-import org.opendaylight.yangtools.yang.common.QName;\r
-\r
-import com.google.common.collect.ImmutableList;\r
-\r
-public class InstanceIdentifier implements Path<InstanceIdentifier>, Immutable, Serializable {\r
-\r
-    private static final long serialVersionUID = 8467409862384206193L;\r
-    private final List<PathArgument> path;\r
-\r
-    private transient String to_string_cache = null;\r
-\r
-    public List<PathArgument> getPath() {\r
-        return path;\r
-    }\r
-\r
-    public InstanceIdentifier(final List<? extends PathArgument> path) {\r
-        this.path =ImmutableList.copyOf(path);\r
-    }\r
-\r
-    private InstanceIdentifier(NodeIdentifier nodeIdentifier) {\r
-        this.path = ImmutableList.<PathArgument>of(nodeIdentifier);\r
-    }\r
-\r
-    @Override\r
-    public int hashCode() {\r
-        final int prime = 31;\r
-        int result = 1;\r
-        result = prime * result + ((path == null) ? 0 : path.hashCode());\r
-        return result;\r
-    }\r
-\r
-    @Override\r
-    public boolean equals(Object obj) {\r
-        if (this == obj)\r
-            return true;\r
-        if (obj == null)\r
-            return false;\r
-        if (getClass() != obj.getClass())\r
-            return false;\r
-        InstanceIdentifier other = (InstanceIdentifier) obj;\r
-        if (path == null) {\r
-            if (other.path != null)\r
-                return false;\r
-        } else if (!path.equals(other.path))\r
-            return false;\r
-        return true;\r
-    }\r
-\r
-    // Static factories & helpers\r
-\r
-    public static InstanceIdentifier of(QName name) {\r
-        return new InstanceIdentifier(new NodeIdentifier(name));\r
-    }\r
-\r
-    static public InstanceIdentifierBuilder builder() {\r
-        return new BuilderImpl();\r
-    }\r
-\r
-    static public InstanceIdentifierBuilder builder(InstanceIdentifier origin) {\r
-        return new BuilderImpl(origin.getPath());\r
-    }\r
-\r
-    public interface PathArgument extends Immutable, Serializable {\r
-        QName getNodeType();\r
-\r
-    }\r
-\r
-    public interface InstanceIdentifierBuilder extends Builder<InstanceIdentifier> {\r
-        InstanceIdentifierBuilder node(QName nodeType);\r
-\r
-        InstanceIdentifierBuilder nodeWithKey(QName nodeType, Map<QName, Object> keyValues);\r
-\r
-        InstanceIdentifierBuilder nodeWithKey(QName nodeType, QName key, Object value);\r
-\r
-        @Deprecated\r
-        InstanceIdentifier getIdentifier();\r
-    }\r
-\r
-    public static final class NodeIdentifier implements PathArgument {\r
-\r
-        /**\r
-         * \r
-         */\r
-        private static final long serialVersionUID = -2255888212390871347L;\r
-\r
-        private final QName nodeType;\r
-\r
-        public NodeIdentifier(QName node) {\r
-            this.nodeType = node;\r
-        }\r
-\r
-        public QName getNodeType() {\r
-            return nodeType;\r
-        }\r
-\r
-        @Override\r
-        public int hashCode() {\r
-            final int prime = 31;\r
-            int result = 1;\r
-            result = prime * result + ((nodeType == null) ? 0 : nodeType.hashCode());\r
-            return result;\r
-        }\r
-\r
-        @Override\r
-        public boolean equals(Object obj) {\r
-            if (this == obj)\r
-                return true;\r
-            if (obj == null)\r
-                return false;\r
-            if (getClass() != obj.getClass())\r
-                return false;\r
-            NodeIdentifier other = (NodeIdentifier) obj;\r
-            if (nodeType == null) {\r
-                if (other.nodeType != null)\r
-                    return false;\r
-            } else if (!nodeType.equals(other.nodeType))\r
-                return false;\r
-            return true;\r
-        }\r
-\r
-        @Override\r
-        public String toString() {\r
-            return nodeType.toString();\r
-        }\r
-    }\r
-\r
-    public static final class NodeIdentifierWithPredicates implements PathArgument {\r
-\r
-        /**\r
-         * \r
-         */\r
-        private static final long serialVersionUID = -4787195606494761540L;\r
-\r
-        private final QName nodeType;\r
-        private final Map<QName, Object> keyValues;\r
-\r
-        public NodeIdentifierWithPredicates(QName node, Map<QName, Object> keyValues) {\r
-            this.nodeType = node;\r
-            this.keyValues = Collections.unmodifiableMap(new HashMap<QName, Object>(keyValues));\r
-        }\r
-\r
-        public NodeIdentifierWithPredicates(QName node, QName key, Object value) {\r
-            this.nodeType = node;\r
-            this.keyValues = Collections.singletonMap(key, value);\r
-        }\r
-\r
-        @Override\r
-        public QName getNodeType() {\r
-            return nodeType;\r
-        }\r
-\r
-        public Map<QName, Object> getKeyValues() {\r
-            return keyValues;\r
-        }\r
-\r
-        @Override\r
-        public int hashCode() {\r
-            final int prime = 31;\r
-            int result = 1;\r
-            result = prime * result + ((keyValues == null) ? 0 : keyValues.hashCode());\r
-            result = prime * result + ((nodeType == null) ? 0 : nodeType.hashCode());\r
-            return result;\r
-        }\r
-\r
-        @Override\r
-        public boolean equals(Object obj) {\r
-            if (this == obj)\r
-                return true;\r
-            if (obj == null)\r
-                return false;\r
-            if (getClass() != obj.getClass())\r
-                return false;\r
-            NodeIdentifierWithPredicates other = (NodeIdentifierWithPredicates) obj;\r
-            if (keyValues == null) {\r
-                if (other.keyValues != null)\r
-                    return false;\r
-            } else if (!keyValues.equals(other.keyValues))\r
-                return false;\r
-            if (nodeType == null) {\r
-                if (other.nodeType != null)\r
-                    return false;\r
-            } else if (!nodeType.equals(other.nodeType))\r
-                return false;\r
-            return true;\r
-        }\r
-\r
-        @Override\r
-        public String toString() {\r
-            return nodeType + "[" + keyValues + "]";\r
-        }\r
-    }\r
-\r
-    private static class BuilderImpl implements InstanceIdentifierBuilder {\r
-\r
-        private final ImmutableList.Builder<PathArgument> path; \r
-\r
-        public BuilderImpl() {\r
-            path = ImmutableList.<PathArgument>builder();\r
-        }\r
-\r
-        public BuilderImpl(List<? extends PathArgument> prefix) {\r
-            path = ImmutableList.<PathArgument>builder();\r
-            path.addAll(prefix);\r
-        }\r
-\r
-        @Override\r
-        public InstanceIdentifierBuilder node(QName nodeType) {\r
-            path.add(new NodeIdentifier(nodeType));\r
-            return this;\r
-        }\r
-\r
-        @Override\r
-        public InstanceIdentifierBuilder nodeWithKey(QName nodeType, QName key, Object value) {\r
-            path.add(new NodeIdentifierWithPredicates(nodeType, key, value));\r
-            return this;\r
-        }\r
-\r
-        @Override\r
-        public InstanceIdentifierBuilder nodeWithKey(QName nodeType, Map<QName, Object> keyValues) {\r
-            path.add(new NodeIdentifierWithPredicates(nodeType, keyValues));\r
-            return this;\r
-        }\r
-\r
-        @Override\r
-        public InstanceIdentifier toInstance() {\r
-            return new InstanceIdentifier(path.build());\r
-        }\r
-\r
-        @Override\r
-        public InstanceIdentifier getIdentifier() {\r
-            return toInstance();\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public boolean contains(final InstanceIdentifier other) {\r
-        if (other == null) {\r
-            throw new IllegalArgumentException("other should not be null");\r
-        }\r
-        final int localSize = this.path.size();\r
-        final List<PathArgument> otherPath = other.getPath();\r
-        if (localSize > other.path.size()) {\r
-            return false;\r
-        }\r
-        for (int i = 0; i < localSize; i++) {\r
-            if (!path.get(i).equals(otherPath.get(i))) {\r
-                return false;\r
-            }\r
-        }\r
-        return true;\r
-    }\r
-\r
-    @Override\r
-    public String toString() {\r
-        if (to_string_cache != null) {\r
-            return to_string_cache;\r
-        }\r
-        StringBuilder builder = new StringBuilder();\r
-        for (PathArgument argument : path) {\r
-            builder.append("/");\r
-            builder.append(argument.toString());\r
-        }\r
-        to_string_cache = builder.toString();\r
-        return to_string_cache;\r
-    }\r
-\r
-    public static InstanceIdentifierBuilder builder(QName node) {\r
-        return builder().node(node);\r
-    }\r
-}\r
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.api;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.concepts.Path;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+public class InstanceIdentifier implements Path<InstanceIdentifier>, Immutable, Serializable {
+
+    private static final long serialVersionUID = 8467409862384206193L;
+    private final List<PathArgument> path;
+
+    private transient String toStringCache = null;
+    private transient Integer hashCodeCache = null;
+
+    public List<PathArgument> getPath() {
+        return path;
+    }
+
+    public InstanceIdentifier(final List<? extends PathArgument> path) {
+        this.path = ImmutableList.copyOf(path);
+    }
+
+    private InstanceIdentifier(final NodeIdentifier nodeIdentifier) {
+        this.path = ImmutableList.<PathArgument> of(nodeIdentifier);
+    }
+
+    @Override
+    public int hashCode() {
+        /*
+         * The hashCodeCache is safe, since the object contract requires
+         * immutability of the object and all objects referenced from this
+         * object.
+         *
+         * Used lists, maps are immutable. Path Arguments (elements) are also
+         * immutable, since the PathArgument contract requires immutability.
+         *
+         * The cache is thread-safe - if multiple computations occurs at the
+         * same time, cache will be overwritten with same result.
+         */
+        if (hashCodeCache == null) {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((path == null) ? 0 : path.hashCode());
+            hashCodeCache = result;
+        }
+        return hashCodeCache;
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        InstanceIdentifier other = (InstanceIdentifier) obj;
+        if (this.hashCode() != obj.hashCode()) {
+            return false;
+        }
+        if (path == null) {
+            if (other.path != null) {
+                return false;
+            }
+        } else if (!path.equals(other.path)) {
+            return false;
+        }
+        return true;
+    }
+
+    public InstanceIdentifier node(final QName name) {
+        return node(new NodeIdentifier(name));
+    }
+
+    public InstanceIdentifier node(final PathArgument arg) {
+        return new InstanceIdentifier(ImmutableList.<PathArgument>builder().addAll(path).add(arg).build());
+    }
+
+    /**
+     * Get the relative path from an ancestor. This method attempts to perform the reverse
+     * of concatenating a base (ancestor) and a path.
+     *
+     * @param ancestor Ancestor against which the relative path should be calculated
+     * @return This object's relative path from parent, or Optional.absent() if the
+     *         specified parent is not in fact an ancestor of this object.
+     */
+    public Optional<InstanceIdentifier> relativeTo(final InstanceIdentifier ancestor) {
+        if (ancestor.contains(this)) {
+            final int common = ancestor.path.size();
+            return Optional.of(new InstanceIdentifier(path.subList(common, path.size())));
+        } else {
+            return Optional.absent();
+        }
+    }
+
+    // Static factories & helpers
+
+    public static InstanceIdentifier of(final QName name) {
+        return new InstanceIdentifier(new NodeIdentifier(name));
+    }
+
+    static public InstanceIdentifierBuilder builder() {
+        return new BuilderImpl();
+    }
+
+    static public InstanceIdentifierBuilder builder(final InstanceIdentifier origin) {
+        return new BuilderImpl(origin.getPath());
+    }
+
+    public static InstanceIdentifierBuilder builder(final QName node) {
+        return builder().node(node);
+    }
+
+    public interface PathArgument extends Immutable, Serializable {
+
+        /**
+         * If applicable returns uniqee QName of data node as defined in YANG
+         * Schema.
+         *
+         * This method may return null, if the corresponding schema node, does
+         * not have QName associated, such as in cases of augmentations.
+         *
+         * @return
+         */
+        QName getNodeType();
+
+    }
+
+    public interface InstanceIdentifierBuilder extends Builder<InstanceIdentifier> {
+        InstanceIdentifierBuilder node(QName nodeType);
+
+        InstanceIdentifierBuilder nodeWithKey(QName nodeType, Map<QName, Object> keyValues);
+
+        InstanceIdentifierBuilder nodeWithKey(QName nodeType, QName key, Object value);
+
+        @Deprecated
+        InstanceIdentifier getIdentifier();
+
+        InstanceIdentifier build();
+    }
+
+    /**
+     * Simple path argument identifying a {@link ContainerNode} or {@link LeafNode} leaf
+     * overall data tree.
+     */
+    public static final class NodeIdentifier implements PathArgument, Comparable<NodeIdentifier> {
+        private static final long serialVersionUID = -2255888212390871347L;
+        private final QName nodeType;
+
+        public NodeIdentifier(final QName node) {
+            this.nodeType = Preconditions.checkNotNull(node);
+        }
+
+        @Override
+        public QName getNodeType() {
+            return nodeType;
+        }
+
+        @Override
+        public int hashCode() {
+            return 31 + nodeType.hashCode();
+        }
+
+        @Override
+        public boolean equals(final Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!(obj instanceof NodeIdentifier)) {
+                return false;
+            }
+            final NodeIdentifier other = (NodeIdentifier) obj;
+            return nodeType.equals(other.nodeType);
+        }
+
+        @Override
+        public String toString() {
+            return nodeType.toString();
+        }
+
+        @Override
+        public int compareTo(final NodeIdentifier o) {
+            return nodeType.compareTo(o.nodeType);
+        }
+    }
+
+    /**
+     * Composite path argument identifying a {@link MapEntryNode} leaf
+     * overall data tree.
+     */
+    public static final class NodeIdentifierWithPredicates implements PathArgument {
+        private static final long serialVersionUID = -4787195606494761540L;
+
+        private final QName nodeType;
+        private final Map<QName, Object> keyValues;
+
+        public NodeIdentifierWithPredicates(final QName node, final Map<QName, Object> keyValues) {
+            this.nodeType = Preconditions.checkNotNull(node);
+            this.keyValues = ImmutableMap.copyOf(keyValues);
+        }
+
+        public NodeIdentifierWithPredicates(final QName node, final QName key, final Object value) {
+            this.nodeType = node;
+            this.keyValues = ImmutableMap.of(key, value);
+        }
+
+        @Override
+        public QName getNodeType() {
+            return nodeType;
+        }
+
+        public Map<QName, Object> getKeyValues() {
+            return keyValues;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((keyValues == null) ? 0 : keyValues.hashCode());
+            result = prime * result + ((nodeType == null) ? 0 : nodeType.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(final Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            NodeIdentifierWithPredicates other = (NodeIdentifierWithPredicates) obj;
+            if (keyValues == null) {
+                if (other.keyValues != null) {
+                    return false;
+                }
+            } else if (!keyValues.equals(other.keyValues)) {
+                return false;
+            }
+            if (nodeType == null) {
+                if (other.nodeType != null) {
+                    return false;
+                }
+            } else if (!nodeType.equals(other.nodeType)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            return nodeType + "[" + keyValues + "]";
+        }
+    }
+
+    /**
+     * Simple path argument identifying a {@link LeafSetEntryNode} leaf
+     * overall data tree.
+     */
+    public static final class NodeWithValue implements PathArgument {
+        private static final long serialVersionUID = -3637456085341738431L;
+
+        private final QName nodeType;
+        private final Object value;
+
+        public NodeWithValue(final QName node, final Object value) {
+            this.nodeType = Preconditions.checkNotNull(node);
+            this.value = value;
+        }
+
+        @Override
+        public QName getNodeType() {
+            return nodeType;
+        }
+
+        public Object getValue() {
+            return value;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((value == null) ? 0 : value.hashCode());
+            result = prime * result + ((nodeType == null) ? 0 : nodeType.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(final Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            NodeWithValue other = (NodeWithValue) obj;
+            if (value == null) {
+                if (other.value != null) {
+                    return false;
+                }
+            } else if (!value.equals(other.value)) {
+                return false;
+            }
+            if (nodeType == null) {
+                if (other.nodeType != null) {
+                    return false;
+                }
+            } else if (!nodeType.equals(other.nodeType)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            return nodeType + "[" + value + "]";
+        }
+
+    }
+
+    /**
+     * Composite path argument identifying a {@link AugmentationNode} leaf
+     * overall data tree.
+     */
+    public static final class AugmentationIdentifier implements PathArgument {
+        private static final long serialVersionUID = -8122335594681936939L;
+        private final ImmutableSet<QName> childNames;
+
+        @Override
+        public QName getNodeType() {
+            // This should rather throw exception than return always null
+            throw new UnsupportedOperationException("Augmentation node has no QName");
+        }
+
+        public AugmentationIdentifier(final Set<QName> childNames) {
+            this.childNames = ImmutableSet.copyOf(childNames);
+        }
+
+        /**
+         * Augmentation node has no QName
+         */
+        @Deprecated
+        public AugmentationIdentifier(final QName nodeType, final Set<QName> childNames) {
+            this(childNames);
+        }
+
+        public Set<QName> getPossibleChildNames() {
+            return childNames;
+        }
+
+        @Override
+        public String toString() {
+            final StringBuffer sb = new StringBuffer("AugmentationIdentifier{");
+            sb.append("childNames=").append(childNames);
+            sb.append('}');
+            return sb.toString();
+        }
+
+        @Override
+        public boolean equals(final Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (!(o instanceof AugmentationIdentifier)) {
+                return false;
+            }
+
+            AugmentationIdentifier that = (AugmentationIdentifier) o;
+
+            if (!childNames.equals(that.childNames)) {
+                return false;
+            }
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            return childNames.hashCode();
+        }
+    }
+
+    private static class BuilderImpl implements InstanceIdentifierBuilder {
+
+        private final ImmutableList.Builder<PathArgument> path;
+
+        public BuilderImpl() {
+            path = ImmutableList.<PathArgument> builder();
+        }
+
+        public BuilderImpl(final List<? extends PathArgument> prefix) {
+            path = ImmutableList.<PathArgument> builder();
+            path.addAll(prefix);
+        }
+
+        @Override
+        public InstanceIdentifierBuilder node(final QName nodeType) {
+            path.add(new NodeIdentifier(nodeType));
+            return this;
+        }
+
+        @Override
+        public InstanceIdentifierBuilder nodeWithKey(final QName nodeType, final QName key, final Object value) {
+            path.add(new NodeIdentifierWithPredicates(nodeType, key, value));
+            return this;
+        }
+
+        @Override
+        public InstanceIdentifierBuilder nodeWithKey(final QName nodeType, final Map<QName, Object> keyValues) {
+            path.add(new NodeIdentifierWithPredicates(nodeType, keyValues));
+            return this;
+        }
+
+        @Override
+        @Deprecated
+        public InstanceIdentifier toInstance() {
+            return build();
+        }
+
+        @Override
+        public InstanceIdentifier build() {
+            return new InstanceIdentifier(path.build());
+        }
+
+        @Override
+        @Deprecated
+        public InstanceIdentifier getIdentifier() {
+            return build();
+        }
+    }
+
+    @Override
+    public boolean contains(final InstanceIdentifier other) {
+        if (other == null) {
+            throw new IllegalArgumentException("other should not be null");
+        }
+        final int localSize = this.path.size();
+        final List<PathArgument> otherPath = other.getPath();
+        if (localSize > other.path.size()) {
+            return false;
+        }
+        for (int i = 0; i < localSize; i++) {
+            if (!path.get(i).equals(otherPath.get(i))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        /*
+         * The toStringCache is safe, since the object contract requires
+         * immutability of the object and all objects referenced from this
+         * object.
+         *
+         * Used lists, maps are immutable. Path Arguments (elements) are also
+         * immutable, since the PathArgument contract requires immutability.
+         *
+         * The cache is thread-safe - if multiple computations occurs at the
+         * same time, cache will be overwritten with same result.
+         */
+        if (toStringCache != null) {
+            return toStringCache;
+        }
+
+        final StringBuilder builder = new StringBuilder('/');
+        boolean first = true;
+        for (PathArgument argument : path) {
+            if (first) {
+                first = false;
+            } else {
+                builder.append('/');
+            }
+            builder.append(argument.toString());
+        }
+
+        toStringCache = builder.toString();
+        return toStringCache;
+    }
+}