From 355c2205a7088bc7b3ccabc278c477b838975c65 Mon Sep 17 00:00:00 2001 From: Marek Gradzki Date: Fri, 1 Apr 2016 12:33:39 +0200 Subject: VPP API <-> YANG translation layer integration #2(Writers) Change-Id: If91364f1900693b040aee163f1c6e092381b0efd Signed-off-by: Maros Marsalek Signed-off-by: Marek Gradzki --- .../io/fd/honeycomb/v3po/impl/V3poProvider.java | 4 +- .../v3po/impl/data/VppConfigDataTree.java | 102 +++++++++++++++------ .../data/VppDataBrokerInitializationProvider.java | 17 ++-- .../fd/honeycomb/v3po/impl/data/VppDataTree.java | 2 +- .../v3po/impl/data/VppWriteTransaction.java | 2 +- .../v3po/impl/data/VppWriterRegistry.java | 92 +++++++++++++++++++ .../v3po/impl/trans/VppApiInvocationException.java | 76 +++++++++++++++ .../impl/trans/w/util/TransactionWriteContext.java | 49 ++++++---- .../v3po/impl/trans0/DefaultVppWriter.java | 43 --------- .../impl/trans0/VppApiInvocationException.java | 76 --------------- .../v3po/impl/trans0/VppInterfacesReader.java | 56 ----------- .../fd/honeycomb/v3po/impl/trans0/VppReader.java | 30 ------ .../fd/honeycomb/v3po/impl/trans0/VppWriter.java | 27 ------ .../v3po/impl/vpp/BridgeDomainCustomizer.java | 71 ++++++++------ 14 files changed, 328 insertions(+), 319 deletions(-) create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppWriterRegistry.java create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/VppApiInvocationException.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/DefaultVppWriter.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/VppApiInvocationException.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/VppInterfacesReader.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/VppReader.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/VppWriter.java (limited to 'v3po/impl/src/main/java/io/fd/honeycomb') 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 4afd86099..931ecefd6 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 @@ -22,6 +22,7 @@ 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 io.fd.honeycomb.v3po.impl.data.VppWriterRegistry; import java.io.IOException; import java.util.Collections; import java.util.HashMap; @@ -196,9 +197,10 @@ public class V3poProvider implements BindingAwareProvider, AutoCloseable, Broker startOperationalUpdateTimer(); final VppReaderRegistry readerRegistry = VppReaderRegistry.getInstance(api); + final VppWriterRegistry writerRegistry = VppWriterRegistry.getInstance(api); // TODO make configurable: - vppDataBrokerInitializationProvider = new VppDataBrokerInitializationProvider(db, readerRegistry); + vppDataBrokerInitializationProvider = new VppDataBrokerInitializationProvider(db, readerRegistry, writerRegistry); // TODO pull the registration into Module domBroker.registerProvider(vppDataBrokerInitializationProvider); } 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 41a68e7bb..6fdeea348 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 @@ -16,12 +16,15 @@ package io.fd.honeycomb.v3po.impl.data; +import static com.google.common.base.Preconditions.checkNotNull; +import static java.util.Collections.singletonList; + import com.google.common.base.Optional; -import com.google.common.base.Preconditions; import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.Futures; -import io.fd.honeycomb.v3po.impl.trans0.VppApiInvocationException; -import io.fd.honeycomb.v3po.impl.trans0.VppWriter; +import io.fd.honeycomb.v3po.impl.trans.w.WriteContext; +import io.fd.honeycomb.v3po.impl.trans.w.util.TransactionWriteContext; +import io.fd.honeycomb.v3po.impl.trans.VppApiInvocationException; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -31,6 +34,7 @@ import java.util.Map; import java.util.Set; import javax.annotation.Nonnull; import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; @@ -55,7 +59,14 @@ public final class VppConfigDataTree implements VppDataTree { private final BindingNormalizedNodeSerializer serializer; private final DataTree dataTree; - private final VppWriter writer; + private final VppWriterRegistry writer; + public static final ReadableVppDataTree EMPTY_OPERATIONAL = new ReadableVppDataTree() { + @Override + public CheckedFuture>, ReadFailedException> read( + @Nonnull final YangInstanceIdentifier path) { + return Futures.immediateCheckedFuture(Optional.>absent()); + } + }; /** * Creates configuration data tree instance. @@ -66,10 +77,10 @@ public final class VppConfigDataTree implements VppDataTree { * @param vppWriter service for translation between Java Binding Data and Vpp. */ public VppConfigDataTree(@Nonnull final BindingNormalizedNodeSerializer serializer, - @Nonnull final DataTree dataTree, @Nonnull final VppWriter vppWriter) { - this.serializer = Preconditions.checkNotNull(serializer, "serializer should not be null"); - this.dataTree = Preconditions.checkNotNull(dataTree, "dataTree should not be null"); - this.writer = Preconditions.checkNotNull(vppWriter, "vppWriter should not be null"); + @Nonnull final DataTree dataTree, @Nonnull final VppWriterRegistry vppWriter) { + this.serializer = checkNotNull(serializer, "serializer should not be null"); + this.dataTree = checkNotNull(dataTree, "dataTree should not be null"); + this.writer = checkNotNull(vppWriter, "vppWriter should not be null"); } @Override @@ -78,7 +89,8 @@ public final class VppConfigDataTree implements VppDataTree { } @Override - public void commit(final DataTreeModification modification) throws DataValidationFailedException, VppApiInvocationException { + public void commit(final DataTreeModification modification) + throws DataValidationFailedException, VppApiInvocationException { dataTree.validate(modification); final DataTreeCandidate candidate = dataTree.prepare(modification); @@ -87,16 +99,22 @@ public final class VppConfigDataTree implements VppDataTree { final YangInstanceIdentifier rootPath = candidate.getRootPath(); final Optional> normalizedDataBefore = rootNode.getDataBefore(); final Optional> normalizedDataAfter = rootNode.getDataAfter(); - LOG.debug("VppConfigDataProxy.commit() rootPath={}, rootNode={}, dataBefore={}, dataAfter={}", + LOG.debug("VppConfigDataTree.commit() rootPath={}, rootNode={}, dataBefore={}, dataAfter={}", rootPath, rootNode, normalizedDataBefore, normalizedDataAfter); final Map, DataObject> nodesBefore = extractNetconfData(normalizedDataBefore); - LOG.debug("VppConfigDataProxy.commit() extracted nodesBefore={}", nodesBefore.keySet()); + LOG.debug("VppConfigDataTree.commit() extracted nodesBefore={}", nodesBefore.keySet()); final Map, DataObject> nodesAfter = extractNetconfData(normalizedDataAfter); - LOG.debug("VppConfigDataProxy.commit() extracted nodesAfter={}", nodesAfter.keySet()); + LOG.debug("VppConfigDataTree.commit() extracted nodesAfter={}", nodesAfter.keySet()); - final ChangesProcessor processor = new ChangesProcessor(writer, nodesBefore, nodesAfter); + + final DOMDataReadOnlyTransaction beforeTx = new VppReadOnlyTransaction(EMPTY_OPERATIONAL, takeSnapshot()); + final ConfigSnapshot modificationSnapshot = new ConfigSnapshot(modification); + final DOMDataReadOnlyTransaction afterTx = new VppReadOnlyTransaction(EMPTY_OPERATIONAL, modificationSnapshot); + final WriteContext ctx = new TransactionWriteContext(serializer, beforeTx, afterTx); + + final ChangesProcessor processor = new ChangesProcessor(writer, nodesBefore, nodesAfter, ctx); try { processor.applyChanges(); } catch (VppApiInvocationException e) { @@ -118,9 +136,10 @@ public final class VppConfigDataTree implements VppDataTree { dataTree.commit(candidate); } - private Map, DataObject> extractNetconfData(final Optional> parentOptional) { + private Map, DataObject> extractNetconfData( + final Optional> parentOptional) { if (parentOptional.isPresent()) { - final DataContainerNode parent = (DataContainerNode)parentOptional.get(); + final DataContainerNode parent = (DataContainerNode) parentOptional.get(); return DataTreeUtils.childrenFromNormalized(parent, serializer); } return Collections.emptyMap(); @@ -135,7 +154,7 @@ public final class VppConfigDataTree implements VppDataTree { @Override public CheckedFuture>, ReadFailedException> read( - final YangInstanceIdentifier path) { + @Nonnull final YangInstanceIdentifier path) { final Optional> node = snapshot.readNode(path); if (LOG.isTraceEnabled() && node.isPresent()) { LOG.trace("ConfigSnapshot.read: {}", node.get()); @@ -150,57 +169,80 @@ public final class VppConfigDataTree implements VppDataTree { } private static final class ChangesProcessor { - private final VppWriter writer; + private final VppWriterRegistry writer; private final List> processedNodes; private final Map, DataObject> nodesBefore; private final Map, DataObject> nodesAfter; + private final WriteContext ctx; - ChangesProcessor(@Nonnull final VppWriter writer, + ChangesProcessor(@Nonnull final VppWriterRegistry writer, final Map, DataObject> nodesBefore, - final Map, DataObject> nodesAfter) { - this.writer = Preconditions.checkNotNull(writer, "VppWriter is null!"); - this.nodesBefore = Preconditions.checkNotNull(nodesBefore, "nodesBefore is null!"); - this.nodesAfter = Preconditions.checkNotNull(nodesAfter, "nodesAfter is null!"); + final Map, DataObject> nodesAfter, + @Nonnull final WriteContext writeContext) { + this.ctx = checkNotNull(writeContext, "writeContext is null!"); + this.writer = checkNotNull(writer, "VppWriter is null!"); + this.nodesBefore = checkNotNull(nodesBefore, "nodesBefore is null!"); + this.nodesAfter = checkNotNull(nodesAfter, "nodesAfter is null!"); processedNodes = new ArrayList<>(); } void applyChanges() throws VppApiInvocationException { // TODO we should care about the order of modified subtrees + // TODO maybe WriterRegistry could provide writeAll method and it will process the updates + // in order in which it child writers are registered final Set> allNodes = new HashSet<>(); allNodes.addAll(nodesBefore.keySet()); allNodes.addAll(nodesAfter.keySet()); - LOG.debug("VppConfigDataProxy.applyChanges() all extracted nodes: {}", allNodes); + LOG.debug("ChangesProcessor.applyChanges() all extracted nodes: {}", allNodes); for (InstanceIdentifier node : allNodes) { - LOG.debug("VppConfigDataProxy.applyChanges() processing node={}", node); + LOG.debug("ChangesProcessor.applyChanges() processing node={}", node); final DataObject dataBefore = nodesBefore.get(node); final DataObject dataAfter = nodesAfter.get(node); + LOG.debug("ChangesProcessor.applyChanges() processing dataBefore={}, dataAfter={}", dataBefore, + dataAfter); try { - writer.process(dataBefore, dataAfter); + // TODO is List as input argument really necessary for writer ? + final List dataObjectsBefore = dataBefore == null + ? Collections.emptyList() + : singletonList(dataBefore); + final List dataObjectsAfter = dataAfter == null + ? Collections.emptyList() + : singletonList(dataAfter); + LOG.debug("ChangesProcessor.applyChanges() processing dataObjectsBefore={}, dataObjectsAfter={}", + dataObjectsBefore, dataObjectsAfter); + writer.update(node, dataObjectsBefore, dataObjectsAfter, ctx); processedNodes.add(node); - } catch (VppApiInvocationException e) { + } catch (RuntimeException e) { LOG.error("Error while processing data change (before={}, after={})", dataBefore, dataAfter, e); - throw e; + // FIXME ex handling + throw new VppApiInvocationException("", 1, -1); } } } void revertChanges() throws VppApiInvocationException { - Preconditions.checkNotNull(writer, "VppWriter is null!"); + checkNotNull(writer, "VppWriter is null!"); // revert changes in reverse order they were applied final ListIterator> iterator = processedNodes.listIterator(processedNodes.size()); while (iterator.hasPrevious()) { final InstanceIdentifier node = iterator.previous(); - LOG.debug("VppConfigDataProxy.revertChanges() processing node={}", node); + LOG.debug("ChangesProcessor.revertChanges() processing node={}", node); final DataObject dataBefore = nodesBefore.get(node); final DataObject dataAfter = nodesAfter.get(node); // revert a change by invoking writer with reordered arguments - writer.process(dataAfter, dataBefore); + try { + // TODO is List as input argument really necessary for writer ? + writer.update(node, singletonList(dataAfter), singletonList(dataBefore), ctx); + } catch (RuntimeException e) { + // FIXME ex handling + throw new VppApiInvocationException("", 1, -1); + } } } } 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 129a1b84b..2a14f48b1 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 @@ -16,6 +16,8 @@ package io.fd.honeycomb.v3po.impl.data; +import static com.google.common.base.Preconditions.checkNotNull; + import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.util.concurrent.AsyncFunction; @@ -23,7 +25,6 @@ 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 java.util.Collection; import java.util.Collections; import javassist.ClassPool; @@ -84,12 +85,16 @@ public final class VppDataBrokerInitializationProvider implements Provider, Auto private final DataBroker bindingBroker; private final ReaderRegistry readerRegistry; private final InstanceIdentifier mountPointPath; + private final VppWriterRegistry writerRegistry; private ObjectRegistration mountPointRegistration; private DOMDataBroker broker; - 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"); + public VppDataBrokerInitializationProvider(@Nonnull final DataBroker bindingBroker, + final ReaderRegistry readerRegistry, + final VppWriterRegistry writerRegistry) { + this.bindingBroker = checkNotNull(bindingBroker, "bindingBroker should not be null"); + this.readerRegistry = checkNotNull(readerRegistry, "readerRegistry should not be null"); + this.writerRegistry = checkNotNull(writerRegistry, "writerRegistry should not be null"); this.mountPointPath = getMountPointPath(); } @@ -180,9 +185,7 @@ public final class VppDataBrokerInitializationProvider implements Provider, Auto 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 + final VppDataTree configDataProxy = new VppConfigDataTree(serializer, dataTree, writerRegistry); // TODO make configurable return new VppDataBroker(operationalData, configDataProxy); } diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataTree.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataTree.java index 17d3b7149..a3a4fae65 100644 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataTree.java +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataTree.java @@ -17,7 +17,7 @@ package io.fd.honeycomb.v3po.impl.data; import com.google.common.annotations.Beta; -import io.fd.honeycomb.v3po.impl.trans0.VppApiInvocationException; +import io.fd.honeycomb.v3po.impl.trans.VppApiInvocationException; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException; diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppWriteTransaction.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppWriteTransaction.java index 8cdd10b7e..b7aa2f854 100644 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppWriteTransaction.java +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppWriteTransaction.java @@ -26,7 +26,7 @@ import com.google.common.base.Preconditions; import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; -import io.fd.honeycomb.v3po.impl.trans0.VppApiInvocationException; +import io.fd.honeycomb.v3po.impl.trans.VppApiInvocationException; import javax.annotation.Nonnull; import javax.annotation.concurrent.NotThreadSafe; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppWriterRegistry.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppWriterRegistry.java new file mode 100644 index 000000000..67b45cfd2 --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppWriterRegistry.java @@ -0,0 +1,92 @@ +/* + * 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 io.fd.honeycomb.v3po.impl.trans.util.VppRWUtils; +import io.fd.honeycomb.v3po.impl.trans.w.ChildVppWriter; +import io.fd.honeycomb.v3po.impl.trans.w.VppWriter; +import io.fd.honeycomb.v3po.impl.trans.w.WriteContext; +import io.fd.honeycomb.v3po.impl.trans.w.impl.CompositeChildVppWriter; +import io.fd.honeycomb.v3po.impl.trans.w.impl.CompositeListVppWriter; +import io.fd.honeycomb.v3po.impl.trans.w.impl.CompositeRootVppWriter; +import io.fd.honeycomb.v3po.impl.trans.w.util.DelegatingWriterRegistry; +import io.fd.honeycomb.v3po.impl.trans.w.util.NoopWriterCustomizer; +import io.fd.honeycomb.v3po.impl.trans.w.util.ReflexiveChildWriterCustomizer; +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.Vpp; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.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 VppWriterRegistry implements VppWriter { + + private static VppWriterRegistry instance; + + private final DelegatingWriterRegistry writer; + + private VppWriterRegistry(@Nonnull final vppApi vppApi) { + final CompositeRootVppWriter vppWriter = initVppStateWriter(vppApi); + writer = new DelegatingWriterRegistry(Collections.>singletonList(vppWriter)); + } + + private static CompositeRootVppWriter initVppStateWriter(@Nonnull final vppApi vppApi) { + final CompositeListVppWriter bridgeDomainWriter = new CompositeListVppWriter<>( + BridgeDomain.class, + new io.fd.honeycomb.v3po.impl.vpp.BridgeDomainCustomizer(vppApi)); + + final ChildVppWriter bridgeDomainsWriter = new CompositeChildVppWriter<>( + BridgeDomains.class, + VppRWUtils.singletonChildWriterList(bridgeDomainWriter), + new ReflexiveChildWriterCustomizer()); + + final List>> childWriters = new ArrayList<>(); + childWriters.add(bridgeDomainsWriter); + + return new CompositeRootVppWriter<>( + Vpp.class, + childWriters, + new NoopWriterCustomizer()); + } + + public static synchronized VppWriterRegistry getInstance(@Nonnull final vppApi vppApi) { + if (instance == null) { + instance = new VppWriterRegistry(vppApi); + } + return instance; + } + + @Nonnull + @Override + public InstanceIdentifier getManagedDataObjectType() { + return writer.getManagedDataObjectType(); + } + + @Override + public void update(@Nonnull final InstanceIdentifier id, + @Nonnull final List dataBefore, + @Nonnull final List data, @Nonnull final WriteContext ctx) { + writer.update(id, dataBefore, data, ctx); + } +} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/VppApiInvocationException.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/VppApiInvocationException.java new file mode 100644 index 000000000..b0076cd9c --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/VppApiInvocationException.java @@ -0,0 +1,76 @@ +/* + * 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 com.google.common.base.Preconditions; +import javax.annotation.Nonnull; + +/** + * Throws when Vpp jAPI method invocation failed. + */ +@Beta +public class VppApiInvocationException extends Exception { + private final String methodName; + private final int ctxId; + private final int errorCode; + + /** + * Constructs an VppApiInvocationFailedException with the specified api method name and error code. + * + * @param methodName method name that failed to invoke + * @param ctxId api request context identifier + * @param errorCode negative error code value associated with this failure + * @throws NullPointerException if apiMethodName is null + * @throws IllegalArgumentException if errorCode is nonnegative + */ + public VppApiInvocationException(@Nonnull final String methodName, final int ctxId, final int errorCode) { + super(String.format("vppApi.%s failed with error code: %d (ctxId=%d) ", methodName, errorCode, ctxId)); + this.methodName = Preconditions.checkNotNull(methodName, "apiMethodName is null!"); + this.ctxId = ctxId; + Preconditions.checkArgument(errorCode < 0); + this.errorCode = errorCode; + } + + /** + * Returns method name that failed to invoke. + * + * @return method name + */ + public String getMethodName() { + return methodName; + } + + /** + * Returns api request context identifier. + * + * @return value of context identifier + */ + public int getCtxId() { + return ctxId; + } + + /** + * Returns the error code associated with this failure. + * + * @return a negative integer error code + */ + public int getErrorCode() { + return errorCode; + } +} + diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/util/TransactionWriteContext.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/util/TransactionWriteContext.java index 3a1fd2f57..7c1a63da6 100644 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/util/TransactionWriteContext.java +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/util/TransactionWriteContext.java @@ -22,29 +22,30 @@ import io.fd.honeycomb.v3po.impl.trans.util.Context; import io.fd.honeycomb.v3po.impl.trans.w.WriteContext; import java.util.Collections; import java.util.List; -import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +import java.util.Map; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; +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.NormalizedNode; public class TransactionWriteContext implements WriteContext, AutoCloseable { - private final ReadOnlyTransaction beforeTx; - private final ReadOnlyTransaction afterTx; + private final DOMDataReadOnlyTransaction beforeTx; + private final DOMDataReadOnlyTransaction afterTx; private final Context ctx; + private final BindingNormalizedNodeSerializer serializer; - public TransactionWriteContext(final ReadOnlyTransaction beforeTx, final ReadOnlyTransaction afterTx, - final Context ctx) { - super(); + public TransactionWriteContext(final BindingNormalizedNodeSerializer serializer, + final DOMDataReadOnlyTransaction beforeTx, + final DOMDataReadOnlyTransaction afterTx) { + this.serializer = serializer; this.beforeTx = beforeTx; this.afterTx = afterTx; - this.ctx = ctx; - } - - public TransactionWriteContext(final ReadOnlyTransaction beforeTx, - final ReadOnlyTransaction afterTx) { - this(beforeTx, afterTx, new Context()); + this.ctx = new Context(); } @Override @@ -53,16 +54,26 @@ public class TransactionWriteContext implements WriteContext, AutoCloseable { } private List read(final InstanceIdentifier currentId, - final ReadOnlyTransaction tx) { + final DOMDataReadOnlyTransaction tx) { // FIXME how to read all for list (using wildcarded ID) ? - final CheckedFuture, ReadFailedException> read = - tx.read(LogicalDatastoreType.CONFIGURATION, currentId); + final YangInstanceIdentifier path = serializer.toYangInstanceIdentifier(currentId); + + final CheckedFuture>, ReadFailedException> read = + tx.read(LogicalDatastoreType.CONFIGURATION, path); + try { - final Optional optional = read.checkedGet(); - return optional.isPresent() - ? Collections.singletonList(optional.get()) - : Collections.emptyList(); + final Optional> optional = read.checkedGet(); + + if (!optional.isPresent()) { + return Collections.emptyList(); + } + + final NormalizedNode data = optional.get(); + final Map.Entry, DataObject> entry = + serializer.fromNormalizedNode(path, data); + + return Collections.singletonList(entry.getValue()); } catch (ReadFailedException e) { throw new IllegalStateException("Unable to perform read", e); } diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/DefaultVppWriter.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/DefaultVppWriter.java deleted file mode 100644 index 573353b55..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/DefaultVppWriter.java +++ /dev/null @@ -1,43 +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.trans0; - -import java.util.Objects; -import javax.annotation.Nullable; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class DefaultVppWriter implements VppWriter { - private static final Logger LOG = LoggerFactory.getLogger(DefaultVppWriter.class); - - @Override - public void process(@Nullable final DataObject dataBefore, @Nullable final DataObject dataAfter) - throws VppApiInvocationException { - LOG.debug("Processing modification: dataBefore={}, dataAfter={}", dataBefore, dataAfter); - - if (Objects.equals(dataBefore, dataAfter)) { - LOG.debug("No modification"); - } else if (dataBefore == null) { - LOG.debug("modification type: CREATE"); - } else if (dataAfter == null) { - LOG.debug("modification type: DELETE"); - } else { - LOG.debug("modification type: UPDATE"); - } - } -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/VppApiInvocationException.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/VppApiInvocationException.java deleted file mode 100644 index 119563bdd..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/VppApiInvocationException.java +++ /dev/null @@ -1,76 +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.trans0; - -import com.google.common.annotations.Beta; -import com.google.common.base.Preconditions; -import javax.annotation.Nonnull; - -/** - * Throws when Vpp jAPI method invocation failed. - */ -@Beta -public class VppApiInvocationException extends Exception { - private final String methodName; - private final int ctxId; - private final int errorCode; - - /** - * Constructs an VppApiInvocationFailedException with the specified api method name and error code. - * - * @param methodName method name that failed to invoke - * @param ctxId api request context identifier - * @param errorCode negative error code value associated with this failure - * @throws NullPointerException if apiMethodName is null - * @throws IllegalArgumentException if errorCode is nonnegative - */ - public VppApiInvocationException(@Nonnull final String methodName, final int ctxId, final int errorCode) { - super(String.format("vppApi.%s failed with error code: %d (ctxId=%d) ", methodName, errorCode, ctxId)); - this.methodName = Preconditions.checkNotNull(methodName, "apiMethodName is null!"); - this.ctxId = ctxId; - Preconditions.checkArgument(errorCode < 0); - this.errorCode = errorCode; - } - - /** - * Returns method name that failed to invoke. - * - * @return method name - */ - public String getMethodName() { - return methodName; - } - - /** - * Returns api request context identifier. - * - * @return value of context identifier - */ - public int getCtxId() { - return ctxId; - } - - /** - * Returns the error code associated with this failure. - * - * @return a negative integer error code - */ - public int getErrorCode() { - return errorCode; - } -} - diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/VppInterfacesReader.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/VppInterfacesReader.java deleted file mode 100644 index 39b5f0208..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/VppInterfacesReader.java +++ /dev/null @@ -1,56 +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.trans0; - -import java.util.Collections; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.EthernetCsmacd; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class VppInterfacesReader implements VppReader { - private static final Logger LOG = LoggerFactory.getLogger(VppInterfacesReader.class); - - @Override - public Interfaces read(final InstanceIdentifier id) { - LOG.info("VppInterfacesReader.read, id={}", id); - - InterfaceBuilder ifaceBuilder = new InterfaceBuilder(); - final String interfaceName = "eth0"; - ifaceBuilder.setName(interfaceName); - ifaceBuilder.setDescription("eth0 description"); - ifaceBuilder.setEnabled(false); - ifaceBuilder.setKey(new InterfaceKey(interfaceName)); - ifaceBuilder.setType(EthernetCsmacd.class); - ifaceBuilder.setLinkUpDownTrapEnable(Interface.LinkUpDownTrapEnable.Disabled); - - InterfacesBuilder ifacesBuilder = new InterfacesBuilder(); - ifacesBuilder.setInterface(Collections.singletonList(ifaceBuilder.build())); - return ifacesBuilder.build(); - } - - @Override - public Class getManagedDataObjectType() { - return null; - } -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/VppReader.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/VppReader.java deleted file mode 100644 index 5a4215edb..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/VppReader.java +++ /dev/null @@ -1,30 +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.trans0; - -import com.google.common.annotations.Beta; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -@Beta -public interface VppReader { - - C read(InstanceIdentifier id); - - Class getManagedDataObjectType(); - -} \ No newline at end of file diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/VppWriter.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/VppWriter.java deleted file mode 100644 index ee6e1f4be..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/VppWriter.java +++ /dev/null @@ -1,27 +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.trans0; - -import com.google.common.annotations.Beta; -import javax.annotation.Nullable; -import org.opendaylight.yangtools.yang.binding.DataObject; - -@Beta -public interface VppWriter { - - void process(@Nullable C dataBefore, @Nullable C dataAfter) throws VppApiInvocationException; -} \ No newline at end of file diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vpp/BridgeDomainCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vpp/BridgeDomainCustomizer.java index f707164eb..c56ebb1a8 100644 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vpp/BridgeDomainCustomizer.java +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vpp/BridgeDomainCustomizer.java @@ -16,6 +16,8 @@ package io.fd.honeycomb.v3po.impl.vpp; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import io.fd.honeycomb.v3po.impl.trans.util.Context; @@ -38,9 +40,9 @@ public class BridgeDomainCustomizer private static final Logger LOG = LoggerFactory.getLogger(BridgeDomainCustomizer.class); - static final byte ADD_BD = (byte) 1; - static final int NO_RET_VAL = -77; - static final int RELEASE = 1; + private static final byte ADD_OR_UPDATE_BD = (byte) 1; + private static final int RESPONSE_NOT_READY = -77; + private static final int RELEASE = 1; public BridgeDomainCustomizer(final org.openvpp.vppjapi.vppApi api) { super(api); @@ -53,30 +55,37 @@ public class BridgeDomainCustomizer return ((BridgeDomains) parentData).getBridgeDomain(); } + private int waitForResponse(final int ctxId) { + int rv; + while ((rv = getVppApi().getRetval(ctxId, RELEASE)) == RESPONSE_NOT_READY) { + // TODO limit attempts + } + return rv; + } + + private int addOrUpdateBridgeDomain(final int bdId, @Nonnull final BridgeDomain bd) { + byte flood = booleanToByte(bd.isFlood()); + byte forward = booleanToByte(bd.isForward()); + byte learn = booleanToByte(bd.isLearn()); + byte uuf = booleanToByte(bd.isUnknownUnicastFlood()); + byte arpTerm = booleanToByte(bd.isArpTermination()); + + int ctxId = getVppApi().bridgeDomainAddDel(bdId, flood, forward, learn, uuf, arpTerm, ADD_OR_UPDATE_BD); + return waitForResponse(ctxId); + } + @Override public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final BridgeDomain current, @Nonnull final Context ctx) { + LOG.debug("writeCurrentAttributes: id={}, current={}, ctx={}", id, current, ctx); final String bdName = current.getName(); int bdId = getVppApi().findOrAddBridgeDomainId(bdName); checkState(bdId > 0, "Unable to find or create bridge domain. Return code: %s", bdId); - byte flood = booleanToByte(current.isFlood()); - byte forward = booleanToByte(current.isForward()); - byte learn = booleanToByte(current.isLearn()); - byte uuf = booleanToByte(current.isUnknownUnicastFlood()); - byte arpTerm = booleanToByte(current.isArpTermination()); - - int ctxId = getVppApi().bridgeDomainAddDel(bdId, flood, forward, learn, uuf, arpTerm, ADD_BD); - - int rv = NO_RET_VAL; - while (rv == -77) { - rv = getVppApi().getRetval(ctxId, RELEASE /* release */); - // TODO limit attempts - } - checkState(rv > 0, "Bridge domain %s(%s) write failed. Return code: %s", bdName, bdId, rv); + int rv = addOrUpdateBridgeDomain(bdId, current); - bdId = getVppApi().bridgeDomainIdFromName(bdName); + checkState(rv >= 0, "Bridge domain %s(%s) write failed. Return code: %s", bdName, bdId, rv); LOG.debug("Bridge domain {} written as {} successfully", bdName, bdId); } @@ -88,9 +97,10 @@ public class BridgeDomainCustomizer public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final BridgeDomain dataBefore, @Nonnull final Context ctx) { + LOG.debug("deleteCurrentAttributes: id={}, dataBefore={}, ctx={}", id, dataBefore, ctx); String bdName = id.firstKeyOf(BridgeDomain.class).getName(); - int bdId = getVppApi().findOrAddBridgeDomainId(bdName); + int bdId = getVppApi().bridgeDomainIdFromName(bdName); checkState(bdId > 0, "Unable to delete bridge domain. Does not exist. Return code: %s", bdId); int ctxId = getVppApi().bridgeDomainAddDel(bdId, @@ -101,13 +111,9 @@ public class BridgeDomainCustomizer (byte) 0 /* arpTerm */, (byte) 0 /* isAdd */); - int rv = NO_RET_VAL; - while (rv == NO_RET_VAL) { - rv = getVppApi().getRetval(ctxId, RELEASE /* release */); - // TODO limit attempts - } + int rv = waitForResponse(ctxId); - checkState(rv > 0, "Bridge domain delete failed. Return code: %s", rv); + checkState(rv >= 0, "Bridge domain delete failed. Return code: %s", rv); LOG.debug("Bridge domain {} deleted as {} successfully", bdName, bdId); } @@ -115,9 +121,18 @@ public class BridgeDomainCustomizer public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final BridgeDomain dataBefore, @Nonnull final BridgeDomain dataAfter, @Nonnull final Context ctx) { - // Most basic update implementation: Delete + Write - deleteCurrentAttributes(id, dataBefore, ctx); - writeCurrentAttributes(id, dataAfter, ctx); + LOG.debug("updateCurrentAttributes: id={}, dataBefore={}, dataAfter={}, ctx={}", id, dataBefore, dataAfter, ctx); + + final String bdName = checkNotNull(dataAfter.getName()); + checkArgument(bdName.equals(dataBefore.getName()), "BridgeDomain name changed. It should be deleted and then created."); + + int bdId = getVppApi().bridgeDomainIdFromName(bdName); + checkState(bdId > 0, "Unable to find bridge domain. Return code: %s", bdId); + + final int rv = addOrUpdateBridgeDomain(bdId, dataAfter); + + checkState(rv >= 0, "Bridge domain %s(%s) update failed. Return code: %s", bdName, bdId, rv); + LOG.debug("Bridge domain {}({}) updated successfully", bdName, bdId); } } -- cgit 1.2.3-korg