From d4b205bc665bebffec8545af5c4992327149c9c3 Mon Sep 17 00:00:00 2001 From: Maros Marsalek Date: Wed, 13 Jul 2016 11:52:51 +0200 Subject: HONEYCOMB-122 Update reader registry to share similar APIs as writer + Extract common registry builder base code (Reader registry is not flat, so there is not full control over ordering as with writers but it is sufficient) + Split CompositeReader into CompositeReader, SubtreeReader and GenericReader + No need to build composite structure in ReaderFactories (registry does that internally) + Keep only ReaderCustomizer + ListReaderCustomizer, no root reader (same for writers) Change-Id: Ic4e5bc96ad47a6cbcada4efcc2209db5c16d2a6c Signed-off-by: Maros Marsalek --- .../v3po/translate/impl/TraversalType.java | 37 --- .../impl/read/AbstractCompositeReader.java | 267 --------------------- .../translate/impl/read/CompositeChildReader.java | 123 ---------- .../translate/impl/read/CompositeListReader.java | 157 ------------ .../translate/impl/read/CompositeRootReader.java | 110 --------- .../translate/impl/read/GenericListReader.java | 114 +++++++++ .../v3po/translate/impl/read/GenericReader.java | 70 ++++++ .../impl/write/AbstractCompositeWriter.java | 136 ----------- .../translate/impl/write/GenericListWriter.java | 10 +- .../v3po/translate/impl/write/GenericWriter.java | 11 +- .../translate/impl/write/GenericWriterTest.java | 4 +- 11 files changed, 198 insertions(+), 841 deletions(-) delete mode 100644 v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/TraversalType.java delete mode 100644 v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/AbstractCompositeReader.java delete mode 100644 v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/CompositeChildReader.java delete mode 100644 v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/CompositeListReader.java delete mode 100644 v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/CompositeRootReader.java create mode 100644 v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/GenericListReader.java create mode 100644 v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/GenericReader.java delete mode 100644 v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/AbstractCompositeWriter.java (limited to 'v3po/translate-impl') diff --git a/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/TraversalType.java b/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/TraversalType.java deleted file mode 100644 index 3fa0f8d24..000000000 --- a/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/TraversalType.java +++ /dev/null @@ -1,37 +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; - -/** - * Type of traversal to be used by readers/writers in a tree - */ -public enum TraversalType { - - /** - * Read current attributes before reading from children - */ - PREORDER, - - /** - * Read from children before reading current attributes - */ - POSTORDER - - // TODO implement different traversal types as injectable iterators - // TODO implement above traversal types in readers - -} \ No newline at end of file diff --git a/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/AbstractCompositeReader.java b/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/AbstractCompositeReader.java deleted file mode 100644 index c99e0edc4..000000000 --- a/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/AbstractCompositeReader.java +++ /dev/null @@ -1,267 +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.read; - -import static com.google.common.base.Preconditions.checkArgument; - -import com.google.common.annotations.Beta; -import com.google.common.base.Optional; -import com.google.common.base.Predicate; -import com.google.common.collect.Iterables; -import io.fd.honeycomb.v3po.translate.impl.TraversalType; -import io.fd.honeycomb.v3po.translate.util.ReflectionUtils; -import io.fd.honeycomb.v3po.translate.util.RWUtils; -import io.fd.honeycomb.v3po.translate.read.ChildReader; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.read.Reader; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.opendaylight.yangtools.concepts.Builder; -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.Identifier; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@Beta -abstract class AbstractCompositeReader> implements Reader { - - private static final Logger LOG = LoggerFactory.getLogger(AbstractCompositeReader.class); - - private final Map, ChildReader>> childReaders; - private final Map, ChildReader>> augReaders; - private final InstanceIdentifier instanceIdentifier; - private final TraversalType traversalType; - - AbstractCompositeReader(final Class managedDataObjectType, - final List>> childReaders, - final List>> augReaders, - final TraversalType traversalType) { - this.traversalType = traversalType; - this.childReaders = RWUtils.uniqueLinkedIndex(childReaders, RWUtils.MANAGER_CLASS_FUNCTION); - this.augReaders = RWUtils.uniqueLinkedIndex(augReaders, RWUtils.MANAGER_CLASS_AUG_FUNCTION); - this.instanceIdentifier = InstanceIdentifier.create(managedDataObjectType); - } - - @Nonnull - @Override - public final InstanceIdentifier getManagedDataObjectType() { - return instanceIdentifier; - } - - /** - * @param id {@link InstanceIdentifier} pointing to current node. In case of keyed list, key must be present. - * - */ - protected Optional readCurrent(final InstanceIdentifier id, - @Nonnull final ReadContext ctx) throws ReadFailedException { - LOG.debug("{}: Reading current: {}", this, id); - final B builder = getBuilder(id); - // Cache empty value to determine if anything has changed later TODO cache in a field - final D emptyValue = builder.build(); - - switch (traversalType) { - case PREORDER: { - LOG.trace("{}: Reading current attributes", this); - readCurrentAttributes(id, builder, ctx); - readChildren(id, ctx, builder); - break; - } - case POSTORDER: { - readChildren(id, ctx, builder); - LOG.trace("{}: Reading current attributes", this); - readCurrentAttributes(id, builder, ctx); - break; - } - } - - // Need to check whether anything was filled in to determine if data is present or not. - final D built = builder.build(); - final Optional read = built.equals(emptyValue) - ? Optional.absent() - : Optional.of(built); - - LOG.debug("{}: Current node read successfully. Result: {}", this, read); - return read; - } - - private void readChildren(final InstanceIdentifier id, final @Nonnull ReadContext ctx, final B builder) - throws ReadFailedException { - // TODO expect exceptions from reader - for (ChildReader> child : childReaders.values()) { - LOG.debug("{}: Reading child from: {}", this, child); - child.read(id, builder, ctx); - } - - for (ChildReader> child : augReaders.values()) { - LOG.debug("{}: Reading augment from: {}", this, child); - child.read(id, builder, ctx); - } - } - - @Nonnull - @Override - @SuppressWarnings("unchecked") - public Optional read(@Nonnull final InstanceIdentifier id, - @Nonnull final ReadContext ctx) - throws ReadFailedException { - LOG.trace("{}: Reading : {}", this, id); - if (id.getTargetType().equals(getManagedDataObjectType().getTargetType())) { - return readCurrent((InstanceIdentifier) id, ctx); - } else { - return readSubtree(id, ctx); - } - } - - private Optional readSubtree(final InstanceIdentifier id, - @Nonnull final ReadContext ctx) - throws ReadFailedException { - LOG.debug("{}: Reading subtree: {}", this, id); - final Class next = RWUtils.getNextId(id, getManagedDataObjectType()).getType(); - final ChildReader> reader = childReaders.get(next); - final ChildReader> augReader = augReaders.get(next); - - if (reader != null) { - LOG.debug("{}: Reading subtree: {} from: {}", this, id, reader); - return reader.read(id, ctx); - }if (augReader != null) { - LOG.debug("{}: Reading subtree: {} from: {}", this, id, augReader); - return augReader.read(id, ctx); - } else { - LOG.debug("{}: Dedicated subtree reader missing for: {}. Reading current and filtering", this, next); - // If there's no dedicated reader, use read current - final InstanceIdentifier currentId = RWUtils.cutId(id, getManagedDataObjectType()); - final Optional current = readCurrent(currentId, ctx); - // then perform post-reading filtering (return only requested sub-node) - final Optional readSubtree = current.isPresent() - ? filterSubtree(current.get(), id, getManagedDataObjectType().getTargetType()) - : current; - - LOG.debug("{}: Subtree: {} read successfully. Result: {}", this, id, readSubtree); - return readSubtree; - } - } - - /** - * Fill in current node's attributes - * - * @param id {@link InstanceIdentifier} pointing to current node. In case of keyed list, key must be present. - * @param builder Builder object for current node where the read attributes must be placed - * @param ctx Current read context - */ - protected abstract void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final B builder, - @Nonnull final ReadContext ctx) throws ReadFailedException; - - /** - * Return new instance of a builder object for current node - * - * @param id {@link InstanceIdentifier} pointing to current node. In case of keyed list, key must be present. - * @return Builder object for current node type - */ - protected abstract B getBuilder(InstanceIdentifier id); - - // TODO move filtering out of here into a dedicated Filter ifc - @Nonnull - private static Optional filterSubtree(@Nonnull final DataObject parent, - @Nonnull final InstanceIdentifier absolutPath, - @Nonnull final Class managedType) { - final InstanceIdentifier.PathArgument nextId = - RWUtils.getNextId(absolutPath, InstanceIdentifier.create(parent.getClass())); - - final Optional nextParent = findNextParent(parent, nextId, managedType); - - if (Iterables.getLast(absolutPath.getPathArguments()).equals(nextId)) { - return nextParent; // we found the dataObject identified by absolutePath - } else if (nextParent.isPresent()) { - return filterSubtree(nextParent.get(), absolutPath, nextId.getType()); - } else { - return nextParent; // we can't go further, return Optional.absent() - } - } - - private static Optional findNextParent(@Nonnull final DataObject parent, - @Nonnull final InstanceIdentifier.PathArgument nextId, - @Nonnull final Class managedType) { - // TODO is there a better way than reflection ? e.g. convert into NN and filter out with a utility - Optional method = ReflectionUtils.findMethodReflex(managedType, "get", - Collections.>emptyList(), nextId.getType()); - - if (method.isPresent()) { - return Optional.fromNullable(filterSingle(parent, nextId, method.get())); - } else { - // List child nodes - method = ReflectionUtils.findMethodReflex(managedType, - "get" + nextId.getType().getSimpleName(), Collections.>emptyList(), List.class); - - if (method.isPresent()) { - return filterList(parent, nextId, method.get()); - } else { - throw new IllegalStateException( - "Unable to filter " + nextId + " from " + parent + " getters not found using reflexion"); - } - } - } - - @SuppressWarnings("unchecked") - private static Optional filterList(final DataObject parent, - final InstanceIdentifier.PathArgument nextId, - final Method method) { - final List invoke = (List) invoke(method, nextId, parent); - - checkArgument(nextId instanceof InstanceIdentifier.IdentifiableItem, - "Unable to perform wildcarded read for %s", nextId); - final Identifier key = ((InstanceIdentifier.IdentifiableItem) nextId).getKey(); - return Iterables.tryFind(invoke, new Predicate() { - @Override - public boolean apply(@Nullable final DataObject input) { - final Optional keyGetter = - ReflectionUtils.findMethodReflex(nextId.getType(), "get", - Collections.>emptyList(), key.getClass()); - final Object actualKey; - actualKey = invoke(keyGetter.get(), nextId, input); - return key.equals(actualKey); - } - }); - } - - private static DataObject filterSingle(final DataObject parent, - final InstanceIdentifier.PathArgument nextId, final Method method) { - return nextId.getType().cast(invoke(method, nextId, parent)); - } - - private static Object invoke(final Method method, - final InstanceIdentifier.PathArgument nextId, final DataObject parent) { - try { - return method.invoke(parent); - } catch (IllegalAccessException | InvocationTargetException e) { - throw new IllegalArgumentException("Unable to get " + nextId + " from " + parent, e); - } - } - - @Override - public String toString() { - return String.format("Reader[%s]", getManagedDataObjectType().getTargetType().getSimpleName()); - } -} diff --git a/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/CompositeChildReader.java b/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/CompositeChildReader.java deleted file mode 100644 index 89f9f5675..000000000 --- a/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/CompositeChildReader.java +++ /dev/null @@ -1,123 +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.read; - -import com.google.common.annotations.Beta; -import com.google.common.base.Optional; -import io.fd.honeycomb.v3po.translate.impl.TraversalType; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.util.RWUtils; -import io.fd.honeycomb.v3po.translate.read.ChildReader; -import io.fd.honeycomb.v3po.translate.spi.read.ChildReaderCustomizer; -import java.util.List; -import javax.annotation.Nonnull; -import javax.annotation.concurrent.ThreadSafe; -import org.opendaylight.yangtools.concepts.Builder; -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; - -/** - * Composite implementation of {@link ChildReader} able to place the read result into - * parent builder object. - */ -@Beta -@ThreadSafe -public final class CompositeChildReader> extends AbstractCompositeReader - implements ChildReader { - - private final ChildReaderCustomizer customizer; - - /** - * Create new {@link CompositeChildReader} - * - * @param managedDataObjectType Class object for managed data type - * @param childReaders Child nodes(container, list) readers - * @param augReaders Child augmentations readers - * @param customizer Customizer instance to customize this generic reader - * - */ - public CompositeChildReader(@Nonnull final Class managedDataObjectType, - @Nonnull final List>> childReaders, - @Nonnull final List>> augReaders, - @Nonnull final ChildReaderCustomizer customizer) { - this(managedDataObjectType, childReaders, augReaders, customizer, TraversalType.PREORDER); - } - - /** - * Create new {@link CompositeChildReader} - * - * @param managedDataObjectType Class object for managed data type - * @param childReaders Child nodes(container, list) readers - * @param augReaders Child augmentations readers - * @param customizer Customizer instance to customize this generic reader - * @param traversalType Type of traversal to use in the tree of readers - * - */ - public CompositeChildReader(@Nonnull final Class managedDataObjectType, - @Nonnull final List>> childReaders, - @Nonnull final List>> augReaders, - @Nonnull final ChildReaderCustomizer customizer, - @Nonnull final TraversalType traversalType) { - super(managedDataObjectType, childReaders, augReaders, traversalType); - this.customizer = customizer; - } - - /** - * @see {@link CompositeChildReader#CompositeChildReader(Class, List, List, ChildReaderCustomizer)} - */ - public CompositeChildReader(@Nonnull final Class managedDataObjectType, - @Nonnull final List>> childReaders, - @Nonnull final ChildReaderCustomizer customizer) { - this(managedDataObjectType, childReaders, RWUtils.emptyAugReaderList(), customizer); - } - - /** - * @see {@link CompositeChildReader#CompositeChildReader(Class, List, List, ChildReaderCustomizer)} - */ - public CompositeChildReader(@Nonnull final Class managedDataObjectType, - @Nonnull final ChildReaderCustomizer customizer) { - this(managedDataObjectType, RWUtils.emptyChildReaderList(), RWUtils.emptyAugReaderList(), - customizer); - } - - @Override - public final void read(@Nonnull final InstanceIdentifier parentId, - @Nonnull final Builder parentBuilder, - @Nonnull final ReadContext ctx) throws ReadFailedException { - final Optional read = readCurrent(RWUtils.appendTypeToId(parentId, getManagedDataObjectType()), ctx); - - if(read.isPresent()) { - customizer.merge(parentBuilder, read.get()); - } - } - - @Override - protected void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final B builder, - @Nonnull final ReadContext ctx) - throws ReadFailedException { - customizer.readCurrentAttributes(id, builder, ctx); - } - - @Override - protected B getBuilder(@Nonnull final InstanceIdentifier id) { - return customizer.getBuilder(id); - } - -} diff --git a/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/CompositeListReader.java b/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/CompositeListReader.java deleted file mode 100644 index 7c438f669..000000000 --- a/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/CompositeListReader.java +++ /dev/null @@ -1,157 +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.read; - -import static com.google.common.base.Preconditions.checkArgument; - -import com.google.common.annotations.Beta; -import com.google.common.base.Optional; -import io.fd.honeycomb.v3po.translate.impl.TraversalType; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.util.RWUtils; -import io.fd.honeycomb.v3po.translate.read.ChildReader; -import io.fd.honeycomb.v3po.translate.read.ListReader; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.spi.read.ListReaderCustomizer; -import java.util.ArrayList; -import java.util.List; -import javax.annotation.Nonnull; -import javax.annotation.concurrent.ThreadSafe; -import org.opendaylight.yangtools.concepts.Builder; -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; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Composite implementation of {@link ChildReader} able to place the read result into parent builder object intended - * for list node type. - * - * This reader checks if the IDs are wildcarded in which case it performs read of all list entries. In case the ID has a - * key, it reads only the specified value. - */ -@Beta -@ThreadSafe -public final class CompositeListReader, K extends Identifier, B extends Builder> - extends AbstractCompositeReader implements ChildReader, ListReader { - - private static final Logger LOG = LoggerFactory.getLogger(CompositeListReader.class); - - private final ListReaderCustomizer customizer; - - /** - * Create new {@link CompositeListReader} - * - * @param managedDataObjectType Class object for managed data type. Must come from a list node type. - * @param childReaders Child nodes(container, list) readers - * @param augReaders Child augmentations readers - * @param customizer Customizer instance to customize this generic reader - */ - public CompositeListReader(@Nonnull final Class managedDataObjectType, - @Nonnull final List>> childReaders, - @Nonnull final List>> augReaders, - @Nonnull final ListReaderCustomizer customizer) { - this(managedDataObjectType, childReaders, augReaders, customizer, TraversalType.PREORDER); - } - - /** - * Create new {@link CompositeListReader} - * - * @param managedDataObjectType Class object for managed data type. Must come from a list node type. - * @param childReaders Child nodes(container, list) readers - * @param augReaders Child augmentations readers - * @param customizer Customizer instance to customize this generic reader - * @param traversalType Type of traversal to use in the tree of readers - */ - public CompositeListReader(@Nonnull final Class managedDataObjectType, - @Nonnull final List>> childReaders, - @Nonnull final List>> augReaders, - @Nonnull final ListReaderCustomizer customizer, - @Nonnull final TraversalType traversalType) { - super(managedDataObjectType, childReaders, augReaders, traversalType); - this.customizer = customizer; - } - - /** - * @see {@link CompositeListReader#CompositeListReader(Class, List, List, ListReaderCustomizer)} - */ - public CompositeListReader(@Nonnull final Class managedDataObjectType, - @Nonnull final List>> childReaders, - @Nonnull final ListReaderCustomizer customizer) { - this(managedDataObjectType, childReaders, RWUtils.emptyAugReaderList(), customizer); - } - - /** - * @see {@link CompositeListReader#CompositeListReader(Class, List, List, ListReaderCustomizer)} - */ - public CompositeListReader(@Nonnull final Class managedDataObjectType, - @Nonnull final ListReaderCustomizer customizer) { - this(managedDataObjectType, RWUtils.emptyChildReaderList(), RWUtils.emptyAugReaderList(), - customizer); - } - - @Override - public void read(@Nonnull final InstanceIdentifier id, - @Nonnull final Builder parentBuilder, - @Nonnull final ReadContext ctx) throws ReadFailedException { - // Create ID pointing to current node - final InstanceIdentifier currentId = RWUtils.appendTypeToId(id, getManagedDataObjectType()); - // Read all, since current ID is definitely wildcarded - final List ifcs = readList(currentId, ctx); - customizer.merge(parentBuilder, ifcs); - } - - @Override - @Nonnull - public List readList(@Nonnull final InstanceIdentifier id, - @Nonnull final ReadContext ctx) throws ReadFailedException { - LOG.trace("{}: Reading all list entries", this); - final List allIds = customizer.getAllIds(id, ctx); - LOG.debug("{}: Reading list entries for: {}", this, allIds); - - final ArrayList allEntries = new ArrayList<>(allIds.size()); - for (K key : allIds) { - final InstanceIdentifier.IdentifiableItem currentBdItem = - RWUtils.getCurrentIdItem(id, key); - final InstanceIdentifier keyedId = RWUtils.replaceLastInId(id, currentBdItem); - final Optional read = readCurrent(keyedId, ctx); - if(read.isPresent()) { - final DataObject singleItem = read.get(); - checkArgument(getManagedDataObjectType().getTargetType().isAssignableFrom(singleItem.getClass())); - allEntries.add(getManagedDataObjectType().getTargetType().cast(singleItem)); - } - } - return allEntries; - } - - @Override - protected void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final B builder, - @Nonnull final ReadContext ctx) - throws ReadFailedException { - customizer.readCurrentAttributes(id, builder, ctx); - } - - @Override - protected B getBuilder(@Nonnull final InstanceIdentifier id) { - return customizer.getBuilder(id); - } - -} diff --git a/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/CompositeRootReader.java b/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/CompositeRootReader.java deleted file mode 100644 index ea157aafd..000000000 --- a/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/CompositeRootReader.java +++ /dev/null @@ -1,110 +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.read; - -import com.google.common.annotations.Beta; -import io.fd.honeycomb.v3po.translate.impl.TraversalType; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.util.RWUtils; -import io.fd.honeycomb.v3po.translate.read.ChildReader; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.Reader; -import io.fd.honeycomb.v3po.translate.spi.read.RootReaderCustomizer; -import java.util.List; -import javax.annotation.Nonnull; -import javax.annotation.concurrent.ThreadSafe; -import org.opendaylight.yangtools.concepts.Builder; -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; - -/** - * Composite implementation of {@link Reader} - */ -@Beta -@ThreadSafe -public final class CompositeRootReader> extends AbstractCompositeReader - implements Reader { - - private final RootReaderCustomizer customizer; - - /** - * Create new {@link CompositeRootReader} - * - * @param managedDataObjectType Class object for managed data type - * @param childReaders Child nodes(container, list) readers - * @param augReaders Child augmentations readers - * @param customizer Customizer instance to customize this generic reader - * - */ - public CompositeRootReader(@Nonnull final Class managedDataObjectType, - @Nonnull final List>> childReaders, - @Nonnull final List>> augReaders, - @Nonnull final RootReaderCustomizer customizer) { - this(managedDataObjectType, childReaders, augReaders, customizer, TraversalType.PREORDER); - } - - /** - * Create new {@link CompositeRootReader} - * - * @param managedDataObjectType Class object for managed data type - * @param childReaders Child nodes(container, list) readers - * @param augReaders Child augmentations readers - * @param customizer Customizer instance to customize this generic reader - * @param traversalType Type of traversal to use in the tree of readers - * - */ - public CompositeRootReader(@Nonnull final Class managedDataObjectType, - @Nonnull final List>> childReaders, - @Nonnull final List>> augReaders, - @Nonnull final RootReaderCustomizer customizer, - @Nonnull final TraversalType traversalType) { - super(managedDataObjectType, childReaders, augReaders, traversalType); - this.customizer = customizer; - } - - /** - * @see {@link CompositeRootReader#CompositeRootReader(Class, List, List, RootReaderCustomizer)} - */ - public CompositeRootReader(@Nonnull final Class managedDataObjectType, - @Nonnull final List>> childReaders, - @Nonnull final RootReaderCustomizer customizer) { - this(managedDataObjectType, childReaders, RWUtils.emptyAugReaderList(), customizer); - } - - /** - * @see {@link CompositeRootReader#CompositeRootReader(Class, List, List, RootReaderCustomizer)} - */ - public CompositeRootReader(@Nonnull final Class managedDataObjectType, - @Nonnull final RootReaderCustomizer customizer) { - this(managedDataObjectType, RWUtils.emptyChildReaderList(), RWUtils.emptyAugReaderList(), - customizer); - } - - @Override - protected void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final B builder, - @Nonnull final ReadContext ctx) throws ReadFailedException { - customizer.readCurrentAttributes(id, builder, ctx); - } - - @Override - protected B getBuilder(@Nonnull final InstanceIdentifier id) { - return customizer.getBuilder(id); - } - -} diff --git a/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/GenericListReader.java b/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/GenericListReader.java new file mode 100644 index 000000000..54dad5517 --- /dev/null +++ b/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/GenericListReader.java @@ -0,0 +1,114 @@ +/* + * 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.read; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.annotations.Beta; +import com.google.common.base.Optional; +import io.fd.honeycomb.v3po.translate.read.ListReader; +import io.fd.honeycomb.v3po.translate.read.ReadContext; +import io.fd.honeycomb.v3po.translate.read.ReadFailedException; +import io.fd.honeycomb.v3po.translate.spi.read.ListReaderCustomizer; +import io.fd.honeycomb.v3po.translate.util.RWUtils; +import io.fd.honeycomb.v3po.translate.util.read.AbstractGenericReader; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Nonnull; +import javax.annotation.concurrent.ThreadSafe; +import org.opendaylight.yangtools.concepts.Builder; +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; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Composite implementation of {@link ListReader} able to place the read result into parent builder object intended + * for list node type. + *

+ * This reader checks if the IDs are wildcarded in which case it performs read of all list entries. In case the ID has a + * key, it reads only the specified value. + */ +@Beta +@ThreadSafe +public final class GenericListReader, K extends Identifier, B extends Builder> + extends AbstractGenericReader implements ListReader { + + private static final Logger LOG = LoggerFactory.getLogger(GenericListReader.class); + + private final ListReaderCustomizer customizer; + + /** + * Create new {@link GenericListReader} + * + * @param managedDataObjectType Class object for managed data type. Must come from a list node type. + * @param customizer Customizer instance to customize this generic reader + */ + public GenericListReader(@Nonnull final InstanceIdentifier managedDataObjectType, + @Nonnull final ListReaderCustomizer customizer) { + super(managedDataObjectType); + this.customizer = customizer; + } + + @Override + @Nonnull + public List readList(@Nonnull final InstanceIdentifier id, + @Nonnull final ReadContext ctx) throws ReadFailedException { + LOG.trace("{}: Reading all list entries", this); + final List allIds = getAllIds(id, ctx); + LOG.debug("{}: Reading list entries for: {}", this, allIds); + + final ArrayList allEntries = new ArrayList<>(allIds.size()); + for (K key : allIds) { + final InstanceIdentifier.IdentifiableItem currentBdItem = RWUtils.getCurrentIdItem(id, key); + final InstanceIdentifier keyedId = RWUtils.replaceLastInId(id, currentBdItem); + final Optional read = readCurrent(keyedId, ctx); + if (read.isPresent()) { + final DataObject singleItem = read.get(); + checkArgument(getManagedDataObjectType().getTargetType().isAssignableFrom(singleItem.getClass())); + allEntries.add(getManagedDataObjectType().getTargetType().cast(singleItem)); + } + } + return allEntries; + } + + @Override + public List getAllIds(@Nonnull final InstanceIdentifier id, @Nonnull final ReadContext ctx) + throws ReadFailedException { + return customizer.getAllIds(id, ctx); + } + + @Override + public void merge(@Nonnull final Builder builder, @Nonnull final List readData) { + customizer.merge(builder, readData); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final B builder, + @Nonnull final ReadContext ctx) + throws ReadFailedException { + customizer.readCurrentAttributes(id, builder, ctx); + } + + @Override + public B getBuilder(@Nonnull final InstanceIdentifier id) { + return customizer.getBuilder(id); + } + +} diff --git a/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/GenericReader.java b/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/GenericReader.java new file mode 100644 index 000000000..eace7fa89 --- /dev/null +++ b/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/GenericReader.java @@ -0,0 +1,70 @@ +/* + * 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.read; + +import com.google.common.annotations.Beta; +import io.fd.honeycomb.v3po.translate.read.ReadContext; +import io.fd.honeycomb.v3po.translate.read.ReadFailedException; +import io.fd.honeycomb.v3po.translate.read.Reader; +import io.fd.honeycomb.v3po.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.v3po.translate.util.read.AbstractGenericReader; +import javax.annotation.Nonnull; +import javax.annotation.concurrent.ThreadSafe; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Composite implementation of {@link Reader}. + */ +@Beta +@ThreadSafe +public final class GenericReader> extends AbstractGenericReader + implements Reader { + + private final ReaderCustomizer customizer; + + /** + * Create a new {@link GenericReader}. + * + * @param id Instance identifier for managed data type + * @param customizer Customizer instance to customize this generic reader + */ + public GenericReader(@Nonnull final InstanceIdentifier id, + @Nonnull final ReaderCustomizer customizer) { + super(id); + this.customizer = customizer; + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final B builder, + @Nonnull final ReadContext ctx) throws ReadFailedException { + customizer.readCurrentAttributes(id, builder, ctx); + } + + @Override + public B getBuilder(@Nonnull final InstanceIdentifier id) { + return customizer.getBuilder(id); + } + + @Override + public void merge(@Nonnull final Builder parentBuilder, @Nonnull final C readValue) { + customizer.merge(parentBuilder, readValue); + } + +} 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 deleted file mode 100644 index 5f1391c74..000000000 --- a/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/AbstractCompositeWriter.java +++ /dev/null @@ -1,136 +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 static com.google.common.base.Preconditions.checkArgument; - -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 javax.annotation.Nullable; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -abstract class AbstractCompositeWriter implements Writer { - - private static final Logger LOG = LoggerFactory.getLogger(AbstractCompositeWriter.class); - - private final InstanceIdentifier instanceIdentifier; - - AbstractCompositeWriter(final InstanceIdentifier type) { - this.instanceIdentifier = type; - } - - protected void writeCurrent(final InstanceIdentifier id, final D data, final WriteContext ctx) - throws WriteFailedException { - LOG.debug("{}: Writing current: {} data: {}", this, id, data); - writeCurrentAttributes(id, data, ctx); - LOG.debug("{}: Current node written successfully", this); - } - - protected void updateCurrent(final InstanceIdentifier id, final D dataBefore, final D dataAfter, - final WriteContext ctx) throws WriteFailedException { - LOG.debug("{}: Updating current: {} dataBefore: {}, datAfter: {}", this, id, dataBefore, dataAfter); - - if (dataBefore.equals(dataAfter)) { - LOG.debug("{}: Skipping current(no update): {}", this, id); - // No change, ignore - return; - } - updateCurrentAttributes(id, dataBefore, dataAfter, ctx); - LOG.debug("{}: Current node updated successfully", this); - } - - protected void deleteCurrent(final InstanceIdentifier id, final D dataBefore, final WriteContext ctx) - throws WriteFailedException { - LOG.debug("{}: Deleting current: {} dataBefore: {}", this, id, dataBefore); - deleteCurrentAttributes(id, dataBefore, ctx); - } - - @SuppressWarnings("unchecked") - @Override - public void update(@Nonnull final InstanceIdentifier id, - @Nullable final DataObject dataBefore, - @Nullable final DataObject dataAfter, - @Nonnull final WriteContext ctx) throws WriteFailedException { - LOG.debug("{}: Updating : {}", this, id); - LOG.trace("{}: Updating : {}, from: {} to: {}", this, id, dataBefore, dataAfter); - - checkArgument(idPointsToCurrent(id), "Cannot handle data: %s. Only: %s can be handled by writer: %s", - id, getManagedDataObjectType(), this); - - if (isWrite(dataBefore, dataAfter)) { - writeCurrent((InstanceIdentifier) id, castToManaged(dataAfter), ctx); - } else if (isDelete(dataBefore, dataAfter)) { - deleteCurrent((InstanceIdentifier) id, castToManaged(dataBefore), ctx); - } else { - checkArgument(dataBefore != null && dataAfter != null, "No data to process"); - updateCurrent((InstanceIdentifier) id, castToManaged(dataBefore), castToManaged(dataAfter), ctx); - } - } - - private void checkDataType(@Nonnull final DataObject dataAfter) { - checkArgument(getManagedDataObjectType().getTargetType().isAssignableFrom(dataAfter.getClass())); - } - - private D castToManaged(final DataObject data) { - checkDataType(data); - return getManagedDataObjectType().getTargetType().cast(data); - } - - private static boolean isWrite(final DataObject dataBefore, - final DataObject dataAfter) { - return dataBefore == null && dataAfter != null; - } - - private static boolean isDelete(final DataObject dataBefore, - final DataObject dataAfter) { - return dataAfter == null && dataBefore != null; - } - - private boolean idPointsToCurrent(final @Nonnull InstanceIdentifier id) { - return id.getTargetType().equals(getManagedDataObjectType().getTargetType()); - } - - protected abstract void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final D data, - @Nonnull final WriteContext ctx) throws WriteFailedException; - - protected abstract void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final D dataBefore, - @Nonnull final WriteContext ctx) throws WriteFailedException; - - protected abstract void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final D dataBefore, - @Nonnull final D dataAfter, - @Nonnull final WriteContext ctx) throws WriteFailedException; - - @Nonnull - @Override - public InstanceIdentifier getManagedDataObjectType() { - return instanceIdentifier; - } - - - @Override - public String toString() { - return String.format("Writer[%s]", getManagedDataObjectType().getTargetType().getSimpleName()); - } -} 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 index b61fb51f7..32daf5975 100644 --- 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 @@ -17,10 +17,12 @@ package io.fd.honeycomb.v3po.translate.impl.write; import io.fd.honeycomb.v3po.translate.spi.write.ListWriterCustomizer; +import io.fd.honeycomb.v3po.translate.spi.write.WriterCustomizer; import io.fd.honeycomb.v3po.translate.util.RWUtils; +import io.fd.honeycomb.v3po.translate.util.write.AbstractGenericWriter; +import io.fd.honeycomb.v3po.translate.write.ListWriter; 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; @@ -28,12 +30,12 @@ import org.opendaylight.yangtools.yang.binding.Identifier; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; /** - * Special writer handling updates for nodes of type list. + * Generic list node writer with customizable behavior thanks to injected customizer. */ public final class GenericListWriter, K extends Identifier> extends - AbstractCompositeWriter implements Writer { + AbstractGenericWriter implements ListWriter { - private final ListWriterCustomizer customizer; + private final WriterCustomizer customizer; public GenericListWriter(@Nonnull final InstanceIdentifier type, @Nonnull final ListWriterCustomizer customizer) { diff --git a/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/GenericWriter.java b/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/GenericWriter.java index 6ca80ca37..65c192ffa 100644 --- a/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/GenericWriter.java +++ b/v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/GenericWriter.java @@ -16,7 +16,8 @@ package io.fd.honeycomb.v3po.translate.impl.write; -import io.fd.honeycomb.v3po.translate.spi.write.RootWriterCustomizer; +import io.fd.honeycomb.v3po.translate.spi.write.WriterCustomizer; +import io.fd.honeycomb.v3po.translate.util.write.AbstractGenericWriter; import io.fd.honeycomb.v3po.translate.write.WriteContext; import io.fd.honeycomb.v3po.translate.write.WriteFailedException; import javax.annotation.Nonnull; @@ -24,14 +25,14 @@ import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; /** - * Special writer handling updates for any complex nodes. + * Generic writer with customizable behavior thanks to injected customizer. */ -public final class GenericWriter extends AbstractCompositeWriter { +public final class GenericWriter extends AbstractGenericWriter { - private final RootWriterCustomizer customizer; + private final WriterCustomizer customizer; public GenericWriter(@Nonnull final InstanceIdentifier type, - @Nonnull final RootWriterCustomizer customizer) { + @Nonnull final WriterCustomizer customizer) { super(type); this.customizer = customizer; } 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 index 919072bcb..87f18965b 100644 --- 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 @@ -20,7 +20,7 @@ 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.spi.write.WriterCustomizer; import io.fd.honeycomb.v3po.translate.write.WriteContext; import org.junit.Before; import org.junit.Test; @@ -34,7 +34,7 @@ public class GenericWriterTest { private static final InstanceIdentifier DATA_OBJECT_INSTANCE_IDENTIFIER = InstanceIdentifier.create(DataObject.class); @Mock - private RootWriterCustomizer customizer; + private WriterCustomizer customizer; @Mock private WriteContext ctx; -- cgit 1.2.3-korg