Merge "Fix for Bug 511 (model + integration-test)"
[yangtools.git] / yang / yang-data-api / src / main / java / org / opendaylight / yangtools / yang / data / api / InstanceIdentifier.java
index f954256611f99050855819326bb4e14f3cee9b9a..f3a6c3800fe6d5fdd2c765ca204ce73602a245ce 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.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(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(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;
+    }
+
+    // Static factories & helpers
+
+    public static InstanceIdentifier of(QName name) {
+        return new InstanceIdentifier(new NodeIdentifier(name));
+    }
+
+    static public InstanceIdentifierBuilder builder() {
+        return new BuilderImpl();
+    }
+
+    static public InstanceIdentifierBuilder builder(InstanceIdentifier origin) {
+        return new BuilderImpl(origin.getPath());
+    }
+
+    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
+     * overal data tree.
+     *
+     */
+    public static final class NodeIdentifier implements PathArgument {
+
+        /**
+         *
+         */
+        private static final long serialVersionUID = -2255888212390871347L;
+
+        private final QName nodeType;
+
+        public NodeIdentifier(QName node) {
+            this.nodeType = node;
+        }
+
+        @Override
+        public QName getNodeType() {
+            return nodeType;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((nodeType == null) ? 0 : nodeType.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            NodeIdentifier other = (NodeIdentifier) obj;
+            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.toString();
+        }
+    }
+
+    /**
+     *
+     * Composite path argument identifying a {@link MapEntryNode} leaf
+     * overal 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(QName node, Map<QName, Object> keyValues) {
+            this.nodeType = node;
+            this.keyValues = ImmutableMap.copyOf(keyValues);
+        }
+
+        public NodeIdentifierWithPredicates(QName node, QName key, 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(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
+     * overal data tree.
+     *
+     */
+    public static final class NodeWithValue implements PathArgument {
+
+       /**
+        *
+        * Composite path argument identifying a {@link AugmentationNode} leaf
+        * overal data tree.
+        *
+        */
+        private static final long serialVersionUID = -3637456085341738431L;
+
+        private final QName nodeType;
+        private final Object value;
+
+        public NodeWithValue(QName node, Object value) {
+            this.nodeType = 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(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 + "]";
+        }
+
+    }
+
+
+    public static final class AugmentationIdentifier implements PathArgument {
+
+
+        private static final long serialVersionUID = -8122335594681936939L;
+        private final QName nodeType;
+        private final ImmutableSet<QName> childNames;
+
+        @Override
+        public QName getNodeType() {
+            return nodeType;
+        }
+
+        public AugmentationIdentifier(QName nodeType, Set<QName> childNames) {
+            super();
+            this.nodeType = nodeType;
+            this.childNames = ImmutableSet.copyOf(childNames);
+        }
+
+        public Set<QName> getPossibleChildNames() {
+            return childNames;
+        }
+
+    }
+
+    private static class BuilderImpl implements InstanceIdentifierBuilder {
+
+        private final ImmutableList.Builder<PathArgument> path;
+
+        public BuilderImpl() {
+            path = ImmutableList.<PathArgument> builder();
+        }
+
+        public BuilderImpl(List<? extends PathArgument> prefix) {
+            path = ImmutableList.<PathArgument> builder();
+            path.addAll(prefix);
+        }
+
+        @Override
+        public InstanceIdentifierBuilder node(QName nodeType) {
+            path.add(new NodeIdentifier(nodeType));
+            return this;
+        }
+
+        @Override
+        public InstanceIdentifierBuilder nodeWithKey(QName nodeType, QName key, Object value) {
+            path.add(new NodeIdentifierWithPredicates(nodeType, key, value));
+            return this;
+        }
+
+        @Override
+        public InstanceIdentifierBuilder nodeWithKey(QName nodeType, 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;
+        }
+        StringBuilder builder = new StringBuilder();
+        for (PathArgument argument : path) {
+            builder.append("/");
+            builder.append(argument.toString());
+        }
+        toStringCache = builder.toString();
+        return toStringCache;
+    }
+
+    public static InstanceIdentifierBuilder builder(QName node) {
+        return builder().node(node);
+    }
+}