From b7ddb9bb91dd0fd886a9e4dde7c9d73d06879bf6 Mon Sep 17 00:00:00 2001 From: Maros Marsalek Date: Thu, 17 Mar 2016 09:56:42 +0100 Subject: Initial implementation of VPP readers Composite, recursive and extensible readers Change-Id: I86084fa0c4127bddd87f68ff6a48b79c27a9589c Signed-off-by: Maros Marsalek --- .../honeycomb/v3po/impl/trans/ChildVppReader.java | 1 + .../trans/impl/AbstractCompositeVppReader.java | 233 +++++++++++++++++++++ .../impl/trans/impl/CompositeChildVppReader.java | 80 +++++++ .../impl/trans/impl/CompositeListVppReader.java | 127 +++++++++++ .../impl/trans/impl/CompositeRootVppReader.java | 71 +++++++ .../trans/impl/spi/ChildVppReaderCustomizer.java | 29 +++ .../trans/impl/spi/ListVppReaderCustomizer.java | 37 ++++ .../trans/impl/spi/RootVppReaderCustomizer.java | 29 +++ .../impl/trans/util/DelegatingReaderRegistry.java | 79 +++++++ .../v3po/impl/trans/util/NoopReaderCustomizer.java | 29 +++ .../trans/util/ReflexiveChildReaderCustomizer.java | 56 +++++ .../trans/util/ReflexiveRootReaderCustomizer.java | 41 ++++ .../impl/trans/util/VppApiReaderCustomizer.java | 33 +++ .../v3po/impl/trans/util/VppReaderUtils.java | 152 ++++++++++++++ 14 files changed, 997 insertions(+) create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/AbstractCompositeVppReader.java create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/CompositeChildVppReader.java create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/CompositeListVppReader.java create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/CompositeRootVppReader.java create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/spi/ChildVppReaderCustomizer.java create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/spi/ListVppReaderCustomizer.java create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/spi/RootVppReaderCustomizer.java create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/DelegatingReaderRegistry.java create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/NoopReaderCustomizer.java create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/ReflexiveChildReaderCustomizer.java create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/ReflexiveRootReaderCustomizer.java create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/VppApiReaderCustomizer.java create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/VppReaderUtils.java (limited to 'v3po/impl/src/main/java') diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/ChildVppReader.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/ChildVppReader.java index 5d57c6064..8f2a1ce9e 100644 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/ChildVppReader.java +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/ChildVppReader.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.fd.honeycomb.v3po.impl.trans; import com.google.common.annotations.Beta; diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/AbstractCompositeVppReader.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/AbstractCompositeVppReader.java new file mode 100644 index 000000000..566c4fcc8 --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/AbstractCompositeVppReader.java @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.impl.trans.impl; + +import com.google.common.annotations.Beta; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.base.Predicate; +import com.google.common.collect.Collections2; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import io.fd.honeycomb.v3po.impl.trans.ChildVppReader; +import io.fd.honeycomb.v3po.impl.trans.VppReader; +import io.fd.honeycomb.v3po.impl.trans.util.VppReaderUtils; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.LinkedHashMap; +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; + +@Beta +abstract class AbstractCompositeVppReader> implements VppReader { + + // TODO add debug + trace logs here and there + + private final Map, ChildVppReader>> childReaders; + private final Map, ChildVppReader>> augReaders; + private final InstanceIdentifier instanceIdentifier; + + public AbstractCompositeVppReader( + final Class managedDataObjectType, + final List>> childReaders, + final List>> augReaders) { + this.childReaders = childReadersToMap(childReaders); + this.augReaders = augReadersToMap(augReaders); + this.instanceIdentifier = InstanceIdentifier.create(managedDataObjectType); + } + + protected final Map, ChildVppReader>> childReadersToMap( + final List>> childReaders) { + final LinkedHashMap, ChildVppReader>> + classVppReaderLinkedHashMap = new LinkedHashMap<>(); + + for (ChildVppReader> childReader : childReaders) { + Preconditions.checkArgument( + classVppReaderLinkedHashMap.put(childReader.getManagedDataObjectType().getTargetType(), childReader) == null, + "Duplicate (%s) child readers detected under: %s", childReader.getManagedDataObjectType(), + getManagedDataObjectType()); + } + + return classVppReaderLinkedHashMap; + } + + // FIXME add child/augReaders to one list and unify toMap helper methods + move to utils + protected final Map, ChildVppReader>> augReadersToMap( + final List>> childReaders) { + final LinkedHashMap, ChildVppReader>> + classVppReaderLinkedHashMap = new LinkedHashMap<>(); + + for (ChildVppReader childReader : childReaders) { + Preconditions.checkArgument( + classVppReaderLinkedHashMap.put(childReader.getManagedDataObjectType().getTargetType(), + (ChildVppReader>) childReader) == null, + "Duplicate (%s) child readers detected under: %s", childReader.getManagedDataObjectType(), + getManagedDataObjectType()); + } + return classVppReaderLinkedHashMap; + } + + @Nonnull + @Override + public final InstanceIdentifier getManagedDataObjectType() { + return instanceIdentifier; + } + + protected List readCurrent(final InstanceIdentifier 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(); + + readCurrentAttributes(id, builder); + + for (ChildVppReader> child : childReaders.values()) { + child.read(id, builder); + } + + for (ChildVppReader> child : augReaders.values()) { + child.read(id, builder); + } + + // Need to check whether anything was filled in to determine if data is present or not. + final D built = builder.build(); + return built.equals(emptyValue) ? Collections.emptyList() : Collections.singletonList(built); + } + + @Nonnull + @Override + @SuppressWarnings("unchecked") + public List read(@Nonnull final InstanceIdentifier id) { + // This is read for one of children, we need to read and then filter, not parent) + + // If this is target, just read + if (id.getTargetType().equals(getManagedDataObjectType().getTargetType())) { + return readCurrent((InstanceIdentifier) id); + } else { + return readSubtree(id); + } + } + + private List readSubtree(final InstanceIdentifier id) { + // Read only specific subtree + final Class next = VppReaderUtils.getNextId(id, getManagedDataObjectType()).getType(); + final ChildVppReader> vppReader = childReaders.get(next); + + if (vppReader != null) { + return vppReader.read(id); + } else { + // If there's no dedicated reader, use read current + final InstanceIdentifier currentId = VppReaderUtils.cutId(id, getManagedDataObjectType()); + final List current = readCurrent(currentId); + // then perform post-reading filtering (return only requested sub-node) + return current.isEmpty() ? current : filterSubtree(current, id, getManagedDataObjectType().getTargetType()) ; + } + } + + @SuppressWarnings("unchecked") + protected InstanceIdentifier getCurrentId(final InstanceIdentifier parentId) { + Preconditions.checkArgument(!parentId.contains(getManagedDataObjectType()), + "Unexpected InstanceIdentifier %s, already contains %s", parentId, getManagedDataObjectType()); + final InstanceIdentifier.PathArgument t = Iterables.getOnlyElement(getManagedDataObjectType().getPathArguments()); + return (InstanceIdentifier) InstanceIdentifier.create(Iterables.concat( + parentId.getPathArguments(), Collections.singleton(t))); + } + + protected abstract void readCurrentAttributes(final InstanceIdentifier id, B builder); + + protected abstract B getBuilder(InstanceIdentifier id); + + // TODO move filtering out of here into a dedicated Filter ifc + @Nonnull + private static List filterSubtree(@Nonnull final List built, + @Nonnull final InstanceIdentifier absolutPath, + @Nonnull final Class managedType) { + // TODO is there a better way than reflection ? + + List filtered = Lists.newArrayList(); + for (DataObject parent : built) { + final InstanceIdentifier.PathArgument nextId = + VppReaderUtils.getNextId(absolutPath, InstanceIdentifier.create(parent.getClass())); + + Optional method = VppReaderUtils.findMethodReflex(managedType, "get", + Collections.>emptyList(), nextId.getType()); + + if (method.isPresent()) { + filterSingle(filtered, parent, nextId, method); + } else { + // List child nodes + method = VppReaderUtils.findMethodReflex(managedType, + "get" + nextId.getType().getSimpleName(), Collections.>emptyList(), List.class); + + if (method.isPresent()) { + filterList(filtered, parent, nextId, method); + } else { + throw new IllegalStateException( + "Unable to filter " + nextId + " from " + parent + " getters not found using reflexion"); + } + } + } + + return filtered; + } + + @SuppressWarnings("unchecked") + private static void filterList(final List filtered, final DataObject parent, + final InstanceIdentifier.PathArgument nextId, final Optional method) { + final List invoke = (List)invoke(method.get(), nextId, parent); + + if (nextId instanceof InstanceIdentifier.IdentifiableItem) { + final Identifier key = ((InstanceIdentifier.IdentifiableItem) nextId).getKey(); + filtered.addAll(Collections2.filter(invoke, new Predicate() { + @Override + public boolean apply(@Nullable final DataObject input) { + final Optional keyGetter = + VppReaderUtils.findMethodReflex(nextId.getType(), "get", + Collections.>emptyList(), key.getClass()); + final Object actualKey; + actualKey = invoke(keyGetter.get(), nextId, input); + return key.equals(actualKey); + } + })); + } else { + filtered.addAll(invoke); + } + } + + private static void filterSingle(final List filtered, final DataObject parent, + final InstanceIdentifier.PathArgument nextId, final Optional method) { + filtered.add(nextId.getType().cast(invoke(method.get(), 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); + } + } + +} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/CompositeChildVppReader.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/CompositeChildVppReader.java new file mode 100644 index 000000000..7c66695c4 --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/CompositeChildVppReader.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.impl.trans.impl; + +import com.google.common.annotations.Beta; +import com.google.common.base.Optional; +import io.fd.honeycomb.v3po.impl.trans.ChildVppReader; +import io.fd.honeycomb.v3po.impl.trans.impl.spi.ChildVppReaderCustomizer; +import io.fd.honeycomb.v3po.impl.trans.util.VppReaderUtils; +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; + +@Beta +@ThreadSafe +public class CompositeChildVppReader> extends AbstractCompositeVppReader + implements ChildVppReader { + + private final ChildVppReaderCustomizer customizer; + + public CompositeChildVppReader(@Nonnull final Class managedDataObjectType, + @Nonnull final List>> childReaders, + @Nonnull final List>> augReaders, + @Nonnull final ChildVppReaderCustomizer customizer) { + super(managedDataObjectType, childReaders, augReaders); + this.customizer = customizer; + } + + public CompositeChildVppReader(@Nonnull final Class managedDataObjectType, + @Nonnull final List>> childReaders, + @Nonnull final ChildVppReaderCustomizer customizer) { + this(managedDataObjectType, childReaders, VppReaderUtils.emptyAugReaderList(), customizer); + } + + public CompositeChildVppReader(@Nonnull final Class managedDataObjectType, + @Nonnull final ChildVppReaderCustomizer customizer) { + this(managedDataObjectType, VppReaderUtils.emptyChildReaderList(), VppReaderUtils.emptyAugReaderList(), + customizer); + } + + @Override + public final void read(@Nonnull final InstanceIdentifier parentId, + @Nonnull final Builder parentBuilder) { + final Optional read = Optional.fromNullable(readCurrent(getCurrentId(parentId)).get(0)); + + if(read.isPresent()) { + customizer.merge(parentBuilder, read.get()); + } + } + + @Override + protected void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final B builder) { + customizer.readCurrentAttributes(builder); + } + + @Override + protected B getBuilder(@Nonnull final InstanceIdentifier id) { + return customizer.getBuilder(); + } + +} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/CompositeListVppReader.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/CompositeListVppReader.java new file mode 100644 index 000000000..f280fdb76 --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/CompositeListVppReader.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.impl.trans.impl; + +import com.google.common.annotations.Beta; +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; +import io.fd.honeycomb.v3po.impl.trans.ChildVppReader; +import io.fd.honeycomb.v3po.impl.trans.impl.spi.ListVppReaderCustomizer; +import io.fd.honeycomb.v3po.impl.trans.util.VppReaderUtils; +import java.util.Collections; +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; + +@Beta +@ThreadSafe +public final class CompositeListVppReader, K extends Identifier, B extends Builder> + extends AbstractCompositeVppReader implements ChildVppReader { + + private ListVppReaderCustomizer customizer; + + public CompositeListVppReader(@Nonnull final Class managedDataObjectType, + @Nonnull final List>> childReaders, + @Nonnull final List>> augReaders, + @Nonnull final ListVppReaderCustomizer customizer) { + super(managedDataObjectType, childReaders, augReaders); + this.customizer = customizer; + } + + public CompositeListVppReader(@Nonnull final Class managedDataObjectType, + @Nonnull final List>> childReaders, + @Nonnull final ListVppReaderCustomizer customizer) { + this(managedDataObjectType, childReaders, VppReaderUtils.emptyAugReaderList(), customizer); + } + + public CompositeListVppReader(@Nonnull final Class managedDataObjectType, + @Nonnull final ListVppReaderCustomizer customizer) { + this(managedDataObjectType, VppReaderUtils.emptyChildReaderList(), VppReaderUtils.emptyAugReaderList(), + customizer); + } + + @Override + protected List readCurrent(@Nonnull final InstanceIdentifier id) { + if(shouldReadAll(id)) { + return readList(id); + } + return super.readCurrent(id); + } + + @Override + public void read(@Nonnull final InstanceIdentifier id, + @Nonnull final Builder parentBuilder) { + final InstanceIdentifier currentId = getCurrentId(id); + + final List ifcs; + if (shouldReadAll(id)) { + ifcs = readList(currentId); + } else { + final Optional readSingle = Optional.fromNullable(read(id).get(0)); + final Optional read = readSingle.transform(new Function() { + @Override + public C apply(final DataObject input) { + Preconditions.checkArgument(getManagedDataObjectType().getTargetType().isAssignableFrom(input.getClass())); + return getManagedDataObjectType().getTargetType().cast(input); + } + }); + ifcs = read.isPresent() ? Collections.singletonList(read.get()) : Collections.emptyList(); + } + + customizer.merge(parentBuilder, ifcs); + } + + private List readList(@Nonnull final InstanceIdentifier id) { + Preconditions.checkArgument(id.getTargetType().equals(getManagedDataObjectType().getTargetType()), + "Id %s does not contain expected type %s", id, getManagedDataObjectType()); + + return Lists.transform(customizer.getAllIds(id), new Function, C>() { + @Override + public C apply(final InstanceIdentifier input) { + final List read = read(input); + Preconditions.checkState(read.size() == 1); + Preconditions.checkArgument(getManagedDataObjectType().getTargetType().isAssignableFrom(read.get(0).getClass())); + return getManagedDataObjectType().getTargetType().cast(read.get(0)); + } + }); + } + + private boolean shouldReadAll(@Nonnull final InstanceIdentifier id) { + final InstanceIdentifier instanceIdentifier = id.firstIdentifierOf(getManagedDataObjectType().getTargetType()); + return instanceIdentifier == null || instanceIdentifier.isWildcarded(); + } + + @Override + protected void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final B builder) { + customizer.readCurrentAttributes(id, builder); + } + + @Override + protected B getBuilder(@Nonnull final InstanceIdentifier id) { + return customizer.getBuilder(id.firstKeyOf(getManagedDataObjectType().getTargetType())); + } + +} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/CompositeRootVppReader.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/CompositeRootVppReader.java new file mode 100644 index 000000000..605f1b628 --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/CompositeRootVppReader.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.impl.trans.impl; + +import com.google.common.annotations.Beta; +import io.fd.honeycomb.v3po.impl.trans.ChildVppReader; +import io.fd.honeycomb.v3po.impl.trans.VppReader; +import io.fd.honeycomb.v3po.impl.trans.impl.spi.RootVppReaderCustomizer; +import io.fd.honeycomb.v3po.impl.trans.util.VppReaderUtils; +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; + +@Beta +@ThreadSafe +public final class CompositeRootVppReader> extends AbstractCompositeVppReader + implements VppReader { + + private final RootVppReaderCustomizer customizer; + + public CompositeRootVppReader(@Nonnull final Class managedDataObjectType, + @Nonnull final List>> childReaders, + @Nonnull final List>> childAugReaders, + @Nonnull final RootVppReaderCustomizer customizer) { + super(managedDataObjectType, childReaders, childAugReaders); + this.customizer = customizer; + } + + public CompositeRootVppReader(@Nonnull final Class managedDataObjectType, + @Nonnull final List>> childReaders, + @Nonnull final RootVppReaderCustomizer customizer) { + this(managedDataObjectType, childReaders, VppReaderUtils.emptyAugReaderList(), customizer); + } + + public CompositeRootVppReader(@Nonnull final Class managedDataObjectType, + @Nonnull final RootVppReaderCustomizer customizer) { + this(managedDataObjectType, VppReaderUtils.emptyChildReaderList(), VppReaderUtils.emptyAugReaderList(), + customizer); + } + + @Override + protected void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final B builder) { + customizer.readCurrentAttributes(builder); + } + + @Override + protected B getBuilder(@Nonnull final InstanceIdentifier id) { + // TODO instantiate builder from customizer(as is) or reflection ? + return customizer.getBuilder(); + } + +} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/spi/ChildVppReaderCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/spi/ChildVppReaderCustomizer.java new file mode 100644 index 000000000..7cf0b60f6 --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/spi/ChildVppReaderCustomizer.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.impl.trans.impl.spi; + +import com.google.common.annotations.Beta; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; + +@Beta +public interface ChildVppReaderCustomizer> extends + RootVppReaderCustomizer { + + // FIXME need to capture parent builder type, but that's a inconvenient + void merge(Builder parentBuilder, C readValue); +} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/spi/ListVppReaderCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/spi/ListVppReaderCustomizer.java new file mode 100644 index 000000000..855e8488d --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/spi/ListVppReaderCustomizer.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.impl.trans.impl.spi; + +import com.google.common.annotations.Beta; +import java.util.List; +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; + +@Beta +public interface ListVppReaderCustomizer, K extends Identifier, B extends Builder> { + + void readCurrentAttributes(final InstanceIdentifier id, B builder); + + B getBuilder(K id); + + List> getAllIds(InstanceIdentifier id); + + void merge(Builder builder, List currentBuilder); +} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/spi/RootVppReaderCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/spi/RootVppReaderCustomizer.java new file mode 100644 index 000000000..fe09220d2 --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/spi/RootVppReaderCustomizer.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.impl.trans.impl.spi; + +import com.google.common.annotations.Beta; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; + +@Beta +public interface RootVppReaderCustomizer> { + + B getBuilder(); + + void readCurrentAttributes(B builder); +} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/DelegatingReaderRegistry.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/DelegatingReaderRegistry.java new file mode 100644 index 000000000..0aeda896a --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/DelegatingReaderRegistry.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.impl.trans.util; + +import com.google.common.base.Function; +import com.google.common.base.Preconditions; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import io.fd.honeycomb.v3po.impl.trans.ReaderRegistry; +import io.fd.honeycomb.v3po.impl.trans.VppReader; +import java.util.List; +import java.util.Map; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public final class DelegatingReaderRegistry implements ReaderRegistry { + + private final Map, VppReader> rootReaders; + + public DelegatingReaderRegistry(@Nonnull final List> rootReaders) { + this.rootReaders = toMap(rootReaders); + } + + private static Map, VppReader> toMap( + final List> rootReaders) { + return Maps + .uniqueIndex(rootReaders, new Function, Class>() { + @Override + public Class apply(final VppReader input) { + return input.getManagedDataObjectType().getTargetType(); + } + }); + } + + @Override + @Nonnull + public List readAll() { + final List objects = Lists.newArrayListWithExpectedSize(rootReaders.size()); + for (VppReader rootReader : rootReaders.values()) { + final List read = rootReader.read(rootReader.getManagedDataObjectType()); + objects.addAll(read); + } + return objects; + } + + @Nonnull + @Override + public List read(@Nonnull final InstanceIdentifier id) { + final InstanceIdentifier.PathArgument first = Preconditions.checkNotNull( + Iterables.getFirst(id.getPathArguments(), null), "Empty id"); + final VppReader vppReader = rootReaders.get(first.getType()); + Preconditions.checkNotNull(vppReader, + "Unable to read %s. Missing reader. Current readers for: %s", id, rootReaders.keySet()); + return vppReader.read(id); + } + + @Nonnull + @Override + public InstanceIdentifier getManagedDataObjectType() { + throw new UnsupportedOperationException("Root registry has no type"); + } + +} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/NoopReaderCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/NoopReaderCustomizer.java new file mode 100644 index 000000000..050f7171f --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/NoopReaderCustomizer.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.impl.trans.util; + +import io.fd.honeycomb.v3po.impl.trans.impl.spi.RootVppReaderCustomizer; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; + +public abstract class NoopReaderCustomizer> implements RootVppReaderCustomizer { + + @Override + public void readCurrentAttributes(final B builder) { + // Noop + } +} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/ReflexiveChildReaderCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/ReflexiveChildReaderCustomizer.java new file mode 100644 index 000000000..28a44eb07 --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/ReflexiveChildReaderCustomizer.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.impl.trans.util; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import io.fd.honeycomb.v3po.impl.trans.impl.spi.ChildVppReaderCustomizer; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Collections; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; + +/** + * Might be slow ! + */ +public class ReflexiveChildReaderCustomizer> + extends ReflexiveRootReaderCustomizer + implements ChildVppReaderCustomizer { + + public ReflexiveChildReaderCustomizer(final Class builderClass) { + super(builderClass); + } + + // TODO Could be just a default implementation in interface (making this a mixin) + + @Override + public void merge(final Builder parentBuilder, final C readValue) { + final Optional method = + VppReaderUtils.findMethodReflex(parentBuilder.getClass(), "set", + Collections.>singletonList(readValue.getClass()), parentBuilder.getClass()); + + Preconditions.checkArgument(method.isPresent(), "Unable to set %s to %s", readValue, parentBuilder); + + try { + method.get().invoke(parentBuilder, readValue); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new IllegalArgumentException("Unable to set " + readValue + " to " + parentBuilder, e); + } + } + +} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/ReflexiveRootReaderCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/ReflexiveRootReaderCustomizer.java new file mode 100644 index 000000000..2a98bbe5b --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/ReflexiveRootReaderCustomizer.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.impl.trans.util; + +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; + +/** + * Might be slow ! + */ +public class ReflexiveRootReaderCustomizer> extends NoopReaderCustomizer { + + private final Class builderClass; + + public ReflexiveRootReaderCustomizer(final Class builderClass) { + this.builderClass = builderClass; + } + + @Override + public B getBuilder() { + try { + return builderClass.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + throw new IllegalStateException("Unable to instantiate " + builderClass, e); + } + } +} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/VppApiReaderCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/VppApiReaderCustomizer.java new file mode 100644 index 000000000..584c7823f --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/VppApiReaderCustomizer.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.impl.trans.util; + +import com.google.common.annotations.Beta; + +@Beta +public abstract class VppApiReaderCustomizer { + + private final org.openvpp.vppjapi.vppApi vppApi; + + public VppApiReaderCustomizer(final org.openvpp.vppjapi.vppApi vppApi) { + this.vppApi = vppApi; + } + + public org.openvpp.vppjapi.vppApi getVppApi() { + return vppApi; + } +} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/VppReaderUtils.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/VppReaderUtils.java new file mode 100644 index 000000000..07c54ae90 --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/VppReaderUtils.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.impl.trans.util; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; +import io.fd.honeycomb.v3po.impl.trans.ChildVppReader; +import java.lang.reflect.Method; +import java.util.Collections; +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.Identifiable; +import org.opendaylight.yangtools.yang.binding.Identifier; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public final class VppReaderUtils { + + private VppReaderUtils() {} + + /** + * Find next item in ID after provided type + */ + @Nonnull + public static InstanceIdentifier.PathArgument getNextId(@Nonnull final InstanceIdentifier id, + @Nonnull final InstanceIdentifier type) { + // TODO this is inefficient(maybe, depending on actual Iterable type) + final Iterable pathArguments = id.getPathArguments(); + final int i = Iterables.indexOf(pathArguments, new Predicate() { + @Override + public boolean apply(final InstanceIdentifier.PathArgument input) { + return input.getType().isAssignableFrom(type.getTargetType()); + } + }); + Preconditions.checkArgument(i >= 0, "Unable to find %s type in %s", type.getTargetType(), id); + return Iterables.get(pathArguments, i + 1); + } + + public static List>> emptyChildReaderList() { + return Collections.emptyList(); + } + + public static List>> emptyAugReaderList() { + return Collections.emptyList(); + } + + public static List>> singletonAugReaderList( + ChildVppReader> item) { + return Collections.>>singletonList(item); + } + + public static List>> singletonChildReaderList( + ChildVppReader> item) { + return Collections.>>singletonList(item); + } + + /** + * Replace last item in ID with a provided IdentifiableItem of the same type + */ + @SuppressWarnings("unchecked") + @Nonnull + public static , K extends Identifier> InstanceIdentifier getCurrentId( + @Nonnull final InstanceIdentifier id, final InstanceIdentifier.IdentifiableItem currentBdItem) { + + final Iterable pathArguments = id.getPathArguments(); + final Iterable withoutCurrent = + Iterables.limit(pathArguments, Iterables.size(pathArguments) - 1); + final Iterable concat = + Iterables.concat(withoutCurrent, Collections.singleton(currentBdItem)); + return (InstanceIdentifier) InstanceIdentifier.create(concat); + } + + /** + * Create IdentifiableItem from target type of provided ID with provided key + */ + @Nonnull + public static , K extends Identifier> InstanceIdentifier.IdentifiableItem getCurrentIdItem( + @Nonnull final InstanceIdentifier id, final K key) { + return new InstanceIdentifier.IdentifiableItem<>(id.getTargetType(), key); + } + + /** + * Trim InstanceIdentifier at indexOf(type) + */ + @SuppressWarnings("unchecked") + @Nonnull + public static InstanceIdentifier cutId(@Nonnull final InstanceIdentifier id, + @Nonnull final InstanceIdentifier type) { + final Iterable pathArguments = id.getPathArguments(); + final int i = Iterables.indexOf(pathArguments, new Predicate() { + @Override + public boolean apply(final InstanceIdentifier.PathArgument input) { + return input.getType().equals(type.getTargetType()); + } + }); + Preconditions.checkArgument(i >= 0, "ID %s does not contain %s", id, type); + return (InstanceIdentifier) InstanceIdentifier.create(Iterables.limit(pathArguments, i + 1)); + } + + /** + * Find a specific method using reflection + */ + @Nonnull + public static Optional findMethodReflex(@Nonnull final Class managedType, + @Nonnull final String prefix, + @Nonnull final List> paramTypes, + @Nonnull final Class retType) { + top: + for (Method method : managedType.getMethods()) { + if (!method.getName().toLowerCase().startsWith(prefix.toLowerCase())) { + continue; + } + + final Class[] parameterTypes = method.getParameterTypes(); + if (parameterTypes.length != paramTypes.size()) { + continue; + } + + for (int i = 0; i < parameterTypes.length; i++) { + if (!parameterTypes[i].isAssignableFrom(paramTypes.get(i))) { + continue top; + } + } + + if (!method.getReturnType().equals(retType)) { + continue; + } + + return Optional.of(method); + } + + return Optional.absent(); + } +} -- cgit 1.2.3-korg