X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=binding%2Fyang-binding%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fbinding%2FInstanceIdentifier.java;h=8627422ee753f926f43654ea83c90b81e7d5cdf0;hb=8fc4a97304080fafab158ef877e6fc180c030ac0;hp=5dfbfb851377c285961e6e751cfc5e6fce0337ef;hpb=d7102f62fabf0d78c507c4c7a5144248c21360bb;p=mdsal.git diff --git a/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/InstanceIdentifier.java b/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/InstanceIdentifier.java index 5dfbfb8513..8627422ee7 100644 --- a/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/InstanceIdentifier.java +++ b/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/InstanceIdentifier.java @@ -15,13 +15,14 @@ import com.google.common.base.MoreObjects.ToStringHelper; import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; -import java.io.IOException; +import java.io.ObjectStreamException; import java.io.Serializable; -import java.lang.reflect.Field; -import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; -import java.util.List; +import java.util.Objects; +import java.util.Optional; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; import org.opendaylight.yangtools.concepts.Builder; import org.opendaylight.yangtools.concepts.Immutable; import org.opendaylight.yangtools.concepts.Path; @@ -60,29 +61,18 @@ import org.opendaylight.yangtools.util.HashCodeBuilder; */ public class InstanceIdentifier implements Path>, Immutable, Serializable { - private static final Field PATHARGUMENTS_FIELD; - private static final long serialVersionUID = 2L; + private static final long serialVersionUID = 3L; + /* - * Protected to differentiate internal and external access. Internal - * access is required never to modify the contents. References passed - * to outside entities have to be wrapped in an unmodifiable view. + * Protected to differentiate internal and external access. Internal access is required never to modify + * the contents. References passed to outside entities have to be wrapped in an unmodifiable view. */ - protected final transient Iterable pathArguments; - private final Class targetType; + final Iterable pathArguments; + + private final @NonNull Class targetType; private final boolean wildcarded; private final int hash; - static { - final Field f; - try { - f = InstanceIdentifier.class.getDeclaredField("pathArguments"); - } catch (NoSuchFieldException | SecurityException e) { - throw new ExceptionInInitializerError(e); - } - f.setAccessible(true); - PATHARGUMENTS_FIELD = f; - } - InstanceIdentifier(final Class type, final Iterable pathArguments, final boolean wildcarded, final int hash) { this.pathArguments = requireNonNull(pathArguments); @@ -96,7 +86,7 @@ public class InstanceIdentifier implements Path getTargetType() { + public final @NonNull Class getTargetType() { return targetType; } @@ -105,7 +95,7 @@ public class InstanceIdentifier implements Path getPathArguments() { + public final @NonNull Iterable getPathArguments() { return Iterables.unmodifiableIterable(pathArguments); } @@ -211,7 +201,7 @@ public class InstanceIdentifier implements Path InstanceIdentifier firstIdentifierOf(final Class type) { + public final @Nullable InstanceIdentifier firstIdentifierOf(final Class type) { int count = 1; for (final PathArgument a : pathArguments) { if (type.equals(a.getType())) { @@ -227,23 +217,6 @@ public class InstanceIdentifier implements Path & DataObject, K extends Identifier> K firstKeyOf(final Class listItem, - final Class listKey) { - return firstKeyOf(listItem); - } - /** * Return the key associated with the first component of specified type in * an identifier. @@ -252,7 +225,7 @@ public class InstanceIdentifier implements Path & DataObject, K extends Identifier> K firstKeyOf( + public final & DataObject, K extends Identifier> @Nullable K firstKeyOf( final Class listItem) { for (final PathArgument i : pathArguments) { if (listItem.equals(i.getType())) { @@ -338,40 +311,89 @@ public class InstanceIdentifier implements Path InstanceIdentifier childIdentifier(final AbstractPathArgument arg) { + private @NonNull InstanceIdentifier childIdentifier(final AbstractPathArgument arg) { return trustedCreate(arg, Iterables.concat(pathArguments, Collections.singleton(arg)), HashCodeBuilder.nextHashCode(hash, arg), isWildcarded()); } - public final > InstanceIdentifier child(final Class container) { - return childIdentifier(new Item<>(container)); + /** + * Create an InstanceIdentifier for a child container. This method is a more efficient equivalent to + * {@code builder().child(container).build()}. + * + * @param container Container to append + * @param Container type + * @return An InstanceIdentifier. + * @throws NullPointerException if {@code container} is null + */ + public final > @NonNull InstanceIdentifier child(final Class container) { + return childIdentifier(Item.of(container)); } - public final & ChildOf, K extends Identifier> KeyedInstanceIdentifier - child(final Class listItem, final K listKey) { - return (KeyedInstanceIdentifier) childIdentifier(new IdentifiableItem<>(listItem, listKey)); + /** + * Create an InstanceIdentifier for a child list item. This method is a more efficient equivalent to + * {@code builder().child(listItem, listKey).build()}. + * + * @param listItem List to append + * @param listKey List key + * @param List type + * @param Key type + * @return An InstanceIdentifier. + * @throws NullPointerException if any argument is null + */ + @SuppressWarnings("unchecked") + public final & ChildOf, K extends Identifier> + @NonNull KeyedInstanceIdentifier child(final Class listItem, final K listKey) { + return (KeyedInstanceIdentifier) childIdentifier(IdentifiableItem.of(listItem, listKey)); } - public final > InstanceIdentifier augmentation( - final Class container) { - return childIdentifier(new Item<>(container)); + /** + * Create an InstanceIdentifier for a child container. This method is a more efficient equivalent to + * {@code builder().child(caze, container).build()}. + * + * @param caze Choice case class + * @param container Container to append + * @param Case type + * @param Container type + * @return An InstanceIdentifier. + * @throws NullPointerException if any argument is null + */ + public final & DataObject, N extends ChildOf> + @NonNull InstanceIdentifier child(final Class caze, final Class container) { + return childIdentifier(Item.of(caze, container)); } - @Deprecated - private List legacyCache; - /** - * Return the path as a list. + * Create an InstanceIdentifier for a child list item. This method is a more efficient equivalent to + * {@code builder().child(caze, listItem, listKey).build()}. * - * @deprecated Use {@link #getPathArguments()} instead. + * @param caze Choice case class + * @param listItem List to append + * @param listKey List key + * @param Case type + * @param List type + * @param Key type + * @return An InstanceIdentifier. + * @throws NullPointerException if any argument is null */ - @Deprecated - public final List getPath() { - if (legacyCache == null) { - legacyCache = ImmutableList.copyOf(pathArguments); - } + @SuppressWarnings("unchecked") + public final & DataObject, K extends Identifier, + N extends Identifiable & ChildOf> @NonNull KeyedInstanceIdentifier child( + final Class caze, final Class listItem, final K listKey) { + return (KeyedInstanceIdentifier) childIdentifier(IdentifiableItem.of(caze, listItem, listKey)); + } - return legacyCache; + /** + * Create an InstanceIdentifier for a child augmentation. This method is a more efficient equivalent to + * {@code builder().augmentation(container).build()}. + * + * @param container Container to append + * @param Container type + * @return An InstanceIdentifier. + * @throws NullPointerException if {@code container} is null + */ + public final > @NonNull InstanceIdentifier augmentation( + final Class container) { + return childIdentifier(Item.of(container)); } /** @@ -379,30 +401,37 @@ public class InstanceIdentifier implements Path builder() { - return new InstanceIdentifierBuilderImpl<>(new Item<>(targetType), pathArguments, hash, isWildcarded()); + public @NonNull InstanceIdentifierBuilder builder() { + return new InstanceIdentifierBuilderImpl<>(Item.of(targetType), pathArguments, hash, isWildcarded()); } /** - * Create a new InstanceIdentifierBuilder given a base InstanceIdentifier. + * Create an InstanceIdentifierBuilder for a specific type of InstanceIdentifier as specified by container. * - * @deprecated Use {@link #builder()} instead. + * @param container Base container + * @param Type of the container + * @return A new {@link InstanceIdentifierBuilder} + * @throws NullPointerException if {@code container} is null */ - @Deprecated - public static InstanceIdentifierBuilder builder(final InstanceIdentifier base) { - return base.builder(); + public static > @NonNull InstanceIdentifierBuilder builder( + final Class container) { + return new InstanceIdentifierBuilderImpl().addWildNode(Item.of(container)); } /** - * Create an InstanceIdentifierBuilder for a specific type of InstanceIdentifier as specified by container. + * Create an InstanceIdentifierBuilder for a specific type of InstanceIdentifier as specified by container in + * a {@code grouping} used in the {@code case} statement. * + * @param caze Choice case class * @param container Base container + * @param Case type * @param Type of the container - * @return New IsntanceIdentifierBuilder + * @return A new {@link InstanceIdentifierBuilder} + * @throws NullPointerException if any argument is null */ - public static > InstanceIdentifierBuilder builder( - final Class container) { - return new InstanceIdentifierBuilderImpl().addNode(container); + public static & DataObject, T extends ChildOf> + @NonNull InstanceIdentifierBuilder builder(final Class caze, final Class container) { + return new InstanceIdentifierBuilderImpl().addWildNode(Item.of(caze, container)); } /** @@ -414,10 +443,32 @@ public class InstanceIdentifier implements Path List type * @param List key * @return A new {@link InstanceIdentifierBuilder} + * @throws NullPointerException if any argument is null */ public static & ChildOf, - K extends Identifier> InstanceIdentifierBuilder builder(final Class listItem, final K listKey) { - return new InstanceIdentifierBuilderImpl().addNode(listItem, listKey); + K extends Identifier> @NonNull InstanceIdentifierBuilder builder(final Class listItem, + final K listKey) { + return new InstanceIdentifierBuilderImpl().addNode(IdentifiableItem.of(listItem, listKey)); + } + + /** + * Create an InstanceIdentifierBuilder for a specific type of InstanceIdentifier which represents an + * {@link IdentifiableItem} in a {@code grouping} used in the {@code case} statement. + * + * @param caze Choice case class + * @param listItem list item class + * @param listKey key value + * @param Case type + * @param List type + * @param List key + * @return A new {@link InstanceIdentifierBuilder} + * @throws NullPointerException if any argument is null + */ + public static & DataObject, + N extends Identifiable & ChildOf, K extends Identifier> + @NonNull InstanceIdentifierBuilder builder(final Class caze, final Class listItem, + final K listKey) { + return new InstanceIdentifierBuilderImpl().addNode(IdentifiableItem.of(caze, listItem, listKey)); } /** @@ -427,8 +478,9 @@ public class InstanceIdentifier implements Path internalCreate(final Iterable pathArguments) { + private static @NonNull InstanceIdentifier internalCreate(final Iterable pathArguments) { final Iterator it = requireNonNull(pathArguments, "pathArguments may not be null") .iterator(); final HashCodeBuilder hashBuilder = new HashCodeBuilder<>(); @@ -466,14 +518,14 @@ public class InstanceIdentifier implements Path create(final Iterable pathArguments) { + public static @NonNull InstanceIdentifier create(final Iterable pathArguments) { if (pathArguments instanceof ImmutableCollection) { @SuppressWarnings("unchecked") final Iterable immutableArguments = (Iterable) pathArguments; return internalCreate(immutableArguments); - } else { - return internalCreate(ImmutableList.copyOf(pathArguments)); } + + return internalCreate(ImmutableList.copyOf(pathArguments)); } /** @@ -490,8 +542,8 @@ public class InstanceIdentifier implements Path InstanceIdentifier create(final Class type) { - return (InstanceIdentifier) create(Collections.singletonList(new Item<>(type))); + public static @NonNull InstanceIdentifier create(final Class type) { + return (InstanceIdentifier) create(ImmutableList.of(Item.of(type))); } /** @@ -513,12 +565,12 @@ public class InstanceIdentifier implements Path InstanceIdentifier trustedCreate(final PathArgument arg, + static @NonNull InstanceIdentifier trustedCreate(final PathArgument arg, final Iterable pathArguments, final int hash, boolean wildcarded) { if (Identifiable.class.isAssignableFrom(arg.getType()) && !wildcarded) { Identifier key = null; - if (arg instanceof IdentifiableItem) { - key = ((IdentifiableItem)arg).key; + if (arg instanceof IdentifiableItem) { + key = ((IdentifiableItem)arg).getKey(); } else { wildcarded = true; } @@ -534,14 +586,31 @@ public class InstanceIdentifier implements Path { - Class getType(); + /** + * Return the data object type backing this PathArgument. + * + * @return Data object type. + */ + @NonNull Class getType(); + + /** + * Return an optional enclosing case type. This is used only when {@link #getType()} references a node defined + * in a {@code grouping} which is reference inside a {@code case} statement in order to safely reference the + * node. + * + * @return Optional case class. + */ + default Optional> getCaseType() { + return Optional.empty(); + } } private abstract static class AbstractPathArgument implements PathArgument, Serializable { private static final long serialVersionUID = 1L; - private final Class type; - protected AbstractPathArgument(final Class type) { + private final @NonNull Class type; + + AbstractPathArgument(final Class type) { this.type = requireNonNull(type, "Type may not be null."); } @@ -550,29 +619,44 @@ public class InstanceIdentifier implements Path other = (AbstractPathArgument) obj; - return type.equals(other.type); + return type.equals(other.type) && Objects.equals(getKey(), other.getKey()) + && getCaseType().equals(other.getCaseType()); } @Override - public int compareTo(final PathArgument arg) { - return type.getCanonicalName().compareTo(arg.getType().getCanonicalName()); + public final int compareTo(final PathArgument arg) { + final int cmp = compareClasses(type, arg.getType()); + if (cmp != 0) { + return cmp; + } + final Optional> caseType = getCaseType(); + if (!caseType.isPresent()) { + return arg.getCaseType().isPresent() ? -1 : 1; + } + final Optional> argCaseType = getCaseType(); + return argCaseType.isPresent() ? compareClasses(caseType.get(), argCaseType.get()) : 1; + } + + private static int compareClasses(final Class first, final Class second) { + return first.getCanonicalName().compareTo(second.getCanonicalName()); } } @@ -582,13 +666,41 @@ public class InstanceIdentifier implements Path Item type */ - public static final class Item extends AbstractPathArgument { + public static class Item extends AbstractPathArgument { private static final long serialVersionUID = 1L; - public Item(final Class type) { + Item(final Class type) { super(type); } + /** + * Return a PathArgument instance backed by the specified class. + * + * @param type Backing class + * @param Item type + * @return A new PathArgument + * @throws NullPointerException if {@code} is null. + */ + public static @NonNull Item of(final Class type) { + return new Item<>(type); + } + + /** + * Return a PathArgument instance backed by the specified class, which in turn is defined in a {@code grouping} + * used in a corresponding {@code case} statement. + * + * @param caseType defining case class + * @param type Backing class + * @param Case type + * @param Item type + * @return A new PathArgument + * @throws NullPointerException if any argument is null. + */ + public static & DataObject, T extends ChildOf> @NonNull Item of( + final Class caseType, final Class type) { + return new CaseItem<>(caseType, type); + } + @Override public String toString() { return getType().getName(); @@ -602,28 +714,58 @@ public class InstanceIdentifier implements Path An object that is identifiable by an identifier * @param The identifier of the object */ - public static final class IdentifiableItem & DataObject, T extends Identifier> + public static class IdentifiableItem & DataObject, T extends Identifier> extends AbstractPathArgument { private static final long serialVersionUID = 1L; - private final T key; - public IdentifiableItem(final Class type, final T key) { + private final @NonNull T key; + + IdentifiableItem(final Class type, final T key) { super(type); this.key = requireNonNull(key, "Key may not be null."); } - public T getKey() { - return this.key; + /** + * Return an IdentifiableItem instance backed by the specified class with specified key. + * + * @param type Backing class + * @param key Key + * @param List type + * @param Key type + * @return An IdentifiableItem + * @throws NullPointerException if any argument is null. + */ + public static & DataObject, I extends Identifier> + @NonNull IdentifiableItem of(final Class type, final I key) { + return new IdentifiableItem<>(type, key); } - @Override - public boolean equals(final Object obj) { - return super.equals(obj) && key.equals(((IdentifiableItem) obj).getKey()); + /** + * Return an IdentifiableItem instance backed by the specified class with specified key. The class is in turn + * defined in a {@code grouping} used in a corresponding {@code case} statement. + * + * @param caseType defining case class + * @param type Backing class + * @param Case type + * @param List type + * @param Key type + * @return A new PathArgument + * @throws NullPointerException if any argument is null. + */ + public static & DataObject, T extends ChildOf & Identifiable, + I extends Identifier> @NonNull IdentifiableItem of(final Class caseType, + final Class type, final I key) { + return new CaseIdentifiableItem<>(caseType, type, key); } + /** + * Return the data object type backing this PathArgument. + * + * @return Data object type. + */ @Override - public int hashCode() { - return super.hashCode() * 31 + key.hashCode(); + public final @NonNull T getKey() { + return key; } @Override @@ -632,44 +774,107 @@ public class InstanceIdentifier implements Path & DataObject, T extends ChildOf> + extends Item { + private static final long serialVersionUID = 1L; + + private final Class caseType; + + CaseItem(final Class caseType, final Class type) { + super(type); + this.caseType = requireNonNull(caseType); + } + + @Override + public Optional> getCaseType() { + return Optional.of(caseType); + } + } + + private static final class CaseIdentifiableItem & DataObject, + T extends ChildOf & Identifiable, K extends Identifier> extends IdentifiableItem { + private static final long serialVersionUID = 1L; + + private final Class caseType; + + CaseIdentifiableItem(final Class caseType, final Class type, final K key) { + super(type, key); + this.caseType = requireNonNull(caseType); + } + + @Override + public Optional> getCaseType() { + return Optional.of(caseType); + } + } public interface InstanceIdentifierBuilder extends Builder> { /** - * Append the specified container as a child of the current InstanceIdentifier referenced by the builder. - * - * This method should be used when you want to build an instance identifier by appending top-level - * elements - * - * Example, + * Append the specified container as a child of the current InstanceIdentifier referenced by the builder. This + * method should be used when you want to build an instance identifier by appending top-level elements, for + * example *
          *     InstanceIdentifier.builder().child(Nodes.class).build();
-         *
          * 
* + *

* NOTE :- The above example is only for illustration purposes InstanceIdentifier.builder() has been deprecated * and should not be used. Use InstanceIdentifier.builder(Nodes.class) instead * - * @param container - * @param - * @return + * @param container Container to append + * @param Container type + * @return this builder + * @throws NullPointerException if {@code container} is null */ - > InstanceIdentifierBuilder child( - Class container); + > @NonNull InstanceIdentifierBuilder child(Class container); + + /** + * Append the specified container as a child of the current InstanceIdentifier referenced by the builder. This + * method should be used when you want to build an instance identifier by appending a container node to the + * identifier and the {@code container} is defined in a {@code grouping} used in a {@code case} statement. + * + * @param caze Choice case class + * @param container Container to append + * @param Case type + * @param Container type + * @return this builder + * @throws NullPointerException if {@code container} is null + */ + & DataObject, N extends ChildOf> + @NonNull InstanceIdentifierBuilder child(Class caze, Class container); /** - * Append the specified listItem as a child of the current InstanceIdentifier referenced by the builder. + * Append the specified listItem as a child of the current InstanceIdentifier referenced by the builder. This + * method should be used when you want to build an instance identifier by appending a specific list element to + * the identifier. * - * This method should be used when you want to build an instance identifier by appending a specific list element - * to the identifier + * @param listItem List to append + * @param listKey List key + * @param List type + * @param Key type + * @return this builder + * @throws NullPointerException if any argument is null + */ + & ChildOf, K extends Identifier> + @NonNull InstanceIdentifierBuilder child(Class listItem, K listKey); + + /** + * Append the specified listItem as a child of the current InstanceIdentifier referenced by the builder. This + * method should be used when you want to build an instance identifier by appending a specific list element to + * the identifier and the {@code list} is defined in a {@code grouping} used in a {@code case} statement. * - * @param listItem - * @param listKey - * @param - * @param - * @return + * @param caze Choice case class + * @param listItem List to append + * @param listKey List key + * @param Case type + * @param List type + * @param Key type + * @return this builder + * @throws NullPointerException if any argument is null */ - & ChildOf, K extends Identifier> InstanceIdentifierBuilder child( - Class listItem, K listKey); + & DataObject, K extends Identifier, + N extends Identifiable & ChildOf> @NonNull InstanceIdentifierBuilder child( + Class caze, Class listItem, K listKey); /** * Build an identifier which refers to a specific augmentation of the current InstanceIdentifier referenced by @@ -678,8 +883,9 @@ public class InstanceIdentifier implements Path augmentation type * @return this builder + * @throws NullPointerException if {@code container} is null */ - > InstanceIdentifierBuilder augmentation( + > @NonNull InstanceIdentifierBuilder augmentation( Class container); /** @@ -689,35 +895,9 @@ public class InstanceIdentifier implements Path build(); - - /* - * @deprecated use #build() - */ - @Deprecated - InstanceIdentifier toInstance(); - } - - private void writeObject(final java.io.ObjectOutputStream out) throws IOException { - out.defaultWriteObject(); - out.writeInt(Iterables.size(pathArguments)); - for (Object o : pathArguments) { - out.writeObject(o); - } } - private void readObject(final java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { - in.defaultReadObject(); - - final int size = in.readInt(); - final List args = new ArrayList<>(size); - for (int i = 0; i < size; ++i) { - args.add((PathArgument) in.readObject()); - } - - try { - PATHARGUMENTS_FIELD.set(this, ImmutableList.copyOf(args)); - } catch (IllegalArgumentException | IllegalAccessException e) { - throw new IOException(e); - } + private Object writeReplace() throws ObjectStreamException { + return new InstanceIdentifierV3<>(this); } }