From d54ea758da8dcf71d52727c4f01f87090c50bf2e Mon Sep 17 00:00:00 2001 From: Maros Marsalek Date: Tue, 17 May 2016 09:10:39 +0200 Subject: HONEYCOMB-61: Add BA broker for context data tree With broker, context data can be accessed in a transactional manner, same as config data + Renamed data-api concepts to not include DataTree + Renamed context related concepts to better distinguish between them + Now passing full ReadContext to read customizers + Naming context is backed by context data broker Change-Id: I0b2876dd74a31a9ced7d9b5145672868e12f8b82 Signed-off-by: Maros Marsalek --- .../v3po/util/AbstractInterfaceTypeCustomizer.java | 10 +- .../translate/v3po/util/DataTreeNamingContext.java | 193 --------------------- .../v3po/translate/v3po/util/NamingContext.java | 89 +++++++--- .../util/rev160406/NamingContextImplModule.java | 7 +- .../src/main/yang/vpp-util.yang | 9 - 5 files changed, 73 insertions(+), 235 deletions(-) delete mode 100644 v3po/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/DataTreeNamingContext.java (limited to 'v3po/vpp-translate-utils/src/main') diff --git a/v3po/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/AbstractInterfaceTypeCustomizer.java b/v3po/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/AbstractInterfaceTypeCustomizer.java index 45ac193cf..e1a5bf2bc 100644 --- a/v3po/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/AbstractInterfaceTypeCustomizer.java +++ b/v3po/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/AbstractInterfaceTypeCustomizer.java @@ -45,17 +45,17 @@ public abstract class AbstractInterfaceTypeCustomizer } private void checkProperInterfaceType(@Nonnull final WriteContext writeContext, - @Nonnull final InstanceIdentifier id) { + @Nonnull final InstanceIdentifier id) { final InstanceIdentifier ifcTypeFromIid = id.firstIdentifierOf(Interface.class); checkArgument(ifcTypeFromIid != null, "Instance identifier does not contain {} type", Interface.class); checkArgument(id.firstKeyOf(Interface.class) != null, "Instance identifier does not contain keyed {} type", Interface.class); - final Optional interfaceConfigOperational = writeContext.readAfter(ifcTypeFromIid); - checkState(interfaceConfigOperational.isPresent(), - "Unable to get Interface configuration for an interface being updated under ID"); + final Optional interfaceConfig = writeContext.readAfter(ifcTypeFromIid); + checkState(interfaceConfig.isPresent(), + "Unable to get Interface configuration for an interface: %s currently being updated", ifcTypeFromIid); IllegalInterfaceTypeException - .checkInterfaceType((Interface) interfaceConfigOperational.get(), getExpectedInterfaceType()); + .checkInterfaceType(interfaceConfig.get(), getExpectedInterfaceType()); } protected abstract Class getExpectedInterfaceType(); diff --git a/v3po/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/DataTreeNamingContext.java b/v3po/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/DataTreeNamingContext.java deleted file mode 100644 index 3b20b2876..000000000 --- a/v3po/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/DataTreeNamingContext.java +++ /dev/null @@ -1,193 +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.translate.v3po.util; - -import com.google.common.collect.Lists; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import javax.annotation.Nonnull; -import javax.annotation.concurrent.ThreadSafe; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.Contexts; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; -import org.opendaylight.yangtools.yang.common.QName; -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.NormalizedNode; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException; -import org.opendaylight.yangtools.yang.data.impl.schema.Builders; -import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Naming context keeping a mapping between int index and string name. - * Provides artificial names to unknown indices. - */ -@ThreadSafe -public class DataTreeNamingContext extends NamingContext { - - // FIXME this has to be accessed by readers/writers in a transactional manner and the transaction will only be committed once - // the Read or Write operation finishes successfully - // Context datatree has to become a first class citizen of Honeycomb, and Honeycomb needs to create and provide - // context read write transaction as part of context to read/write customizers - // This will then become just a utility writer relying on transaction provided by the infrastructure - // Btw. the context transaction needs to disable commit/submit when being passed to customizers - - private static final Logger LOG = LoggerFactory.getLogger(DataTreeNamingContext.class); - - private static final QName NAME_KEY_QNAME = QName.create(Contexts.QNAME, "name"); - private static final QName INDEX_QNAME = QName.create(Contexts.QNAME, "index"); - - private final String instanceName; - private final DataTree contextDataTree; - - private final YangInstanceIdentifier.NodeIdentifierWithPredicates namingContextNodeId; - private final YangInstanceIdentifier namingContextIid; - - public DataTreeNamingContext(final String artificialNamePrefix, final String instanceName, - final DataTree contextDataTree) { - super(artificialNamePrefix); - this.instanceName = instanceName; - this.contextDataTree = contextDataTree; - - namingContextNodeId = getNodeId( - org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.NamingContext.QNAME, - Collections.singletonMap(NAME_KEY_QNAME, instanceName)); - namingContextIid = YangInstanceIdentifier.create( - getNodeId(Contexts.QNAME), - getNodeId(org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.NamingContext.QNAME), - namingContextNodeId); - - // FIXME read current mappings and initialize map - mergeNewContextInDataTree(instanceName); - } - - // TODO move the data tree aspect into a dedicated class - private void mergeNewContextInDataTree(final String instanceName) { - final DataTreeModification dataTreeModification = getModification(); - - final YangInstanceIdentifier.NodeIdentifier namingContextsNodeIdForMapNode = getNodeId( - org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.NamingContext.QNAME); - - final ContainerNode newMapping = Builders.containerBuilder() - .withNodeIdentifier(getNodeId(Contexts.QNAME)) - .withChild(Builders.mapBuilder() - .withNodeIdentifier(namingContextsNodeIdForMapNode) - .withChild(Builders.mapEntryBuilder() - .withNodeIdentifier(namingContextNodeId) - .withChild(ImmutableNodes.leafNode(NAME_KEY_QNAME, instanceName)) - .withChild(Builders.containerBuilder() - .withNodeIdentifier(getNodeId(Mappings.QNAME)) - .withChild(Builders.mapBuilder() - .withNodeIdentifier(getNodeId(Mapping.QNAME)) - .build()) - .build()) - .build()) - .build()) - .build(); - - // FIXME add logs or debug to resolve: -// 2016-05-13 15:48:52,401 | WARN | config-pusher | DataTreeNamingContext | 240 - io.fd.honeycomb.v3po.vpp-translate-utils - 1.0.0.SNAPSHOT | Unable to update context: interface-context in context data tree -// org.opendaylight.yangtools.yang.data.api.schema.tree.ModifiedNodeDoesNotExistException: Node /(urn:honeycomb:params:xml:ns:yang:naming:context?revision=2016-05-13)contexts/naming-context/naming-context[{(urn:honeycomb:params:xml:ns:yang:naming:context?revision=2016-05-13)name=interface-context}] does not exist. Cannot apply modification to its children. -// at org.opendaylight.yangtools.yang.data.impl.schema.tree.AbstractNodeContainerModificationStrategy.checkTouchApplicable(AbstractNodeContainerModificationStrategy.java:276)[55:org.opendaylight.yangtools.yang-data-impl:0.8.0.Beryllium] - // FIXME looks like a timing issue, did not occur when debugging - - dataTreeModification.merge(YangInstanceIdentifier.create(getNodeId(Contexts.QNAME)), newMapping); - - commitModification(dataTreeModification); - } - - private void commitModification(final DataTreeModification dataTreeModification) { - try { - dataTreeModification.ready(); - contextDataTree.validate(dataTreeModification); - contextDataTree.commit(contextDataTree.prepare(dataTreeModification)); - } catch (DataValidationFailedException e) { - LOG.warn("Unable to update context: {} in context data tree", instanceName, e); - throw new IllegalStateException("Unable to update context in context data tree", e); - } - } - - private DataTreeModification getModification() { - final DataTreeSnapshot dataTreeSnapshot = contextDataTree.takeSnapshot(); - return dataTreeSnapshot.newModification(); - } - - private static YangInstanceIdentifier.NodeIdentifierWithPredicates getNodeId(@Nonnull final QName qName, - @Nonnull final Map keys) { - return new YangInstanceIdentifier.NodeIdentifierWithPredicates(qName, keys); - } - - private static YangInstanceIdentifier.NodeIdentifier getNodeId(@Nonnull final QName qName) { - return new YangInstanceIdentifier.NodeIdentifier(qName); - } - - public synchronized void addName(final int index, final String name) { - addMappingToDataTree(name, index); - super.addName(index, name); - } - - private void addMappingToDataTree(final String name, final int index) { - final DataTreeModification dataTreeModification = getModification(); - - final YangInstanceIdentifier.NodeIdentifierWithPredicates mappingNodeId = getNodeId(Mapping.QNAME, - Collections.singletonMap(NAME_KEY_QNAME, name)); - - final List pathArguments = namingContextIid.getPathArguments(); - final ArrayList newPathArgs = Lists.newArrayList(pathArguments); - newPathArgs.add(getNodeId(Mappings.QNAME)); - newPathArgs.add(getNodeId(Mapping.QNAME)); - newPathArgs.add(mappingNodeId); - - final YangInstanceIdentifier identifier = YangInstanceIdentifier.create(newPathArgs); - - final NormalizedNode newMapping = Builders.mapEntryBuilder() - .withNodeIdentifier(mappingNodeId) - .withChild(ImmutableNodes.leafNode(NAME_KEY_QNAME, name)) - .withChild(ImmutableNodes.leafNode(INDEX_QNAME, index)) - .build(); - - dataTreeModification.write(identifier, newMapping); - - commitModification(dataTreeModification); - } - - public synchronized int removeName(@Nonnull final String name) { - removeMappingFromDataTree(name); - return super.removeName(name); - } - - private void removeMappingFromDataTree(final String name) { - final DataTreeModification dataTreeModification = getModification(); - - final YangInstanceIdentifier.NodeIdentifierWithPredicates mappingNodeId = getNodeId(Mapping.QNAME, - Collections.singletonMap(NAME_KEY_QNAME, name)); - - final YangInstanceIdentifier identifier = YangInstanceIdentifier.create( - namingContextIid.getLastPathArgument(), getNodeId(Mappings.QNAME), getNodeId(Mapping.QNAME), mappingNodeId); - - dataTreeModification.delete(identifier); - - commitModification(dataTreeModification); - } -} diff --git a/v3po/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/NamingContext.java b/v3po/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/NamingContext.java index 9affd0695..d32f27203 100644 --- a/v3po/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/NamingContext.java +++ b/v3po/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/NamingContext.java @@ -17,48 +17,88 @@ package io.fd.honeycomb.v3po.translate.v3po.util; import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; -import com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; +import com.google.common.base.Optional; +import io.fd.honeycomb.v3po.translate.MappingContext; +import java.util.stream.Collector; +import java.util.stream.Collectors; import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.Contexts; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.NamingContextKey; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingBuilder; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * Naming context keeping a mapping between int index and string name. - * Provides artificial names to unknown indices. + * Utility adapter on top of {@link MappingContext} */ -public class NamingContext implements AutoCloseable { +public final class NamingContext implements AutoCloseable { private static final Logger LOG = LoggerFactory.getLogger(NamingContext.class); - private final BiMap nameMapping = HashBiMap.create(); private final String artificialNamePrefix; + private KeyedInstanceIdentifier + namingContextIid; - public NamingContext(final String artificialNamePrefix) { + /** + * Collector expecting only a single resulting item from a stream + */ + private static final Collector SINGLE_ITEM_COLLECTOR = Collectors.collectingAndThen( + Collectors.toList(), + list -> { + if (list.size() != 1) { + throw new IllegalStateException("Unexpected size of list: " + list + ". Single item expected"); + } + return list.get(0); + }); + + public NamingContext(final String artificialNamePrefix, final String instanceName) { this.artificialNamePrefix = artificialNamePrefix; + namingContextIid = InstanceIdentifier.create(Contexts.class).child( + org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.NamingContext.class, + new NamingContextKey(instanceName)); } @Nonnull - public synchronized String getName(final int index) { - if(!nameMapping.inverse().containsKey(index)) { + public synchronized String getName(final int index, final MappingContext mappingContext) { + if (!containsName(index, mappingContext)) { final String artificialName = getArtificialName(index); LOG.info("Assigning artificial name: {} for index: {}", artificialName, index); - addName(index, artificialName); + addName(index, artificialName, mappingContext); } - return nameMapping.inverse().get(index); + + final Optional read = mappingContext.read(namingContextIid.child(Mappings.class)); + checkState(read.isPresent(), "Mapping for index: %s is not present. But should be", index); + + return read.get().getMapping().stream() + .filter(mapping -> mapping.getIndex().equals(index)) + .collect(SINGLE_ITEM_COLLECTOR).getName(); + } + + public synchronized boolean containsName(final int index, final MappingContext mappingContext) { + final Optional read = mappingContext.read(namingContextIid.child(Mappings.class)); + return read.isPresent() + ? read.get().getMapping().stream().anyMatch(mapping -> mapping.getIndex().equals(index)) + : false; } - public synchronized boolean containsName(final int index) { - return nameMapping.inverse().containsKey(index); + public synchronized void addName(final int index, final String name, final MappingContext mappingContext) { + final KeyedInstanceIdentifier mappingIid = getMappingIid(name); + mappingContext.put(mappingIid, new MappingBuilder().setIndex(index).setName(name).build()); } - public synchronized void addName(final int index, final String name) { - nameMapping.put(name, index); + private KeyedInstanceIdentifier getMappingIid(final String name) { + return namingContextIid.child(Mappings.class).child(Mapping.class, new MappingKey(name)); } - public synchronized int removeName(final String name) { - return nameMapping.remove(name); + public synchronized void removeName(final String name, final MappingContext mappingContext) { + mappingContext.delete(getMappingIid(name)); } /** @@ -68,14 +108,15 @@ public class NamingContext implements AutoCloseable { * @return integer index value matching supplied name * @throws IllegalArgumentException if name was not found */ - public synchronized int getIndex(String name) { - checkArgument(nameMapping.containsKey(name), "Name %s not found. Known names: %s", - name, nameMapping); - return nameMapping.get(name); + public synchronized int getIndex(final String name, final MappingContext mappingContext) { + final Optional read = mappingContext.read(getMappingIid(name)); + checkArgument(read.isPresent(), "No mapping stored for name: %s", name); + return read.get().getIndex(); + } - public synchronized boolean containsIndex(String interfaceName) { - return nameMapping.containsKey(interfaceName); + public synchronized boolean containsIndex(final String name, final MappingContext mappingContext) { + return mappingContext.read(getMappingIid(name)).isPresent(); } private String getArtificialName(final int index) { @@ -84,6 +125,6 @@ public class NamingContext implements AutoCloseable { @Override public void close() throws Exception { - nameMapping.clear(); + /// Not removing the mapping from backing storage } } diff --git a/v3po/vpp-translate-utils/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/util/rev160406/NamingContextImplModule.java b/v3po/vpp-translate-utils/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/util/rev160406/NamingContextImplModule.java index 50b577a25..60a816d89 100644 --- a/v3po/vpp-translate-utils/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/util/rev160406/NamingContextImplModule.java +++ b/v3po/vpp-translate-utils/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/util/rev160406/NamingContextImplModule.java @@ -1,6 +1,6 @@ package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.util.rev160406; -import io.fd.honeycomb.v3po.translate.v3po.util.DataTreeNamingContext; +import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; public class NamingContextImplModule extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.util.rev160406.AbstractNamingContextImplModule { public NamingContextImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { @@ -18,10 +18,9 @@ public class NamingContextImplModule extends org.opendaylight.yang.gen.v1.urn.ho @Override public java.lang.AutoCloseable createInstance() { - return new DataTreeNamingContext( + return new NamingContext( getArtificialNamePrefix(), - getIdentifier().getInstanceName(), - getContextDataTreeDependency()); + getIdentifier().getInstanceName()); } } diff --git a/v3po/vpp-translate-utils/src/main/yang/vpp-util.yang b/v3po/vpp-translate-utils/src/main/yang/vpp-util.yang index bd903848c..23615d09e 100644 --- a/v3po/vpp-translate-utils/src/main/yang/vpp-util.yang +++ b/v3po/vpp-translate-utils/src/main/yang/vpp-util.yang @@ -31,15 +31,6 @@ module vpp-util { leaf artificial-name-prefix { type string; } - - container context-data-tree { - uses config:service-ref { - refine type { - mandatory true; - config:required-identity dapi:data-tree; - } - } - } } } -- cgit 1.2.3-korg