diff options
author | 2016-07-27 11:05:51 +0200 | |
---|---|---|
committer | 2016-07-29 16:32:07 +0200 | |
commit | 81c9cdfa5a9e91b91d73a6a2b20cff8b612d7de3 (patch) | |
tree | c941a2e5ea9df88acdfc64392b03228fdd18eb2b /v3po/data-impl/src/main/java/io | |
parent | 10d33239e1e0d10a2f51e6739d18035e61600eb8 (diff) |
HONEYCOMB-130: Separate v3po plugin from HC infra
Creating folders:
- common/
- infra/
- v3po/
- vpp-common/
Change-Id: I2c39e1b17e39e7c0f0628f44aa5fe08563fa06e4
Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
Diffstat (limited to 'v3po/data-impl/src/main/java/io')
9 files changed, 0 insertions, 1624 deletions
diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataBroker.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataBroker.java deleted file mode 100644 index c418ed332..000000000 --- a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataBroker.java +++ /dev/null @@ -1,198 +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.data.impl; - -import static com.google.common.base.Preconditions.checkNotNull; - -import io.fd.honeycomb.v3po.data.DataModification; -import io.fd.honeycomb.v3po.data.ModifiableDataManager; -import io.fd.honeycomb.v3po.data.ReadableDataManager; -import java.io.Closeable; -import java.io.IOException; -import java.util.Collections; -import java.util.Map; -import javax.annotation.Nonnull; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener; -import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; -import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension; -import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain; -import org.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Data Broker which provides data transaction functionality for YANG capable data provider using {@link NormalizedNode} - * data format. - */ -public class DataBroker implements DOMDataBroker, Closeable { - - private static final Logger LOG = LoggerFactory.getLogger(DataBroker.class); - private final TransactionFactory transactionFactory; - - /** - * Creates DataBroker instance. - * - * @param transactionFactory transaction producing factory - */ - public DataBroker(final TransactionFactory transactionFactory) { - this.transactionFactory = transactionFactory; - } - - @Override - public DOMDataReadOnlyTransaction newReadOnlyTransaction() { - LOG.trace("DataBroker({}).newReadOnlyTransaction()", this); - return transactionFactory.newReadOnlyTransaction(); - } - - @Override - public DOMDataReadWriteTransaction newReadWriteTransaction() { - LOG.trace("DataBroker({}).newReadWriteTransaction()", this); - return transactionFactory.newReadWriteTransaction(); - } - - @Override - public DOMDataWriteTransaction newWriteOnlyTransaction() { - LOG.trace("DataBroker({}).newWriteOnlyTransaction()", this); - return transactionFactory.newWriteOnlyTransaction(); - } - - @Override - public ListenerRegistration<DOMDataChangeListener> registerDataChangeListener(final LogicalDatastoreType store, - final YangInstanceIdentifier path, - final DOMDataChangeListener listener, - final DataChangeScope triggeringScope) { - throw new UnsupportedOperationException("Not supported"); - } - - @Override - public DOMTransactionChain createTransactionChain(final TransactionChainListener listener) { - throw new UnsupportedOperationException("Not supported"); - } - - @Nonnull - @Override - public Map<Class<? extends DOMDataBrokerExtension>, DOMDataBrokerExtension> getSupportedExtensions() { - return Collections.emptyMap(); - } - - /** - * Create DataBroker for a modifiable config DT, but only readable Operational - */ - @Nonnull - public static DataBroker create(@Nonnull final ModifiableDataManager configDataTree, - @Nonnull final ReadableDataManager operationalDataTree) { - checkNotNull(operationalDataTree, "operationalDataTree should not be null"); - checkNotNull(configDataTree, "configDataTree should not be null"); - return new DataBroker(new MainPipelineTxFactory(configDataTree, operationalDataTree)); - } - - /** - * Create DataBroker for modifiable operational DT, but no support for config - */ - @Nonnull - public static DataBroker create(@Nonnull final ModifiableDataManager operationalDataTree) { - checkNotNull(operationalDataTree, "operationalDataTree should not be null"); - return new DataBroker(new ContextPipelineTxFactory(operationalDataTree)); - } - - @Override - public void close() throws IOException { - // NOOP - } - - /** - * Transaction provider factory to be used by {@link DataBroker} - */ - public interface TransactionFactory { - - DOMDataReadOnlyTransaction newReadOnlyTransaction(); - - DOMDataReadWriteTransaction newReadWriteTransaction(); - - DOMDataWriteTransaction newWriteOnlyTransaction(); - } - - /** - * Transaction factory specific for Honeycomb's main pipeline (config: read+write, operational: read-only) - */ - private static class MainPipelineTxFactory implements TransactionFactory { - private final ReadableDataManager operationalDataTree; - private final ModifiableDataManager configDataTree; - - MainPipelineTxFactory(@Nonnull final ModifiableDataManager configDataTree, - @Nonnull final ReadableDataManager operationalDataTree) { - this.operationalDataTree = operationalDataTree; - this.configDataTree = configDataTree; - } - - @Override - public DOMDataReadOnlyTransaction newReadOnlyTransaction() { - return ReadOnlyTransaction.create(configDataTree.newModification(), operationalDataTree); - } - - @Override - public DOMDataReadWriteTransaction newReadWriteTransaction() { - final DataModification configModification = configDataTree.newModification(); - return new ReadWriteTransaction( - ReadOnlyTransaction.create(configModification, operationalDataTree), - WriteTransaction.createConfigOnly(configModification)); - } - - @Override - public DOMDataWriteTransaction newWriteOnlyTransaction() { - return WriteTransaction.createConfigOnly(configDataTree.newModification()); - } - } - - /** - * Transaction factory specific for Honeycomb's context pipeline (config: none, operational: read+write) - */ - private static class ContextPipelineTxFactory implements TransactionFactory { - private final ModifiableDataManager operationalDataTree; - - ContextPipelineTxFactory(@Nonnull final ModifiableDataManager operationalDataTree) { - this.operationalDataTree = operationalDataTree; - } - - @Override - public DOMDataReadOnlyTransaction newReadOnlyTransaction() { - return ReadOnlyTransaction.createOperationalOnly(operationalDataTree); - } - - @Override - public DOMDataReadWriteTransaction newReadWriteTransaction() { - final DataModification dataModification = operationalDataTree.newModification(); - return new ReadWriteTransaction( - ReadOnlyTransaction.createOperationalOnly(dataModification), - WriteTransaction.createOperationalOnly(dataModification)); - } - - @Override - public DOMDataWriteTransaction newWriteOnlyTransaction() { - return WriteTransaction.createOperationalOnly(operationalDataTree.newModification()); - } - } -} - - diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeDelegator.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeDelegator.java deleted file mode 100644 index 2c2581ec0..000000000 --- a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeDelegator.java +++ /dev/null @@ -1,236 +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.data.impl; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.util.concurrent.Futures.immediateCheckedFuture; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Optional; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; -import com.google.common.util.concurrent.CheckedFuture; -import io.fd.honeycomb.v3po.data.DataModification; -import io.fd.honeycomb.v3po.data.ReadableDataManager; -import io.fd.honeycomb.v3po.translate.TranslationException; -import io.fd.honeycomb.v3po.translate.util.RWUtils; -import io.fd.honeycomb.v3po.translate.util.TransactionMappingContext; -import io.fd.honeycomb.v3po.translate.util.write.TransactionWriteContext; -import io.fd.honeycomb.v3po.translate.write.DataObjectUpdate; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.registry.WriterRegistry; -import java.util.Map; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; -import org.opendaylight.yangtools.binding.data.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; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Extension of {@link ModifiableDataTreeManager} that propagates data changes to underlying writer layer before they - * are fully committed in the backing data tree. Data changes are propagated in BA format. - */ -public final class ModifiableDataTreeDelegator extends ModifiableDataTreeManager { - - private static final Logger LOG = LoggerFactory.getLogger(ModifiableDataTreeDelegator.class); - private static final ReadableDataManager EMPTY_OPERATIONAL = p -> immediateCheckedFuture(Optional.absent()); - - private final WriterRegistry writerRegistry; - private final org.opendaylight.controller.md.sal.binding.api.DataBroker contextBroker; - // TODO what to use instead of deprecated BindingNormalizedNodeSerializer ? - private final BindingNormalizedNodeSerializer serializer; - - /** - * Creates configuration data tree instance. - * @param serializer service for serialization between Java Binding Data representation and NormalizedNode - * representation. - * @param dataTree data tree for configuration data representation - * @param writerRegistry service for translation between Java Binding Data and data provider, capable of performing - * @param contextBroker BA broker providing full access to mapping context data - */ - public ModifiableDataTreeDelegator(@Nonnull final BindingNormalizedNodeSerializer serializer, - @Nonnull final DataTree dataTree, - @Nonnull final WriterRegistry writerRegistry, - @Nonnull final org.opendaylight.controller.md.sal.binding.api.DataBroker contextBroker) { - super(dataTree); - this.contextBroker = checkNotNull(contextBroker, "contextBroker should not be null"); - this.serializer = checkNotNull(serializer, "serializer should not be null"); - this.writerRegistry = checkNotNull(writerRegistry, "writerRegistry should not be null"); - } - - @Override - public DataModification newModification() { - return new ConfigSnapshot(super.newModification()); - } - - private final class ConfigSnapshot extends ModifiableDataTreeManager.ConfigSnapshot { - - private final DataModification untouchedModification; - - /** - * @param untouchedModification DataModification captured while this modification/snapshot was created. - * To be used later while invoking writers to provide them with before state - * (state without current modifications). - * It must be captured as close as possible to when current modification started. - */ - ConfigSnapshot(final DataModification untouchedModification) { - this.untouchedModification = untouchedModification; - } - - /** - * Pass the changes to underlying writer layer. - * Transform from BI to BA. - * Revert(Write data before to subtrees that have been successfully modified before failure) in case of failure. - */ - @Override - protected void processCandidate(final DataTreeCandidate candidate) - throws TranslationException { - - final DataTreeCandidateNode rootNode = candidate.getRootNode(); - final YangInstanceIdentifier rootPath = candidate.getRootPath(); - LOG.trace("ConfigDataTree.modify() rootPath={}, rootNode={}, dataBefore={}, dataAfter={}", - rootPath, rootNode, rootNode.getDataBefore(), rootNode.getDataAfter()); - - final ModificationDiff modificationDiff = - ModificationDiff.recursivelyFromCandidate(YangInstanceIdentifier.EMPTY, rootNode); - LOG.debug("ConfigDataTree.modify() diff: {}", modificationDiff); - - // Distinguish between updates (create + update) and deletes - final WriterRegistry.DataObjectUpdates baUpdates = toBindingAware(modificationDiff.getUpdates()); - LOG.debug("ConfigDataTree.modify() extracted updates={}", baUpdates); - - try (final WriteContext ctx = getTransactionWriteContext()) { - writerRegistry.update(baUpdates, ctx); - - final CheckedFuture<Void, TransactionCommitFailedException> contextUpdateResult = - ((TransactionMappingContext) ctx.getMappingContext()).submit(); - // Blocking on context data update - contextUpdateResult.checkedGet(); - - } catch (WriterRegistry.BulkUpdateException e) { - LOG.warn("Failed to apply all changes", e); - LOG.info("Trying to revert successful changes for current transaction"); - - try { - e.revertChanges(); - LOG.info("Changes successfully reverted"); - } catch (WriterRegistry.Reverter.RevertFailedException revertFailedException) { - // fail with failed revert - LOG.error("Failed to revert successful changes", revertFailedException); - throw revertFailedException; - } - - throw e; // fail with success revert - } catch (TransactionCommitFailedException e) { - // FIXME revert should probably occur when context is not written successfully - final String msg = "Error while updating mapping context data"; - LOG.error(msg, e); - throw new TranslationException(msg, e); - } catch (TranslationException e) { - LOG.error("Error while processing data change (updates={})", baUpdates, e); - throw e; - } - } - - private TransactionWriteContext getTransactionWriteContext() { - // Before Tx must use modification - final DOMDataReadOnlyTransaction beforeTx = ReadOnlyTransaction.create(untouchedModification, EMPTY_OPERATIONAL); - // After Tx must use current modification - final DOMDataReadOnlyTransaction afterTx = ReadOnlyTransaction.create(this, EMPTY_OPERATIONAL); - final TransactionMappingContext mappingContext = new TransactionMappingContext( - contextBroker.newReadWriteTransaction()); - return new TransactionWriteContext(serializer, beforeTx, afterTx, mappingContext); - } - - private WriterRegistry.DataObjectUpdates toBindingAware( - final Map<YangInstanceIdentifier, ModificationDiff.NormalizedNodeUpdate> biNodes) { - return ModifiableDataTreeDelegator.toBindingAware(biNodes, serializer); - } - } - - @VisibleForTesting - static WriterRegistry.DataObjectUpdates toBindingAware( - final Map<YangInstanceIdentifier, ModificationDiff.NormalizedNodeUpdate> biNodes, - final BindingNormalizedNodeSerializer serializer) { - - final Multimap<InstanceIdentifier<?>, DataObjectUpdate> dataObjectUpdates = HashMultimap.create(); - final Multimap<InstanceIdentifier<?>, DataObjectUpdate.DataObjectDelete> dataObjectDeletes = - HashMultimap.create(); - - for (Map.Entry<YangInstanceIdentifier, ModificationDiff.NormalizedNodeUpdate> biEntry : biNodes.entrySet()) { - final InstanceIdentifier<?> unkeyedIid = - RWUtils.makeIidWildcarded(serializer.fromYangInstanceIdentifier(biEntry.getKey())); - - ModificationDiff.NormalizedNodeUpdate normalizedNodeUpdate = biEntry.getValue(); - final DataObjectUpdate dataObjectUpdate = toDataObjectUpdate(normalizedNodeUpdate, serializer); - if (dataObjectUpdate != null) { - if (dataObjectUpdate instanceof DataObjectUpdate.DataObjectDelete) { - dataObjectDeletes.put(unkeyedIid, ((DataObjectUpdate.DataObjectDelete) dataObjectUpdate)); - } else { - dataObjectUpdates.put(unkeyedIid, dataObjectUpdate); - } - } - } - return new WriterRegistry.DataObjectUpdates(dataObjectUpdates, dataObjectDeletes); - } - - @Nullable - private static DataObjectUpdate toDataObjectUpdate( - final ModificationDiff.NormalizedNodeUpdate normalizedNodeUpdate, - final BindingNormalizedNodeSerializer serializer) { - - InstanceIdentifier<?> baId = serializer.fromYangInstanceIdentifier(normalizedNodeUpdate.getId()); - checkNotNull(baId, "Unable to transform instance identifier: %s into BA", normalizedNodeUpdate.getId()); - - DataObject dataObjectBefore = getDataObject(serializer, - normalizedNodeUpdate.getDataBefore(), normalizedNodeUpdate.getId()); - DataObject dataObjectAfter = - getDataObject(serializer, normalizedNodeUpdate.getDataAfter(), normalizedNodeUpdate.getId()); - - return dataObjectBefore == null && dataObjectAfter == null - ? null - : DataObjectUpdate.create(baId, dataObjectBefore, dataObjectAfter); - } - - @Nullable - private static DataObject getDataObject(@Nonnull final BindingNormalizedNodeSerializer serializer, - @Nullable final NormalizedNode<?, ?> data, - @Nonnull final YangInstanceIdentifier id) { - DataObject dataObject = null; - if (data != null) { - final Map.Entry<InstanceIdentifier<?>, DataObject> dataObjectEntry = - serializer.fromNormalizedNode(id, data); - if (dataObjectEntry != null) { - dataObject = dataObjectEntry.getValue(); - } - } - return dataObject; - } - -} - - - diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeManager.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeManager.java deleted file mode 100644 index 1082c479b..000000000 --- a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeManager.java +++ /dev/null @@ -1,122 +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.data.impl; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.util.concurrent.Futures.immediateCheckedFuture; - -import com.google.common.base.Optional; -import com.google.common.util.concurrent.CheckedFuture; -import io.fd.honeycomb.v3po.data.DataModification; -import io.fd.honeycomb.v3po.data.ModifiableDataManager; -import io.fd.honeycomb.v3po.translate.TranslationException; -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; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * DataTree backed implementation for modifiable data manager. - */ -public class ModifiableDataTreeManager implements ModifiableDataManager { - - private static final Logger LOG = LoggerFactory.getLogger(ModifiableDataTreeManager.class); - - private final DataTree dataTree; - - public ModifiableDataTreeManager(@Nonnull final DataTree dataTree) { - this.dataTree = checkNotNull(dataTree, "dataTree should not be null"); - } - - @Override - public DataModification newModification() { - return new ConfigSnapshot(); - } - - @Override - public final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(@Nonnull final YangInstanceIdentifier path) { - return newModification().read(path); - } - - protected class ConfigSnapshot implements DataModification { - private final DataTreeModification modification; - private boolean validated = false; - - ConfigSnapshot() { - this(dataTree.takeSnapshot().newModification()); - } - - protected ConfigSnapshot(final DataTreeModification modification) { - this.modification = modification; - } - - @Override - public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read( - @Nonnull final YangInstanceIdentifier path) { - final Optional<NormalizedNode<?, ?>> node = modification.readNode(path); - if (LOG.isTraceEnabled() && node.isPresent()) { - LOG.trace("ConfigSnapshot.read: {}", node.get()); - } - return immediateCheckedFuture(node); - } - - @Override - public final void delete(final YangInstanceIdentifier path) { - modification.delete(path); - } - - @Override - public final void merge(final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) { - modification.merge(path, data); - } - - @Override - public final void write(final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) { - modification.write(path, data); - } - - @Override - public final void commit() throws DataValidationFailedException, TranslationException { - if(!validated) { - validate(); - } - final DataTreeCandidate candidate = dataTree.prepare(modification); - processCandidate(candidate); - dataTree.commit(candidate); - } - - protected void processCandidate(final DataTreeCandidate candidate) throws TranslationException { - // NOOP - } - - @Override - public final void validate() throws DataValidationFailedException { - modification.ready(); - dataTree.validate(modification); - validated = true; - } - } -} - - - diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModificationDiff.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModificationDiff.java deleted file mode 100644 index abc0062de..000000000 --- a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModificationDiff.java +++ /dev/null @@ -1,278 +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.data.impl; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.common.collect.ImmutableMap; -import java.util.Collections; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.Map; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode; -import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode; -import org.opendaylight.yangtools.yang.data.api.schema.LeafNode; -import org.opendaylight.yangtools.yang.data.api.schema.MixinNode; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode; -import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType; - -/** - * Recursively collects and provides all unique and non-null modifications (modified normalized nodes). - */ -final class ModificationDiff { - - private static final ModificationDiff EMPTY_DIFF = new ModificationDiff(Collections.emptyMap()); - private static final EnumSet LEAF_MODIFICATIONS = EnumSet.of(ModificationType.WRITE, ModificationType.DELETE); - - private final Map<YangInstanceIdentifier, NormalizedNodeUpdate> updates; - - private ModificationDiff(@Nonnull Map<YangInstanceIdentifier, NormalizedNodeUpdate> updates) { - this.updates = updates; - } - - /** - * Get processed modifications. - * - * @return mapped modifications, where key is keyed {@link YangInstanceIdentifier}. - */ - Map<YangInstanceIdentifier, NormalizedNodeUpdate> getUpdates() { - return updates; - } - - private ModificationDiff merge(final ModificationDiff other) { - if (this == EMPTY_DIFF) { - return other; - } - - if (other == EMPTY_DIFF) { - return this; - } - - return new ModificationDiff(join(updates, other.updates)); - } - - private static Map<YangInstanceIdentifier, NormalizedNodeUpdate> join(Map<YangInstanceIdentifier, NormalizedNodeUpdate> first, - Map<YangInstanceIdentifier, NormalizedNodeUpdate> second) { - final Map<YangInstanceIdentifier, NormalizedNodeUpdate> merged = new HashMap<>(); - merged.putAll(first); - merged.putAll(second); - return merged; - } - - private static ModificationDiff create(YangInstanceIdentifier id, DataTreeCandidateNode candidate) { - return new ModificationDiff(ImmutableMap.of(id, NormalizedNodeUpdate.create(id, candidate))); - } - - /** - * Produce an aggregated diff from a candidate node recursively. MixinNodes are ignored as modifications and so - * are complex nodes which direct leaves were not modified. - */ - @Nonnull - static ModificationDiff recursivelyFromCandidate(@Nonnull final YangInstanceIdentifier yangIid, - @Nonnull final DataTreeCandidateNode currentCandidate) { - // recursively process child nodes for exact modifications - return recursivelyChildrenFromCandidate(yangIid, currentCandidate) - // also add modification on current level, if elligible - .merge(isModification(currentCandidate) - ? ModificationDiff.create(yangIid, currentCandidate) - : EMPTY_DIFF); - } - - /** - * Check whether current node was modified. {@link MixinNode}s are ignored - * and only nodes which direct leaves(or choices) are modified are considered a modification. - */ - private static Boolean isModification(@Nonnull final DataTreeCandidateNode currentCandidate) { - // Mixin nodes are not considered modifications - if (isMixin(currentCandidate) && !isAugment(currentCandidate)) { - return false; - } else { - return isCurrentModified(currentCandidate); - } - } - - private static Boolean isCurrentModified(final @Nonnull DataTreeCandidateNode currentCandidate) { - // Check if there are any modified leaves and if so, consider current node as modified - final Boolean directLeavesModified = currentCandidate.getChildNodes().stream() - .filter(ModificationDiff::isLeaf) - // For some reason, we get modifications on unmodified list keys TODO debug and report ODL bug - // and that messes up our modifications collection here, so we need to skip - .filter(ModificationDiff::isBeforeAndAfterDifferent) - .filter(child -> LEAF_MODIFICATIONS.contains(child.getModificationType())) - .findFirst() - .isPresent(); - - return directLeavesModified - // Also check choices (choices do not exist in BA world and if anything within a choice was modified, - // consider its parent as being modified) - || currentCandidate.getChildNodes().stream() - .filter(ModificationDiff::isChoice) - // Recursively check each choice if there was any change to it - .filter(ModificationDiff::isCurrentModified) - .findFirst() - .isPresent(); - } - - /** - * Process all non-leaf child nodes recursively, creating aggregated {@link ModificationDiff}. - */ - private static ModificationDiff recursivelyChildrenFromCandidate(final @Nonnull YangInstanceIdentifier yangIid, - final @Nonnull DataTreeCandidateNode currentCandidate) { - // recursively process child nodes for specific modifications - return currentCandidate.getChildNodes().stream() - // not interested in modifications to leaves - .filter(child -> !isLeaf(child)) - .map(candidate -> recursivelyFromCandidate(yangIid.node(candidate.getIdentifier()), candidate)) - .reduce(ModificationDiff::merge) - .orElse(EMPTY_DIFF); - } - - /** - * Check whether candidate.before and candidate.after is different. If not return false. - */ - private static boolean isBeforeAndAfterDifferent(@Nonnull final DataTreeCandidateNode candidateNode) { - if (candidateNode.getDataBefore().isPresent()) { - return !candidateNode.getDataBefore().get().equals(candidateNode.getDataAfter().orNull()); - } - - // considering not a modification if data after is also null - return candidateNode.getDataAfter().isPresent(); - } - - /** - * Check whether candidate node is for a leaf type node. - */ - private static boolean isLeaf(final DataTreeCandidateNode candidateNode) { - // orNull intentional, some candidate nodes have both data after and data before null - return candidateNode.getDataAfter().orNull() instanceof LeafNode<?> - || candidateNode.getDataBefore().orNull() instanceof LeafNode<?>; - } - - /** - * Check whether candidate node is for a Mixin type node. - */ - private static boolean isMixin(final DataTreeCandidateNode candidateNode) { - // orNull intentional, some candidate nodes have both data after and data before null - return candidateNode.getDataAfter().orNull() instanceof MixinNode - || candidateNode.getDataBefore().orNull() instanceof MixinNode; - } - - /** - * Check whether candidate node is for an Augmentation type node. - */ - private static boolean isAugment(final DataTreeCandidateNode candidateNode) { - // orNull intentional, some candidate nodes have both data after and data before null - return candidateNode.getDataAfter().orNull() instanceof AugmentationNode - || candidateNode.getDataBefore().orNull() instanceof AugmentationNode; - } - - /** - * Check whether candidate node is for a Choice type node. - */ - private static boolean isChoice(final DataTreeCandidateNode candidateNode) { - // orNull intentional, some candidate nodes have both data after and data before null - return candidateNode.getDataAfter().orNull() instanceof ChoiceNode - || candidateNode.getDataBefore().orNull() instanceof ChoiceNode; - } - - @Override - public String toString() { - return "ModificationDiff{updates=" + updates + '}'; - } - - /** - * Update to a normalized node identifiable by its {@link YangInstanceIdentifier}. - */ - static final class NormalizedNodeUpdate { - - @Nonnull - private final YangInstanceIdentifier id; - @Nullable - private final NormalizedNode<?, ?> dataBefore; - @Nullable - private final NormalizedNode<?, ?> dataAfter; - - private NormalizedNodeUpdate(@Nonnull final YangInstanceIdentifier id, - @Nullable final NormalizedNode<?, ?> dataBefore, - @Nullable final NormalizedNode<?, ?> dataAfter) { - this.id = checkNotNull(id); - this.dataAfter = dataAfter; - this.dataBefore = dataBefore; - } - - @Nullable - public NormalizedNode<?, ?> getDataBefore() { - return dataBefore; - } - - @Nullable - public NormalizedNode<?, ?> getDataAfter() { - return dataAfter; - } - - @Nonnull - public YangInstanceIdentifier getId() { - return id; - } - - static NormalizedNodeUpdate create(@Nonnull final YangInstanceIdentifier id, - @Nonnull final DataTreeCandidateNode candidate) { - return create(id, candidate.getDataBefore().orNull(), candidate.getDataAfter().orNull()); - } - - static NormalizedNodeUpdate create(@Nonnull final YangInstanceIdentifier id, - @Nullable final NormalizedNode<?, ?> dataBefore, - @Nullable final NormalizedNode<?, ?> dataAfter) { - checkArgument(!(dataBefore == null && dataAfter == null), "Both before and after data are null"); - return new NormalizedNodeUpdate(id, dataBefore, dataAfter); - } - - @Override - public boolean equals(final Object other) { - if (this == other) { - return true; - } - if (other == null || getClass() != other.getClass()) { - return false; - } - - final NormalizedNodeUpdate that = (NormalizedNodeUpdate) other; - - return id.equals(that.id); - - } - - @Override - public int hashCode() { - return id.hashCode(); - } - - @Override - public String toString() { - return "NormalizedNodeUpdate{" + "id=" + id - + ", dataBefore=" + dataBefore - + ", dataAfter=" + dataAfter - + '}'; - } - } - -} diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapter.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapter.java deleted file mode 100644 index 9b71dfd62..000000000 --- a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapter.java +++ /dev/null @@ -1,151 +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.data.impl; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.common.base.Optional; -import io.fd.honeycomb.v3po.translate.util.JsonUtils; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardOpenOption; -import javax.annotation.Nonnull; -import org.opendaylight.controller.sal.core.api.model.SchemaService; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -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.DataTreeCandidate; -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.model.api.SchemaContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Adapter for a DataTree that stores current state of data in backing DataTree on each successful commit. - * Uses JSON format. - */ -public class PersistingDataTreeAdapter implements DataTree, AutoCloseable { - - private static final Logger LOG = LoggerFactory.getLogger(PersistingDataTreeAdapter.class); - - private final DataTree delegateDependency; - private final SchemaService schemaServiceDependency; - private final Path path; - - /** - * Create new Persisting DataTree adapter - * - * @param delegate backing data tree that actually handles all the operations - * @param persistPath path to a file (existing or not) to be used as storage for persistence. Full control over - * a file at peristPath is expected - * @param schemaService schemaContext provier - */ - public PersistingDataTreeAdapter(@Nonnull final DataTree delegate, - @Nonnull final SchemaService schemaService, - @Nonnull final Path persistPath) { - this.path = testPersistPath(checkNotNull(persistPath, "persistPath is null")); - this.delegateDependency = checkNotNull(delegate, "delegate is null"); - this.schemaServiceDependency = checkNotNull(schemaService, "schemaService is null"); - } - - /** - * Test whether file at persistPath exists and is readable or create it along with its parent structure - */ - private Path testPersistPath(final Path persistPath) { - try { - checkArgument(!Files.isDirectory(persistPath), "Path %s points to a directory", persistPath); - if(Files.exists(persistPath)) { - checkArgument(Files.isReadable(persistPath), - "Provided path %s points to existing, but non-readable file", persistPath); - return persistPath; - } - Files.createDirectories(persistPath.getParent()); - Files.write(persistPath, new byte[]{}, StandardOpenOption.CREATE); - } catch (IOException | UnsupportedOperationException e) { - LOG.warn("Provided path for persistence: {} is not usable", persistPath, e); - throw new IllegalArgumentException("Path " + persistPath + " cannot be used as "); - } - - return persistPath; - } - - @Override - public DataTreeSnapshot takeSnapshot() { - return delegateDependency.takeSnapshot(); - } - - @Override - public void setSchemaContext(final SchemaContext schemaContext) { - delegateDependency.setSchemaContext(schemaContext); - } - - @Override - public void commit(final DataTreeCandidate dataTreeCandidate) { - LOG.trace("Commit detected"); - delegateDependency.commit(dataTreeCandidate); - LOG.debug("Delegate commit successful. Persisting data"); - - // FIXME doing full read and full write might not be the fastest way of persisting data here - final DataTreeSnapshot dataTreeSnapshot = delegateDependency.takeSnapshot(); - - // TODO this can be handled in background by a dedicated thread + a limited blocking queue - // TODO enable configurable granularity for persists. Maybe doing write on every modification is too much - // and we could do bulk persist - persistCurrentData(dataTreeSnapshot.readNode(YangInstanceIdentifier.EMPTY)); - } - - private void persistCurrentData(final Optional<NormalizedNode<?, ?>> currentRoot) { - if(currentRoot.isPresent()) { - try { - LOG.trace("Persisting current data: {} into: {}", currentRoot.get(), path); - JsonUtils.writeJsonRoot(currentRoot.get(), schemaServiceDependency.getGlobalContext(), - Files.newOutputStream(path, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)); - LOG.trace("Data persisted successfully in {}", path); - } catch (IOException e) { - throw new IllegalStateException("Unable to persist current data", e); - } - } else { - LOG.debug("Skipping persistence, since there's no data to persist"); - } - } - - @Override - public YangInstanceIdentifier getRootPath() { - return delegateDependency.getRootPath(); - } - - @Override - public void validate(final DataTreeModification dataTreeModification) throws DataValidationFailedException { - delegateDependency.validate(dataTreeModification); - } - - @Override - public DataTreeCandidate prepare( - final DataTreeModification dataTreeModification) { - return delegateDependency.prepare(dataTreeModification); - } - - @Override - public void close() throws Exception { - LOG.trace("Closing {} for {}", getClass().getSimpleName(), path); - // NOOP - } -} diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransaction.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransaction.java deleted file mode 100644 index 2850a0d9a..000000000 --- a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransaction.java +++ /dev/null @@ -1,119 +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.data.impl; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkState; -import static java.util.Objects.requireNonNull; - -import com.google.common.base.Function; -import com.google.common.base.Optional; -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.data.ReadableDataManager; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -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.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -final class ReadOnlyTransaction implements DOMDataReadOnlyTransaction { - - private static final Logger LOG = LoggerFactory.getLogger(ReadOnlyTransaction.class); - - @Nullable - private ReadableDataManager operationalData; - @Nullable - private ReadableDataManager configSnapshot; - - private boolean closed = false; - - /** - * @param configData config data tree manager. Null if config reads are not to be supported - * @param operationalData operational data tree manager. Null if operational reads are not to be supported - */ - private ReadOnlyTransaction(@Nullable final ReadableDataManager configData, - @Nullable final ReadableDataManager operationalData) { - this.configSnapshot = configData; - this.operationalData = operationalData; - } - - @Override - public synchronized void close() { - closed = true; - configSnapshot = null; - operationalData = null; - } - - @Override - public synchronized CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read( - final LogicalDatastoreType store, - final YangInstanceIdentifier path) { - LOG.debug("ReadOnlyTransaction.read(), store={}, path={}", store, path); - checkState(!closed, "Transaction has been closed"); - - if (store == LogicalDatastoreType.OPERATIONAL) { - checkArgument(operationalData != null, "{} reads not supported", store); - return operationalData.read(path); - } else { - checkArgument(configSnapshot != null, "{} reads not supported", store); - return configSnapshot.read(path); - } - } - - @Override - public CheckedFuture<Boolean, ReadFailedException> exists(final LogicalDatastoreType store, - final YangInstanceIdentifier path) { - LOG.debug("ReadOnlyTransaction.exists() store={}, path={}", store, path); - - ListenableFuture<Boolean> listenableFuture = Futures.transform(read(store, path), IS_NODE_PRESENT); - return Futures.makeChecked(listenableFuture, ANY_EX_TO_READ_FAILED_EXCEPTION_MAPPER); - } - - @Nonnull - @Override - public Object getIdentifier() { - return this; - } - - @Nonnull - static ReadOnlyTransaction createOperationalOnly(@Nonnull final ReadableDataManager operationalData) { - return new ReadOnlyTransaction(null, requireNonNull(operationalData)); - } - - @Nonnull - static ReadOnlyTransaction createConfigOnly(@Nonnull final ReadableDataManager configData) { - return new ReadOnlyTransaction(requireNonNull(configData), null); - } - - @Nonnull - static ReadOnlyTransaction create(@Nonnull final ReadableDataManager configData, - @Nonnull final ReadableDataManager operationalData) { - return new ReadOnlyTransaction(requireNonNull(configData), requireNonNull(operationalData)); - } - - private static final Function<? super Optional<NormalizedNode<?, ?>>, ? extends Boolean> IS_NODE_PRESENT = - (Function<Optional<NormalizedNode<?, ?>>, Boolean>) input -> input == null ? Boolean.FALSE : input.isPresent(); - - private static final Function<? super Exception, ReadFailedException> ANY_EX_TO_READ_FAILED_EXCEPTION_MAPPER = - (Function<Exception, ReadFailedException>) e -> new ReadFailedException("Exists failed", e); -}
\ No newline at end of file diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadWriteTransaction.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadWriteTransaction.java deleted file mode 100644 index 88b46437e..000000000 --- a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadWriteTransaction.java +++ /dev/null @@ -1,101 +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.data.impl; - -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.ListenableFuture; -import javax.annotation.Nonnull; -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; -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.common.api.data.TransactionCommitFailedException; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; -import org.opendaylight.yangtools.yang.common.RpcResult; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; - -/** - * Composite DOM transaction that delegates reads to a {@link DOMDataReadTransaction} delegate and writes to a {@link - * DOMDataWriteTransaction} delegate. - */ -final class ReadWriteTransaction implements DOMDataReadWriteTransaction { - - private final DOMDataReadOnlyTransaction delegateReadTx; - private final DOMDataWriteTransaction delegateWriteTx; - - ReadWriteTransaction(@Nonnull final DOMDataReadOnlyTransaction delegateReadTx, - @Nonnull final DOMDataWriteTransaction delegateWriteTx) { - this.delegateReadTx = Preconditions.checkNotNull(delegateReadTx, "delegateReadTx should not be null"); - this.delegateWriteTx = Preconditions.checkNotNull(delegateWriteTx, "delegateWriteTx should not be null"); - } - - @Override - public boolean cancel() { - delegateReadTx.close(); - return delegateWriteTx.cancel(); - } - - @Override - public void put(final LogicalDatastoreType store, final YangInstanceIdentifier path, - final NormalizedNode<?, ?> data) { - delegateWriteTx.put(store, path, data); - } - - @Override - public void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path, - final NormalizedNode<?, ?> data) { - delegateWriteTx.merge(store, path, data); - } - - @Override - public void delete(final LogicalDatastoreType store, final YangInstanceIdentifier path) { - delegateWriteTx.delete(store, path); - } - - @Override - public CheckedFuture<Void, TransactionCommitFailedException> submit() { - return delegateWriteTx.submit(); - } - - @Override - public ListenableFuture<RpcResult<TransactionStatus>> commit() { - return delegateWriteTx.commit(); - } - - @Override - public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(final LogicalDatastoreType store, - final YangInstanceIdentifier path) { - return delegateReadTx.read(store, path); - } - - @Override - public CheckedFuture<Boolean, ReadFailedException> exists(final LogicalDatastoreType store, - final YangInstanceIdentifier path) { - return delegateReadTx.exists(store, path); - } - - @Override - public Object getIdentifier() { - return this; - } -} - diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadableDataTreeDelegator.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadableDataTreeDelegator.java deleted file mode 100644 index aff023ebc..000000000 --- a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadableDataTreeDelegator.java +++ /dev/null @@ -1,242 +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.data.impl; - -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.data.ReadableDataManager; -import io.fd.honeycomb.v3po.translate.MappingContext; -import io.fd.honeycomb.v3po.translate.ModificationCache; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.read.registry.ReaderRegistry; -import io.fd.honeycomb.v3po.translate.util.TransactionMappingContext; -import java.util.Collection; -import java.util.Map; -import javax.annotation.Nonnull; -import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; -import org.opendaylight.yangtools.binding.data.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; - -/** - * ReadableDataTree implementation for operational data. - */ -public final class ReadableDataTreeDelegator implements ReadableDataManager { - private static final Logger LOG = LoggerFactory.getLogger(ReadableDataTreeDelegator.class); - - private final BindingNormalizedNodeSerializer serializer; - private final ReaderRegistry readerRegistry; - private final SchemaContext globalContext; - private final org.opendaylight.controller.md.sal.binding.api.DataBroker contextBroker; - - /** - * Creates operational data tree instance. - * @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 data provider. - * @param contextBroker BA broker for context data - */ - public ReadableDataTreeDelegator(@Nonnull BindingNormalizedNodeSerializer serializer, - @Nonnull final SchemaContext globalContext, - @Nonnull final ReaderRegistry readerRegistry, - @Nonnull final org.opendaylight.controller.md.sal.binding.api.DataBroker contextBroker) { - this.contextBroker = checkNotNull(contextBroker, "contextBroker should not be null"); - this.globalContext = checkNotNull(globalContext, "globalContext 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<?, ?>>, - org.opendaylight.controller.md.sal.common.api.data.ReadFailedException> read( - @Nonnull final YangInstanceIdentifier yangInstanceIdentifier) { - - try(TransactionMappingContext mappingContext = new TransactionMappingContext(contextBroker.newReadWriteTransaction()); - ReadContext ctx = new ReadContextImpl(mappingContext)) { - - final Optional<NormalizedNode<?, ?>> value; - if (checkNotNull(yangInstanceIdentifier).equals(YangInstanceIdentifier.EMPTY)) { - value = readRoot(ctx); - } else { - value = readNode(yangInstanceIdentifier, ctx); - } - - // Submit context mapping updates - final CheckedFuture<Void, TransactionCommitFailedException> contextUpdateResult = - ((TransactionMappingContext) ctx.getMappingContext()).submit(); - // Blocking on context data update - contextUpdateResult.checkedGet(); - - return Futures.immediateCheckedFuture(value); - - } catch (ReadFailedException e) { - return Futures.immediateFailedCheckedFuture( - new org.opendaylight.controller.md.sal.common.api.data.ReadFailedException( - "Failed to read VPP data", e)); - } catch (TransactionCommitFailedException e) { - // FIXME revert should probably occur when context is not written successfully - final String msg = "Error while updating mapping context data"; - LOG.error(msg, e); - return Futures.immediateFailedCheckedFuture( - new org.opendaylight.controller.md.sal.common.api.data.ReadFailedException(msg, e) - ); - } - } - - private Optional<NormalizedNode<?, ?>> readNode(final YangInstanceIdentifier yangInstanceIdentifier, - final ReadContext ctx) throws ReadFailedException { - LOG.debug("OperationalDataTree.readNode(), yangInstanceIdentifier={}", yangInstanceIdentifier); - final InstanceIdentifier<?> path = serializer.fromYangInstanceIdentifier(yangInstanceIdentifier); - checkNotNull(path, "Invalid instance identifier %s. Cannot create BA equivalent.", yangInstanceIdentifier); - LOG.debug("OperationalDataTree.readNode(), path={}", path); - - final Optional<? extends DataObject> dataObject; - - dataObject = readerRegistry.read(path, ctx); - if (dataObject.isPresent()) { - final NormalizedNode<?, ?> value = toNormalizedNodeFunction(path).apply(dataObject.get()); - return Optional.<NormalizedNode<?, ?>>fromNullable(value); - } else { - return Optional.absent(); - } - } - - private Optional<NormalizedNode<?, ?>> readRoot(final ReadContext ctx) throws ReadFailedException { - LOG.debug("OperationalDataTree.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(ctx); - - 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 Optional.<NormalizedNode<?, ?>>of(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 = - globalContext.getDataChildByName(yangInstanceIdentifier.getLastPathArgument().getNodeType()); - 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(); - } - } - - @SuppressWarnings("unchecked") - private Function<DataObject, NormalizedNode<?, ?>> toNormalizedNodeFunction(final InstanceIdentifier path) { - return dataObject -> { - LOG.trace("OperationalDataTree.toNormalizedNode(), path={}, dataObject={}", path, dataObject); - final Map.Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> entry = - serializer.toNormalizedNode(path, dataObject); - - LOG.trace("OperationalDataTree.toNormalizedNode(), normalizedNodeEntry={}", entry); - return entry.getValue(); - }; - } - - private static final class ReadContextImpl implements ReadContext { - - private final ModificationCache ctx = new ModificationCache(); - private final MappingContext mappingContext; - - private ReadContextImpl(final MappingContext mappingContext) { - this.mappingContext = mappingContext; - } - - @Nonnull - @Override - public ModificationCache getModificationCache() { - return ctx; - } - - @Nonnull - @Override - public MappingContext getMappingContext() { - return mappingContext; - } - - @Override - public void close() { - // Make sure to clear the storage in case some customizer stored a reference to it to prevent memory leaks - ctx.close(); - } - } -} diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/WriteTransaction.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/WriteTransaction.java deleted file mode 100644 index c8f9bd3db..000000000 --- a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/WriteTransaction.java +++ /dev/null @@ -1,177 +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.data.impl; - -import static com.google.common.base.Preconditions.checkArgument; -import static java.util.Objects.requireNonNull; -import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.CANCELED; -import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.COMMITED; -import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.FAILED; -import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.NEW; -import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.SUBMITED; - -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.data.DataModification; -import io.fd.honeycomb.v3po.translate.TranslationException; -import java.util.function.Consumer; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import javax.annotation.concurrent.NotThreadSafe; -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; -import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; -import org.opendaylight.yangtools.yang.common.RpcResult; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@NotThreadSafe -final class WriteTransaction implements DOMDataWriteTransaction { - - private static final Logger LOG = LoggerFactory.getLogger(WriteTransaction.class); - - @Nullable - private DataModification operationalModification; - @Nullable - private DataModification configModification; - private TransactionStatus status = NEW; - - private WriteTransaction(@Nullable final DataModification configModification, - @Nullable final DataModification operationalModification) { - this.operationalModification = operationalModification; - this.configModification = configModification; - } - - private void checkIsNew() { - Preconditions.checkState(status == NEW, "Transaction was submitted or canceled"); - } - - @Override - public void put(final LogicalDatastoreType store, final YangInstanceIdentifier path, - final NormalizedNode<?, ?> data) { - LOG.debug("WriteTransaction.put() store={}, path={}, data={}", store, path, data); - checkIsNew(); - handleOperation(store, (modification) -> modification.write(path, data)); - } - - private void handleOperation(final LogicalDatastoreType store, - final Consumer<DataModification> r) { - switch (store) { - case CONFIGURATION: - checkArgument(configModification != null, "Modification of %s is not supported", store); - r.accept(configModification); - break; - case OPERATIONAL: - checkArgument(operationalModification != null, "Modification of %s is not supported", store); - r.accept(operationalModification); - break; - } - } - - @Override - public void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path, - final NormalizedNode<?, ?> data) { - LOG.debug("WriteTransaction.merge() store={}, path={}, data={}", store, path, data); - checkIsNew(); - handleOperation(store, (modification) -> modification.merge(path, data)); - } - - @Override - public boolean cancel() { - if (status != NEW) { - // only NEW transactions can be cancelled - return false; - } else { - status = CANCELED; - return true; - } - } - - @Override - public void delete(LogicalDatastoreType store, final YangInstanceIdentifier path) { - LOG.debug("WriteTransaction.delete() store={}, path={}", store, path); - checkIsNew(); - handleOperation(store, (modification) -> modification.delete(path)); - } - - @Override - public CheckedFuture<Void, TransactionCommitFailedException> submit() { - LOG.trace("WriteTransaction.submit()"); - checkIsNew(); - - try { - status = SUBMITED; - - // Validate first to catch any issues before attempting commit - if (configModification != null) { - configModification.validate(); - } - if (operationalModification != null) { - operationalModification.validate(); - } - - if(configModification != null) { - configModification.commit(); - } - if(operationalModification != null) { - operationalModification.commit(); - } - - status = COMMITED; - } catch (DataValidationFailedException | TranslationException e) { - status = FAILED; - LOG.error("Failed modify data tree", e); - return Futures.immediateFailedCheckedFuture( - new TransactionCommitFailedException("Failed to validate DataTreeModification", e)); - } - return Futures.immediateCheckedFuture(null); - } - - @Override - @Deprecated - public ListenableFuture<RpcResult<TransactionStatus>> commit() { - throw new UnsupportedOperationException("deprecated"); - } - - @Override - public Object getIdentifier() { - return this; - } - - - @Nonnull - static WriteTransaction createOperationalOnly(@Nonnull final DataModification operationalData) { - return new WriteTransaction(null, requireNonNull(operationalData)); - } - - @Nonnull - static WriteTransaction createConfigOnly(@Nonnull final DataModification configData) { - return new WriteTransaction(requireNonNull(configData), null); - } - - @Nonnull - static WriteTransaction create(@Nonnull final DataModification configData, - @Nonnull final DataModification operationalData) { - return new WriteTransaction(requireNonNull(configData), requireNonNull(operationalData)); - } -} |