summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarek Gradzki <mgradzki@cisco.com>2016-03-29 13:37:36 +0200
committerMarek Gradzki <mgradzki@cisco.com>2016-03-31 16:14:27 +0200
commit7f826dbcd18ba75520af0b770f655b3e665c66b0 (patch)
treebf34896c46cc4ddc539dce5ddc160921e4e392d9
parent127fe232b331b91f516b6669270384450d7deeb4 (diff)
VPP API <-> YANG translation layer integration
Prototype that uses Readers API for non-list nodes. Change-Id: I482dcfe09d094456b014e55edbc38ce6e98afcc3 Signed-off-by: Marek Gradzki <mgradzki@cisco.com> Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poProvider.java8
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/ReadableVppDataTree.java3
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppConfigDataTree.java8
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerInitializationProvider.java33
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppOperationalDataTree.java149
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppReaderRegistry.java112
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/ReaderRegistry.java12
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/util/DelegatingReaderRegistry.java13
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vppstate/BridgeDomainCustomizer.java21
-rw-r--r--v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerInitializationProviderTest.java7
-rw-r--r--v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppOperationalDataTreeTest.java24
-rw-r--r--v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vppstate/VppStateTest.java5
12 files changed, 338 insertions, 57 deletions
diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poProvider.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poProvider.java
index 54acce3f2..8a0dead0e 100644
--- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poProvider.java
+++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poProvider.java
@@ -21,6 +21,7 @@ import com.google.common.collect.Lists;
import com.google.common.util.concurrent.CheckedFuture;
import com.google.common.util.concurrent.Futures;
import io.fd.honeycomb.v3po.impl.data.VppDataBrokerInitializationProvider;
+import io.fd.honeycomb.v3po.impl.data.VppReaderRegistry;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
@@ -187,8 +188,11 @@ public class V3poProvider implements BindingAwareProvider, AutoCloseable {
vppPollOperData);
startOperationalUpdateTimer();
- // TODO make configurable
- vppDataBrokerInitializationProvider = new VppDataBrokerInitializationProvider(db);
+ final VppReaderRegistry readerRegistry = VppReaderRegistry.getInstance(api);
+
+ // TODO make configurable:
+ vppDataBrokerInitializationProvider = new VppDataBrokerInitializationProvider(db, readerRegistry);
+ // TODO pull the registration into Module
domBroker.registerProvider(vppDataBrokerInitializationProvider);
}
diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/ReadableVppDataTree.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/ReadableVppDataTree.java
index 18e854a81..19248ddf0 100644
--- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/ReadableVppDataTree.java
+++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/ReadableVppDataTree.java
@@ -19,6 +19,7 @@ package io.fd.honeycomb.v3po.impl.data;
import com.google.common.annotations.Beta;
import com.google.common.base.Optional;
import com.google.common.util.concurrent.CheckedFuture;
+import javax.annotation.Nonnull;
import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
@@ -34,5 +35,5 @@ public interface ReadableVppDataTree {
* @param path Path of the node
* @return a CheckFuture containing the result of the read.
*/
- CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(YangInstanceIdentifier path);
+ CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(@Nonnull final YangInstanceIdentifier path);
}
diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppConfigDataTree.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppConfigDataTree.java
index 66bcf489d..41a68e7bb 100644
--- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppConfigDataTree.java
+++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppConfigDataTree.java
@@ -136,7 +136,11 @@ public final class VppConfigDataTree implements VppDataTree {
@Override
public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(
final YangInstanceIdentifier path) {
- return Futures.immediateCheckedFuture(snapshot.readNode(path));
+ final Optional<NormalizedNode<?, ?>> node = snapshot.readNode(path);
+ if (LOG.isTraceEnabled() && node.isPresent()) {
+ LOG.trace("ConfigSnapshot.read: {}", node.get());
+ }
+ return Futures.immediateCheckedFuture(node);
}
@Override
@@ -183,7 +187,7 @@ public final class VppConfigDataTree implements VppDataTree {
}
void revertChanges() throws VppApiInvocationException {
- Preconditions.checkNotNull(writer, "VppWriter is nuserializerll!");
+ Preconditions.checkNotNull(writer, "VppWriter is null!");
// revert changes in reverse order they were applied
final ListIterator<InstanceIdentifier<?>> iterator = processedNodes.listIterator(processedNodes.size());
diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerInitializationProvider.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerInitializationProvider.java
index 50181e2fb..b7a24ea90 100644
--- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerInitializationProvider.java
+++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerInitializationProvider.java
@@ -22,8 +22,8 @@ import com.google.common.util.concurrent.AsyncFunction;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import io.fd.honeycomb.v3po.impl.LoggingFuturesCallBack;
+import io.fd.honeycomb.v3po.impl.trans.r.ReaderRegistry;
import io.fd.honeycomb.v3po.impl.trans0.DefaultVppWriter;
-import io.fd.honeycomb.v3po.impl.trans0.VppInterfacesReader;
import java.util.Collection;
import java.util.Collections;
import javassist.ClassPool;
@@ -43,7 +43,8 @@ import org.opendaylight.controller.sal.core.api.Broker;
import org.opendaylight.controller.sal.core.api.Provider;
import org.opendaylight.controller.sal.core.api.model.SchemaService;
import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
+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.vpp.state.BridgeDomains;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
@@ -81,11 +82,13 @@ public final class VppDataBrokerInitializationProvider implements Provider, Auto
private final TopologyId VPP_TOPOLOGY_ID = TopologyId.getDefaultInstance("vpp-topology");
private final NodeId VPP_TOPOLOGY_NODE_ID = NodeId.getDefaultInstance("vpp");
private final DataBroker bindingBroker;
+ private final ReaderRegistry readerRegistry;
private final InstanceIdentifier<Node> mountPointPath;
private ObjectRegistration<DOMMountPoint> mountPointRegistration;
- public VppDataBrokerInitializationProvider(@Nonnull final DataBroker bindingBroker) {
+ public VppDataBrokerInitializationProvider(@Nonnull final DataBroker bindingBroker, final ReaderRegistry readerRegistry) {
this.bindingBroker = Preconditions.checkNotNull(bindingBroker, "bindingBroker should not be null");
+ this.readerRegistry = Preconditions.checkNotNull(readerRegistry, "readerRegistry should not be null");
this.mountPointPath = getMountPointPath();
}
@@ -123,7 +126,7 @@ public final class VppDataBrokerInitializationProvider implements Provider, Auto
createMountPointPlaceholder();
- initialVppStateSynchronization(broker);
+ initialVppConfigSynchronization(broker);
}
@Override
@@ -170,12 +173,13 @@ public final class VppDataBrokerInitializationProvider implements Provider, Auto
private DOMDataBroker initVppDataBroker(final SchemaContext globalContext,
final BindingNormalizedNodeSerializer serializer) {
final ReadableVppDataTree operationalData =
- new VppOperationalDataTree(serializer, new VppInterfacesReader()); // TODO make configurable
+ new VppOperationalDataTree(serializer, globalContext, readerRegistry); // TODO make configurable
final DataTree dataTree =
InMemoryDataTreeFactory.getInstance().create(TreeType.CONFIGURATION); // TODO make configurable
dataTree.setSchemaContext(globalContext);
+ // FIXME use the new writer API
final VppDataTree configDataProxy = new VppConfigDataTree(serializer, dataTree,
new DefaultVppWriter()); // TODO make configurable
return new VppDataBroker(operationalData, configDataProxy);
@@ -202,21 +206,32 @@ public final class VppDataBrokerInitializationProvider implements Provider, Auto
// TODO operational and config models are not 1-1
// decide what part of operational data should be written to config during initialization
- private void initialVppStateSynchronization(final DOMDataBroker broker) {
+ private void initialVppConfigSynchronization(final DOMDataBroker broker) {
// read from operational
final DOMDataReadOnlyTransaction readTx = broker.newReadOnlyTransaction();
- final YangInstanceIdentifier interfacesID = YangInstanceIdentifier.of(Interfaces.QNAME);
+ final YangInstanceIdentifier
+ id = YangInstanceIdentifier.builder().node(VppState.QNAME).node(BridgeDomains.QNAME).build();
+
+ LOG.trace("initialVppStateSynchronization id: {}", id);
final ListenableFuture<Void> writeFuture = Futures.transform(
- readTx.read(LogicalDatastoreType.OPERATIONAL, interfacesID),
+ readTx.read(LogicalDatastoreType.OPERATIONAL, id),
new AsyncFunction<Optional<NormalizedNode<?, ?>>, Void>() {
@Override
public ListenableFuture<Void> apply(final Optional<NormalizedNode<?, ?>> readResult)
throws Exception {
if (readResult.isPresent()) {
final DOMDataWriteTransaction writeTx = broker.newWriteOnlyTransaction();
- writeTx.put(LogicalDatastoreType.CONFIGURATION, interfacesID, readResult.get());
+ final NormalizedNode<?, ?> node = readResult.get();
+ LOG.trace("Read result: {}", node);
+
+ // FIXME
+ // this will fail because we are reading OPERATIONAL data and writing to CONFIGURATION
+ // we need to provide extensible way to register initializer that would
+ // translate between models
+
+ // writeTx.put(LogicalDatastoreType.CONFIGURATION, id, node);
return writeTx.submit();
} else {
return Futures
diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppOperationalDataTree.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppOperationalDataTree.java
index fbfd9104d..c378365f3 100644
--- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppOperationalDataTree.java
+++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppOperationalDataTree.java
@@ -16,65 +16,170 @@
package io.fd.honeycomb.v3po.impl.data;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.getOnlyElement;
+
+import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Multimap;
import com.google.common.util.concurrent.CheckedFuture;
import com.google.common.util.concurrent.Futures;
-import io.fd.honeycomb.v3po.impl.trans0.VppReader;
+import io.fd.honeycomb.v3po.impl.trans.r.ReaderRegistry;
+import java.util.Collection;
+import java.util.List;
import java.util.Map;
import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+
/**
* ReadableVppDataTree implementation for operational data.
*/
public final class VppOperationalDataTree implements ReadableVppDataTree {
private static final Logger LOG = LoggerFactory.getLogger(VppOperationalDataTree.class);
+
private final BindingNormalizedNodeSerializer serializer;
- private final VppReader reader;
+ private final ReaderRegistry readerRegistry;
+ private final SchemaContext globalContext;
/**
* Creates operational data tree instance.
*
- * @param serializer service for serialization between Java Binding Data representation and NormalizedNode
- * representation.
- * @param reader service for translation between Vpp and Java Binding Data.
+ * @param serializer service for serialization between Java Binding Data representation and NormalizedNode
+ * representation.
+ * @param globalContext service for obtaining top level context data from all yang modules.
+ * @param readerRegistry service responsible for translation between DataObjects and VPP APIs.
*/
public VppOperationalDataTree(@Nonnull BindingNormalizedNodeSerializer serializer,
- @Nonnull VppReader reader) {
- this.serializer = Preconditions.checkNotNull(serializer, "serializer should not be null");
- this.reader = Preconditions.checkNotNull(reader, "reader should not be null");
+ @Nonnull final SchemaContext globalContext, @Nonnull ReaderRegistry readerRegistry) {
+ this.globalContext = checkNotNull(globalContext, "serializer should not be null");
+ this.serializer = checkNotNull(serializer, "serializer should not be null");
+ this.readerRegistry = checkNotNull(readerRegistry, "reader should not be null");
}
@Override
public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(
- final YangInstanceIdentifier yangInstanceIdentifier) {
- // TODO What if the path is ROOT/empty?
+ @Nonnull final YangInstanceIdentifier yangInstanceIdentifier) {
+
+ if (checkNotNull(yangInstanceIdentifier).equals(YangInstanceIdentifier.EMPTY)) {
+ LOG.debug("VppOperationalDataProxy.read(), yangInstanceIdentifier=ROOT");
+ return Futures.immediateCheckedFuture(Optional.<NormalizedNode<?, ?>>of(readRoot()));
+ }
+
+ LOG.debug("VppOperationalDataProxy.read(), yangInstanceIdentifier={}", yangInstanceIdentifier);
final InstanceIdentifier<?> path = serializer.fromYangInstanceIdentifier(yangInstanceIdentifier);
+ if (path == null) {
+ // TODO try to translate wildcarded identifiers here as a workaround if it is expected to be used that way
+ // Currently its not possible to read list using wildcarded ID. SO we may not need this at all.
+ }
+ checkNotNull(path, "Invalid instance identifier %s. Cannot create BA equivalent.", yangInstanceIdentifier);
LOG.debug("VppOperationalDataProxy.read(), path={}", path);
- final DataObject dataObject = reader.read(path); // FIXME we need to expect a list of dataObjects here
- return Futures.immediateCheckedFuture(toNormalizedNode(path, dataObject));
+ final List<? extends DataObject> dataObjects = readerRegistry.read(path);
+
+ if (dataObjects.isEmpty()) {
+ return Futures.immediateCheckedFuture(Optional.<NormalizedNode<?, ?>>absent());
+ }
+
+ final NormalizedNode<?, ?> value = wrapDataObjects(yangInstanceIdentifier, path, dataObjects);
+ return Futures.immediateCheckedFuture(Optional.<NormalizedNode<?, ?>>fromNullable(value));
}
- private Optional<NormalizedNode<?, ?>> toNormalizedNode(final InstanceIdentifier path,
- final DataObject dataObject) {
- LOG.trace("VppOperationalDataProxy.toNormalizedNode(), path={}, path={}", path, dataObject);
- final Map.Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> entry =
- serializer.toNormalizedNode(path, dataObject);
+ private DataSchemaNode getSchemaNode(final @Nonnull YangInstanceIdentifier yangInstanceIdentifier) {
+ return globalContext.getDataChildByName(yangInstanceIdentifier.getLastPathArgument().getNodeType());
+ }
+
+ private NormalizedNode<?, ?> readRoot() {
+ final DataContainerNodeAttrBuilder<YangInstanceIdentifier.NodeIdentifier, ContainerNode> dataNodeBuilder =
+ Builders.containerBuilder()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(SchemaContext.NAME));
+
+ final Multimap<InstanceIdentifier<? extends DataObject>, ? extends DataObject> dataObjects =
+ readerRegistry.readAll();
+
+ for (final InstanceIdentifier<? extends DataObject> instanceIdentifier : dataObjects.keySet()) {
+ final YangInstanceIdentifier rootElementId = serializer.toYangInstanceIdentifier(instanceIdentifier);
+ final NormalizedNode<?, ?> node =
+ wrapDataObjects(rootElementId, instanceIdentifier, dataObjects.get(instanceIdentifier));
+ dataNodeBuilder.withChild((DataContainerChild<?, ?>) node);
+ }
+
+ return dataNodeBuilder.build();
+ }
+
+ private NormalizedNode<?, ?> wrapDataObjects(final YangInstanceIdentifier yangInstanceIdentifier,
+ final InstanceIdentifier<? extends DataObject> instanceIdentifier,
+ final Collection<? extends DataObject> dataObjects) {
+ final Collection<NormalizedNode<?, ?>> normalizedRootElements = Collections2
+ .transform(dataObjects, toNormalizedNodeFunction(instanceIdentifier));
+
+ final DataSchemaNode schemaNode = getSchemaNode(yangInstanceIdentifier);
+ if (schemaNode instanceof ListSchemaNode) {
+ // In case of a list, wrap all the values in a Mixin parent node
+ final ListSchemaNode listSchema = (ListSchemaNode) schemaNode;
+ return wrapListIntoMixinNode(normalizedRootElements, listSchema);
+ } else {
+ Preconditions.checkState(dataObjects.size() == 1, "Singleton list was expected");
+ return getOnlyElement(normalizedRootElements);
+ }
+ }
+
+ private static DataContainerChild<?, ?> wrapListIntoMixinNode(
+ final Collection<NormalizedNode<?, ?>> normalizedRootElements, final ListSchemaNode listSchema) {
+ if (listSchema.getKeyDefinition().isEmpty()) {
+ final CollectionNodeBuilder<UnkeyedListEntryNode, UnkeyedListNode> listBuilder =
+ Builders.unkeyedListBuilder();
+ for (NormalizedNode<?, ?> normalizedRootElement : normalizedRootElements) {
+ listBuilder.withChild((UnkeyedListEntryNode) normalizedRootElement);
+ }
+ return listBuilder.build();
+ } else {
+ final CollectionNodeBuilder<MapEntryNode, ? extends MapNode> listBuilder =
+ listSchema.isUserOrdered()
+ ? Builders.orderedMapBuilder()
+ : Builders.mapBuilder();
+
+ for (NormalizedNode<?, ?> normalizedRootElement : normalizedRootElements) {
+ listBuilder.withChild((MapEntryNode) normalizedRootElement);
+ }
+ return listBuilder.build();
+ }
+ }
- final NormalizedNode<?, ?> value = entry.getValue();
- LOG.trace("VppOperationalDataProxy.toNormalizedNode(), value={}", value);
+ @SuppressWarnings("unchecked")
+ private Function<DataObject, NormalizedNode<?, ?>> toNormalizedNodeFunction(final InstanceIdentifier path) {
+ return new Function<DataObject, NormalizedNode<?, ?>>() {
+ @Override
+ public NormalizedNode<?, ?> apply(@Nullable final DataObject dataObject) {
+ LOG.trace("VppOperationalDataProxy.toNormalizedNode(), path={}, dataObject={}", path, dataObject);
+ final Map.Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> entry =
+ serializer.toNormalizedNode(path, dataObject);
- final Optional<NormalizedNode<?, ?>> optional = Optional.<NormalizedNode<?, ?>>fromNullable(value);
- LOG.trace("VppOperationalDataProxy.toNormalizedNode(), optional={}", optional);
- return optional;
+ LOG.trace("VppOperationalDataProxy.toNormalizedNode(), normalizedNodeEntry={}", entry);
+ return entry.getValue();
+ }
+ };
}
}
diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppReaderRegistry.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppReaderRegistry.java
new file mode 100644
index 000000000..c5d4a8194
--- /dev/null
+++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppReaderRegistry.java
@@ -0,0 +1,112 @@
+/*
+ * 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.data;
+
+import com.google.common.collect.Multimap;
+import io.fd.honeycomb.v3po.impl.trans.r.ChildVppReader;
+import io.fd.honeycomb.v3po.impl.trans.r.ReaderRegistry;
+import io.fd.honeycomb.v3po.impl.trans.r.VppReader;
+import io.fd.honeycomb.v3po.impl.trans.r.impl.CompositeChildVppReader;
+import io.fd.honeycomb.v3po.impl.trans.r.impl.CompositeListVppReader;
+import io.fd.honeycomb.v3po.impl.trans.r.impl.CompositeRootVppReader;
+import io.fd.honeycomb.v3po.impl.trans.r.util.DelegatingReaderRegistry;
+import io.fd.honeycomb.v3po.impl.trans.r.util.ReflexiveChildReaderCustomizer;
+import io.fd.honeycomb.v3po.impl.trans.r.util.ReflexiveRootReaderCustomizer;
+import io.fd.honeycomb.v3po.impl.trans.util.VppRWUtils;
+import io.fd.honeycomb.v3po.impl.vppstate.BridgeDomainCustomizer;
+import io.fd.honeycomb.v3po.impl.vppstate.VersionCustomizer;
+import java.util.ArrayList;
+import java.util.Collections;
+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.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.vppjapi.vppApi;
+
+// TODO use some DI framework instead of singleton
+public class VppReaderRegistry implements ReaderRegistry {
+
+ private static VppReaderRegistry instance;
+
+ private final DelegatingReaderRegistry reader;
+
+ private VppReaderRegistry(@Nonnull final vppApi vppApi) {
+ final CompositeRootVppReader<VppState, VppStateBuilder> vppStateReader = initVppStateReader(vppApi);
+ // TODO add more root readers
+ reader = new DelegatingReaderRegistry(Collections.<VppReader<? extends DataObject>>singletonList(vppStateReader));
+ }
+
+ private static CompositeRootVppReader<VppState, VppStateBuilder> initVppStateReader(@Nonnull final vppApi vppApi) {
+
+ final ChildVppReader<Version> versionReader = new CompositeChildVppReader<>(
+ Version.class, new VersionCustomizer(vppApi));
+
+ final CompositeListVppReader<BridgeDomain, BridgeDomainKey, BridgeDomainBuilder>
+ bridgeDomainReader = new CompositeListVppReader<>(
+ BridgeDomain.class,
+ new BridgeDomainCustomizer(vppApi));
+
+ final ChildVppReader<BridgeDomains> bridgeDomainsReader = new CompositeChildVppReader<>(
+ BridgeDomains.class,
+ VppRWUtils.singletonChildReaderList(bridgeDomainReader),
+ new ReflexiveChildReaderCustomizer<>(BridgeDomainsBuilder.class));
+
+ final List<ChildVppReader<? extends ChildOf<VppState>>> childVppReaders = new ArrayList<>();
+ childVppReaders.add(versionReader);
+ childVppReaders.add(bridgeDomainsReader);
+
+ return new CompositeRootVppReader<>(
+ VppState.class,
+ childVppReaders,
+ VppRWUtils.<VppState>emptyAugReaderList(),
+ new ReflexiveRootReaderCustomizer<>(VppStateBuilder.class));
+ }
+
+ public static synchronized VppReaderRegistry getInstance(@Nonnull final vppApi vppApi) {
+ if (instance == null) {
+ instance = new VppReaderRegistry(vppApi);
+ }
+ return instance;
+ }
+
+ @Nonnull
+ @Override
+ public Multimap<InstanceIdentifier<? extends DataObject>, ? extends DataObject> readAll() {
+ return reader.readAll();
+ }
+
+ @Nonnull
+ @Override
+ public List<? extends DataObject> read(@Nonnull final InstanceIdentifier<? extends DataObject> id) {
+ return reader.read(id);
+ }
+
+ @Nonnull
+ @Override
+ public InstanceIdentifier<DataObject> getManagedDataObjectType() {
+ return reader.getManagedDataObjectType();
+ }
+}
diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/ReaderRegistry.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/ReaderRegistry.java
index 49705fe3b..8c592a699 100644
--- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/ReaderRegistry.java
+++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/ReaderRegistry.java
@@ -17,19 +17,23 @@
package io.fd.honeycomb.v3po.impl.trans.r;
import com.google.common.annotations.Beta;
-import java.util.List;
+import com.google.common.collect.Multimap;
import javax.annotation.Nonnull;
import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
/**
- * Simple delegating reader suitable as a holder for all other root readers, providing readAll feature
+ * Simple delegating reader suitable as a holder for all other root readers, providing readAll feature.
*/
@Beta
public interface ReaderRegistry extends VppReader<DataObject> {
/**
- * Perform read on all underlying readers and merge the results into a single list
+ * Performs read on all registered root readers and merges the results into a Multimap.
+ * Keys represent identifiers for root DataObjects from the data tree modeled by YANG.
+ *
+ * @return multimap that preserves deterministic iteration order across non-distinct key values
*/
@Nonnull
- List<? extends DataObject> readAll();
+ Multimap<InstanceIdentifier<? extends DataObject>, ? extends DataObject> readAll();
}
diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/util/DelegatingReaderRegistry.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/util/DelegatingReaderRegistry.java
index 033e01b09..4e50e5aa8 100644
--- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/util/DelegatingReaderRegistry.java
+++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/util/DelegatingReaderRegistry.java
@@ -19,10 +19,11 @@ package io.fd.honeycomb.v3po.impl.trans.r.util;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.Iterables;
-import io.fd.honeycomb.v3po.impl.trans.util.VppRWUtils;
+import com.google.common.collect.LinkedListMultimap;
+import com.google.common.collect.Multimap;
import io.fd.honeycomb.v3po.impl.trans.r.ReaderRegistry;
import io.fd.honeycomb.v3po.impl.trans.r.VppReader;
-import java.util.ArrayList;
+import io.fd.honeycomb.v3po.impl.trans.util.VppRWUtils;
import java.util.List;
import java.util.Map;
import javax.annotation.Nonnull;
@@ -54,15 +55,15 @@ public final class DelegatingReaderRegistry implements ReaderRegistry {
@Override
@Nonnull
- public List<? extends DataObject> readAll() {
- LOG.debug("Reading from all delegates");
+ public Multimap<InstanceIdentifier<? extends DataObject>, ? extends DataObject> readAll() {
+ LOG.debug("Reading from all delegates: {}", this);
LOG.trace("Reading from all delegates: {}", rootReaders.values());
- final List<DataObject> objects = new ArrayList<>(rootReaders.size());
+ final Multimap<InstanceIdentifier<? extends DataObject>, DataObject> objects = LinkedListMultimap.create();
for (VppReader<? extends DataObject> rootReader : rootReaders.values()) {
LOG.debug("Reading from delegate: {}", rootReader);
final List<? extends DataObject> read = rootReader.read(rootReader.getManagedDataObjectType());
- objects.addAll(read);
+ objects.putAll(rootReader.getManagedDataObjectType(), read);
}
return objects;
}
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 1930a83e5..07193a16c 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,7 +19,6 @@ package io.fd.honeycomb.v3po.impl.vppstate;
import com.google.common.collect.Lists;
import io.fd.honeycomb.v3po.impl.trans.r.impl.spi.ListVppReaderCustomizer;
import io.fd.honeycomb.v3po.impl.trans.util.VppApiCustomizer;
-import io.fd.honeycomb.v3po.impl.trans.util.VppRWUtils;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nonnull;
@@ -66,7 +65,9 @@ public final class BridgeDomainCustomizer extends VppApiCustomizer
builder.setInterface(getIfcs(bridgeDomainDetails));
- final vppL2Fib[] vppL2Fibs = getVppApi().l2FibTableDump(bdId);
+ // final vppL2Fib[] vppL2Fibs = getVppApi().l2FibTableDump(bdId); FIXME we need writer for L2Fib
+ final vppL2Fib[] vppL2Fibs = getL2Fibs(bdId);
+
final List<L2Fib> l2Fibs = Lists.newArrayListWithCapacity(vppL2Fibs.length);
for (vppL2Fib vppL2Fib : vppL2Fibs) {
l2Fibs.add(new L2FibBuilder()
@@ -82,6 +83,22 @@ public final class BridgeDomainCustomizer extends VppApiCustomizer
builder.setL2Fib(l2Fibs);
}
+ // FIXME remove when list read is implemented
+ // updating L2Fib was BD was is implemented
+ // this was added to test reading list
+ private vppL2Fib[] getL2Fibs(final int bdId) {
+ if (bdId == 0) {
+ return new vppL2Fib[]{
+ new vppL2Fib(new byte[]{1, 2, 3, 4, 5, 6}, true, "ifc1", true, true)
+ };
+ } else {
+ return new vppL2Fib[]{
+ new vppL2Fib(new byte[]{1, 2, 3, 4, 5, 6}, true, "ifc1", true, true),
+ new vppL2Fib(new byte[]{2, 2, 3, 4, 5, 6}, true, "ifc2", true, true),
+ };
+ }
+ }
+
private static String getMacAddress(byte[] mac) {
StringBuilder sb = new StringBuilder(18);
for (byte b : mac) {
diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerInitializationProviderTest.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerInitializationProviderTest.java
index 782a7b6fe..5ac1f0130 100644
--- a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerInitializationProviderTest.java
+++ b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerInitializationProviderTest.java
@@ -26,6 +26,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.MockitoAnnotations.initMocks;
import com.google.common.util.concurrent.CheckedFuture;
+import io.fd.honeycomb.v3po.impl.trans.r.ReaderRegistry;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
@@ -41,14 +42,16 @@ public class VppDataBrokerInitializationProviderTest {
private DataBroker bindingBroker;
@Mock
private WriteTransaction writeTx;
+ @Mock
+ private ReaderRegistry readerRegistry;
- private VppDataBrokerInitializationProvider provider;
+ private VppDataBrokerInitializationProvider provider;
@Before
public void setUp() throws Exception {
initMocks(this);
doReturn(writeTx).when(bindingBroker).newWriteOnlyTransaction();
- provider = new VppDataBrokerInitializationProvider(bindingBroker);
+ provider = new VppDataBrokerInitializationProvider(bindingBroker, readerRegistry);
}
@Test
diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppOperationalDataTreeTest.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppOperationalDataTreeTest.java
index 9a3377563..62ddf5ca0 100644
--- a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppOperationalDataTreeTest.java
+++ b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppOperationalDataTreeTest.java
@@ -18,6 +18,7 @@ package io.fd.honeycomb.v3po.impl.data;
import static junit.framework.Assert.assertEquals;
import static junit.framework.TestCase.assertTrue;
+import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -26,7 +27,8 @@ import static org.mockito.MockitoAnnotations.initMocks;
import com.google.common.base.Optional;
import com.google.common.util.concurrent.CheckedFuture;
-import io.fd.honeycomb.v3po.impl.trans0.VppReader;
+import io.fd.honeycomb.v3po.impl.trans.r.ReaderRegistry;
+import java.util.Collections;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
@@ -35,15 +37,19 @@ import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
public class VppOperationalDataTreeTest {
@Mock
private BindingNormalizedNodeSerializer serializer;
@Mock
- private VppReader reader;
+ private ReaderRegistry reader;
private VppOperationalDataTree operationalData;
@@ -51,24 +57,32 @@ public class VppOperationalDataTreeTest {
private InstanceIdentifier<DataObject> id;
@Mock
private Map.Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> entry;
+ @Mock
+ private SchemaContext globalContext;
+ @Mock
+ private DataSchemaNode schemaNode;
@Before
public void setUp() {
initMocks(this);
- operationalData = new VppOperationalDataTree(serializer, reader);
+ operationalData = new VppOperationalDataTree(serializer, globalContext, reader);
}
@Test
public void testRead() throws Exception {
final YangInstanceIdentifier yangId = mock(YangInstanceIdentifier.class);
+ final YangInstanceIdentifier.PathArgument pArg = mock(YangInstanceIdentifier.PathArgument.class);
+ doReturn(pArg).when(yangId).getLastPathArgument();
+ doReturn(QName.create("namespace", "2012-12-12", "local")).when(pArg).getNodeType();
+ doReturn(schemaNode).when(globalContext).getDataChildByName(any(QName.class));
doReturn(id).when(serializer).fromYangInstanceIdentifier(yangId);
final DataObject dataObject = mock(DataObject.class);
- when(reader.read(id)).thenReturn(dataObject);
+ doReturn(Collections.singletonList(dataObject)).when(reader).read(id);
when(serializer.toNormalizedNode(id, dataObject)).thenReturn(entry);
- final NormalizedNode<?, ?> expectedValue = mock(NormalizedNode.class);
+ final DataContainerChild<?, ?> expectedValue = mock(DataContainerChild.class);
doReturn(expectedValue).when(entry).getValue();
final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> future = operationalData.read(yangId);
diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vppstate/VppStateTest.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vppstate/VppStateTest.java
index 66831c77a..cdb3024d8 100644
--- a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vppstate/VppStateTest.java
+++ b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vppstate/VppStateTest.java
@@ -22,6 +22,7 @@ import static org.mockito.Matchers.anyString;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
+import com.google.common.collect.Multimap;
import io.fd.honeycomb.v3po.impl.trans.r.VppReader;
import io.fd.honeycomb.v3po.impl.trans.r.impl.CompositeRootVppReader;
import io.fd.honeycomb.v3po.impl.trans.r.util.DelegatingReaderRegistry;
@@ -140,9 +141,9 @@ public class VppStateTest {
@Test
public void testReadAll() throws Exception {
- final List<? extends DataObject> dataObjects = readerRegistry.readAll();
+ final Multimap<InstanceIdentifier<? extends DataObject>, ? extends DataObject> dataObjects = readerRegistry.readAll();
assertEquals(dataObjects.size(), 1);
- final DataObject dataObject = dataObjects.get(0);
+ final DataObject dataObject = Iterables.getOnlyElement(dataObjects.get(Iterables.getOnlyElement(dataObjects.keySet())));
assertTrue(dataObject instanceof VppState);
assertVersion((VppState) dataObject);
assertEquals(2, ((VppState) dataObject).getBridgeDomains().getBridgeDomain().size());