From a60162e7c26a1d11976d8d78ee369b23805154aa Mon Sep 17 00:00:00 2001 From: Maros Marsalek Date: Thu, 17 Mar 2016 14:29:25 +0100 Subject: Address TODOs for VPP readers Cleanup the mapping methods Clenup and document SPIs Exctract SubtreeManager interface Change-Id: Idaacebf949926107b0e4f2f467e5a4470126fa96 Signed-off-by: Maros Marsalek --- .../honeycomb/v3po/impl/trans/ChildVppReader.java | 12 +- .../honeycomb/v3po/impl/trans/ReaderRegistry.java | 8 +- .../honeycomb/v3po/impl/trans/SubtreeManager.java | 39 +++++ .../io/fd/honeycomb/v3po/impl/trans/VppReader.java | 27 ++-- .../trans/impl/AbstractCompositeVppReader.java | 87 ++++------- .../impl/trans/impl/CompositeChildVppReader.java | 36 ++++- .../impl/trans/impl/CompositeListVppReader.java | 87 ++++++----- .../impl/trans/impl/CompositeRootVppReader.java | 35 +++-- .../trans/impl/spi/ChildVppReaderCustomizer.java | 13 +- .../trans/impl/spi/ListVppReaderCustomizer.java | 24 ++- .../trans/impl/spi/RootVppReaderCustomizer.java | 18 ++- .../impl/trans/util/DelegatingReaderRegistry.java | 41 +++--- .../v3po/impl/trans/util/NoopReaderCustomizer.java | 3 +- .../v3po/impl/trans/util/ReflectionUtils.java | 79 ++++++++++ .../trans/util/ReflexiveChildReaderCustomizer.java | 2 +- .../trans/util/ReflexiveRootReaderCustomizer.java | 3 +- .../impl/trans/util/VppApiReaderCustomizer.java | 10 +- .../honeycomb/v3po/impl/trans/util/VppRWUtils.java | 164 +++++++++++++++++++++ .../v3po/impl/trans/util/VppReaderUtils.java | 152 ------------------- .../v3po/impl/vppstate/BridgeDomainCustomizer.java | 50 +++---- .../v3po/impl/vppstate/VersionCustomizer.java | 11 +- .../v3po/impl/vppstate/VppStateUtils.java | 79 ---------- .../io/fd/honeycomb/v3po/impl/vppstate/BdTest.java | 56 +++++-- .../v3po/impl/vppstate/VppStateUtils.java | 72 +++++++++ 24 files changed, 663 insertions(+), 445 deletions(-) create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/SubtreeManager.java create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/ReflectionUtils.java create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/VppRWUtils.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/VppReaderUtils.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vppstate/VppStateUtils.java create mode 100644 v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vppstate/VppStateUtils.java diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/ChildVppReader.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/ChildVppReader.java index 8f2a1ce9e..040c8fdef 100644 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/ChildVppReader.java +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/ChildVppReader.java @@ -24,16 +24,20 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; /** * Child VPP reader allowing its parent to pass the builder object + * + * @param Specific DataObject derived type, that is handled by this reader */ @Beta public interface ChildVppReader extends VppReader { /** - * Read subtree starting from node managed by this reader and place the subtree within parent builder object if - * the data exists. + * Reads subtree starting from node managed by this reader and place the subtree within parent builder object if the + * data exists. * - * @param id Unique identifier pointing to the node managed by this reader. Useful when necessary to determine - * the exact position within more complex subtrees. + * @param id Unique identifier pointing to the node managed by this reader. Useful when necessary to + * determine the exact position within more complex subtrees. + * @param parentBuilder Builder of parent DataObject. Objects read on this level (if any) must be placed into the + * parent builder. */ void read(@Nonnull final InstanceIdentifier id, @Nonnull final Builder parentBuilder); diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/ReaderRegistry.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/ReaderRegistry.java index cea5c8137..54809c98e 100644 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/ReaderRegistry.java +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/ReaderRegistry.java @@ -16,6 +16,7 @@ package io.fd.honeycomb.v3po.impl.trans; +import com.google.common.annotations.Beta; import java.util.List; import javax.annotation.Nonnull; import org.opendaylight.yangtools.yang.binding.DataObject; @@ -23,7 +24,12 @@ import org.opendaylight.yangtools.yang.binding.DataObject; /** * Simple delegating reader suitable as a holder for all other root readers, providing readAll feature */ +@Beta public interface ReaderRegistry extends VppReader { - @Nonnull List readAll(); + /** + * Perform read on all underlying readers and merge the results into a single list + */ + @Nonnull + List readAll(); } diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/SubtreeManager.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/SubtreeManager.java new file mode 100644 index 000000000..0aa927cd0 --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/SubtreeManager.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.impl.trans; + +import com.google.common.annotations.Beta; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Base identifiable subtree manager(reader, writer etc.) + * + * @param Specific DataObject derived type, that is managed by this manager + */ +@Beta +public interface SubtreeManager { + + /** + * Gets the type of node managed by this reader + * + * @return Class object for node managed by this reader + */ + @Nonnull + InstanceIdentifier getManagedDataObjectType(); +} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/VppReader.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/VppReader.java index 0033cfc07..c8c13f65a 100644 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/VppReader.java +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/VppReader.java @@ -23,10 +23,12 @@ import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; /** - * Base VPP reader, responsible for translation between DataObjects and VPP apis + * Base VPP reader, responsible for translation between DataObjects and VPP APIs + * + * @param Specific DataObject derived type, that is handled by this reader */ @Beta -public interface VppReader { +public interface VppReader extends SubtreeManager { // TODO add vpp read context that will be shared by all readers during a single read to keep useful information // preventing possible duplicate reads from VPP @@ -35,21 +37,12 @@ public interface VppReader { /** * Reads from VPP data identified by id * - * @param id unique identifier of subtree to be read. - * The subtree must contain managed data object type enforcing it to point - * to the node type managed by this reader or below. For identifiers pointing below - * node managed by this reader, its reader's responsibility to filter out the right - * node or to delegate the read to a child reader. - * - * @return List of DataObjects identified by id. If the ID points to a single node, it will be wrapped in a list + * @param id unique identifier of subtree to be read. The subtree must contain managed data object type. For + * identifiers pointing below node managed by this reader, it's reader's responsibility to filter out the + * right node or to delegate the read to a child reader. + * @return List of DataObjects identified by id. If the ID points to a single node, it will be wrapped in a list */ - @Nonnull List read(@Nonnull final InstanceIdentifier id); - + @Nonnull + List read(@Nonnull final InstanceIdentifier id); - /** - * Get the type of node managed by this reader - * - * @return Class object for node managed by this reader - */ - @Nonnull InstanceIdentifier getManagedDataObjectType(); } diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/AbstractCompositeVppReader.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/AbstractCompositeVppReader.java index 566c4fcc8..121d50dcb 100644 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/AbstractCompositeVppReader.java +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/AbstractCompositeVppReader.java @@ -18,18 +18,16 @@ package io.fd.honeycomb.v3po.impl.trans.impl; import com.google.common.annotations.Beta; import com.google.common.base.Optional; -import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; -import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import io.fd.honeycomb.v3po.impl.trans.ChildVppReader; import io.fd.honeycomb.v3po.impl.trans.VppReader; -import io.fd.honeycomb.v3po.impl.trans.util.VppReaderUtils; +import io.fd.honeycomb.v3po.impl.trans.util.ReflectionUtils; +import io.fd.honeycomb.v3po.impl.trans.util.VppRWUtils; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Collections; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import javax.annotation.Nonnull; @@ -50,52 +48,23 @@ abstract class AbstractCompositeVppReader, ChildVppReader>> augReaders; private final InstanceIdentifier instanceIdentifier; - public AbstractCompositeVppReader( - final Class managedDataObjectType, + AbstractCompositeVppReader(final Class managedDataObjectType, final List>> childReaders, final List>> augReaders) { - this.childReaders = childReadersToMap(childReaders); - this.augReaders = augReadersToMap(augReaders); + this.childReaders = VppRWUtils.uniqueLinkedIndex(childReaders, VppRWUtils.MANAGER_CLASS_FUNCTION); + this.augReaders = VppRWUtils.uniqueLinkedIndex(augReaders, VppRWUtils.MANAGER_CLASS_AUG_FUNCTION); this.instanceIdentifier = InstanceIdentifier.create(managedDataObjectType); } - protected final Map, ChildVppReader>> childReadersToMap( - final List>> childReaders) { - final LinkedHashMap, ChildVppReader>> - classVppReaderLinkedHashMap = new LinkedHashMap<>(); - - for (ChildVppReader> childReader : childReaders) { - Preconditions.checkArgument( - classVppReaderLinkedHashMap.put(childReader.getManagedDataObjectType().getTargetType(), childReader) == null, - "Duplicate (%s) child readers detected under: %s", childReader.getManagedDataObjectType(), - getManagedDataObjectType()); - } - - return classVppReaderLinkedHashMap; - } - - // FIXME add child/augReaders to one list and unify toMap helper methods + move to utils - protected final Map, ChildVppReader>> augReadersToMap( - final List>> childReaders) { - final LinkedHashMap, ChildVppReader>> - classVppReaderLinkedHashMap = new LinkedHashMap<>(); - - for (ChildVppReader childReader : childReaders) { - Preconditions.checkArgument( - classVppReaderLinkedHashMap.put(childReader.getManagedDataObjectType().getTargetType(), - (ChildVppReader>) childReader) == null, - "Duplicate (%s) child readers detected under: %s", childReader.getManagedDataObjectType(), - getManagedDataObjectType()); - } - return classVppReaderLinkedHashMap; - } - @Nonnull @Override public final InstanceIdentifier getManagedDataObjectType() { return instanceIdentifier; } + /** + * @param id {@link InstanceIdentifier} pointing to current node. In case of keyed list, key must be present. + */ protected List readCurrent(final InstanceIdentifier id) { final B builder = getBuilder(id); // Cache empty value to determine if anything has changed later TODO cache in a field @@ -103,6 +72,7 @@ abstract class AbstractCompositeVppReader> child : childReaders.values()) { child.read(id, builder); } @@ -132,53 +102,57 @@ abstract class AbstractCompositeVppReader readSubtree(final InstanceIdentifier id) { // Read only specific subtree - final Class next = VppReaderUtils.getNextId(id, getManagedDataObjectType()).getType(); + final Class next = VppRWUtils.getNextId(id, getManagedDataObjectType()).getType(); final ChildVppReader> vppReader = childReaders.get(next); if (vppReader != null) { return vppReader.read(id); } else { // If there's no dedicated reader, use read current - final InstanceIdentifier currentId = VppReaderUtils.cutId(id, getManagedDataObjectType()); + final InstanceIdentifier currentId = VppRWUtils.cutId(id, getManagedDataObjectType()); final List current = readCurrent(currentId); // then perform post-reading filtering (return only requested sub-node) return current.isEmpty() ? current : filterSubtree(current, id, getManagedDataObjectType().getTargetType()) ; } } - @SuppressWarnings("unchecked") - protected InstanceIdentifier getCurrentId(final InstanceIdentifier parentId) { - Preconditions.checkArgument(!parentId.contains(getManagedDataObjectType()), - "Unexpected InstanceIdentifier %s, already contains %s", parentId, getManagedDataObjectType()); - final InstanceIdentifier.PathArgument t = Iterables.getOnlyElement(getManagedDataObjectType().getPathArguments()); - return (InstanceIdentifier) InstanceIdentifier.create(Iterables.concat( - parentId.getPathArguments(), Collections.singleton(t))); - } - + /** + * Fill in current node's attributes + * + * @param id {@link InstanceIdentifier} pointing to current node. In case of keyed list, key must be present. + * @param builder Builder object for current node where the read attributes must be placed + */ protected abstract void readCurrentAttributes(final InstanceIdentifier id, B builder); - protected abstract B getBuilder(InstanceIdentifier id); + /** + * Return new instance of a builder object for current node + * + * @param id {@link InstanceIdentifier} pointing to current node. In case of keyed list, key must be present. + * @return Builder object for current node type + */ + protected abstract B getBuilder(InstanceIdentifier id); // TODO move filtering out of here into a dedicated Filter ifc @Nonnull private static List filterSubtree(@Nonnull final List built, @Nonnull final InstanceIdentifier absolutPath, @Nonnull final Class managedType) { - // TODO is there a better way than reflection ? + // TODO is there a better way than reflection ? e.g. convert into NN and filter out with a utility + // FIXME this needs to be recursive. right now it expects only 1 additional element in ID + test List filtered = Lists.newArrayList(); for (DataObject parent : built) { final InstanceIdentifier.PathArgument nextId = - VppReaderUtils.getNextId(absolutPath, InstanceIdentifier.create(parent.getClass())); + VppRWUtils.getNextId(absolutPath, InstanceIdentifier.create(parent.getClass())); - Optional method = VppReaderUtils.findMethodReflex(managedType, "get", + Optional method = ReflectionUtils.findMethodReflex(managedType, "get", Collections.>emptyList(), nextId.getType()); if (method.isPresent()) { filterSingle(filtered, parent, nextId, method); } else { // List child nodes - method = VppReaderUtils.findMethodReflex(managedType, + method = ReflectionUtils.findMethodReflex(managedType, "get" + nextId.getType().getSimpleName(), Collections.>emptyList(), List.class); if (method.isPresent()) { @@ -204,7 +178,7 @@ abstract class AbstractCompositeVppReader keyGetter = - VppReaderUtils.findMethodReflex(nextId.getType(), "get", + ReflectionUtils.findMethodReflex(nextId.getType(), "get", Collections.>emptyList(), key.getClass()); final Object actualKey; actualKey = invoke(keyGetter.get(), nextId, input); @@ -229,5 +203,4 @@ abstract class AbstractCompositeVppReader> extends AbstractCompositeVppReader +public final class CompositeChildVppReader> extends AbstractCompositeVppReader implements ChildVppReader { private final ChildVppReaderCustomizer customizer; + /** + * Create new {@link CompositeChildVppReader} + * + * @param managedDataObjectType Class object for managed data type + * @param childReaders Child nodes(container, list) readers + * @param augReaders Child augmentations readers + * @param customizer Customizer instance to customize this generic reader + * + */ public CompositeChildVppReader(@Nonnull final Class managedDataObjectType, @Nonnull final List>> childReaders, @Nonnull final List>> augReaders, @@ -45,22 +58,29 @@ public class CompositeChildVppReader> this.customizer = customizer; } + /** + * @see {@link CompositeChildVppReader#CompositeChildVppReader(Class, List, List, ChildVppReaderCustomizer)} + */ public CompositeChildVppReader(@Nonnull final Class managedDataObjectType, @Nonnull final List>> childReaders, @Nonnull final ChildVppReaderCustomizer customizer) { - this(managedDataObjectType, childReaders, VppReaderUtils.emptyAugReaderList(), customizer); + this(managedDataObjectType, childReaders, VppRWUtils.emptyAugReaderList(), customizer); } + /** + * @see {@link CompositeChildVppReader#CompositeChildVppReader(Class, List, List, ChildVppReaderCustomizer)} + */ public CompositeChildVppReader(@Nonnull final Class managedDataObjectType, @Nonnull final ChildVppReaderCustomizer customizer) { - this(managedDataObjectType, VppReaderUtils.emptyChildReaderList(), VppReaderUtils.emptyAugReaderList(), + this(managedDataObjectType, VppRWUtils.emptyChildReaderList(), VppRWUtils.emptyAugReaderList(), customizer); } @Override public final void read(@Nonnull final InstanceIdentifier parentId, @Nonnull final Builder parentBuilder) { - final Optional read = Optional.fromNullable(readCurrent(getCurrentId(parentId)).get(0)); + final Optional read = Optional.fromNullable(readCurrent(VppRWUtils.appendTypeToId(parentId, + getManagedDataObjectType())).get(0)); if(read.isPresent()) { customizer.merge(parentBuilder, read.get()); @@ -69,12 +89,12 @@ public class CompositeChildVppReader> @Override protected void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final B builder) { - customizer.readCurrentAttributes(builder); + customizer.readCurrentAttributes(id, builder); } @Override - protected B getBuilder(@Nonnull final InstanceIdentifier id) { - return customizer.getBuilder(); + protected B getBuilder(@Nonnull final InstanceIdentifier id) { + return customizer.getBuilder(id); } } diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/CompositeListVppReader.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/CompositeListVppReader.java index f280fdb76..d64a83ccc 100644 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/CompositeListVppReader.java +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/CompositeListVppReader.java @@ -16,15 +16,15 @@ package io.fd.honeycomb.v3po.impl.trans.impl; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; + import com.google.common.annotations.Beta; import com.google.common.base.Function; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import io.fd.honeycomb.v3po.impl.trans.ChildVppReader; import io.fd.honeycomb.v3po.impl.trans.impl.spi.ListVppReaderCustomizer; -import io.fd.honeycomb.v3po.impl.trans.util.VppReaderUtils; -import java.util.Collections; +import io.fd.honeycomb.v3po.impl.trans.util.VppRWUtils; import java.util.List; import javax.annotation.Nonnull; import javax.annotation.concurrent.ThreadSafe; @@ -36,13 +36,29 @@ import org.opendaylight.yangtools.yang.binding.Identifiable; import org.opendaylight.yangtools.yang.binding.Identifier; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +/** + * Composite implementation of {@link ChildVppReader} able to place the read result into + * parent builder object intended for list node type. + * + * This reader checks if the IDs are wildcarded in which case it performs read of all + * list entries. In case the ID has a key, it reads only the specified value. + */ @Beta @ThreadSafe public final class CompositeListVppReader, K extends Identifier, B extends Builder> extends AbstractCompositeVppReader implements ChildVppReader { - private ListVppReaderCustomizer customizer; - + private final ListVppReaderCustomizer customizer; + + /** + * Create new {@link CompositeListVppReader} + * + * @param managedDataObjectType Class object for managed data type. Must come from a list node type. + * @param childReaders Child nodes(container, list) readers + * @param augReaders Child augmentations readers + * @param customizer Customizer instance to customize this generic reader + * + */ public CompositeListVppReader(@Nonnull final Class managedDataObjectType, @Nonnull final List>> childReaders, @Nonnull final List>> augReaders, @@ -51,60 +67,51 @@ public final class CompositeListVppReader this.customizer = customizer; } + /** + * @see {@link CompositeListVppReader#CompositeListVppReader(Class, List, List, ListVppReaderCustomizer)} + */ public CompositeListVppReader(@Nonnull final Class managedDataObjectType, @Nonnull final List>> childReaders, @Nonnull final ListVppReaderCustomizer customizer) { - this(managedDataObjectType, childReaders, VppReaderUtils.emptyAugReaderList(), customizer); + this(managedDataObjectType, childReaders, VppRWUtils.emptyAugReaderList(), customizer); } + /** + * @see {@link CompositeListVppReader#CompositeListVppReader(Class, List, List, ListVppReaderCustomizer)} + */ public CompositeListVppReader(@Nonnull final Class managedDataObjectType, @Nonnull final ListVppReaderCustomizer customizer) { - this(managedDataObjectType, VppReaderUtils.emptyChildReaderList(), VppReaderUtils.emptyAugReaderList(), + this(managedDataObjectType, VppRWUtils.emptyChildReaderList(), VppRWUtils.emptyAugReaderList(), customizer); } @Override protected List readCurrent(@Nonnull final InstanceIdentifier id) { - if(shouldReadAll(id)) { - return readList(id); - } - return super.readCurrent(id); + return shouldReadAll(id) ? readList(id) : super.readCurrent(id); } @Override public void read(@Nonnull final InstanceIdentifier id, @Nonnull final Builder parentBuilder) { - final InstanceIdentifier currentId = getCurrentId(id); - - final List ifcs; - if (shouldReadAll(id)) { - ifcs = readList(currentId); - } else { - final Optional readSingle = Optional.fromNullable(read(id).get(0)); - final Optional read = readSingle.transform(new Function() { - @Override - public C apply(final DataObject input) { - Preconditions.checkArgument(getManagedDataObjectType().getTargetType().isAssignableFrom(input.getClass())); - return getManagedDataObjectType().getTargetType().cast(input); - } - }); - ifcs = read.isPresent() ? Collections.singletonList(read.get()) : Collections.emptyList(); - } - + // Create ID pointing to current node + final InstanceIdentifier currentId = VppRWUtils.appendTypeToId(id, getManagedDataObjectType()); + // Read all, since current ID is definitely wildcarded + final List ifcs = readList(currentId); customizer.merge(parentBuilder, ifcs); } private List readList(@Nonnull final InstanceIdentifier id) { - Preconditions.checkArgument(id.getTargetType().equals(getManagedDataObjectType().getTargetType()), - "Id %s does not contain expected type %s", id, getManagedDataObjectType()); - - return Lists.transform(customizer.getAllIds(id), new Function, C>() { + return Lists.transform(customizer.getAllIds(id), new Function() { @Override - public C apply(final InstanceIdentifier input) { - final List read = read(input); - Preconditions.checkState(read.size() == 1); - Preconditions.checkArgument(getManagedDataObjectType().getTargetType().isAssignableFrom(read.get(0).getClass())); - return getManagedDataObjectType().getTargetType().cast(read.get(0)); + public C apply(final K key) { + final InstanceIdentifier.IdentifiableItem currentBdItem = + VppRWUtils.getCurrentIdItem(id, key); + final InstanceIdentifier keyedId = VppRWUtils.replaceLastInId(id, currentBdItem); + final List read = read(keyedId); + checkState(read.size() == 1); + final DataObject singleItem = read.get(0); + checkArgument(getManagedDataObjectType().getTargetType().isAssignableFrom(singleItem.getClass())); + return getManagedDataObjectType().getTargetType().cast(singleItem); } }); } @@ -120,8 +127,8 @@ public final class CompositeListVppReader } @Override - protected B getBuilder(@Nonnull final InstanceIdentifier id) { - return customizer.getBuilder(id.firstKeyOf(getManagedDataObjectType().getTargetType())); + protected B getBuilder(@Nonnull final InstanceIdentifier id) { + return customizer.getBuilder(id); } } diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/CompositeRootVppReader.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/CompositeRootVppReader.java index 605f1b628..1e6b7e93a 100644 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/CompositeRootVppReader.java +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/CompositeRootVppReader.java @@ -20,7 +20,7 @@ import com.google.common.annotations.Beta; import io.fd.honeycomb.v3po.impl.trans.ChildVppReader; import io.fd.honeycomb.v3po.impl.trans.VppReader; import io.fd.honeycomb.v3po.impl.trans.impl.spi.RootVppReaderCustomizer; -import io.fd.honeycomb.v3po.impl.trans.util.VppReaderUtils; +import io.fd.honeycomb.v3po.impl.trans.util.VppRWUtils; import java.util.List; import javax.annotation.Nonnull; import javax.annotation.concurrent.ThreadSafe; @@ -30,6 +30,9 @@ import org.opendaylight.yangtools.yang.binding.ChildOf; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +/** + * Composite implementation of {@link VppReader} + */ @Beta @ThreadSafe public final class CompositeRootVppReader> extends AbstractCompositeVppReader @@ -37,35 +40,49 @@ public final class CompositeRootVppReader customizer; + /** + * Create new {@link CompositeRootVppReader} + * + * @param managedDataObjectType Class object for managed data type + * @param childReaders Child nodes(container, list) readers + * @param augReaders Child augmentations readers + * @param customizer Customizer instance to customize this generic reader + * + */ public CompositeRootVppReader(@Nonnull final Class managedDataObjectType, @Nonnull final List>> childReaders, - @Nonnull final List>> childAugReaders, + @Nonnull final List>> augReaders, @Nonnull final RootVppReaderCustomizer customizer) { - super(managedDataObjectType, childReaders, childAugReaders); + super(managedDataObjectType, childReaders, augReaders); this.customizer = customizer; } + /** + * @see {@link CompositeRootVppReader#CompositeRootVppReader(Class, List, List, RootVppReaderCustomizer)} + */ public CompositeRootVppReader(@Nonnull final Class managedDataObjectType, @Nonnull final List>> childReaders, @Nonnull final RootVppReaderCustomizer customizer) { - this(managedDataObjectType, childReaders, VppReaderUtils.emptyAugReaderList(), customizer); + this(managedDataObjectType, childReaders, VppRWUtils.emptyAugReaderList(), customizer); } + /** + * @see {@link CompositeRootVppReader#CompositeRootVppReader(Class, List, List, RootVppReaderCustomizer)} + */ public CompositeRootVppReader(@Nonnull final Class managedDataObjectType, @Nonnull final RootVppReaderCustomizer customizer) { - this(managedDataObjectType, VppReaderUtils.emptyChildReaderList(), VppReaderUtils.emptyAugReaderList(), + this(managedDataObjectType, VppRWUtils.emptyChildReaderList(), VppRWUtils.emptyAugReaderList(), customizer); } @Override protected void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final B builder) { - customizer.readCurrentAttributes(builder); + customizer.readCurrentAttributes(id, builder); } @Override - protected B getBuilder(@Nonnull final InstanceIdentifier id) { - // TODO instantiate builder from customizer(as is) or reflection ? - return customizer.getBuilder(); + protected B getBuilder(@Nonnull final InstanceIdentifier id) { + return customizer.getBuilder(id); } } diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/spi/ChildVppReaderCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/spi/ChildVppReaderCustomizer.java index 7cf0b60f6..29cfe3eeb 100644 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/spi/ChildVppReaderCustomizer.java +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/spi/ChildVppReaderCustomizer.java @@ -17,13 +17,22 @@ package io.fd.honeycomb.v3po.impl.trans.impl.spi; import com.google.common.annotations.Beta; +import javax.annotation.Nonnull; import org.opendaylight.yangtools.concepts.Builder; import org.opendaylight.yangtools.yang.binding.DataObject; +/** + * io.fd.honeycomb.v3po.impl.trans.impl.CompositeChildVppReader SPI to customize its behavior + */ @Beta public interface ChildVppReaderCustomizer> extends RootVppReaderCustomizer { - // FIXME need to capture parent builder type, but that's a inconvenient - void merge(Builder parentBuilder, C readValue); + // FIXME need to capture parent builder type, but that's inconvenient at best, is it ok to leave it Builder and + // cast in specific customizers ? ... probably better than adding another type parameter + + /** + * Merge read data into provided parent builder + */ + void merge(@Nonnull final Builder parentBuilder, @Nonnull final C readValue); } diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/spi/ListVppReaderCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/spi/ListVppReaderCustomizer.java index 855e8488d..8a6812dd6 100644 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/spi/ListVppReaderCustomizer.java +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/spi/ListVppReaderCustomizer.java @@ -18,20 +18,30 @@ package io.fd.honeycomb.v3po.impl.trans.impl.spi; import com.google.common.annotations.Beta; import java.util.List; +import javax.annotation.Nonnull; import org.opendaylight.yangtools.concepts.Builder; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.Identifiable; import org.opendaylight.yangtools.yang.binding.Identifier; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +/** + * io.fd.honeycomb.v3po.impl.trans.impl.CompositeListVppReader SPI to customize its behavior + */ @Beta -public interface ListVppReaderCustomizer, K extends Identifier, B extends Builder> { - - void readCurrentAttributes(final InstanceIdentifier id, B builder); - - B getBuilder(K id); +public interface ListVppReaderCustomizer, K extends Identifier, B extends Builder> + extends RootVppReaderCustomizer { - List> getAllIds(InstanceIdentifier id); + /** + * Return list with IDs of all list nodes to be read. + * + * @param id wildcarded ID pointing to list node managed by enclosing reader + */ + @Nonnull + List getAllIds(@Nonnull final InstanceIdentifier id); - void merge(Builder builder, List currentBuilder); + /** + * Merge read data into provided parent builder + */ + void merge(@Nonnull final Builder builder, @Nonnull final List readData); } diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/spi/RootVppReaderCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/spi/RootVppReaderCustomizer.java index fe09220d2..463e4f9d6 100644 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/spi/RootVppReaderCustomizer.java +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/spi/RootVppReaderCustomizer.java @@ -17,13 +17,27 @@ package io.fd.honeycomb.v3po.impl.trans.impl.spi; import com.google.common.annotations.Beta; +import javax.annotation.Nonnull; import org.opendaylight.yangtools.concepts.Builder; import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +/** + * io.fd.honeycomb.v3po.impl.trans.impl.CompositeRootVppReader SPI to customize its behavior + */ @Beta public interface RootVppReaderCustomizer> { - B getBuilder(); + // TODO add (un)checked, well defined exception here to indicate issues in the customizer + + /** + * Create new builder that will be used to build read value + */ + @Nonnull + B getBuilder(@Nonnull final InstanceIdentifier id); - void readCurrentAttributes(B builder); + /** + * Add current data (identified by id) to the provided builder + */ + void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final B builder); } diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/DelegatingReaderRegistry.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/DelegatingReaderRegistry.java index 0aeda896a..5225bab63 100644 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/DelegatingReaderRegistry.java +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/DelegatingReaderRegistry.java @@ -16,42 +16,41 @@ package io.fd.honeycomb.v3po.impl.trans.util; -import com.google.common.base.Function; -import com.google.common.base.Preconditions; +import static com.google.common.base.Preconditions.checkNotNull; + import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; import io.fd.honeycomb.v3po.impl.trans.ReaderRegistry; import io.fd.honeycomb.v3po.impl.trans.VppReader; +import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.annotation.Nonnull; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +/** + * Simple reader registry able to perform and aggregated read (ROOT read) on top of all + * provided readers. Also able to delegate a specific read to one of the delegate readers. + * + * This could serve as a utility to hold & hide all available readers in upper layers. + */ public final class DelegatingReaderRegistry implements ReaderRegistry { private final Map, VppReader> rootReaders; + /** + * Create new {@link DelegatingReaderRegistry} + * + * @param rootReaders List of delegate readers + */ public DelegatingReaderRegistry(@Nonnull final List> rootReaders) { - this.rootReaders = toMap(rootReaders); - } - - private static Map, VppReader> toMap( - final List> rootReaders) { - return Maps - .uniqueIndex(rootReaders, new Function, Class>() { - @Override - public Class apply(final VppReader input) { - return input.getManagedDataObjectType().getTargetType(); - } - }); + this.rootReaders = VppRWUtils.uniqueLinkedIndex(checkNotNull(rootReaders), VppRWUtils.MANAGER_CLASS_FUNCTION); } @Override @Nonnull public List readAll() { - final List objects = Lists.newArrayListWithExpectedSize(rootReaders.size()); + final List objects = new ArrayList<>(rootReaders.size()); for (VppReader rootReader : rootReaders.values()) { final List read = rootReader.read(rootReader.getManagedDataObjectType()); objects.addAll(read); @@ -62,14 +61,18 @@ public final class DelegatingReaderRegistry implements ReaderRegistry { @Nonnull @Override public List read(@Nonnull final InstanceIdentifier id) { - final InstanceIdentifier.PathArgument first = Preconditions.checkNotNull( + final InstanceIdentifier.PathArgument first = checkNotNull( Iterables.getFirst(id.getPathArguments(), null), "Empty id"); final VppReader vppReader = rootReaders.get(first.getType()); - Preconditions.checkNotNull(vppReader, + checkNotNull(vppReader, "Unable to read %s. Missing reader. Current readers for: %s", id, rootReaders.keySet()); return vppReader.read(id); } + /** + * @throws UnsupportedOperationException This getter is not supported for reader registry since it does not manage a + * specific node type + */ @Nonnull @Override public InstanceIdentifier getManagedDataObjectType() { diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/NoopReaderCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/NoopReaderCustomizer.java index 050f7171f..b485a6db4 100644 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/NoopReaderCustomizer.java +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/NoopReaderCustomizer.java @@ -19,11 +19,12 @@ package io.fd.honeycomb.v3po.impl.trans.util; import io.fd.honeycomb.v3po.impl.trans.impl.spi.RootVppReaderCustomizer; import org.opendaylight.yangtools.concepts.Builder; import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; public abstract class NoopReaderCustomizer> implements RootVppReaderCustomizer { @Override - public void readCurrentAttributes(final B builder) { + public void readCurrentAttributes(InstanceIdentifier id, final B builder) { // Noop } } diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/ReflectionUtils.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/ReflectionUtils.java new file mode 100644 index 000000000..6602d750d --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/ReflectionUtils.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.impl.trans.util; + +import com.google.common.base.Optional; +import java.lang.reflect.Method; +import java.util.List; +import javax.annotation.Nonnull; + +/** + * Reflection based utilities + */ +public final class ReflectionUtils { + + private ReflectionUtils() {} + + /** + * Find a specific method using reflection + * + * @param managedType Class object to find method in + * @param prefix Method name prefix used when finding the method. Case does not matter. + * @param paramTypes List of input argument types + * @param retType Return type + * + * @return Found method or Optional.absent() if there's no such method + */ + @Nonnull + public static Optional findMethodReflex(@Nonnull final Class managedType, + @Nonnull final String prefix, + @Nonnull final List> paramTypes, + @Nonnull final Class retType) { + for (Method method : managedType.getMethods()) { + if(isMethodMatch(prefix, paramTypes, retType, method)) { + return Optional.of(method); + } + } + + return Optional.absent(); + } + + private static boolean isMethodMatch(final @Nonnull String prefix, + final @Nonnull List> paramTypes, + final @Nonnull Class retType, final Method method) { + if (!method.getName().toLowerCase().startsWith(prefix.toLowerCase())) { + return false; + } + + final Class[] parameterTypes = method.getParameterTypes(); + if (parameterTypes.length != paramTypes.size()) { + return false; + } + + for (int i = 0; i < parameterTypes.length; i++) { + if (!parameterTypes[i].isAssignableFrom(paramTypes.get(i))) { + return false; + } + } + + if (!method.getReturnType().equals(retType)) { + return false; + } + + return true; + } +} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/ReflexiveChildReaderCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/ReflexiveChildReaderCustomizer.java index 28a44eb07..d67a3afbb 100644 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/ReflexiveChildReaderCustomizer.java +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/ReflexiveChildReaderCustomizer.java @@ -41,7 +41,7 @@ public class ReflexiveChildReaderCustomizer parentBuilder, final C readValue) { final Optional method = - VppReaderUtils.findMethodReflex(parentBuilder.getClass(), "set", + ReflectionUtils.findMethodReflex(parentBuilder.getClass(), "set", Collections.>singletonList(readValue.getClass()), parentBuilder.getClass()); Preconditions.checkArgument(method.isPresent(), "Unable to set %s to %s", readValue, parentBuilder); diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/ReflexiveRootReaderCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/ReflexiveRootReaderCustomizer.java index 2a98bbe5b..2568f9886 100644 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/ReflexiveRootReaderCustomizer.java +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/ReflexiveRootReaderCustomizer.java @@ -18,6 +18,7 @@ package io.fd.honeycomb.v3po.impl.trans.util; import org.opendaylight.yangtools.concepts.Builder; import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; /** * Might be slow ! @@ -31,7 +32,7 @@ public class ReflexiveRootReaderCustomizer id) { try { return builderClass.newInstance(); } catch (InstantiationException | IllegalAccessException e) { diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/VppApiReaderCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/VppApiReaderCustomizer.java index 584c7823f..1ca898c8c 100644 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/VppApiReaderCustomizer.java +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/VppApiReaderCustomizer.java @@ -18,15 +18,23 @@ package io.fd.honeycomb.v3po.impl.trans.util; import com.google.common.annotations.Beta; +/** + * Abstract utility to hold the vppApi reference. + */ @Beta public abstract class VppApiReaderCustomizer { private final org.openvpp.vppjapi.vppApi vppApi; - public VppApiReaderCustomizer(final org.openvpp.vppjapi.vppApi vppApi) { + protected VppApiReaderCustomizer(final org.openvpp.vppjapi.vppApi vppApi) { this.vppApi = vppApi; } + /** + * Get vppApi reference + * + * @return vppApi reference + */ public org.openvpp.vppjapi.vppApi getVppApi() { return vppApi; } diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/VppRWUtils.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/VppRWUtils.java new file mode 100644 index 000000000..1cc0dfe92 --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/VppRWUtils.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.impl.trans.util; + +import com.google.common.base.Function; +import com.google.common.base.Preconditions; +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; +import com.google.common.collect.Maps; +import io.fd.honeycomb.v3po.impl.trans.ChildVppReader; +import io.fd.honeycomb.v3po.impl.trans.SubtreeManager; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.Augmentation; +import org.opendaylight.yangtools.yang.binding.ChildOf; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.Identifiable; +import org.opendaylight.yangtools.yang.binding.Identifier; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public final class VppRWUtils { + + private VppRWUtils() {} + + /** + * Find next item in ID after provided type + */ + @Nonnull + public static InstanceIdentifier.PathArgument getNextId(@Nonnull final InstanceIdentifier id, + @Nonnull final InstanceIdentifier type) { + // TODO this is inefficient(maybe, depending on actual Iterable type) + final Iterable pathArguments = id.getPathArguments(); + final int i = Iterables.indexOf(pathArguments, new Predicate() { + @Override + public boolean apply(final InstanceIdentifier.PathArgument input) { + return input.getType().isAssignableFrom(type.getTargetType()); + } + }); + Preconditions.checkArgument(i >= 0, "Unable to find %s type in %s", type.getTargetType(), id); + return Iterables.get(pathArguments, i + 1); + } + + public static List>> emptyChildReaderList() { + return Collections.emptyList(); + } + + public static List>> emptyAugReaderList() { + return Collections.emptyList(); + } + + public static List>> singletonAugReaderList( + ChildVppReader> item) { + return Collections.>>singletonList(item); + } + + public static List>> singletonChildReaderList( + ChildVppReader> item) { + return Collections.>>singletonList(item); + } + + /** + * Replace last item in ID with a provided IdentifiableItem of the same type + */ + @SuppressWarnings("unchecked") + @Nonnull + public static , K extends Identifier> InstanceIdentifier replaceLastInId( + @Nonnull final InstanceIdentifier id, final InstanceIdentifier.IdentifiableItem currentBdItem) { + + final Iterable pathArguments = id.getPathArguments(); + final Iterable withoutCurrent = + Iterables.limit(pathArguments, Iterables.size(pathArguments) - 1); + final Iterable concat = + Iterables.concat(withoutCurrent, Collections.singleton(currentBdItem)); + return (InstanceIdentifier) InstanceIdentifier.create(concat); + } + + /** + * Create IdentifiableItem from target type of provided ID with provided key + */ + @Nonnull + public static , K extends Identifier> InstanceIdentifier.IdentifiableItem getCurrentIdItem( + @Nonnull final InstanceIdentifier id, final K key) { + return new InstanceIdentifier.IdentifiableItem<>(id.getTargetType(), key); + } + + /** + * Trim InstanceIdentifier at indexOf(type) + */ + @SuppressWarnings("unchecked") + @Nonnull + public static InstanceIdentifier cutId(@Nonnull final InstanceIdentifier id, + @Nonnull final InstanceIdentifier type) { + final Iterable pathArguments = id.getPathArguments(); + final int i = Iterables.indexOf(pathArguments, new Predicate() { + @Override + public boolean apply(final InstanceIdentifier.PathArgument input) { + return input.getType().equals(type.getTargetType()); + } + }); + Preconditions.checkArgument(i >= 0, "ID %s does not contain %s", id, type); + return (InstanceIdentifier) InstanceIdentifier.create(Iterables.limit(pathArguments, i + 1)); + } + + /** + * Create a map from a collection, checking for duplicity in the process + */ + @Nonnull + public static Map uniqueLinkedIndex(@Nonnull final Collection values, @Nonnull final Function keyFunction) { + final Map objectObjectLinkedHashMap = Maps.newLinkedHashMap(); + for (V value : values) { + final K key = keyFunction.apply(value); + Preconditions.checkArgument(objectObjectLinkedHashMap.put(key, value) == null, + "Duplicate key detected : %s", key); + } + return objectObjectLinkedHashMap; + } + + public static final Function, Class> + MANAGER_CLASS_FUNCTION = new Function, Class>() { + @Override + public Class apply(final SubtreeManager input) { + return input.getManagedDataObjectType().getTargetType(); + } + }; + + public static final Function>, Class> + MANAGER_CLASS_AUG_FUNCTION = new Function>, Class>() { + + @Override + @SuppressWarnings("unchecked") + public Class apply(final SubtreeManager> input) { + final Class> targetType = input.getManagedDataObjectType().getTargetType(); + Preconditions.checkArgument(DataObject.class.isAssignableFrom(targetType)); + return (Class) targetType; + } + }; + + @SuppressWarnings("unchecked") + public static InstanceIdentifier appendTypeToId( + final InstanceIdentifier parentId, final InstanceIdentifier type) { + Preconditions.checkArgument(!parentId.contains(type), + "Unexpected InstanceIdentifier %s, already contains %s", parentId, type); + final InstanceIdentifier.PathArgument t = Iterables.getOnlyElement(type.getPathArguments()); + return (InstanceIdentifier) InstanceIdentifier.create(Iterables.concat( + parentId.getPathArguments(), Collections.singleton(t))); + } +} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/VppReaderUtils.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/VppReaderUtils.java deleted file mode 100644 index 07c54ae90..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/VppReaderUtils.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (c) 2016 Cisco and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.fd.honeycomb.v3po.impl.trans.util; - -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; -import com.google.common.base.Predicate; -import com.google.common.collect.Iterables; -import io.fd.honeycomb.v3po.impl.trans.ChildVppReader; -import java.lang.reflect.Method; -import java.util.Collections; -import java.util.List; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.yang.binding.Augmentation; -import org.opendaylight.yangtools.yang.binding.ChildOf; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.Identifiable; -import org.opendaylight.yangtools.yang.binding.Identifier; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -public final class VppReaderUtils { - - private VppReaderUtils() {} - - /** - * Find next item in ID after provided type - */ - @Nonnull - public static InstanceIdentifier.PathArgument getNextId(@Nonnull final InstanceIdentifier id, - @Nonnull final InstanceIdentifier type) { - // TODO this is inefficient(maybe, depending on actual Iterable type) - final Iterable pathArguments = id.getPathArguments(); - final int i = Iterables.indexOf(pathArguments, new Predicate() { - @Override - public boolean apply(final InstanceIdentifier.PathArgument input) { - return input.getType().isAssignableFrom(type.getTargetType()); - } - }); - Preconditions.checkArgument(i >= 0, "Unable to find %s type in %s", type.getTargetType(), id); - return Iterables.get(pathArguments, i + 1); - } - - public static List>> emptyChildReaderList() { - return Collections.emptyList(); - } - - public static List>> emptyAugReaderList() { - return Collections.emptyList(); - } - - public static List>> singletonAugReaderList( - ChildVppReader> item) { - return Collections.>>singletonList(item); - } - - public static List>> singletonChildReaderList( - ChildVppReader> item) { - return Collections.>>singletonList(item); - } - - /** - * Replace last item in ID with a provided IdentifiableItem of the same type - */ - @SuppressWarnings("unchecked") - @Nonnull - public static , K extends Identifier> InstanceIdentifier getCurrentId( - @Nonnull final InstanceIdentifier id, final InstanceIdentifier.IdentifiableItem currentBdItem) { - - final Iterable pathArguments = id.getPathArguments(); - final Iterable withoutCurrent = - Iterables.limit(pathArguments, Iterables.size(pathArguments) - 1); - final Iterable concat = - Iterables.concat(withoutCurrent, Collections.singleton(currentBdItem)); - return (InstanceIdentifier) InstanceIdentifier.create(concat); - } - - /** - * Create IdentifiableItem from target type of provided ID with provided key - */ - @Nonnull - public static , K extends Identifier> InstanceIdentifier.IdentifiableItem getCurrentIdItem( - @Nonnull final InstanceIdentifier id, final K key) { - return new InstanceIdentifier.IdentifiableItem<>(id.getTargetType(), key); - } - - /** - * Trim InstanceIdentifier at indexOf(type) - */ - @SuppressWarnings("unchecked") - @Nonnull - public static InstanceIdentifier cutId(@Nonnull final InstanceIdentifier id, - @Nonnull final InstanceIdentifier type) { - final Iterable pathArguments = id.getPathArguments(); - final int i = Iterables.indexOf(pathArguments, new Predicate() { - @Override - public boolean apply(final InstanceIdentifier.PathArgument input) { - return input.getType().equals(type.getTargetType()); - } - }); - Preconditions.checkArgument(i >= 0, "ID %s does not contain %s", id, type); - return (InstanceIdentifier) InstanceIdentifier.create(Iterables.limit(pathArguments, i + 1)); - } - - /** - * Find a specific method using reflection - */ - @Nonnull - public static Optional findMethodReflex(@Nonnull final Class managedType, - @Nonnull final String prefix, - @Nonnull final List> paramTypes, - @Nonnull final Class retType) { - top: - for (Method method : managedType.getMethods()) { - if (!method.getName().toLowerCase().startsWith(prefix.toLowerCase())) { - continue; - } - - final Class[] parameterTypes = method.getParameterTypes(); - if (parameterTypes.length != paramTypes.size()) { - continue; - } - - for (int i = 0; i < parameterTypes.length; i++) { - if (!parameterTypes[i].isAssignableFrom(paramTypes.get(i))) { - continue top; - } - } - - if (!method.getReturnType().equals(retType)) { - continue; - } - - return Optional.of(method); - } - - return Optional.absent(); - } -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vppstate/BridgeDomainCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vppstate/BridgeDomainCustomizer.java index 447f8509c..97d1867c2 100644 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vppstate/BridgeDomainCustomizer.java +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vppstate/BridgeDomainCustomizer.java @@ -19,8 +19,9 @@ package io.fd.honeycomb.v3po.impl.vppstate; import com.google.common.collect.Lists; import io.fd.honeycomb.v3po.impl.trans.impl.spi.ListVppReaderCustomizer; import io.fd.honeycomb.v3po.impl.trans.util.VppApiReaderCustomizer; -import io.fd.honeycomb.v3po.impl.trans.util.VppReaderUtils; +import java.util.ArrayList; import java.util.List; +import javax.annotation.Nonnull; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.BridgeDomainsBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain; @@ -32,6 +33,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.L2Fib; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.L2FibBuilder; import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.openvpp.vppjapi.vppBridgeDomainDetails; import org.openvpp.vppjapi.vppBridgeDomainInterfaceDetails; @@ -40,27 +42,19 @@ import org.openvpp.vppjapi.vppL2Fib; public final class BridgeDomainCustomizer extends VppApiReaderCustomizer implements ListVppReaderCustomizer { - public BridgeDomainCustomizer(final org.openvpp.vppjapi.vppApi vppApi) { + public BridgeDomainCustomizer(@Nonnull final org.openvpp.vppjapi.vppApi vppApi) { super(vppApi); } @Override - public void readCurrentAttributes(final InstanceIdentifier id, - final BridgeDomainBuilder builder) { + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final BridgeDomainBuilder builder) { final BridgeDomainKey key = id.firstKeyOf(id.getTargetType()); - final int bdId; - try { - bdId = Integer.parseInt(key.getName()); - } catch (NumberFormatException e) { - // LOG.warn("Invalid key", e); - return; - } + // TODO find out if bd exists based on name and if not return + + final int bdId = getVppApi().bridgeDomainIdFromName(key.getName()); final vppBridgeDomainDetails bridgeDomainDetails = getVppApi().getBridgeDomainDetails(bdId); - // FIXME, the problem here is that while going to VPP, the id for vbd is integer ID - // However in the models vbd's key is the name - // And you can get vbd name from vbd's ID using vppAPI, but not the other way around, making the API hard to use - // TO solve it, we need to store the vbd ID <-> vbd Name mapping in the (not-yet-available) read context and use it here builder.setName(key.getName()); // builder.setName(bridgeDomainDetails.name); builder.setArpTermination(bridgeDomainDetails.arpTerm); @@ -99,7 +93,7 @@ public final class BridgeDomainCustomizer extends VppApiReaderCustomizer } private List getIfcs(final vppBridgeDomainDetails bridgeDomainDetails) { - final List ifcs = Lists.newArrayListWithExpectedSize(bridgeDomainDetails.interfaces.length); + final List ifcs = new ArrayList<>(bridgeDomainDetails.interfaces.length); for (vppBridgeDomainInterfaceDetails anInterface : bridgeDomainDetails.interfaces) { ifcs.add(new InterfaceBuilder() .setBridgedVirtualInterface(bridgeDomainDetails.bviInterfaceName.equals(anInterface.interfaceName)) @@ -110,27 +104,29 @@ public final class BridgeDomainCustomizer extends VppApiReaderCustomizer return ifcs; } + @Nonnull @Override - public BridgeDomainBuilder getBuilder(final BridgeDomainKey id) { + public BridgeDomainBuilder getBuilder(@Nonnull final InstanceIdentifier id) { return new BridgeDomainBuilder(); } + @Nonnull @Override - public List> getAllIds(final InstanceIdentifier id) { - final int[] ints = getVppApi().bridgeDomainDump(-1); - final List> allIds = Lists.newArrayListWithExpectedSize(ints.length); - for (int i : ints) { - final InstanceIdentifier.IdentifiableItem currentBdItem = - VppReaderUtils.getCurrentIdItem(id, new BridgeDomainKey(Integer.toString(i))); - final InstanceIdentifier e = VppReaderUtils.getCurrentId(id, currentBdItem); - allIds.add(e); + public List getAllIds(@Nonnull final InstanceIdentifier id) { + final int[] bIds = getVppApi().bridgeDomainDump(-1); + final List allIds = new ArrayList<>(bIds.length); + for (int bId : bIds) { + // FIXME this is highly inefficient having to dump all of the bridge domain details + final vppBridgeDomainDetails bridgeDomainDetails = getVppApi().getBridgeDomainDetails(bId); + final String bName = bridgeDomainDetails.name; + allIds.add(new BridgeDomainKey(bName)); } return allIds; } @Override - public void merge(final Builder builder, final List currentBuilder) { - ((BridgeDomainsBuilder) builder).setBridgeDomain(currentBuilder); + public void merge(@Nonnull final Builder builder, @Nonnull final List readData) { + ((BridgeDomainsBuilder) builder).setBridgeDomain(readData); } } diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vppstate/VersionCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vppstate/VersionCustomizer.java index 3ba21bbfb..641d61805 100644 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vppstate/VersionCustomizer.java +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vppstate/VersionCustomizer.java @@ -18,33 +18,36 @@ package io.fd.honeycomb.v3po.impl.vppstate; import io.fd.honeycomb.v3po.impl.trans.impl.spi.ChildVppReaderCustomizer; import io.fd.honeycomb.v3po.impl.trans.util.VppApiReaderCustomizer; +import javax.annotation.Nonnull; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppStateBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.Version; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.VersionBuilder; import org.opendaylight.yangtools.concepts.Builder; import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.openvpp.vppjapi.vppVersion; public final class VersionCustomizer extends VppApiReaderCustomizer implements ChildVppReaderCustomizer { - public VersionCustomizer(final org.openvpp.vppjapi.vppApi vppApi) { + public VersionCustomizer(@Nonnull final org.openvpp.vppjapi.vppApi vppApi) { super(vppApi); } @Override - public void merge(final Builder parentBuilder, final Version readValue) { + public void merge(@Nonnull final Builder parentBuilder, @Nonnull final Version readValue) { ((VppStateBuilder) parentBuilder).setVersion(readValue); } + @Nonnull @Override - public VersionBuilder getBuilder() { + public VersionBuilder getBuilder(@Nonnull InstanceIdentifier id) { return new VersionBuilder(); } @Override - public void readCurrentAttributes(final VersionBuilder builder) { + public void readCurrentAttributes(@Nonnull InstanceIdentifier id, @Nonnull final VersionBuilder builder) { final vppVersion vppVersion = getVppApi().getVppVersion(); builder.setBranch(vppVersion.gitBranch); builder.setName(vppVersion.programName); diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vppstate/VppStateUtils.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vppstate/VppStateUtils.java deleted file mode 100644 index 7a4a08eaf..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vppstate/VppStateUtils.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2016 Cisco and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.fd.honeycomb.v3po.impl.vppstate; - -import io.fd.honeycomb.v3po.impl.trans.ChildVppReader; -import io.fd.honeycomb.v3po.impl.trans.impl.CompositeChildVppReader; -import io.fd.honeycomb.v3po.impl.trans.impl.CompositeListVppReader; -import io.fd.honeycomb.v3po.impl.trans.impl.CompositeRootVppReader; -import io.fd.honeycomb.v3po.impl.trans.impl.spi.RootVppReaderCustomizer; -import io.fd.honeycomb.v3po.impl.trans.util.ReflexiveChildReaderCustomizer; -import io.fd.honeycomb.v3po.impl.trans.util.ReflexiveRootReaderCustomizer; -import io.fd.honeycomb.v3po.impl.trans.util.VppReaderUtils; -import java.util.ArrayList; -import java.util.List; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppStateBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.BridgeDomains; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.BridgeDomainsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.Version; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainKey; -import org.opendaylight.yangtools.yang.binding.ChildOf; -import org.openvpp.vppjapi.vppApi; - -public final class VppStateUtils { - - public VppStateUtils() {} - - /** - * Create root VppState reader with all its children wired - */ - public static CompositeRootVppReader getVppStateReader(@Nonnull final vppApi vppApi) { - final RootVppReaderCustomizer rootVppReaderCustomizer = - new ReflexiveRootReaderCustomizer<>(VppStateBuilder.class); - - final ChildVppReader versionReader = new CompositeChildVppReader<>( - Version.class, - new VersionCustomizer(vppApi)); - - final CompositeListVppReader - identifierBuilderCompositeListVppReader = new CompositeListVppReader<>( - BridgeDomain.class, - new BridgeDomainCustomizer(vppApi)); - - final List>> bdChildReaders = new ArrayList<>(); - bdChildReaders.add(identifierBuilderCompositeListVppReader); - - final ChildVppReader bridgeDomainsReader = new CompositeChildVppReader<>( - BridgeDomains.class, - bdChildReaders, - new ReflexiveChildReaderCustomizer<>(BridgeDomainsBuilder.class)); - - final List>> childVppReaders = new ArrayList<>(); - childVppReaders.add(versionReader); - childVppReaders.add(bridgeDomainsReader); - - return new CompositeRootVppReader<>( - VppState.class, - childVppReaders, - VppReaderUtils.emptyAugReaderList(), - rootVppReaderCustomizer); - } -} diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vppstate/BdTest.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vppstate/BdTest.java index ab3f6e054..7439bcd30 100644 --- a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vppstate/BdTest.java +++ b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vppstate/BdTest.java @@ -18,6 +18,7 @@ package io.fd.honeycomb.v3po.impl.vppstate; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.anyString; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; @@ -27,9 +28,12 @@ import io.fd.honeycomb.v3po.impl.trans.util.DelegatingReaderRegistry; import java.util.Collections; import java.util.List; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Matchers; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppStateBuilder; @@ -63,19 +67,46 @@ public class BdTest { private CompositeRootVppReader vppStateReader; private DelegatingReaderRegistry readerRegistry; private vppBridgeDomainDetails bdDetails; + private vppBridgeDomainDetails bdDetails2; @Before public void setUp() throws Exception { api = PowerMockito.mock(vppApi.class); bdDetails = new vppBridgeDomainDetails(); - setIfcs(bdDetails); - setBaseAttrs(bdDetails); + setBaseAttrs(bdDetails, "bdn1", 1); + + bdDetails2 = new vppBridgeDomainDetails(); + setIfcs(bdDetails2); + setBaseAttrs(bdDetails2, "bdn2", 2); final vppL2Fib[] l2Fibs = getL2Fibs(); PowerMockito.doReturn(l2Fibs).when(api).l2FibTableDump(Matchers.anyInt()); - PowerMockito.doReturn(bdDetails).when(api).getBridgeDomainDetails(Matchers.anyInt()); + PowerMockito.doAnswer(new Answer() { + + @Override + public vppBridgeDomainDetails answer(final InvocationOnMock invocationOnMock) throws Throwable { + final Integer idx = (Integer) invocationOnMock.getArguments()[0]; + switch (idx) { + case 1 : return bdDetails; + case 2 : return bdDetails2; + default: return null; + } + } + }).when(api).getBridgeDomainDetails(Matchers.anyInt()); + + PowerMockito.doAnswer(new Answer() { + @Override + public Object answer(final InvocationOnMock invocationOnMock) throws Throwable { + final String name = (String) invocationOnMock.getArguments()[0]; + switch (name) { + case "bdn1" : return 1; + case "bdn2" : return 2; + default: return null; + } + } + }).when(api).bridgeDomainIdFromName(anyString()); PowerMockito.doReturn(new int[] {1, 2}).when(api).bridgeDomainDump(Matchers.anyInt()); PowerMockito.doReturn(VERSION).when(api).getVppVersion(); vppStateReader = VppStateUtils.getVppStateReader(api); @@ -96,10 +127,10 @@ public class BdTest { bdDetails.interfaces = new vppBridgeDomainInterfaceDetails[] {ifcDetails}; } - private void setBaseAttrs(final vppBridgeDomainDetails bdDetails) { - bdDetails.name = "bdn"; + private void setBaseAttrs(final vppBridgeDomainDetails bdDetails, final String bdn, final int i) { + bdDetails.name = bdn; bdDetails.arpTerm = true; - bdDetails.bdId = 1; + bdDetails.bdId = i; bdDetails.bviInterfaceName = "ifc"; bdDetails.flood = true; bdDetails.forward = true; @@ -154,7 +185,7 @@ public class BdTest { // Deep child without a dedicated reader with specific l2fib key List read = readerRegistry.read(InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child( - BridgeDomain.class, new BridgeDomainKey("1")) + BridgeDomain.class, new BridgeDomainKey("bdn1")) .child(L2Fib.class, new L2FibKey(new PhysAddress("01:02:03:04:05:06")))); // System.err.println(read); assertEquals(read.size(), 1); @@ -162,7 +193,7 @@ public class BdTest { // non existing l2fib read = readerRegistry.read(InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child( - BridgeDomain.class, new BridgeDomainKey("1")) + BridgeDomain.class, new BridgeDomainKey("bdn1")) .child(L2Fib.class, new L2FibKey(new PhysAddress("FF:FF:FF:04:05:06")))); // System.err.println(read); assertEquals(read.size(), 0); @@ -175,7 +206,7 @@ public class BdTest { public void testReadL2FibAll() throws Exception { // Deep child without a dedicated reader final InstanceIdentifier id = InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child( - BridgeDomain.class, new BridgeDomainKey("1")).child(L2Fib.class); + BridgeDomain.class, new BridgeDomainKey("bdn1")).child(L2Fib.class); final List read = readerRegistry.read(id); // System.err.println(read); assertEquals(read.toString(), read.size(), 2); @@ -204,19 +235,18 @@ public class BdTest { final List read = readerRegistry.read(InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child( - BridgeDomain.class, new BridgeDomainKey("1"))); + BridgeDomain.class, new BridgeDomainKey("bdn1"))); -// System.err.println(read); assertEquals(read.size(), 1); assertEquals(Iterables.find(readRoot.getBridgeDomains().getBridgeDomain(), new Predicate() { @Override public boolean apply(final BridgeDomain input) { -// System.err.println(input.getKey()); - return input.getKey().getName().equals("1"); + return input.getKey().getName().equals("bdn1"); } }), read.get(0)); } + @Ignore("Bridge domain customizer does not check whether the bd exists or not and fails with NPE, add it there") @Test public void testReadBridgeDomainNotExisting() throws Exception { final List read = diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vppstate/VppStateUtils.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vppstate/VppStateUtils.java new file mode 100644 index 000000000..e28e5b092 --- /dev/null +++ b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vppstate/VppStateUtils.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.impl.vppstate; + +import io.fd.honeycomb.v3po.impl.trans.ChildVppReader; +import io.fd.honeycomb.v3po.impl.trans.impl.CompositeChildVppReader; +import io.fd.honeycomb.v3po.impl.trans.impl.CompositeListVppReader; +import io.fd.honeycomb.v3po.impl.trans.impl.CompositeRootVppReader; +import io.fd.honeycomb.v3po.impl.trans.util.ReflexiveChildReaderCustomizer; +import io.fd.honeycomb.v3po.impl.trans.util.ReflexiveRootReaderCustomizer; +import io.fd.honeycomb.v3po.impl.trans.util.VppRWUtils; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppStateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.BridgeDomains; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.BridgeDomainsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.Version; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainKey; +import org.opendaylight.yangtools.yang.binding.ChildOf; +import org.openvpp.vppjapi.vppApi; + +final class VppStateUtils { + + public VppStateUtils() {} + + /** + * Create root VppState reader with all its children wired + */ + static CompositeRootVppReader getVppStateReader(@Nonnull final vppApi vppApi) { + + final ChildVppReader versionReader = new CompositeChildVppReader<>( + Version.class, new VersionCustomizer(vppApi)); + + final CompositeListVppReader + bridgeDomainReader = new CompositeListVppReader<>( + BridgeDomain.class, + new BridgeDomainCustomizer(vppApi)); + + final ChildVppReader bridgeDomainsReader = new CompositeChildVppReader<>( + BridgeDomains.class, + VppRWUtils.singletonChildReaderList(bridgeDomainReader), + new ReflexiveChildReaderCustomizer<>(BridgeDomainsBuilder.class)); + + final List>> childVppReaders = new ArrayList<>(); + childVppReaders.add(versionReader); + childVppReaders.add(bridgeDomainsReader); + + return new CompositeRootVppReader<>( + VppState.class, + childVppReaders, + VppRWUtils.emptyAugReaderList(), + new ReflexiveRootReaderCustomizer<>(VppStateBuilder.class)); + } +} -- cgit 1.2.3-korg