diff options
author | Maros Marsalek <mmarsale@cisco.com> | 2016-03-17 09:56:42 +0100 |
---|---|---|
committer | Maros Marsalek <mmarsale@cisco.com> | 2016-03-22 09:46:43 +0000 |
commit | b7ddb9bb91dd0fd886a9e4dde7c9d73d06879bf6 (patch) | |
tree | 39a64fbc82d547835c10a031cbe358cd1c17a3f0 /v3po/impl | |
parent | a2936b555922edc9d7d7c6dedca4447994656be2 (diff) |
Initial implementation of VPP readers
Composite, recursive and extensible readers
Change-Id: I86084fa0c4127bddd87f68ff6a48b79c27a9589c
Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
Diffstat (limited to 'v3po/impl')
14 files changed, 997 insertions, 0 deletions
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<D extends DataObject, B extends Builder<D>> implements VppReader<D> { + + // TODO add debug + trace logs here and there + + private final Map<Class<? extends DataObject>, ChildVppReader<? extends ChildOf<D>>> childReaders; + private final Map<Class<? extends DataObject>, ChildVppReader<? extends Augmentation<D>>> augReaders; + private final InstanceIdentifier<D> instanceIdentifier; + + public AbstractCompositeVppReader( + final Class<D> managedDataObjectType, + final List<ChildVppReader<? extends ChildOf<D>>> childReaders, + final List<ChildVppReader<? extends Augmentation<D>>> augReaders) { + this.childReaders = childReadersToMap(childReaders); + this.augReaders = augReadersToMap(augReaders); + this.instanceIdentifier = InstanceIdentifier.create(managedDataObjectType); + } + + protected final Map<Class<? extends DataObject>, ChildVppReader<? extends ChildOf<D>>> childReadersToMap( + final List<ChildVppReader<? extends ChildOf<D>>> childReaders) { + final LinkedHashMap<Class<? extends DataObject>, ChildVppReader<? extends ChildOf<D>>> + classVppReaderLinkedHashMap = new LinkedHashMap<>(); + + for (ChildVppReader<? extends ChildOf<D>> 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<Class<? extends DataObject>, ChildVppReader<? extends Augmentation<D>>> augReadersToMap( + final List<ChildVppReader<? extends Augmentation<D>>> childReaders) { + final LinkedHashMap<Class<? extends DataObject>, ChildVppReader<? extends Augmentation<D>>> + classVppReaderLinkedHashMap = new LinkedHashMap<>(); + + for (ChildVppReader<? extends DataObject> childReader : childReaders) { + Preconditions.checkArgument( + classVppReaderLinkedHashMap.put(childReader.getManagedDataObjectType().getTargetType(), + (ChildVppReader<? extends Augmentation<D>>) childReader) == null, + "Duplicate (%s) child readers detected under: %s", childReader.getManagedDataObjectType(), + getManagedDataObjectType()); + } + return classVppReaderLinkedHashMap; + } + + @Nonnull + @Override + public final InstanceIdentifier<D> getManagedDataObjectType() { + return instanceIdentifier; + } + + protected List<D> readCurrent(final InstanceIdentifier<D> 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<? extends ChildOf<D>> child : childReaders.values()) { + child.read(id, builder); + } + + for (ChildVppReader<? extends Augmentation<D>> 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.<D>emptyList() : Collections.singletonList(built); + } + + @Nonnull + @Override + @SuppressWarnings("unchecked") + public List<? extends DataObject> read(@Nonnull final InstanceIdentifier<? extends DataObject> 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<D>) id); + } else { + return readSubtree(id); + } + } + + private List<? extends DataObject> readSubtree(final InstanceIdentifier<? extends DataObject> id) { + // Read only specific subtree + final Class<? extends DataObject> next = VppReaderUtils.getNextId(id, getManagedDataObjectType()).getType(); + final ChildVppReader<? extends ChildOf<D>> vppReader = childReaders.get(next); + + if (vppReader != null) { + return vppReader.read(id); + } else { + // If there's no dedicated reader, use read current + final InstanceIdentifier<D> currentId = VppReaderUtils.cutId(id, getManagedDataObjectType()); + final List<D> 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<D> getCurrentId(final InstanceIdentifier<? extends DataObject> parentId) { + Preconditions.checkArgument(!parentId.contains(getManagedDataObjectType()), + "Unexpected InstanceIdentifier %s, already contains %s", parentId, getManagedDataObjectType()); + final InstanceIdentifier.PathArgument t = Iterables.getOnlyElement(getManagedDataObjectType().getPathArguments()); + return (InstanceIdentifier<D>) InstanceIdentifier.create(Iterables.concat( + parentId.getPathArguments(), Collections.singleton(t))); + } + + protected abstract void readCurrentAttributes(final InstanceIdentifier<D> id, B builder); + + protected abstract B getBuilder(InstanceIdentifier<? extends DataObject> id); + + // TODO move filtering out of here into a dedicated Filter ifc + @Nonnull + private static List<? extends DataObject> filterSubtree(@Nonnull final List<? extends DataObject> built, + @Nonnull final InstanceIdentifier<? extends DataObject> absolutPath, + @Nonnull final Class<?> managedType) { + // TODO is there a better way than reflection ? + + List<DataObject> filtered = Lists.newArrayList(); + for (DataObject parent : built) { + final InstanceIdentifier.PathArgument nextId = + VppReaderUtils.getNextId(absolutPath, InstanceIdentifier.create(parent.getClass())); + + Optional<Method> method = VppReaderUtils.findMethodReflex(managedType, "get", + Collections.<Class<?>>emptyList(), nextId.getType()); + + if (method.isPresent()) { + filterSingle(filtered, parent, nextId, method); + } else { + // List child nodes + method = VppReaderUtils.findMethodReflex(managedType, + "get" + nextId.getType().getSimpleName(), Collections.<Class<?>>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<DataObject> filtered, final DataObject parent, + final InstanceIdentifier.PathArgument nextId, final Optional<Method> method) { + final List<? extends DataObject> invoke = (List<? extends DataObject>)invoke(method.get(), nextId, parent); + + if (nextId instanceof InstanceIdentifier.IdentifiableItem<?, ?>) { + final Identifier key = ((InstanceIdentifier.IdentifiableItem) nextId).getKey(); + filtered.addAll(Collections2.filter(invoke, new Predicate<DataObject>() { + @Override + public boolean apply(@Nullable final DataObject input) { + final Optional<Method> keyGetter = + VppReaderUtils.findMethodReflex(nextId.getType(), "get", + Collections.<Class<?>>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<DataObject> filtered, final DataObject parent, + final InstanceIdentifier.PathArgument nextId, final Optional<Method> 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<C extends DataObject, B extends Builder<C>> extends AbstractCompositeVppReader<C, B> + implements ChildVppReader<C> { + + private final ChildVppReaderCustomizer<C, B> customizer; + + public CompositeChildVppReader(@Nonnull final Class<C> managedDataObjectType, + @Nonnull final List<ChildVppReader<? extends ChildOf<C>>> childReaders, + @Nonnull final List<ChildVppReader<? extends Augmentation<C>>> augReaders, + @Nonnull final ChildVppReaderCustomizer<C, B> customizer) { + super(managedDataObjectType, childReaders, augReaders); + this.customizer = customizer; + } + + public CompositeChildVppReader(@Nonnull final Class<C> managedDataObjectType, + @Nonnull final List<ChildVppReader<? extends ChildOf<C>>> childReaders, + @Nonnull final ChildVppReaderCustomizer<C, B> customizer) { + this(managedDataObjectType, childReaders, VppReaderUtils.<C>emptyAugReaderList(), customizer); + } + + public CompositeChildVppReader(@Nonnull final Class<C> managedDataObjectType, + @Nonnull final ChildVppReaderCustomizer<C, B> customizer) { + this(managedDataObjectType, VppReaderUtils.<C>emptyChildReaderList(), VppReaderUtils.<C>emptyAugReaderList(), + customizer); + } + + @Override + public final void read(@Nonnull final InstanceIdentifier<? extends DataObject> parentId, + @Nonnull final Builder<? extends DataObject> parentBuilder) { + final Optional<C> read = Optional.fromNullable(readCurrent(getCurrentId(parentId)).get(0)); + + if(read.isPresent()) { + customizer.merge(parentBuilder, read.get()); + } + } + + @Override + protected void readCurrentAttributes(@Nonnull final InstanceIdentifier<C> id, @Nonnull final B builder) { + customizer.readCurrentAttributes(builder); + } + + @Override + protected B getBuilder(@Nonnull final InstanceIdentifier<? extends DataObject> 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<C extends DataObject & Identifiable<K>, K extends Identifier<C>, B extends Builder<C>> + extends AbstractCompositeVppReader<C, B> implements ChildVppReader<C> { + + private ListVppReaderCustomizer<C, K, B> customizer; + + public CompositeListVppReader(@Nonnull final Class<C> managedDataObjectType, + @Nonnull final List<ChildVppReader<? extends ChildOf<C>>> childReaders, + @Nonnull final List<ChildVppReader<? extends Augmentation<C>>> augReaders, + @Nonnull final ListVppReaderCustomizer<C, K, B> customizer) { + super(managedDataObjectType, childReaders, augReaders); + this.customizer = customizer; + } + + public CompositeListVppReader(@Nonnull final Class<C> managedDataObjectType, + @Nonnull final List<ChildVppReader<? extends ChildOf<C>>> childReaders, + @Nonnull final ListVppReaderCustomizer<C, K, B> customizer) { + this(managedDataObjectType, childReaders, VppReaderUtils.<C>emptyAugReaderList(), customizer); + } + + public CompositeListVppReader(@Nonnull final Class<C> managedDataObjectType, + @Nonnull final ListVppReaderCustomizer<C, K, B> customizer) { + this(managedDataObjectType, VppReaderUtils.<C>emptyChildReaderList(), VppReaderUtils.<C>emptyAugReaderList(), + customizer); + } + + @Override + protected List<C> readCurrent(@Nonnull final InstanceIdentifier<C> id) { + if(shouldReadAll(id)) { + return readList(id); + } + return super.readCurrent(id); + } + + @Override + public void read(@Nonnull final InstanceIdentifier<? extends DataObject> id, + @Nonnull final Builder<? extends DataObject> parentBuilder) { + final InstanceIdentifier<C> currentId = getCurrentId(id); + + final List<C> ifcs; + if (shouldReadAll(id)) { + ifcs = readList(currentId); + } else { + final Optional<? extends DataObject> readSingle = Optional.fromNullable(read(id).get(0)); + final Optional<C> read = readSingle.transform(new Function<DataObject, C>() { + @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.<C>emptyList(); + } + + customizer.merge(parentBuilder, ifcs); + } + + private List<C> readList(@Nonnull final InstanceIdentifier<C> 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<InstanceIdentifier<? extends DataObject>, C>() { + @Override + public C apply(final InstanceIdentifier<? extends DataObject> input) { + final List<? extends DataObject> 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<? extends DataObject> id) { + final InstanceIdentifier instanceIdentifier = id.firstIdentifierOf(getManagedDataObjectType().getTargetType()); + return instanceIdentifier == null || instanceIdentifier.isWildcarded(); + } + + @Override + protected void readCurrentAttributes(@Nonnull final InstanceIdentifier<C> id, @Nonnull final B builder) { + customizer.readCurrentAttributes(id, builder); + } + + @Override + protected B getBuilder(@Nonnull final InstanceIdentifier<? extends DataObject> 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<C extends DataObject, B extends Builder<C>> extends AbstractCompositeVppReader<C, B> + implements VppReader<C> { + + private final RootVppReaderCustomizer<C, B> customizer; + + public CompositeRootVppReader(@Nonnull final Class<C> managedDataObjectType, + @Nonnull final List<ChildVppReader<? extends ChildOf<C>>> childReaders, + @Nonnull final List<ChildVppReader<? extends Augmentation<C>>> childAugReaders, + @Nonnull final RootVppReaderCustomizer<C, B> customizer) { + super(managedDataObjectType, childReaders, childAugReaders); + this.customizer = customizer; + } + + public CompositeRootVppReader(@Nonnull final Class<C> managedDataObjectType, + @Nonnull final List<ChildVppReader<? extends ChildOf<C>>> childReaders, + @Nonnull final RootVppReaderCustomizer<C, B> customizer) { + this(managedDataObjectType, childReaders, VppReaderUtils.<C>emptyAugReaderList(), customizer); + } + + public CompositeRootVppReader(@Nonnull final Class<C> managedDataObjectType, + @Nonnull final RootVppReaderCustomizer<C, B> customizer) { + this(managedDataObjectType, VppReaderUtils.<C>emptyChildReaderList(), VppReaderUtils.<C>emptyAugReaderList(), + customizer); + } + + @Override + protected void readCurrentAttributes(@Nonnull final InstanceIdentifier<C> id, @Nonnull final B builder) { + customizer.readCurrentAttributes(builder); + } + + @Override + protected B getBuilder(@Nonnull final InstanceIdentifier<? extends DataObject> 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<C extends DataObject, B extends Builder<C>> extends + RootVppReaderCustomizer<C, B> { + + // FIXME need to capture parent builder type, but that's a inconvenient + void merge(Builder<? extends DataObject> 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<C extends DataObject & Identifiable<K>, K extends Identifier<C>, B extends Builder<C>> { + + void readCurrentAttributes(final InstanceIdentifier<C> id, B builder); + + B getBuilder(K id); + + List<InstanceIdentifier<C>> getAllIds(InstanceIdentifier<C> id); + + void merge(Builder<?> builder, List<C> 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<C extends DataObject, B extends Builder<C>> { + + 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<Class<? extends DataObject>, VppReader<? extends DataObject>> rootReaders; + + public DelegatingReaderRegistry(@Nonnull final List<VppReader<? extends DataObject>> rootReaders) { + this.rootReaders = toMap(rootReaders); + } + + private static Map<Class<? extends DataObject>, VppReader<? extends DataObject>> toMap( + final List<VppReader<? extends DataObject>> rootReaders) { + return Maps + .uniqueIndex(rootReaders, new Function<VppReader<? extends DataObject>, Class<? extends DataObject>>() { + @Override + public Class<? extends DataObject> apply(final VppReader<? extends DataObject> input) { + return input.getManagedDataObjectType().getTargetType(); + } + }); + } + + @Override + @Nonnull + public List<? extends DataObject> readAll() { + final List<DataObject> objects = Lists.newArrayListWithExpectedSize(rootReaders.size()); + for (VppReader<? extends DataObject> rootReader : rootReaders.values()) { + final List<? extends DataObject> read = rootReader.read(rootReader.getManagedDataObjectType()); + objects.addAll(read); + } + return objects; + } + + @Nonnull + @Override + public List<? extends DataObject> read(@Nonnull final InstanceIdentifier<? extends DataObject> id) { + final InstanceIdentifier.PathArgument first = Preconditions.checkNotNull( + Iterables.getFirst(id.getPathArguments(), null), "Empty id"); + final VppReader<? extends DataObject> 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<DataObject> 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<C extends DataObject, B extends Builder<C>> implements RootVppReaderCustomizer<C, B> { + + @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<C extends DataObject, B extends Builder<C>> + extends ReflexiveRootReaderCustomizer<C, B> + implements ChildVppReaderCustomizer<C,B> { + + public ReflexiveChildReaderCustomizer(final Class<B> builderClass) { + super(builderClass); + } + + // TODO Could be just a default implementation in interface (making this a mixin) + + @Override + public void merge(final Builder<? extends DataObject> parentBuilder, final C readValue) { + final Optional<Method> method = + VppReaderUtils.findMethodReflex(parentBuilder.getClass(), "set", + Collections.<Class<?>>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<C extends DataObject, B extends Builder<C>> extends NoopReaderCustomizer<C, B> { + + private final Class<B> builderClass; + + public ReflexiveRootReaderCustomizer(final Class<B> 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<? extends DataObject> id, + @Nonnull final InstanceIdentifier<? extends DataObject> type) { + // TODO this is inefficient(maybe, depending on actual Iterable type) + final Iterable<InstanceIdentifier.PathArgument> pathArguments = id.getPathArguments(); + final int i = Iterables.indexOf(pathArguments, new Predicate<InstanceIdentifier.PathArgument>() { + @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 <T> List<ChildVppReader<? extends ChildOf<T>>> emptyChildReaderList() { + return Collections.emptyList(); + } + + public static <T> List<ChildVppReader<? extends Augmentation<T>>> emptyAugReaderList() { + return Collections.emptyList(); + } + + public static <T> List<ChildVppReader<? extends Augmentation<T>>> singletonAugReaderList( + ChildVppReader<? extends Augmentation<T>> item) { + return Collections.<ChildVppReader<? extends Augmentation<T>>>singletonList(item); + } + + public static <T> List<ChildVppReader<? extends ChildOf<T>>> singletonChildReaderList( + ChildVppReader<? extends ChildOf<T>> item) { + return Collections.<ChildVppReader<? extends ChildOf<T>>>singletonList(item); + } + + /** + * Replace last item in ID with a provided IdentifiableItem of the same type + */ + @SuppressWarnings("unchecked") + @Nonnull + public static <D extends DataObject & Identifiable<K>, K extends Identifier<D>> InstanceIdentifier<D> getCurrentId( + @Nonnull final InstanceIdentifier<D> id, final InstanceIdentifier.IdentifiableItem<D, K> currentBdItem) { + + final Iterable<InstanceIdentifier.PathArgument> pathArguments = id.getPathArguments(); + final Iterable<InstanceIdentifier.PathArgument> withoutCurrent = + Iterables.limit(pathArguments, Iterables.size(pathArguments) - 1); + final Iterable<InstanceIdentifier.PathArgument> concat = + Iterables.concat(withoutCurrent, Collections.singleton(currentBdItem)); + return (InstanceIdentifier<D>) InstanceIdentifier.create(concat); + } + + /** + * Create IdentifiableItem from target type of provided ID with provided key + */ + @Nonnull + public static <D extends DataObject & Identifiable<K>, K extends Identifier<D>> InstanceIdentifier.IdentifiableItem<D, K> getCurrentIdItem( + @Nonnull final InstanceIdentifier<D> id, final K key) { + return new InstanceIdentifier.IdentifiableItem<>(id.getTargetType(), key); + } + + /** + * Trim InstanceIdentifier at indexOf(type) + */ + @SuppressWarnings("unchecked") + @Nonnull + public static <D extends DataObject> InstanceIdentifier<D> cutId(@Nonnull final InstanceIdentifier<? extends DataObject> id, + @Nonnull final InstanceIdentifier<D> type) { + final Iterable<InstanceIdentifier.PathArgument> pathArguments = id.getPathArguments(); + final int i = Iterables.indexOf(pathArguments, new Predicate<InstanceIdentifier.PathArgument>() { + @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<D>) InstanceIdentifier.create(Iterables.limit(pathArguments, i + 1)); + } + + /** + * Find a specific method using reflection + */ + @Nonnull + public static Optional<Method> findMethodReflex(@Nonnull final Class<?> managedType, + @Nonnull final String prefix, + @Nonnull final List<Class<?>> 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(); + } +} |