Merge "BUG-994: remove the legacy public constructor"
[yangtools.git] / yang / yang-model-api / src / main / java / org / opendaylight / yangtools / yang / model / api / SchemaPath.java
1 /*
2  * Copyright (c) 2013 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.model.api;
9
10 import com.google.common.base.Preconditions;
11 import com.google.common.collect.ImmutableList;
12 import com.google.common.collect.Iterables;
13
14 import java.util.Arrays;
15 import java.util.Collections;
16 import java.util.List;
17
18 import org.opendaylight.yangtools.concepts.Immutable;
19 import org.opendaylight.yangtools.util.HashCodeBuilder;
20 import org.opendaylight.yangtools.yang.common.QName;
21
22 /**
23  *
24  * Represents unique path to the every node inside the module.
25  *
26  */
27 public class SchemaPath implements Immutable {
28     /**
29      * Shared instance of the conceptual root schema node.
30      */
31     public static final SchemaPath ROOT = new SchemaPath(Collections.<QName>emptyList(), true, Boolean.TRUE.hashCode());
32
33     /**
34      * Shared instance of the "same" relative schema node.
35      */
36     public static final SchemaPath SAME = new SchemaPath(Collections.<QName>emptyList(), false, Boolean.FALSE.hashCode());
37
38     /**
39      * List of QName instances which represents complete path to the node.
40      */
41     private final Iterable<QName> path;
42
43     /**
44      * Boolean value which represents type of schema path (relative or
45      * absolute).
46      */
47     private final boolean absolute;
48
49     /**
50      * Cached hash code. We can use this since we are immutable.
51      */
52     private final int hash;
53
54     /**
55      * Cached legacy path, filled-in when {@link #getPath()} or {@link #getPathTowardsRoot()}
56      * is invoked.
57      */
58     private ImmutableList<QName> legacyPath;
59
60     private ImmutableList<QName> getLegacyPath() {
61         if (legacyPath == null) {
62             legacyPath = ImmutableList.copyOf(path);
63         }
64
65         return legacyPath;
66     }
67
68     /**
69      * Returns the complete path to schema node.
70      *
71      * @return list of <code>QName</code> instances which represents complete
72      *         path to schema node
73      *
74      * @deprecated Use {@link #getPathFromRoot()} instead.
75      */
76     @Deprecated
77     public List<QName> getPath() {
78         return getLegacyPath();
79     }
80
81     private SchemaPath(final Iterable<QName> path, final boolean absolute, final int hash) {
82         this.path = Preconditions.checkNotNull(path);
83         this.absolute = absolute;
84         this.hash = hash;
85     }
86
87     /**
88      * Constructs new instance of this class with the concrete path.
89      *
90      * @param path
91      *            list of QName instances which specifies exact path to the
92      *            module node
93      * @param absolute
94      *            boolean value which specifies if the path is absolute or
95      *            relative
96      *
97      * @return A SchemaPath instance.
98      */
99     public static SchemaPath create(final Iterable<QName> path, final boolean absolute) {
100         final SchemaPath parent = absolute ? ROOT : SAME;
101         return parent.createChild(path);
102     }
103
104     /**
105      * Constructs new instance of this class with the concrete path.
106      *
107      * @param absolute
108      *            boolean value which specifies if the path is absolute or
109      *            relative
110      * @param path
111      *            one or more QName instances which specifies exact path to the
112      *            module node
113      *
114      * @return A SchemaPath instance.
115      */
116     public static SchemaPath create(final boolean absolute, final QName... path) {
117         return create(Arrays.asList(path), absolute);
118     }
119
120     private SchemaPath trustedCreateChild(final Iterable<QName> relative) {
121         if (Iterables.isEmpty(relative)) {
122             return this;
123         }
124
125         final HashCodeBuilder<QName> b = new HashCodeBuilder<>(hash);
126         for (QName p : relative) {
127             b.addArgument(p);
128         }
129
130         return new SchemaPath(Iterables.concat(path, relative), absolute, b.toInstance());
131     }
132
133     /**
134      * Create a child path based on concatenation of this path and a relative path.
135      *
136      * @param relative Relative path
137      * @return A new child path
138      */
139     public SchemaPath createChild(final Iterable<QName> relative) {
140         if (Iterables.isEmpty(relative)) {
141             return this;
142         }
143
144         return trustedCreateChild(ImmutableList.copyOf(relative));
145     }
146
147     /**
148      * Create a child path based on concatenation of this path and a relative path.
149      *
150      * @param relative Relative SchemaPath
151      * @return A new child path
152      */
153     public SchemaPath createChild(final SchemaPath relative) {
154         Preconditions.checkArgument(!relative.isAbsolute(), "Child creation requires relative path");
155         return trustedCreateChild(relative.path);
156     }
157
158     /**
159      * Create a child path based on concatenation of this path and additional
160      * path elements.
161      *
162      * @param elements Relative SchemaPath elements
163      * @return A new child path
164      */
165     public SchemaPath createChild(final QName... elements) {
166         return createChild(Arrays.asList(elements));
167     }
168
169     /**
170      * Returns the list of nodes which need to be traversed to get from the
171      * starting point (root for absolute SchemaPaths) to the node represented
172      * by this object.
173      *
174      * @return list of <code>qname</code> instances which represents
175      *         path from the root to the schema node.
176      */
177     public Iterable<QName> getPathFromRoot() {
178         return path;
179     }
180
181     /**
182      * Returns the list of nodes which need to be traversed to get from this
183      * node to the starting point (root for absolute SchemaPaths).
184      *
185      * @return list of <code>qname</code> instances which represents
186      *         path from the schema node towards the root.
187      */
188     public Iterable<QName> getPathTowardsRoot() {
189         return getLegacyPath().reverse();
190     }
191
192     /**
193      * Returns the immediate parent SchemaPath.
194      *
195      * @return Parent path, null if this SchemaPath is already toplevel.
196      */
197     public SchemaPath getParent() {
198         final int size = Iterables.size(path);
199         if (size != 0) {
200             final SchemaPath parent = isAbsolute() ? ROOT : SAME;
201             return parent.trustedCreateChild(Iterables.limit(path, size - 1));
202         } else {
203             return null;
204         }
205     }
206
207     /**
208      * Describes whether schema path is|isn't absolute.
209      *
210      * @return boolean value which is <code>true</code> if schema path is
211      *         absolute.
212      */
213     public boolean isAbsolute() {
214         return absolute;
215     }
216
217     @Override
218     public int hashCode() {
219         return hash;
220     }
221
222     @Override
223     public boolean equals(final Object obj) {
224         if (this == obj) {
225             return true;
226         }
227         if (obj == null) {
228             return false;
229         }
230         if (getClass() != obj.getClass()) {
231             return false;
232         }
233         SchemaPath other = (SchemaPath) obj;
234         if (absolute != other.absolute) {
235             return false;
236         }
237
238         return Iterables.elementsEqual(path, other.path);
239     }
240
241     @Override
242     public String toString() {
243         StringBuilder builder = new StringBuilder();
244         builder.append("SchemaPath [path=");
245         builder.append(path);
246         builder.append(", absolute=");
247         builder.append(absolute);
248         builder.append("]");
249         return builder.toString();
250     }
251 }