Compute YangInstanceIdentifier.hashCode() lazily
[yangtools.git] / data / yang-data-api / src / main / java / org / opendaylight / yangtools / yang / data / api / FixedYangInstanceIdentifier.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
3  *
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
7  */
8 package org.opendaylight.yangtools.yang.data.api;
9
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static com.google.common.base.Verify.verifyNotNull;
12 import static java.util.Objects.requireNonNull;
13
14 import com.google.common.collect.ImmutableList;
15 import java.io.ObjectStreamException;
16 import java.util.List;
17 import org.eclipse.jdt.annotation.NonNull;
18 import org.opendaylight.yangtools.util.HashCodeBuilder;
19
20 final class FixedYangInstanceIdentifier extends YangInstanceIdentifier implements Cloneable {
21     static final @NonNull FixedYangInstanceIdentifier EMPTY_INSTANCE = new FixedYangInstanceIdentifier(
22         ImmutableList.of());
23     private static final long serialVersionUID = 1L;
24
25     private final ImmutableList<PathArgument> path;
26     private transient volatile YangInstanceIdentifier parent;
27
28     FixedYangInstanceIdentifier(final ImmutableList<PathArgument> path) {
29         this.path = requireNonNull(path, "path must not be null.");
30     }
31
32     static @NonNull FixedYangInstanceIdentifier of(final ImmutableList<PathArgument> path) {
33         return path.isEmpty() ? EMPTY_INSTANCE : new FixedYangInstanceIdentifier(path);
34     }
35
36     static @NonNull FixedYangInstanceIdentifier of(final List<PathArgument> path) {
37         return path.isEmpty() ? EMPTY_INSTANCE : new FixedYangInstanceIdentifier(ImmutableList.copyOf(path));
38     }
39
40     @Override
41     public boolean isEmpty() {
42         return path.isEmpty();
43     }
44
45     @Override
46     public FixedYangInstanceIdentifier clone() {
47         try {
48             return (FixedYangInstanceIdentifier) super.clone();
49         } catch (CloneNotSupportedException e) {
50             throw new IllegalStateException("clone() should be supported", e);
51         }
52     }
53
54     @Override
55     public YangInstanceIdentifier getParent() {
56         if (path.isEmpty()) {
57             return null;
58         }
59
60         YangInstanceIdentifier ret = parent;
61         if (ret == null) {
62             ret = YangInstanceIdentifier.create(path.subList(0, path.size() - 1));
63             parent = ret;
64         }
65
66         return ret;
67     }
68
69     @Override
70     public YangInstanceIdentifier coerceParent() {
71         return verifyNotNull(getParent(), "Empty instance identifier does not have a parent");
72     }
73
74     @Override
75     public YangInstanceIdentifier getAncestor(final int depth) {
76         checkArgument(depth >= 0, "Negative depth is not allowed");
77         checkArgument(depth <= path.size(), "Depth %s exceeds maximum depth %s", depth, path.size());
78
79         if (depth == path.size()) {
80             return this;
81         }
82         if (depth == path.size() - 1) {
83             // Use the parent cache
84             return verifyNotNull(getParent());
85         }
86         return YangInstanceIdentifier.create(path.subList(0, depth));
87     }
88
89     @Override
90     public List<PathArgument> getPathArguments() {
91         return path;
92     }
93
94     @Override
95     public List<PathArgument> getReversePathArguments() {
96         return path.reverse();
97     }
98
99     @Override
100     @NonNull List<PathArgument> tryPathArguments() {
101         return path;
102     }
103
104     @Override
105     @NonNull List<PathArgument> tryReversePathArguments() {
106         return path.reverse();
107     }
108
109     @Override
110     public PathArgument getLastPathArgument() {
111         return path.isEmpty() ? null : path.get(path.size() - 1);
112     }
113
114     @Override
115     YangInstanceIdentifier createRelativeIdentifier(final int skipFromRoot) {
116         return skipFromRoot == path.size() ? EMPTY_INSTANCE
117             : new FixedYangInstanceIdentifier(path.subList(skipFromRoot, path.size()));
118     }
119
120     private Object readResolve() throws ObjectStreamException {
121         return path.isEmpty() ? EMPTY_INSTANCE : this;
122     }
123
124     @Override
125     int computeHashCode() {
126         int ret = 1;
127         for (PathArgument arg : path) {
128             ret = HashCodeBuilder.nextHashCode(ret, arg);
129         }
130         return ret;
131     }
132
133     @Override
134     public FixedYangInstanceIdentifier toOptimized() {
135         return this;
136     }
137 }