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=0c89142533d5c337fc8a503337f7b5b949fc8177;hb=eb7ab8e1bb6a28cfafd22a5a62ea66e5f85a8c2d;hp=909305ec1bdc22a94f15c1d4a9cae6fc1d6715ed;hpb=c6845c69a7e4e47e206697801207151a39c4c866;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 909305ec1b..0c89142533 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 @@ -8,25 +8,25 @@ package org.opendaylight.yangtools.yang.binding; import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Verify.verify; +import static com.google.common.base.Verify.verifyNotNull; import static java.util.Objects.requireNonNull; import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects.ToStringHelper; +import com.google.common.base.VerifyException; 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.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.concepts.Immutable; -import org.opendaylight.yangtools.concepts.Path; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; +import org.opendaylight.yangtools.concepts.HierarchicalIdentifier; import org.opendaylight.yangtools.util.HashCodeBuilder; /** @@ -60,31 +60,20 @@ import org.opendaylight.yangtools.util.HashCodeBuilder; *

* This would be the same as using a path like so, "/nodes/node/openflow:1" to refer to the openflow:1 node */ -public class InstanceIdentifier implements Path>, - Immutable, Serializable { - private static final Field PATHARGUMENTS_FIELD; - private static final long serialVersionUID = 2L; +public class InstanceIdentifier + implements HierarchicalIdentifier> { + 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); @@ -98,16 +87,30 @@ public class InstanceIdentifier implements Path getTargetType() { + public final @NonNull Class getTargetType() { return targetType; } + /** + * Perform a safe target type adaptation of this instance identifier to target type. This method is useful when + * dealing with type-squashed instances. + * + * @return Path argument with target type + * @throws VerifyException if this instance identifier cannot be adapted to target type + * @throws NullPointerException if {@code target} is null + */ + @SuppressWarnings("unchecked") + public final @NonNull InstanceIdentifier verifyTarget(final Class<@NonNull N> target) { + verify(target.equals(targetType), "Cannot adapt %s to %s", this, target); + return (InstanceIdentifier) this; + } + /** * Return the path argument chain which makes up this instance identifier. * * @return Path argument chain. Immutable and does not contain nulls. */ - public final Iterable getPathArguments() { + public final @NonNull Iterable getPathArguments() { return Iterables.unmodifiableIterable(pathArguments); } @@ -213,7 +216,8 @@ public class InstanceIdentifier implements Path InstanceIdentifier firstIdentifierOf(final Class type) { + public final @Nullable InstanceIdentifier firstIdentifierOf( + final Class<@NonNull I> type) { int count = 1; for (final PathArgument a : pathArguments) { if (type.equals(a.getType())) { @@ -234,28 +238,11 @@ 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. - * - * @param listItem component type - * @return key associated with the component, or null if the component type - * is not present. - */ - public final & DataObject, K extends Identifier> K firstKeyOf( - final Class listItem) { + public final & DataObject, K extends Identifier> @Nullable K firstKeyOf( + final Class<@NonNull N> listItem) { for (final PathArgument i : pathArguments) { if (listItem.equals(i.getType())) { @SuppressWarnings("unchecked") @@ -340,7 +327,7 @@ 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()); } @@ -354,7 +341,8 @@ public class InstanceIdentifier implements Path> InstanceIdentifier child(final Class container) { + public final > @NonNull InstanceIdentifier child( + final Class<@NonNull N> container) { return childIdentifier(Item.of(container)); } @@ -370,8 +358,8 @@ public class InstanceIdentifier implements Path & ChildOf, K extends Identifier> KeyedInstanceIdentifier - child(final Class listItem, final K listKey) { + public final & ChildOf, K extends Identifier> + @NonNull KeyedInstanceIdentifier child(final Class<@NonNull N> listItem, final K listKey) { return (KeyedInstanceIdentifier) childIdentifier(IdentifiableItem.of(listItem, listKey)); } @@ -386,8 +374,9 @@ public class InstanceIdentifier implements Path & DataObject, N extends ChildOf> InstanceIdentifier child( - final Class caze, final Class container) { + // FIXME: add a proper caller + public final & DataObject, N extends ChildOf> + @NonNull InstanceIdentifier child(final Class<@NonNull C> caze, final Class<@NonNull N> container) { return childIdentifier(Item.of(caze, container)); } @@ -404,10 +393,11 @@ public class InstanceIdentifier implements Path & DataObject, K extends Identifier, - N extends Identifiable & ChildOf> KeyedInstanceIdentifier child(final Class caze, - final Class listItem, final K listKey) { + N extends Identifiable & ChildOf> @NonNull KeyedInstanceIdentifier child( + final Class<@NonNull C> caze, final Class<@NonNull N> listItem, final K listKey) { return (KeyedInstanceIdentifier) childIdentifier(IdentifiableItem.of(caze, listItem, listKey)); } @@ -420,34 +410,18 @@ public class InstanceIdentifier implements Path> InstanceIdentifier augmentation( - final Class container) { + public final > @NonNull InstanceIdentifier augmentation( + final Class<@NonNull N> container) { return childIdentifier(Item.of(container)); } - @Deprecated - private List legacyCache; - - /** - * Return the path as a list. - * - * @deprecated Use {@link #getPathArguments()} instead. - */ - @Deprecated - public final List getPath() { - if (legacyCache == null) { - legacyCache = ImmutableList.copyOf(pathArguments); - } - - return legacyCache; - } - /** * Create a builder rooted at this key. * * @return A builder instance */ - public InstanceIdentifierBuilder builder() { + // FIXME: rename this method to 'toBuilder()' + public @NonNull InstanceIdentifierBuilder builder() { return new InstanceIdentifierBuilderImpl<>(Item.of(targetType), pathArguments, hash, isWildcarded()); } @@ -459,11 +433,27 @@ public class InstanceIdentifier implements Path> InstanceIdentifierBuilder 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 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 A new {@link InstanceIdentifierBuilder} + * @throws NullPointerException if any argument is null + */ + public static & DataObject, T extends ChildOf> + @NonNull InstanceIdentifierBuilder builder(final Class caze, final Class container) { + return new InstanceIdentifierBuilderImpl().addWildNode(Item.of(caze, container)); + } + /** * Create an InstanceIdentifierBuilder for a specific type of InstanceIdentifier which represents an * {@link IdentifiableItem}. @@ -476,10 +466,61 @@ public class InstanceIdentifier implements Path & ChildOf, - K extends Identifier> InstanceIdentifierBuilder builder(final Class listItem, final K 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)); + } + + public static > + @NonNull InstanceIdentifierBuilder builderOfInherited(final Class root, final Class container) { + // FIXME: we are losing root identity, hence namespaces may not work correctly + return new InstanceIdentifierBuilderImpl().addWildNode(Item.of(container)); + } + + public static & DataObject, + T extends ChildOf> + @NonNull InstanceIdentifierBuilder builderOfInherited(final Class root, + final Class caze, final Class container) { + // FIXME: we are losing root identity, hence namespaces may not work correctly + return new InstanceIdentifierBuilderImpl().addWildNode(Item.of(caze, container)); + } + + public static & ChildOf, + K extends Identifier> + @NonNull InstanceIdentifierBuilder builderOfInherited(final Class root, + final Class listItem, final K listKey) { + // FIXME: we are losing root identity, hence namespaces may not work correctly return new InstanceIdentifierBuilderImpl().addNode(IdentifiableItem.of(listItem, listKey)); } + public static & DataObject, + N extends Identifiable & ChildOf, K extends Identifier> + @NonNull InstanceIdentifierBuilder builderOfInherited(final Class root, + final Class caze, final Class listItem, final K listKey) { + // FIXME: we are losing root identity, hence namespaces may not work correctly + return new InstanceIdentifierBuilderImpl().addNode(IdentifiableItem.of(caze, listItem, listKey)); + } + /** * Create an instance identifier for a very specific object type. This method implements {@link #create(Iterable)} * semantics, except it is used by internal callers, which have assured that the argument is an immutable Iterable. @@ -489,25 +530,27 @@ public class InstanceIdentifier implements Path internalCreate(final Iterable pathArguments) { - final Iterator it = requireNonNull(pathArguments, "pathArguments may not be null") - .iterator(); + private static @NonNull InstanceIdentifier internalCreate(final Iterable pathArguments) { + final var it = requireNonNull(pathArguments, "pathArguments may not be null").iterator(); + checkArgument(it.hasNext(), "pathArguments may not be empty"); + final HashCodeBuilder hashBuilder = new HashCodeBuilder<>(); boolean wildcard = false; - PathArgument arg = null; + PathArgument arg; - while (it.hasNext()) { + do { arg = it.next(); - checkArgument(arg != null, "pathArguments may not contain null elements"); + // Non-null is implied by our callers + final var type = verifyNotNull(arg).getType(); + checkArgument(ChildOf.class.isAssignableFrom(type) || Augmentation.class.isAssignableFrom(type), + "%s is not a valid path argument", type); - // TODO: sanity check ChildOf<>; hashBuilder.addArgument(arg); - if (Identifiable.class.isAssignableFrom(arg.getType()) && !(arg instanceof IdentifiableItem)) { + if (Identifiable.class.isAssignableFrom(type) && !(arg instanceof IdentifiableItem)) { wildcard = true; } - } - checkArgument(arg != null, "pathArguments may not be empty"); + } while (it.hasNext()); return trustedCreate(arg, pathArguments, hashBuilder.build(), wildcard); } @@ -527,10 +570,11 @@ public class InstanceIdentifier implements Path create(final Iterable pathArguments) { - if (pathArguments instanceof ImmutableCollection) { + // FIXME: rename to 'unsafeOf()' + public static @NonNull InstanceIdentifier create(final Iterable pathArguments) { + if (pathArguments instanceof ImmutableCollection) { @SuppressWarnings("unchecked") - final Iterable immutableArguments = (Iterable) pathArguments; + final var immutableArguments = (ImmutableCollection) pathArguments; return internalCreate(immutableArguments); } @@ -550,9 +594,11 @@ public class InstanceIdentifier implements Path InstanceIdentifier create(final Class type) { - return (InstanceIdentifier) create(ImmutableList.of(Item.of(type))); + public static > @NonNull InstanceIdentifier create( + final Class<@NonNull T> type) { + return (InstanceIdentifier) internalCreate(ImmutableList.of(Item.of(type))); } /** @@ -563,6 +609,7 @@ public class InstanceIdentifier implements Path & DataObject, K extends Identifier> K keyOf( final InstanceIdentifier id) { requireNonNull(id); @@ -574,7 +621,7 @@ 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; @@ -600,7 +647,7 @@ public class InstanceIdentifier implements Path getType(); + @NonNull Class getType(); /** * Return an optional enclosing case type. This is used only when {@link #getType()} references a node defined @@ -616,7 +663,8 @@ public class InstanceIdentifier implements Path implements PathArgument, Serializable { private static final long serialVersionUID = 1L; - private final Class type; + + private final @NonNull Class type; AbstractPathArgument(final Class type) { this.type = requireNonNull(type, "Type may not be null."); @@ -677,14 +725,7 @@ public class InstanceIdentifier implements Path extends AbstractPathArgument { private static final long serialVersionUID = 1L; - /** - * Construct an Item. - * - * @param type Backing class - * @deprecated Use {@link #of(Class)} instead. - */ - @Deprecated - public Item(final Class type) { + Item(final Class type) { super(type); } @@ -696,7 +737,7 @@ public class InstanceIdentifier implements Path Item of(final Class type) { + public static @NonNull Item of(final Class type) { return new Item<>(type); } @@ -711,7 +752,7 @@ public class InstanceIdentifier implements Path & DataObject, T extends ChildOf> Item of( + public static & DataObject, T extends ChildOf> @NonNull Item of( final Class caseType, final Class type) { return new CaseItem<>(caseType, type); } @@ -732,17 +773,10 @@ public class InstanceIdentifier implements Path & DataObject, T extends Identifier> extends AbstractPathArgument { private static final long serialVersionUID = 1L; - private final T key; - /** - * Construct an Item. - * - * @param type Backing class - * @param key key - * @deprecated Use {@link #of(Class, Identifier)} instead. - */ - @Deprecated - 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."); } @@ -757,8 +791,8 @@ public class InstanceIdentifier implements Path & DataObject, I extends Identifier> IdentifiableItem of( - final Class type, final I key) { + public static & DataObject, I extends Identifier> + @NonNull IdentifiableItem of(final Class type, final I key) { return new IdentifiableItem<>(type, key); } @@ -775,8 +809,8 @@ public class InstanceIdentifier implements Path & DataObject, T extends ChildOf & Identifiable, - I extends Identifier> IdentifiableItem of(final Class caseType, final Class type, - final I key) { + I extends Identifier> @NonNull IdentifiableItem of(final Class caseType, + final Class type, final I key) { return new CaseIdentifiableItem<>(caseType, type, key); } @@ -786,7 +820,7 @@ public class InstanceIdentifier implements Path implements Path extends Builder> { + // FIXME: rename to 'Builder' + // FIXME: introduce KeyedBuilder with specialized build() method + public interface InstanceIdentifierBuilder { /** - * 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 * @@ -850,14 +884,12 @@ public class InstanceIdentifier implements Path> 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. + * 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 @@ -866,14 +898,13 @@ public class InstanceIdentifier implements Path & DataObject, N extends ChildOf> InstanceIdentifierBuilder child( - Class caze, Class container); + & 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. - * - * This method should be used when you want to build an instance identifier by appending a specific list element - * to the identifier + * 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. * * @param listItem List to append * @param listKey List key @@ -882,14 +913,13 @@ public class InstanceIdentifier implements Path & ChildOf, K extends Identifier> InstanceIdentifierBuilder child( - Class listItem, K listKey); + & ChildOf, K extends Identifier> + @NonNull InstanceIdentifierBuilder child(Class<@NonNull N> 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. + * 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 caze Choice case class * @param listItem List to append @@ -901,8 +931,8 @@ public class InstanceIdentifier implements Path & DataObject, K extends Identifier, - N extends Identifiable & ChildOf> InstanceIdentifierBuilder child(Class caze, - Class listItem, K listKey); + 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 @@ -913,38 +943,18 @@ public class InstanceIdentifier implements Path> InstanceIdentifierBuilder augmentation(Class container); + > @NonNull InstanceIdentifierBuilder augmentation( + Class container); /** * Build the instance identifier. * * @return Resulting instance identifier. */ - @Override - InstanceIdentifier build(); + @NonNull InstanceIdentifier build(); } - 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); } }