Add augmentation() method
[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 /**
19  * Uniquely identifies data location in the overall of data tree 
20  * modeled by YANG.
21  * 
22  * 
23  */
24 public final class InstanceIdentifier<T extends DataObject> implements Path<InstanceIdentifier<? extends DataObject>>,Immutable {
25
26     private final List<PathArgument> path;
27     private final Class<T> targetType;
28     
29     public InstanceIdentifier(Class<T> type) {
30         path = Collections.<PathArgument> singletonList(new Item<>(type));
31         this.targetType = type;
32     }
33
34     public InstanceIdentifier(List<PathArgument> path, Class<T> type) {
35         this.path = Collections.<PathArgument> unmodifiableList(new ArrayList<>(path));
36         this.targetType = type;
37     }
38
39     /**
40      * 
41      * @return path
42      */
43     public List<PathArgument> getPath() {
44         return this.path;
45     }
46
47     public Class<T> getTargetType() {
48         return this.targetType;
49     }
50
51     @Override
52     public String toString() {
53         return "InstanceIdentifier [path=" + path + "]";
54     }
55
56     /**
57      * Path argument of {@link InstanceIdentifier}.
58      * <p>
59      * Interface which implementations are used as path components of the
60      * path in overall data tree.
61      *
62      */
63     public interface PathArgument {
64
65         Class<? extends DataObject> getType();
66
67     }
68
69     public static final class Item<T extends DataObject> implements PathArgument {
70         private final Class<T> type;
71
72         public Item(Class<T> type) {
73             this.type = type;
74         }
75
76         public Class<T> getType() {
77             return type;
78         }
79
80         @Override
81         public int hashCode() {
82             final int prime = 31;
83             int result = 1;
84             result = prime * result + ((type == null) ? 0 : type.hashCode());
85             return result;
86         }
87
88         @Override
89         public boolean equals(Object obj) {
90             if (this == obj)
91                 return true;
92             if (obj == null)
93                 return false;
94             if (getClass() != obj.getClass())
95                 return false;
96             Item<?> other = (Item<?>) obj;
97             if (type == null) {
98                 if (other.type != null)
99                     return false;
100             } else if (!type.equals(other.type))
101                 return false;
102             return true;
103         }
104         
105         @Override
106         public String toString() {
107             return type.getName();
108         }
109     }
110
111     public static final class IdentifiableItem<I extends Identifiable<T> & DataObject, T extends Identifier<I>> implements
112             PathArgument {
113
114         private final T key;
115         private final Class<I> type;
116
117         public IdentifiableItem(Class<I> type, T key) {
118             if (type == null)
119                 throw new IllegalArgumentException("Type must not be null.");
120             if (key == null)
121                 throw new IllegalArgumentException("Key must not be null.");
122             this.type = type;
123             this.key = key;
124         }
125
126         public T getKey() {
127             return this.key;
128         }
129
130         @Override
131         public Class<I> getType() {
132             return this.type;
133         }
134
135         @Override
136         public boolean equals(Object obj) {
137             if (obj == null) {
138                 return false;
139             }
140             if (obj.hashCode() != hashCode()) {
141                 return false;
142             }
143             if (!(obj instanceof IdentifiableItem<?, ?>)) {
144                 return false;
145             }
146             IdentifiableItem<?, ?> foreign = (IdentifiableItem<?, ?>) obj;
147             return key.equals(foreign.getKey());
148         }
149
150         @Override
151         public int hashCode() {
152             return key.hashCode();
153         }
154
155         @Override
156         public String toString() {
157             return type.getName() + "[key=" + key + "]";
158         }
159     }
160
161     public interface InstanceIdentifierBuilder<T extends DataObject> extends Builder<InstanceIdentifier<T>> {
162
163         <N extends DataObject> InstanceIdentifierBuilder<N> node(Class<N> container);
164
165         <N extends Identifiable<K> & DataObject, K extends Identifier<N>> InstanceIdentifierBuilder<N> node(
166                 Class<N> listItem, K listKey);
167
168         <N extends ChildOf<? super T>> InstanceIdentifierBuilder<N> child(Class<N> container);
169         
170         <N extends Identifiable<K> & ChildOf<? super T>, K extends Identifier<N>> InstanceIdentifierBuilder<N> child(
171                 Class<N> listItem, K listKey);
172
173         <N extends DataObject & Augmentation<? super T>> InstanceIdentifierBuilder<N> augmentation(Class<N> container);
174
175     }
176
177     @SuppressWarnings("rawtypes")
178     public static InstanceIdentifierBuilder<?> builder() {
179         return new BuilderImpl();
180     }
181
182     public static <T extends DataObject> InstanceIdentifierBuilder<T> builder(InstanceIdentifier<T> basePath) {
183         return new BuilderImpl<T>(basePath.path,basePath.targetType);
184     }
185
186     private static final class BuilderImpl<T extends DataObject> implements InstanceIdentifierBuilder<T> {
187
188         private List<PathArgument> path;
189         private Class<? extends DataObject> target = null;
190
191         public BuilderImpl() {
192             this.path = new ArrayList<>();
193         }
194         
195
196         public BuilderImpl(List<? extends PathArgument> prefix,Class<? extends DataObject> target) {
197             this.path = new ArrayList<>(prefix);
198             this.target = target;
199         }
200
201         @SuppressWarnings({ "unchecked", "rawtypes" })
202         @Override
203         public InstanceIdentifier<T> toInstance() {
204             List<PathArgument> immutablePath = Collections.unmodifiableList(new ArrayList<PathArgument>(path));
205             return new InstanceIdentifier(immutablePath, target);
206         }
207
208         @Override
209         @SuppressWarnings("unchecked")
210         public <N extends DataObject> InstanceIdentifierBuilder<N> node(Class<N> container) {
211             target = container;
212             path.add(new Item<N>(container));
213             return (InstanceIdentifierBuilder<N>) this;
214         }
215
216         @Override
217         @SuppressWarnings("unchecked")
218         public <N extends DataObject & Identifiable<K> , K extends Identifier<N>> InstanceIdentifierBuilder<N> node(
219                 Class<N> listItem, K listKey) {
220             target = listItem;
221             path.add(new IdentifiableItem<N, K>(listItem, listKey));
222             return (InstanceIdentifierBuilder<N>) this;
223         }
224         
225         @Override
226         public <N extends ChildOf<? super T>> InstanceIdentifierBuilder<N> child(Class<N> container) {
227             return node(container);
228         }
229         
230         @Override
231         public <N extends Identifiable<K> & ChildOf<? super T>, K extends Identifier<N>> InstanceIdentifierBuilder<N> child(
232                 Class<N> listItem, K listKey) {
233             return node(listItem,listKey);
234         }
235
236         @Override
237         public <N extends DataObject & Augmentation<? super T>> InstanceIdentifierBuilder<N> augmentation(
238                 Class<N> container) {
239             return node(container);
240         }
241     }
242
243     @Override
244     public int hashCode() {
245         final int prime = 31;
246         int result = 1;
247         result = prime * result + ((path == null) ? 0 : path.hashCode());
248         return result;
249     }
250
251     @Override
252     public boolean equals(Object obj) {
253         if (this == obj) {
254             return true;
255         }
256         if (obj == null) {
257             return false;
258         }
259         if (getClass() != obj.getClass()) {
260             return false;
261         }
262         InstanceIdentifier<?> other = (InstanceIdentifier<?>) obj;
263         if (path == null) {
264             if (other.path != null) {
265                 return false;
266             }
267         } else if (!path.equals(other.path)) {
268             return false;
269         }
270         return true;
271     }
272
273     @Override
274     public boolean contains(final InstanceIdentifier<?> other) {
275         if(other == null) {
276             throw new IllegalArgumentException("other should not be null");
277         }
278         final int localSize = this.path.size();
279         final List<PathArgument> otherPath = other.getPath();
280         if(localSize > other.path.size()) {
281             return false;
282         }
283         for(int i = 0;i<localSize;i++ ) {
284             if(!path.get(i).equals(otherPath.get(i))) {
285                 return false;
286             }
287         }
288         
289         return true;
290     }
291 }