summaryrefslogtreecommitdiffstats
path: root/v3po/translate-impl/src
diff options
context:
space:
mode:
authorMaros Marsalek <mmarsale@cisco.com>2016-06-29 09:14:51 +0200
committerMaros Marsalek <mmarsale@cisco.com>2016-07-13 11:24:26 +0200
commitfb41618f6e78d5f1a20bbf37c45282c5fc15387d (patch)
tree6ac9da72b8a53c01f1ef2f97562a70b838c510f5 /v3po/translate-impl/src
parentd222ccedd09b5ee76cdcb367ae96c91f49e5f287 (diff)
HONEYCOMB-94 Reimplement writer registry with better ordering options
Now the registry is flat and allows for full control of writer execution order Change-Id: I864e1d676588ffe59b596145e0829e81b1a1ed2f Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
Diffstat (limited to 'v3po/translate-impl/src')
-rw-r--r--v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/AbstractCompositeWriter.java234
-rw-r--r--v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/CompositeChildWriter.java125
-rw-r--r--v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/CompositeListWriter.java203
-rw-r--r--v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/GenericListWriter.java104
-rw-r--r--v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/GenericWriter.java (renamed from v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/CompositeRootWriter.java)38
-rw-r--r--v3po/translate-impl/src/test/java/io/fd/honeycomb/v3po/translate/impl/write/GenericListWriterTest.java83
-rw-r--r--v3po/translate-impl/src/test/java/io/fd/honeycomb/v3po/translate/impl/write/GenericWriterTest.java64
7 files changed, 274 insertions, 577 deletions
diff --git a/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/AbstractCompositeWriter.java b/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/AbstractCompositeWriter.java
index 0212c086b..5f1391c74 100644
--- a/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/AbstractCompositeWriter.java
+++ b/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/AbstractCompositeWriter.java
@@ -18,82 +18,33 @@ package io.fd.honeycomb.v3po.translate.impl.write;
import static com.google.common.base.Preconditions.checkArgument;
-import com.google.common.base.Optional;
-import com.google.common.collect.Lists;
-import io.fd.honeycomb.v3po.translate.impl.TraversalType;
-import io.fd.honeycomb.v3po.translate.util.RWUtils;
-import io.fd.honeycomb.v3po.translate.write.ChildWriter;
import io.fd.honeycomb.v3po.translate.write.WriteContext;
import io.fd.honeycomb.v3po.translate.write.WriteFailedException;
import io.fd.honeycomb.v3po.translate.write.Writer;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
-import org.opendaylight.yangtools.yang.binding.Augmentation;
-import org.opendaylight.yangtools.yang.binding.ChildOf;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-public abstract class AbstractCompositeWriter<D extends DataObject> implements Writer<D> {
+abstract class AbstractCompositeWriter<D extends DataObject> implements Writer<D> {
private static final Logger LOG = LoggerFactory.getLogger(AbstractCompositeWriter.class);
- private final Map<Class<? extends DataObject>, ChildWriter<? extends ChildOf<D>>> childWriters;
- private final Map<Class<? extends DataObject>, ChildWriter<? extends Augmentation<D>>> augWriters;
private final InstanceIdentifier<D> instanceIdentifier;
- private TraversalType traversalType;
- public AbstractCompositeWriter(final Class<D> type,
- final List<ChildWriter<? extends ChildOf<D>>> childWriters,
- final List<ChildWriter<? extends Augmentation<D>>> augWriters,
- final TraversalType traversalType) {
- this.traversalType = traversalType;
- this.instanceIdentifier = InstanceIdentifier.create(type);
- this.childWriters = RWUtils.uniqueLinkedIndex(childWriters, RWUtils.MANAGER_CLASS_FUNCTION);
- this.augWriters = RWUtils.uniqueLinkedIndex(augWriters, RWUtils.MANAGER_CLASS_AUG_FUNCTION);
+ AbstractCompositeWriter(final InstanceIdentifier<D> type) {
+ this.instanceIdentifier = type;
}
protected void writeCurrent(final InstanceIdentifier<D> id, final D data, final WriteContext ctx)
throws WriteFailedException {
LOG.debug("{}: Writing current: {} data: {}", this, id, data);
-
- switch (traversalType) {
- case PREORDER: {
- LOG.trace("{}: Writing current attributes", this);
- writeCurrentAttributes(id, data, ctx);
- writeChildren(id, data, ctx);
- break;
- }
- case POSTORDER: {
- writeChildren(id, data, ctx);
- LOG.trace("{}: Writing current attributes", this);
- writeCurrentAttributes(id, data, ctx);
- break;
- }
- }
-
+ writeCurrentAttributes(id, data, ctx);
LOG.debug("{}: Current node written successfully", this);
}
- private void writeChildren(final InstanceIdentifier<D> id, final D data, final WriteContext ctx)
- throws WriteFailedException {
- for (ChildWriter<? extends ChildOf<D>> child : childWriters.values()) {
- LOG.debug("{}: Writing child in: {}", this, child);
- child.writeChild(id, data, ctx);
- }
-
- for (ChildWriter<? extends Augmentation<D>> child : augWriters.values()) {
- LOG.debug("{}: Writing augment in: {}", this, child);
- child.writeChild(id, data, ctx);
- }
- }
-
protected void updateCurrent(final InstanceIdentifier<D> id, final D dataBefore, final D dataAfter,
final WriteContext ctx) throws WriteFailedException {
LOG.debug("{}: Updating current: {} dataBefore: {}, datAfter: {}", this, id, dataBefore, dataAfter);
@@ -103,69 +54,14 @@ public abstract class AbstractCompositeWriter<D extends DataObject> implements W
// No change, ignore
return;
}
-
- switch (traversalType) {
- case PREORDER: {
- LOG.trace("{}: Updating current attributes", this);
- updateCurrentAttributes(id, dataBefore, dataAfter, ctx);
- updateChildren(id, dataBefore, dataAfter, ctx);
- break;
- }
- case POSTORDER: {
- updateChildren(id, dataBefore, dataAfter, ctx);
- LOG.trace("{}: Updating current attributes", this);
- updateCurrentAttributes(id, dataBefore, dataAfter, ctx);
- break;
- }
- }
-
+ updateCurrentAttributes(id, dataBefore, dataAfter, ctx);
LOG.debug("{}: Current node updated successfully", this);
}
- private void updateChildren(final InstanceIdentifier<D> id, final D dataBefore, final D dataAfter,
- final WriteContext ctx) throws WriteFailedException {
- for (ChildWriter<? extends ChildOf<D>> child : childWriters.values()) {
- LOG.debug("{}: Updating child in: {}", this, child);
- child.updateChild(id, dataBefore, dataAfter, ctx);
- }
-
- for (ChildWriter<? extends Augmentation<D>> child : augWriters.values()) {
- LOG.debug("{}: Updating augment in: {}", this, child);
- child.updateChild(id, dataBefore, dataAfter, ctx);
- }
- }
-
protected void deleteCurrent(final InstanceIdentifier<D> id, final D dataBefore, final WriteContext ctx)
throws WriteFailedException {
LOG.debug("{}: Deleting current: {} dataBefore: {}", this, id, dataBefore);
-
- switch (traversalType) {
- case PREORDER: {
- deleteChildren(id, dataBefore, ctx);
- LOG.trace("{}: Deleting current attributes", this);
- deleteCurrentAttributes(id, dataBefore, ctx);
- break;
- }
- case POSTORDER: {
- LOG.trace("{}: Deleting current attributes", this);
- deleteCurrentAttributes(id, dataBefore, ctx);
- deleteChildren(id, dataBefore, ctx);
- break;
- }
- }
- }
-
- private void deleteChildren(final InstanceIdentifier<D> id, final D dataBefore, final WriteContext ctx)
- throws WriteFailedException {
- for (ChildWriter<? extends Augmentation<D>> child : reverseCollection(augWriters.values())) {
- LOG.debug("{}: Deleting augment in: {}", this, child);
- child.deleteChild(id, dataBefore, ctx);
- }
-
- for (ChildWriter<? extends ChildOf<D>> child : reverseCollection(childWriters.values())) {
- LOG.debug("{}: Deleting child in: {}", this, child);
- child.deleteChild(id, dataBefore, ctx);
- }
+ deleteCurrentAttributes(id, dataBefore, ctx);
}
@SuppressWarnings("unchecked")
@@ -177,28 +73,20 @@ public abstract class AbstractCompositeWriter<D extends DataObject> implements W
LOG.debug("{}: Updating : {}", this, id);
LOG.trace("{}: Updating : {}, from: {} to: {}", this, id, dataBefore, dataAfter);
- if (idPointsToCurrent(id)) {
- if(isWrite(dataBefore, dataAfter)) {
- writeCurrent((InstanceIdentifier<D>) id, castToManaged(dataAfter), ctx);
- } else if(isDelete(dataBefore, dataAfter)) {
- deleteCurrent((InstanceIdentifier<D>) id, castToManaged(dataBefore), ctx);
- } else {
- checkArgument(dataBefore != null && dataAfter != null, "No data to process");
- updateCurrent((InstanceIdentifier<D>) id, castToManaged(dataBefore), castToManaged(dataAfter), ctx);
- }
+ checkArgument(idPointsToCurrent(id), "Cannot handle data: %s. Only: %s can be handled by writer: %s",
+ id, getManagedDataObjectType(), this);
+
+ if (isWrite(dataBefore, dataAfter)) {
+ writeCurrent((InstanceIdentifier<D>) id, castToManaged(dataAfter), ctx);
+ } else if (isDelete(dataBefore, dataAfter)) {
+ deleteCurrent((InstanceIdentifier<D>) id, castToManaged(dataBefore), ctx);
} else {
- if (isWrite(dataBefore, dataAfter)) {
- writeSubtree(id, dataAfter, ctx);
- } else if (isDelete(dataBefore, dataAfter)) {
- deleteSubtree(id, dataBefore, ctx);
- } else {
- checkArgument(dataBefore != null && dataAfter != null, "No data to process");
- updateSubtree(id, dataBefore, dataAfter, ctx);
- }
+ checkArgument(dataBefore != null && dataAfter != null, "No data to process");
+ updateCurrent((InstanceIdentifier<D>) id, castToManaged(dataBefore), castToManaged(dataAfter), ctx);
}
}
- private void checkDataType(final @Nullable DataObject dataAfter) {
+ private void checkDataType(@Nonnull final DataObject dataAfter) {
checkArgument(getManagedDataObjectType().getTargetType().isAssignableFrom(dataAfter.getClass()));
}
@@ -217,100 +105,10 @@ public abstract class AbstractCompositeWriter<D extends DataObject> implements W
return dataAfter == null && dataBefore != null;
}
- private void writeSubtree(final InstanceIdentifier<? extends DataObject> id,
- final DataObject dataAfter, final WriteContext ctx) throws WriteFailedException {
- LOG.debug("{}: Writing subtree: {}", this, id);
-
- final Writer<? extends ChildOf<D>> writer = getNextChildWriter(id);
- final Writer<? extends Augmentation<D>> augWriter = getNextAgumentationWriter(id);
-
- if (writer != null) {
- LOG.debug("{}: Writing subtree: {} in: {}", this, id, writer);
- writer.update(id, null, dataAfter, ctx);
- } else if (augWriter != null) {
- LOG.debug("{}: Updating augmented subtree: {} in: {}", this, id, augWriter);
- augWriter.update(id, null, dataAfter, ctx);
- } else {
- // If there's no dedicated writer, use write current
- // But we need current data after to do so
- final InstanceIdentifier<D> currentId = RWUtils.cutId(id, getManagedDataObjectType());
- Optional<D> currentDataAfter = ctx.readAfter(currentId);
- LOG.debug("{}: Dedicated subtree writer missing for: {}. Writing current.", this,
- RWUtils.getNextId(id, getManagedDataObjectType()).getType(), currentDataAfter);
- writeCurrent(currentId, castToManaged(currentDataAfter.get()), ctx);
- }
- }
-
private boolean idPointsToCurrent(final @Nonnull InstanceIdentifier<? extends DataObject> id) {
return id.getTargetType().equals(getManagedDataObjectType().getTargetType());
}
- private void deleteSubtree(final InstanceIdentifier<? extends DataObject> id,
- final DataObject dataBefore, final WriteContext ctx) throws WriteFailedException {
- LOG.debug("{}: Deleting subtree: {}", this, id);
-
- final Writer<? extends ChildOf<D>> writer = getNextChildWriter(id);
- final Writer<? extends Augmentation<D>> augWriter = getNextAgumentationWriter(id);
-
- if (writer != null) {
- LOG.debug("{}: Deleting subtree: {} in: {}", this, id, writer);
- writer.update(id, dataBefore, null, ctx);
- } else if (augWriter != null) {
- LOG.debug("{}: Updating augmented subtree: {} in: {}", this, id, augWriter);
- augWriter.update(id, dataBefore, null, ctx);
- } else {
- updateSubtreeFromCurrent(id, ctx);
- }
- }
-
- @SuppressWarnings("unchecked")
- private void updateSubtreeFromCurrent(final InstanceIdentifier<? extends DataObject> id, final WriteContext ctx)
- throws WriteFailedException {
- final InstanceIdentifier<D> currentId = RWUtils.cutId(id, getManagedDataObjectType());
- Optional<D> currentDataBefore = ctx.readBefore(currentId);
- Optional<D> currentDataAfter = ctx.readAfter(currentId);
- LOG.debug("{}: Dedicated subtree writer missing for: {}. Updating current without subtree", this,
- RWUtils.getNextId(id, getManagedDataObjectType()).getType(), currentDataAfter);
- updateCurrent((InstanceIdentifier<D>) id, castToManaged(currentDataBefore.orNull()),
- castToManaged(currentDataAfter.orNull()), ctx);
- }
-
- private void updateSubtree(final InstanceIdentifier<? extends DataObject> id,
- final DataObject dataBefore,
- final DataObject dataAfter,
- final WriteContext ctx) throws WriteFailedException {
- LOG.debug("{}: Updating subtree: {}", this, id);
- final Writer<? extends ChildOf<D>> writer = getNextChildWriter(id);
- final Writer<? extends Augmentation<D>> augWriter = getNextAgumentationWriter(id);
-
- if (writer != null) {
- LOG.debug("{}: Updating subtree: {} in: {}", this, id, writer);
- writer.update(id, dataBefore, dataAfter, ctx);
- } else if (augWriter != null) {
- LOG.debug("{}: Updating augmented subtree: {} in: {}", this, id, augWriter);
- augWriter.update(id, dataBefore, dataAfter, ctx);
- } else {
- updateSubtreeFromCurrent(id, ctx);
- }
- }
-
- private Writer<? extends ChildOf<D>> getNextChildWriter(final InstanceIdentifier<? extends DataObject> id) {
- final Class<? extends DataObject> next = RWUtils.getNextId(id, getManagedDataObjectType()).getType();
- return childWriters.get(next);
- }
-
- private Writer<? extends Augmentation<D>> getNextAgumentationWriter(final InstanceIdentifier<? extends DataObject> id) {
- final Class<? extends DataObject> next = RWUtils.getNextId(id, getManagedDataObjectType()).getType();
- return augWriters.get(next);
- }
-
- private static <T> List<T> reverseCollection(final Collection<T> original) {
- // TODO find a better reverse mechanism (probably a different collection for child writers is necessary)
- final ArrayList<T> list = Lists.newArrayList(original);
- Collections.reverse(list);
- return list;
- }
-
protected abstract void writeCurrentAttributes(@Nonnull final InstanceIdentifier<D> id,
@Nonnull final D data,
@Nonnull final WriteContext ctx) throws WriteFailedException;
diff --git a/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/CompositeChildWriter.java b/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/CompositeChildWriter.java
deleted file mode 100644
index 6e0841deb..000000000
--- a/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/CompositeChildWriter.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (c) 2016 Cisco and/or its affiliates.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package io.fd.honeycomb.v3po.translate.impl.write;
-
-import com.google.common.base.Optional;
-import io.fd.honeycomb.v3po.translate.impl.TraversalType;
-import io.fd.honeycomb.v3po.translate.write.ChildWriter;
-import io.fd.honeycomb.v3po.translate.write.WriteContext;
-import io.fd.honeycomb.v3po.translate.util.RWUtils;
-import io.fd.honeycomb.v3po.translate.spi.write.ChildWriterCustomizer;
-import io.fd.honeycomb.v3po.translate.write.WriteFailedException;
-import java.util.List;
-import javax.annotation.Nonnull;
-import org.opendaylight.yangtools.yang.binding.Augmentation;
-import org.opendaylight.yangtools.yang.binding.ChildOf;
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-
-public class CompositeChildWriter<D extends DataObject> extends AbstractCompositeWriter<D>
- implements ChildWriter<D> {
-
- private final ChildWriterCustomizer<D> customizer;
-
- public CompositeChildWriter(@Nonnull final Class<D> type,
- @Nonnull final List<ChildWriter<? extends ChildOf<D>>> childWriters,
- @Nonnull final List<ChildWriter<? extends Augmentation<D>>> augWriters,
- @Nonnull final ChildWriterCustomizer<D> customizer) {
- this(type, childWriters, augWriters, customizer, TraversalType.PREORDER);
- }
-
-
- public CompositeChildWriter(@Nonnull final Class<D> type,
- @Nonnull final List<ChildWriter<? extends ChildOf<D>>> childWriters,
- @Nonnull final List<ChildWriter<? extends Augmentation<D>>> augWriters,
- @Nonnull final ChildWriterCustomizer<D> customizer,
- @Nonnull final TraversalType traversalType) {
- super(type, childWriters, augWriters, traversalType);
- this.customizer = customizer;
- }
-
- public CompositeChildWriter(@Nonnull final Class<D> type,
- @Nonnull final List<ChildWriter<? extends ChildOf<D>>> childWriters,
- @Nonnull final ChildWriterCustomizer<D> customizer) {
- this(type, childWriters, RWUtils.<D>emptyAugWriterList(), customizer);
- }
-
- public CompositeChildWriter(@Nonnull final Class<D> type,
- @Nonnull final ChildWriterCustomizer<D> customizer) {
- this(type, RWUtils.<D>emptyChildWriterList(), RWUtils.<D>emptyAugWriterList(), customizer);
- }
-
- @Override
- protected void writeCurrentAttributes(@Nonnull final InstanceIdentifier<D> id, @Nonnull final D data,
- @Nonnull final WriteContext ctx) throws WriteFailedException {
- customizer.writeCurrentAttributes(id, data, ctx);
- }
-
- @Override
- protected void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<D> id, @Nonnull final D dataBefore,
- @Nonnull WriteContext ctx) throws WriteFailedException {
- customizer.deleteCurrentAttributes(id, dataBefore, ctx);
- }
-
- @Override
- protected void updateCurrentAttributes(@Nonnull final InstanceIdentifier<D> id, @Nonnull final D dataBefore,
- @Nonnull final D dataAfter, @Nonnull WriteContext ctx)
- throws WriteFailedException {
- customizer.updateCurrentAttributes(id, dataBefore, dataAfter, ctx);
- }
-
- @Override
- public void writeChild(@Nonnull final InstanceIdentifier<? extends DataObject> parentId,
- @Nonnull final DataObject parentData, @Nonnull WriteContext ctx)
- throws WriteFailedException {
- final InstanceIdentifier<D> currentId = RWUtils.appendTypeToId(parentId, getManagedDataObjectType());
- final Optional<D> currentData = customizer.extract(currentId, parentData);
- if(currentData.isPresent()) {
- writeCurrent(currentId, currentData.get(), ctx);
- }
- }
-
- @Override
- public void deleteChild(@Nonnull final InstanceIdentifier<? extends DataObject> parentId,
- @Nonnull final DataObject parentDataBefore,
- @Nonnull final WriteContext ctx) throws WriteFailedException {
- final InstanceIdentifier<D> currentId = RWUtils.appendTypeToId(parentId, getManagedDataObjectType());
- final Optional<D> dataBefore = customizer.extract(currentId, parentDataBefore);
- if(dataBefore.isPresent()) {
- deleteCurrent(currentId, dataBefore.get(), ctx);
- }
- }
-
- @Override
- public void updateChild(@Nonnull final InstanceIdentifier<? extends DataObject> parentId,
- @Nonnull final DataObject parentDataBefore, @Nonnull final DataObject parentDataAfter,
- @Nonnull final WriteContext ctx) throws WriteFailedException {
- final InstanceIdentifier<D> currentId = RWUtils.appendTypeToId(parentId, getManagedDataObjectType());
- final Optional<D> before = customizer.extract(currentId, parentDataBefore);
- final Optional<D> after = customizer.extract(currentId, parentDataAfter);
-
- if(before.isPresent()) {
- if(after.isPresent()) {
- updateCurrent(currentId, before.get(), after.get(), ctx);
- } else {
- deleteCurrent(currentId, before.get(), ctx);
- }
- } else if (after.isPresent()){
- writeCurrent(currentId, after.get(), ctx);
- }
- }
-}
diff --git a/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/CompositeListWriter.java b/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/CompositeListWriter.java
deleted file mode 100644
index fe9e8d5e3..000000000
--- a/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/CompositeListWriter.java
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright (c) 2016 Cisco and/or its affiliates.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package io.fd.honeycomb.v3po.translate.impl.write;
-
-import com.google.common.base.Function;
-import com.google.common.base.Optional;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-import io.fd.honeycomb.v3po.translate.impl.TraversalType;
-import io.fd.honeycomb.v3po.translate.spi.write.ListWriterCustomizer;
-import io.fd.honeycomb.v3po.translate.util.RWUtils;
-import io.fd.honeycomb.v3po.translate.write.ChildWriter;
-import io.fd.honeycomb.v3po.translate.write.WriteContext;
-import io.fd.honeycomb.v3po.translate.write.WriteFailedException;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import javax.annotation.Nonnull;
-import org.opendaylight.yangtools.yang.binding.Augmentation;
-import org.opendaylight.yangtools.yang.binding.ChildOf;
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.Identifiable;
-import org.opendaylight.yangtools.yang.binding.Identifier;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-
-public class CompositeListWriter<D extends DataObject & Identifiable<K>, K extends Identifier<D>> extends
- AbstractCompositeWriter<D>
- implements ChildWriter<D> {
-
- private static final Function<DataObject, Object> INDEX_FUNCTION = input -> input instanceof Identifiable<?>
- ? ((Identifiable<?>) input).getKey()
- : input;
-
-
- private final ListWriterCustomizer<D, K> customizer;
-
- public CompositeListWriter(@Nonnull final Class<D> type,
- @Nonnull final List<ChildWriter<? extends ChildOf<D>>> childWriters,
- @Nonnull final List<ChildWriter<? extends Augmentation<D>>> augWriters,
- @Nonnull final ListWriterCustomizer<D, K> customizer) {
- this(type, childWriters, augWriters, customizer, TraversalType.PREORDER);
- }
-
- public CompositeListWriter(@Nonnull final Class<D> type,
- @Nonnull final List<ChildWriter<? extends ChildOf<D>>> childWriters,
- @Nonnull final List<ChildWriter<? extends Augmentation<D>>> augWriters,
- @Nonnull final ListWriterCustomizer<D, K> customizer,
- @Nonnull final TraversalType traversalType) {
- super(type, childWriters, augWriters, traversalType);
- this.customizer = customizer;
- }
-
- public CompositeListWriter(@Nonnull final Class<D> type,
- @Nonnull final List<ChildWriter<? extends ChildOf<D>>> childWriters,
- @Nonnull final ListWriterCustomizer<D, K> customizer) {
- this(type, childWriters, RWUtils.<D>emptyAugWriterList(), customizer);
- }
-
- public CompositeListWriter(@Nonnull final Class<D> type,
- @Nonnull final ListWriterCustomizer<D, K> customizer) {
- this(type, RWUtils.<D>emptyChildWriterList(), RWUtils.<D>emptyAugWriterList(), customizer);
-
- }
-
- @Override
- protected void writeCurrentAttributes(@Nonnull final InstanceIdentifier<D> id, @Nonnull final D data,
- @Nonnull final WriteContext ctx) throws WriteFailedException {
- customizer.writeCurrentAttributes(id, data, ctx);
- }
-
- @Override
- protected void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<D> id, @Nonnull final D dataBefore,
- @Nonnull final WriteContext ctx) throws WriteFailedException {
- customizer.deleteCurrentAttributes(id, dataBefore, ctx);
- }
-
- @Override
- protected void updateCurrentAttributes(@Nonnull final InstanceIdentifier<D> id, @Nonnull final D dataBefore,
- @Nonnull final D dataAfter, @Nonnull final WriteContext ctx)
- throws WriteFailedException {
- customizer.updateCurrentAttributes(id, dataBefore, dataAfter, ctx);
- }
-
- @Override
- public void writeChild(@Nonnull final InstanceIdentifier<? extends DataObject> parentId,
- @Nonnull final DataObject parentData,
- @Nonnull final WriteContext ctx) throws WriteFailedException {
- final InstanceIdentifier<D> currentId = RWUtils.appendTypeToId(parentId, getManagedDataObjectType());
- final Optional<List<D>> currentData = customizer.extract(currentId, parentData);
- if (currentData.isPresent()) {
- for (D entry : currentData.get()) {
- writeCurrent(currentId, entry, ctx);
- }
- }
- }
-
- @Override
- public void deleteChild(@Nonnull final InstanceIdentifier<? extends DataObject> parentId,
- @Nonnull final DataObject parentDataBefore,
- @Nonnull final WriteContext ctx) throws WriteFailedException {
- final InstanceIdentifier<D> currentId = RWUtils.appendTypeToId(parentId, getManagedDataObjectType());
- final Optional<List<D>> dataBefore = customizer.extract(currentId, parentDataBefore);
- if (dataBefore.isPresent()) {
- for (D entry : dataBefore.get()) {
- deleteCurrent(currentId, entry, ctx);
- }
- }
- }
-
- private Map<Object, D> listOfIdentifiableToMap(Optional<List<D>> list) {
- if (list.isPresent()) {
- return Maps.uniqueIndex(list.get(), INDEX_FUNCTION);
- } else {
- return Collections.emptyMap();
- }
-
- }
-
- @Override
- public void updateChild(@Nonnull final InstanceIdentifier<? extends DataObject> parentId,
- @Nonnull final DataObject parentDataBefore, @Nonnull final DataObject parentDataAfter,
- @Nonnull final WriteContext ctx) throws WriteFailedException {
- final InstanceIdentifier<D> currentId = RWUtils.appendTypeToId(parentId, getManagedDataObjectType());
- final Map<Object, D> dataBefore = listOfIdentifiableToMap(customizer.extract(currentId, parentDataBefore));
- final Map<Object, D> dataAfter = listOfIdentifiableToMap(customizer.extract(currentId, parentDataAfter));
-
- // The order of delete/write/update operations can have side-effects for devices like VPP
- // TODO make it configurable
-
- // First perform delete:
- for (Object deletedNodeKey : Sets.difference(dataBefore.keySet(), dataAfter.keySet())) {
- final D deleted = dataBefore.get(deletedNodeKey);
- deleteCurrent(currentId, deleted, ctx);
- }
-
- // Then write/update:
- for (Map.Entry<Object, D> after : dataAfter.entrySet()) {
- final D before = dataBefore.get(after.getKey());
- if(before == null) {
- writeCurrent(currentId, after.getValue(), ctx);
- } else {
- updateCurrent(currentId, before, after.getValue(), ctx);
- }
- }
-
- }
-
- @Override
- protected void writeCurrent(final InstanceIdentifier<D> id, final D data, final WriteContext ctx)
- throws WriteFailedException {
- // Make sure the key is present
- if(isWildcarded(id)) {
- super.writeCurrent(getSpecificId(id, data), data, ctx);
- } else {
- super.writeCurrent(id, data, ctx);
- }
- }
-
- @Override
- protected void updateCurrent(final InstanceIdentifier<D> id, final D dataBefore, final D dataAfter,
- final WriteContext ctx) throws WriteFailedException {
- // Make sure the key is present
- if(isWildcarded(id)) {
- super.updateCurrent(getSpecificId(id, dataBefore), dataBefore, dataAfter, ctx);
- } else {
- super.updateCurrent(id, dataBefore, dataAfter, ctx);
- }
- }
-
- @Override
- protected void deleteCurrent(final InstanceIdentifier<D> id, final D dataBefore, final WriteContext ctx)
- throws WriteFailedException {
- // Make sure the key is present
- if(isWildcarded(id)) {
- super.deleteCurrent(getSpecificId(id, dataBefore), dataBefore, ctx);
- } else {
- super.deleteCurrent(id, dataBefore, ctx);
- }
- }
-
- private boolean isWildcarded(final InstanceIdentifier<D> id) {
- return id.firstIdentifierOf(getManagedDataObjectType().getTargetType()).isWildcarded();
- }
-
- private InstanceIdentifier<D> getSpecificId(final InstanceIdentifier<D> currentId, final D current) {
- return RWUtils.replaceLastInId(currentId,
- new InstanceIdentifier.IdentifiableItem<>(currentId.getTargetType(), current.getKey()));
- }
-}
diff --git a/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/GenericListWriter.java b/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/GenericListWriter.java
new file mode 100644
index 000000000..b61fb51f7
--- /dev/null
+++ b/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/GenericListWriter.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.translate.impl.write;
+
+import io.fd.honeycomb.v3po.translate.spi.write.ListWriterCustomizer;
+import io.fd.honeycomb.v3po.translate.util.RWUtils;
+import io.fd.honeycomb.v3po.translate.write.WriteContext;
+import io.fd.honeycomb.v3po.translate.write.WriteFailedException;
+import io.fd.honeycomb.v3po.translate.write.Writer;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Special writer handling updates for nodes of type list.
+ */
+public final class GenericListWriter<D extends DataObject & Identifiable<K>, K extends Identifier<D>> extends
+ AbstractCompositeWriter<D> implements Writer<D> {
+
+ private final ListWriterCustomizer<D, K> customizer;
+
+ public GenericListWriter(@Nonnull final InstanceIdentifier<D> type,
+ @Nonnull final ListWriterCustomizer<D, K> customizer) {
+ super(type);
+ this.customizer = customizer;
+ }
+
+ @Override
+ protected void writeCurrentAttributes(@Nonnull final InstanceIdentifier<D> id, @Nonnull final D data,
+ @Nonnull final WriteContext ctx) throws WriteFailedException {
+ customizer.writeCurrentAttributes(id, data, ctx);
+ }
+
+ @Override
+ protected void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<D> id, @Nonnull final D dataBefore,
+ @Nonnull final WriteContext ctx) throws WriteFailedException {
+ customizer.deleteCurrentAttributes(id, dataBefore, ctx);
+ }
+
+ @Override
+ protected void updateCurrentAttributes(@Nonnull final InstanceIdentifier<D> id, @Nonnull final D dataBefore,
+ @Nonnull final D dataAfter, @Nonnull final WriteContext ctx)
+ throws WriteFailedException {
+ customizer.updateCurrentAttributes(id, dataBefore, dataAfter, ctx);
+ }
+
+ @Override
+ protected void writeCurrent(final InstanceIdentifier<D> id, final D data, final WriteContext ctx)
+ throws WriteFailedException {
+ // Make sure the key is present
+ if (isWildcarded(id)) {
+ super.writeCurrent(getSpecificId(id, data), data, ctx);
+ } else {
+ super.writeCurrent(id, data, ctx);
+ }
+ }
+
+ @Override
+ protected void updateCurrent(final InstanceIdentifier<D> id, final D dataBefore, final D dataAfter,
+ final WriteContext ctx) throws WriteFailedException {
+ // Make sure the key is present
+ if (isWildcarded(id)) {
+ super.updateCurrent(getSpecificId(id, dataBefore), dataBefore, dataAfter, ctx);
+ } else {
+ super.updateCurrent(id, dataBefore, dataAfter, ctx);
+ }
+ }
+
+ @Override
+ protected void deleteCurrent(final InstanceIdentifier<D> id, final D dataBefore, final WriteContext ctx)
+ throws WriteFailedException {
+ // Make sure the key is present
+ if (isWildcarded(id)) {
+ super.deleteCurrent(getSpecificId(id, dataBefore), dataBefore, ctx);
+ } else {
+ super.deleteCurrent(id, dataBefore, ctx);
+ }
+ }
+
+ private boolean isWildcarded(final InstanceIdentifier<D> id) {
+ return id.firstIdentifierOf(getManagedDataObjectType().getTargetType()).isWildcarded();
+ }
+
+ private InstanceIdentifier<D> getSpecificId(final InstanceIdentifier<D> currentId, final D current) {
+ return RWUtils.replaceLastInId(currentId,
+ new InstanceIdentifier.IdentifiableItem<>(currentId.getTargetType(), current.getKey()));
+ }
+}
diff --git a/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/CompositeRootWriter.java b/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/GenericWriter.java
index 6f46359ff..6ca80ca37 100644
--- a/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/CompositeRootWriter.java
+++ b/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/GenericWriter.java
@@ -16,50 +16,26 @@
package io.fd.honeycomb.v3po.translate.impl.write;
-import io.fd.honeycomb.v3po.translate.impl.TraversalType;
import io.fd.honeycomb.v3po.translate.spi.write.RootWriterCustomizer;
-import io.fd.honeycomb.v3po.translate.util.RWUtils;
-import io.fd.honeycomb.v3po.translate.write.ChildWriter;
import io.fd.honeycomb.v3po.translate.write.WriteContext;
import io.fd.honeycomb.v3po.translate.write.WriteFailedException;
-import java.util.List;
import javax.annotation.Nonnull;
-import org.opendaylight.yangtools.yang.binding.Augmentation;
-import org.opendaylight.yangtools.yang.binding.ChildOf;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-public class CompositeRootWriter<D extends DataObject> extends AbstractCompositeWriter<D> {
+/**
+ * Special writer handling updates for any complex nodes.
+ */
+public final class GenericWriter<D extends DataObject> extends AbstractCompositeWriter<D> {
private final RootWriterCustomizer<D> customizer;
- public CompositeRootWriter(@Nonnull final Class<D> type,
- @Nonnull final List<ChildWriter<? extends ChildOf<D>>> childWriters,
- @Nonnull final List<ChildWriter<? extends Augmentation<D>>> augWriters,
- @Nonnull final RootWriterCustomizer<D> customizer) {
- this(type, childWriters, augWriters, customizer, TraversalType.PREORDER);
- }
-
- public CompositeRootWriter(@Nonnull final Class<D> type,
- @Nonnull final List<ChildWriter<? extends ChildOf<D>>> childWriters,
- @Nonnull final List<ChildWriter<? extends Augmentation<D>>> augWriters,
- @Nonnull final RootWriterCustomizer<D> customizer,
- @Nonnull final TraversalType traversalType) {
- super(type, childWriters, augWriters, traversalType);
+ public GenericWriter(@Nonnull final InstanceIdentifier<D> type,
+ @Nonnull final RootWriterCustomizer<D> customizer) {
+ super(type);
this.customizer = customizer;
}
- public CompositeRootWriter(@Nonnull final Class<D> type,
- @Nonnull final List<ChildWriter<? extends ChildOf<D>>> childWriters,
- @Nonnull final RootWriterCustomizer<D> customizer) {
- this(type, childWriters, RWUtils.<D>emptyAugWriterList(), customizer);
- }
-
- public CompositeRootWriter(@Nonnull final Class<D> type,
- @Nonnull final RootWriterCustomizer<D> customizer) {
- this(type, RWUtils.<D>emptyChildWriterList(), RWUtils.<D>emptyAugWriterList(), customizer);
- }
-
@Override
protected void writeCurrentAttributes(@Nonnull final InstanceIdentifier<D> id, @Nonnull final D data,
@Nonnull final WriteContext ctx) throws WriteFailedException {
diff --git a/v3po/translate-impl/src/test/java/io/fd/honeycomb/v3po/translate/impl/write/GenericListWriterTest.java b/v3po/translate-impl/src/test/java/io/fd/honeycomb/v3po/translate/impl/write/GenericListWriterTest.java
new file mode 100644
index 000000000..54a7466e1
--- /dev/null
+++ b/v3po/translate-impl/src/test/java/io/fd/honeycomb/v3po/translate/impl/write/GenericListWriterTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.translate.impl.write;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import io.fd.honeycomb.v3po.translate.spi.write.ListWriterCustomizer;
+import io.fd.honeycomb.v3po.translate.write.WriteContext;
+import java.util.Collections;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class GenericListWriterTest {
+
+ private static final InstanceIdentifier<IdentifiableDataObject>
+ DATA_OBJECT_INSTANCE_IDENTIFIER = InstanceIdentifier.create(IdentifiableDataObject.class);
+ @Mock
+ private ListWriterCustomizer<IdentifiableDataObject, DataObjectIdentifier> customizer;
+ @Mock
+ private WriteContext ctx;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void testUpdate() throws Exception {
+ final GenericListWriter<IdentifiableDataObject, DataObjectIdentifier> writer =
+ new GenericListWriter<>(DATA_OBJECT_INSTANCE_IDENTIFIER, customizer);
+
+ final IdentifiableDataObject before = mock(IdentifiableDataObject.class);
+ final DataObjectIdentifier beforeKey = mock(DataObjectIdentifier.class);
+ when(before.getKey()).thenReturn(beforeKey);
+ final IdentifiableDataObject after = mock(IdentifiableDataObject.class);
+ final DataObjectIdentifier keyAfter = mock(DataObjectIdentifier.class);
+ when(after.getKey()).thenReturn(keyAfter);
+
+ assertEquals(DATA_OBJECT_INSTANCE_IDENTIFIER, writer.getManagedDataObjectType());
+
+ final InstanceIdentifier<IdentifiableDataObject> keyedIdBefore =
+ (InstanceIdentifier<IdentifiableDataObject>) InstanceIdentifier.create(Collections
+ .singleton(new InstanceIdentifier.IdentifiableItem<>(IdentifiableDataObject.class, beforeKey)));
+ final InstanceIdentifier<IdentifiableDataObject> keyedIdAfter =
+ (InstanceIdentifier<IdentifiableDataObject>) InstanceIdentifier.create(Collections
+ .singleton(new InstanceIdentifier.IdentifiableItem<>(IdentifiableDataObject.class, keyAfter)));
+
+ writer.update(DATA_OBJECT_INSTANCE_IDENTIFIER, before, after, ctx);
+ verify(customizer).updateCurrentAttributes(keyedIdBefore, before, after, ctx);
+
+ writer.update(DATA_OBJECT_INSTANCE_IDENTIFIER, before, null, ctx);
+ verify(customizer).deleteCurrentAttributes(keyedIdBefore, before, ctx);
+
+ writer.update(DATA_OBJECT_INSTANCE_IDENTIFIER, null, after, ctx);
+ verify(customizer).writeCurrentAttributes(keyedIdAfter, after, ctx);
+ }
+
+ private abstract static class IdentifiableDataObject implements DataObject, Identifiable<DataObjectIdentifier> {}
+ private abstract static class DataObjectIdentifier implements Identifier<IdentifiableDataObject> {}
+} \ No newline at end of file
diff --git a/v3po/translate-impl/src/test/java/io/fd/honeycomb/v3po/translate/impl/write/GenericWriterTest.java b/v3po/translate-impl/src/test/java/io/fd/honeycomb/v3po/translate/impl/write/GenericWriterTest.java
new file mode 100644
index 000000000..919072bcb
--- /dev/null
+++ b/v3po/translate-impl/src/test/java/io/fd/honeycomb/v3po/translate/impl/write/GenericWriterTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.translate.impl.write;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import io.fd.honeycomb.v3po.translate.spi.write.RootWriterCustomizer;
+import io.fd.honeycomb.v3po.translate.write.WriteContext;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class GenericWriterTest {
+
+ private static final InstanceIdentifier<DataObject>
+ DATA_OBJECT_INSTANCE_IDENTIFIER = InstanceIdentifier.create(DataObject.class);
+ @Mock
+ private RootWriterCustomizer<DataObject> customizer;
+ @Mock
+ private WriteContext ctx;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void testUpdate() throws Exception {
+ final GenericWriter<DataObject> writer =
+ new GenericWriter<>(DATA_OBJECT_INSTANCE_IDENTIFIER, customizer);
+
+ final DataObject before = mock(DataObject.class);
+ final DataObject after = mock(DataObject.class);
+
+ assertEquals(DATA_OBJECT_INSTANCE_IDENTIFIER, writer.getManagedDataObjectType());
+ writer.update(DATA_OBJECT_INSTANCE_IDENTIFIER, before, after, ctx);
+ verify(customizer).updateCurrentAttributes(DATA_OBJECT_INSTANCE_IDENTIFIER, before, after, ctx);
+
+ writer.update(DATA_OBJECT_INSTANCE_IDENTIFIER, before, null, ctx);
+ verify(customizer).deleteCurrentAttributes(DATA_OBJECT_INSTANCE_IDENTIFIER, before, ctx);
+
+ writer.update(DATA_OBJECT_INSTANCE_IDENTIFIER, null, after, ctx);
+ verify(customizer).writeCurrentAttributes(DATA_OBJECT_INSTANCE_IDENTIFIER, after, ctx);
+ }
+} \ No newline at end of file