2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.yangtools.yang.binding;
10 import java.util.Collections;
11 import java.util.List;
13 import org.opendaylight.yangtools.concepts.Builder;
14 import org.opendaylight.yangtools.concepts.Immutable;
15 import org.opendaylight.yangtools.concepts.Path;
17 import com.google.common.collect.ImmutableList;
18 import com.google.common.collect.Iterables;
21 * Uniquely identifies data location in the overall of data tree
26 public final class InstanceIdentifier<T extends DataObject> implements Path<InstanceIdentifier<? extends DataObject>>,Immutable {
28 private final List<PathArgument> path;
29 private final Class<T> targetType;
31 public InstanceIdentifier(Class<T> type) {
32 path = Collections.<PathArgument> singletonList(new Item<>(type));
33 this.targetType = type;
36 public InstanceIdentifier(List<PathArgument> path, Class<T> type) {
37 this.path = ImmutableList.copyOf(path);
38 this.targetType = type;
45 public List<PathArgument> getPath() {
46 return getPathArguments();
49 public List<PathArgument> getPathArguments() {
53 public Class<T> getTargetType() {
54 return this.targetType;
58 public String toString() {
59 return "InstanceIdentifier [path=" + path + "]";
63 * Return an instance identifier trimmed at the first occurrence of a
64 * specific component type.
66 * @param type component type
67 * @return trimmed instance identifier, or null if the component type
70 @SuppressWarnings("hiding")
71 public <T extends DataObject> InstanceIdentifier<T> firstIdentifierOf(final Class<T> type) {
73 for (final PathArgument a : path) {
74 if (type.equals(a.getType())) {
75 return new InstanceIdentifier<>(path.subList(0, i), type);
85 * Return the key associated with the first component of specified type in
88 * @param listItem component type
89 * @param listKey component key type
90 * @return key associated with the component, or null if the component type
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();
106 * Return the key associated with the last component of the specified identifier.
108 * @param id instance identifier
109 * @return key associated with the last component
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();
118 * Path argument of {@link InstanceIdentifier}.
120 * Interface which implementations are used as path components of the
121 * path in overall data tree.
124 public interface PathArgument {
126 Class<? extends DataObject> getType();
130 public static final class Item<T extends DataObject> implements PathArgument {
131 private final Class<T> type;
133 public Item(Class<T> type) {
138 public Class<T> getType() {
143 public int hashCode() {
144 final int prime = 31;
146 result = prime * result + ((type == null) ? 0 : type.hashCode());
151 public boolean equals(Object obj) {
156 if (getClass() != obj.getClass())
158 Item<?> other = (Item<?>) obj;
160 if (other.type != null)
162 } else if (!type.equals(other.type))
168 public String toString() {
169 return type.getName();
173 public static final class IdentifiableItem<I extends Identifiable<T> & DataObject, T extends Identifier<I>> implements
177 private final Class<I> type;
179 public IdentifiableItem(Class<I> type, T key) {
181 throw new IllegalArgumentException("Type must not be null.");
183 throw new IllegalArgumentException("Key must not be null.");
193 public Class<I> getType() {
198 public boolean equals(Object obj) {
202 if (obj.hashCode() != hashCode()) {
205 if (!(obj instanceof IdentifiableItem<?, ?>)) {
208 IdentifiableItem<?, ?> foreign = (IdentifiableItem<?, ?>) obj;
209 return key.equals(foreign.getKey());
213 public int hashCode() {
214 return key.hashCode();
218 public String toString() {
219 return type.getName() + "[key=" + key + "]";
223 public interface InstanceIdentifierBuilder<T extends DataObject> extends Builder<InstanceIdentifier<T>> {
225 * @deprecated use {@link child(Class)} or {@link augmentation(Class)} instead.
228 <N extends DataObject> InstanceIdentifierBuilder<N> node(Class<N> container);
231 * @deprecated use {@link child(Class,Identifier)} or {@link augmentation(Class,Identifier)} instead.
234 <N extends Identifiable<K> & DataObject, K extends Identifier<N>> InstanceIdentifierBuilder<N> node(
235 Class<N> listItem, K listKey);
237 <N extends ChildOf<? super T>> InstanceIdentifierBuilder<N> child(Class<N> container);
239 <N extends Identifiable<K> & ChildOf<? super T>, K extends Identifier<N>> InstanceIdentifierBuilder<N> child(
240 Class<N> listItem, K listKey);
242 <N extends DataObject & Augmentation<? super T>> InstanceIdentifierBuilder<N> augmentation(Class<N> container);
244 InstanceIdentifier<T> build();
249 * @deprecated use {@link builder(Class)} or {@link builder(Class,Identifier)} instead.
252 @SuppressWarnings("rawtypes")
253 public static InstanceIdentifierBuilder<?> builder() {
254 return new BuilderImpl();
257 public static <T extends ChildOf<? extends DataRoot>> InstanceIdentifierBuilder<T> builder(Class<T> container) {
258 return new BuilderImpl<T>().addNode(container);
261 public static <N extends Identifiable<K> & ChildOf<? extends DataRoot>, K extends Identifier<N>> InstanceIdentifierBuilder<N> builder(
262 Class<N> listItem, K listKey) {
263 return new BuilderImpl<N>().addNode(listItem, listKey);
266 public static <T extends DataObject> InstanceIdentifierBuilder<T> builder(InstanceIdentifier<T> basePath) {
267 return new BuilderImpl<T>(basePath.path,basePath.targetType);
270 private static final class BuilderImpl<T extends DataObject> implements InstanceIdentifierBuilder<T> {
272 private final ImmutableList.Builder<PathArgument> path;
273 private Class<? extends DataObject> target = null;
275 public BuilderImpl() {
276 this.path = ImmutableList.builder();
279 public BuilderImpl(List<? extends PathArgument> prefix,Class<? extends DataObject> target) {
280 this.path = ImmutableList.<PathArgument>builder().addAll(prefix);
281 this.target = target;
284 @SuppressWarnings("unchecked")
285 private <N extends DataObject> InstanceIdentifierBuilder<N> addNode(Class<N> container) {
287 path.add(new Item<N>(container));
288 return (InstanceIdentifierBuilder<N>) this;
291 @SuppressWarnings("unchecked")
292 private <N extends DataObject & Identifiable<K> , K extends Identifier<N>> InstanceIdentifierBuilder<N> addNode(
293 Class<N> listItem, K listKey) {
295 path.add(new IdentifiableItem<N, K>(listItem, listKey));
296 return (InstanceIdentifierBuilder<N>) this;
299 @SuppressWarnings({ "unchecked", "rawtypes" })
301 public InstanceIdentifier<T> toInstance() {
302 return new InstanceIdentifier(path.build(), target);
306 public InstanceIdentifier<T> build() {
311 public <N extends DataObject> InstanceIdentifierBuilder<N> node(Class<N> container) {
312 return addNode(container);
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);
322 public <N extends ChildOf<? super T>> InstanceIdentifierBuilder<N> child(Class<N> container) {
323 return addNode(container);
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);
333 public <N extends DataObject & Augmentation<? super T>> InstanceIdentifierBuilder<N> augmentation(
334 Class<N> container) {
335 return addNode(container);
339 public int hashCode() {
340 final int prime = 31;
342 result = prime * result + ((path == null) ? 0 : path.hashCode());
348 public int hashCode() {
349 final int prime = 31;
351 result = prime * result + ((path == null) ? 0 : path.hashCode());
356 public boolean equals(Object obj) {
363 if (getClass() != obj.getClass()) {
366 InstanceIdentifier<?> other = (InstanceIdentifier<?>) obj;
368 if (other.path != null) {
371 } else if (!path.equals(other.path)) {
378 public boolean contains(final InstanceIdentifier<?> other) {
380 throw new IllegalArgumentException("other should not be null");
382 final int localSize = this.path.size();
383 final List<PathArgument> otherPath = other.getPath();
384 if(localSize > other.path.size()) {
387 for(int i = 0;i<localSize;i++ ) {
388 if(!path.get(i).equals(otherPath.get(i))) {
395 public boolean containsWildcarded(final InstanceIdentifier<?> other) {
397 throw new IllegalArgumentException("other should not be null");
399 final int localSize = this.path.size();
400 final List<PathArgument> otherPath = other.getPath();
401 if(localSize > other.path.size()) {
404 for(int i = 0;i<localSize;i++ ) {
405 final PathArgument localArgument = path.get(i);
406 final PathArgument otherArgument = otherPath.get(i);
407 if(!localArgument.getType().equals(otherArgument.getType())) {
410 if(localArgument instanceof IdentifiableItem<?, ?> && otherArgument instanceof IdentifiableItem<?, ?> && !localArgument.equals(otherPath.get(i))) {
417 public boolean isWildcarded() {
418 for(PathArgument pathArgument : path) {
419 if(Identifiable.class.isAssignableFrom(pathArgument.getType()) && !(pathArgument instanceof IdentifiableItem<?, ?>)) {