Added headers to the concepts bundles
[yangtools.git] / yang / yang-binding / src / main / java / org / opendaylight / yangtools / yang / binding / InstanceIdentifier.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.binding;
9
10 import java.util.ArrayList;
11 import java.util.Collections;
12 import java.util.List;
13
14 import org.opendaylight.yangtools.concepts.Builder;
15 import org.opendaylight.yangtools.concepts.Immutable;
16 import org.opendaylight.yangtools.concepts.Path;
17
18 import com.google.common.collect.ImmutableList;
19 import com.google.common.collect.Iterables;
20
21 /**
22  * Uniquely identifies data location in the overall of data tree 
23  * modeled by YANG.
24  * 
25  * 
26  */
27 public final class InstanceIdentifier<T extends DataObject> implements Path<InstanceIdentifier<? extends DataObject>>,Immutable {
28
29     private final List<PathArgument> path;
30     private final Class<T> targetType;
31
32     public InstanceIdentifier(Class<T> type) {
33         path = Collections.<PathArgument> singletonList(new Item<>(type));
34         this.targetType = type;
35     }
36
37     public InstanceIdentifier(List<PathArgument> path, Class<T> type) {
38         this.path = ImmutableList.copyOf(path);
39         this.targetType = type;
40     }
41
42     /**
43      * 
44      * @return path
45      */
46     public List<PathArgument> getPath() {
47         return getPathArguments();
48     }
49     
50     public List<PathArgument> getPathArguments() {
51         return this.path;
52     }
53
54     public Class<T> getTargetType() {
55         return this.targetType;
56     }
57
58     @Override
59     public String toString() {
60         return "InstanceIdentifier [path=" + path + "]";
61     }
62
63     /**
64      * Return an instance identifier trimmed at the first occurrence of a
65      * specific component type.
66      * 
67      * @param type component type
68      * @return trimmed instance identifier, or null if the component type
69      *         is not present.
70      */
71     public <T extends DataObject> InstanceIdentifier<T> firstIdentifierOf(final Class<T> type) {
72         int i = 1;
73         for (final PathArgument a : path) {
74             if (type.equals(a.getType())) {
75                 return new InstanceIdentifier<>(path.subList(0, i), type);
76             }
77
78             ++i;
79         }
80
81         return null;
82     }
83
84     /**
85      * Return the key associated with the first component of specified type in
86      * an identifier.
87      * 
88      * @param listItem component type
89      * @param listKey component key type
90      * @return key associated with the component, or null if the component type
91      *         is not present.
92      */
93     public <N extends Identifiable<K> & DataObject, K extends Identifier<N>> K firstKeyOf(final Class<N> listItem, final Class<K> listKey) {
94         for (PathArgument i : path) {
95             if (listItem.equals(i.getType())) {
96                 @SuppressWarnings("unchecked")
97                 final K ret = ((IdentifiableItem<N, K>)i).getKey();
98                 return ret;
99             }
100         }
101
102         return null;
103     }
104
105     /**
106      * Return the key associated with the last component of the specified identifier.
107      * 
108      * @param id instance identifier
109      * @return key associated with the last component
110      */
111     public static <N extends Identifiable<K> & DataObject, K extends Identifier<N>> K keyOf(final InstanceIdentifier<N> id) {
112         @SuppressWarnings("unchecked")
113         final K ret = ((IdentifiableItem<N, K>)Iterables.getLast(id.getPath())).getKey();
114         return ret;
115     }
116
117     /**
118      * Path argument of {@link InstanceIdentifier}.
119      * <p>
120      * Interface which implementations are used as path components of the
121      * path in overall data tree.
122      *
123      */
124     public interface PathArgument {
125
126         Class<? extends DataObject> getType();
127
128     }
129
130     public static final class Item<T extends DataObject> implements PathArgument {
131         private final Class<T> type;
132
133         public Item(Class<T> type) {
134             this.type = type;
135         }
136
137         public Class<T> getType() {
138             return type;
139         }
140
141         @Override
142         public int hashCode() {
143             final int prime = 31;
144             int result = 1;
145             result = prime * result + ((type == null) ? 0 : type.hashCode());
146             return result;
147         }
148
149         @Override
150         public boolean equals(Object obj) {
151             if (this == obj)
152                 return true;
153             if (obj == null)
154                 return false;
155             if (getClass() != obj.getClass())
156                 return false;
157             Item<?> other = (Item<?>) obj;
158             if (type == null) {
159                 if (other.type != null)
160                     return false;
161             } else if (!type.equals(other.type))
162                 return false;
163             return true;
164         }
165
166         @Override
167         public String toString() {
168             return type.getName();
169         }
170     }
171
172     public static final class IdentifiableItem<I extends Identifiable<T> & DataObject, T extends Identifier<I>> implements
173             PathArgument {
174
175         private final T key;
176         private final Class<I> type;
177
178         public IdentifiableItem(Class<I> type, T key) {
179             if (type == null)
180                 throw new IllegalArgumentException("Type must not be null.");
181             if (key == null)
182                 throw new IllegalArgumentException("Key must not be null.");
183             this.type = type;
184             this.key = key;
185         }
186
187         public T getKey() {
188             return this.key;
189         }
190
191         @Override
192         public Class<I> getType() {
193             return this.type;
194         }
195
196         @Override
197         public boolean equals(Object obj) {
198             if (obj == null) {
199                 return false;
200             }
201             if (obj.hashCode() != hashCode()) {
202                 return false;
203             }
204             if (!(obj instanceof IdentifiableItem<?, ?>)) {
205                 return false;
206             }
207             IdentifiableItem<?, ?> foreign = (IdentifiableItem<?, ?>) obj;
208             return key.equals(foreign.getKey());
209         }
210
211         @Override
212         public int hashCode() {
213             return key.hashCode();
214         }
215
216         @Override
217         public String toString() {
218             return type.getName() + "[key=" + key + "]";
219         }
220     }
221
222     public interface InstanceIdentifierBuilder<T extends DataObject> extends Builder<InstanceIdentifier<T>> {
223         /**
224          * @deprecated use {@link child(Class)} or {@link augmentation(Class)} instead.
225          */
226         @Deprecated
227         <N extends DataObject> InstanceIdentifierBuilder<N> node(Class<N> container);
228
229         /**
230          * @deprecated use {@link child(Class,Identifier)} or {@link augmentation(Class,Identifier)} instead.
231          */
232         @Deprecated
233         <N extends Identifiable<K> & DataObject, K extends Identifier<N>> InstanceIdentifierBuilder<N> node(
234                 Class<N> listItem, K listKey);
235
236         <N extends ChildOf<? super T>> InstanceIdentifierBuilder<N> child(Class<N> container);
237
238         <N extends Identifiable<K> & ChildOf<? super T>, K extends Identifier<N>> InstanceIdentifierBuilder<N> child(
239                 Class<N> listItem, K listKey);
240
241         <N extends DataObject & Augmentation<? super T>> InstanceIdentifierBuilder<N> augmentation(Class<N> container);
242         
243         InstanceIdentifier<T> build();
244
245     }
246
247     /**
248      * @deprecated use {@link builder(Class)} or {@link builder(Class,Identifier)} instead.
249      */
250     @Deprecated
251     @SuppressWarnings("rawtypes")
252     public static InstanceIdentifierBuilder<?> builder() {
253         return new BuilderImpl();
254     }
255
256     public static <T extends ChildOf<? extends DataRoot>> InstanceIdentifierBuilder<T> builder(Class<T> container) {
257         return new BuilderImpl<T>().addNode(container);
258     }
259
260     public static <N extends Identifiable<K> & ChildOf<? extends DataRoot>, K extends Identifier<N>> InstanceIdentifierBuilder<N> builder(
261             Class<N> listItem, K listKey) {
262         return new BuilderImpl<N>().addNode(listItem, listKey);
263     }
264
265     public static <T extends DataObject> InstanceIdentifierBuilder<T> builder(InstanceIdentifier<T> basePath) {
266         return new BuilderImpl<T>(basePath.path,basePath.targetType);
267     }
268
269     private static final class BuilderImpl<T extends DataObject> implements InstanceIdentifierBuilder<T> {
270
271         private List<PathArgument> path;
272         private Class<? extends DataObject> target = null;
273
274         public BuilderImpl() {
275             this.path = new ArrayList<>();
276         }
277
278         public BuilderImpl(List<? extends PathArgument> prefix,Class<? extends DataObject> target) {
279             this.path = new ArrayList<>(prefix);
280             this.target = target;
281         }
282
283         @SuppressWarnings("unchecked")
284         private <N extends DataObject> InstanceIdentifierBuilder<N> addNode(Class<N> container) {
285             target = container;
286             path.add(new Item<N>(container));
287             return (InstanceIdentifierBuilder<N>) this;
288         }
289
290         @SuppressWarnings("unchecked")
291         private <N extends DataObject & Identifiable<K> , K extends Identifier<N>> InstanceIdentifierBuilder<N> addNode(
292                 Class<N> listItem, K listKey) {
293             target = listItem;
294             path.add(new IdentifiableItem<N, K>(listItem, listKey));
295             return (InstanceIdentifierBuilder<N>) this;
296         }
297
298         @SuppressWarnings({ "unchecked", "rawtypes" })
299         @Override
300         public InstanceIdentifier<T> toInstance() {
301             List<PathArgument> immutablePath = Collections.unmodifiableList(new ArrayList<PathArgument>(path));
302             return new InstanceIdentifier(immutablePath, target);
303         }
304         
305         @Override
306         public InstanceIdentifier<T> build() {
307             return toInstance();
308         }
309
310         @Override
311         public <N extends DataObject> InstanceIdentifierBuilder<N> node(Class<N> container) {
312             return addNode(container);
313         }
314
315         @Override
316         public <N extends DataObject & Identifiable<K> , K extends Identifier<N>> InstanceIdentifierBuilder<N> node(
317                 Class<N> listItem, K listKey) {
318             return addNode(listItem, listKey);
319         }
320
321         @Override
322         public <N extends ChildOf<? super T>> InstanceIdentifierBuilder<N> child(Class<N> container) {
323             return addNode(container);
324         }
325
326         @Override
327         public <N extends Identifiable<K> & ChildOf<? super T>, K extends Identifier<N>> InstanceIdentifierBuilder<N> child(
328                 Class<N> listItem, K listKey) {
329             return addNode(listItem,listKey);
330         }
331
332         @Override
333         public <N extends DataObject & Augmentation<? super T>> InstanceIdentifierBuilder<N> augmentation(
334                 Class<N> container) {
335             return addNode(container);
336         }
337     }
338
339     @Override
340     public int hashCode() {
341         final int prime = 31;
342         int result = 1;
343         result = prime * result + ((path == null) ? 0 : path.hashCode());
344         return result;
345     }
346
347     @Override
348     public boolean equals(Object obj) {
349         if (this == obj) {
350             return true;
351         }
352         if (obj == null) {
353             return false;
354         }
355         if (getClass() != obj.getClass()) {
356             return false;
357         }
358         InstanceIdentifier<?> other = (InstanceIdentifier<?>) obj;
359         if (path == null) {
360             if (other.path != null) {
361                 return false;
362             }
363         } else if (!path.equals(other.path)) {
364             return false;
365         }
366         return true;
367     }
368
369     @Override
370     public boolean contains(final InstanceIdentifier<?> other) {
371         if(other == null) {
372             throw new IllegalArgumentException("other should not be null");
373         }
374         final int localSize = this.path.size();
375         final List<PathArgument> otherPath = other.getPath();
376         if(localSize > other.path.size()) {
377             return false;
378         }
379         for(int i = 0;i<localSize;i++ ) {
380             if(!path.get(i).equals(otherPath.get(i))) {
381                 return false;
382             }
383         }
384         return true;
385     }
386     
387     public boolean containsWildcarded(final InstanceIdentifier<?> other) {
388         if(other == null) {
389             throw new IllegalArgumentException("other should not be null");
390         }
391         final int localSize = this.path.size();
392         final List<PathArgument> otherPath = other.getPath();
393         if(localSize > other.path.size()) {
394             return false;
395         }
396         for(int i = 0;i<localSize;i++ ) {
397             final PathArgument localArgument = path.get(i);
398             if(!localArgument.getType().equals(otherPath.get(i).getType())) {
399                 return false;
400             } 
401             if(localArgument instanceof IdentifiableItem<?, ?> && !localArgument.equals(otherPath.get(i))) {
402                 return false;
403             }
404         }
405         return true;
406     }
407
408     public boolean isWildcarded() {
409         for(PathArgument pathArgument : path) {
410             if(Identifiable.class.isAssignableFrom(pathArgument.getType()) && !(pathArgument instanceof IdentifiableItem<?, ?>)) {
411                 return true;
412             }
413         }
414         return false;
415     }
416 }