Initial implementation of VPP readers
authorMaros Marsalek <[email protected]>
Thu, 17 Mar 2016 08:56:42 +0000 (09:56 +0100)
committerMaros Marsalek <[email protected]>
Tue, 22 Mar 2016 09:46:43 +0000 (09:46 +0000)
Composite, recursive and extensible readers

Change-Id: I86084fa0c4127bddd87f68ff6a48b79c27a9589c
Signed-off-by: Maros Marsalek <[email protected]>
14 files changed:
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/ChildVppReader.java
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/AbstractCompositeVppReader.java [new file with mode: 0644]
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/CompositeChildVppReader.java [new file with mode: 0644]
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/CompositeListVppReader.java [new file with mode: 0644]
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/CompositeRootVppReader.java [new file with mode: 0644]
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/spi/ChildVppReaderCustomizer.java [new file with mode: 0644]
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/spi/ListVppReaderCustomizer.java [new file with mode: 0644]
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/impl/spi/RootVppReaderCustomizer.java [new file with mode: 0644]
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/DelegatingReaderRegistry.java [new file with mode: 0644]
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/NoopReaderCustomizer.java [new file with mode: 0644]
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/ReflexiveChildReaderCustomizer.java [new file with mode: 0644]
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/ReflexiveRootReaderCustomizer.java [new file with mode: 0644]
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/VppApiReaderCustomizer.java [new file with mode: 0644]
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/VppReaderUtils.java [new file with mode: 0644]

index 5d57c60..8f2a1ce 100644 (file)
@@ -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 (file)
index 0000000..566c4fc
--- /dev/null
@@ -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 (file)
index 0000000..7c66695
--- /dev/null
@@ -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 (file)
index 0000000..f280fdb
--- /dev/null
@@ -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 (file)
index 0000000..605f1b6
--- /dev/null
@@ -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 (file)
index 0000000..7cf0b60
--- /dev/null
@@ -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 (file)
index 0000000..855e848
--- /dev/null
@@ -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 (file)
index 0000000..fe09220
--- /dev/null
@@ -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 (file)
index 0000000..0aeda89
--- /dev/null
@@ -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 (file)
index 0000000..050f717
--- /dev/null
@@ -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 (file)
index 0000000..28a44eb
--- /dev/null
@@ -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 (file)
index 0000000..2a98bbe
--- /dev/null
@@ -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 (file)
index 0000000..584c782
--- /dev/null
@@ -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 (file)
index 0000000..07c54ae
--- /dev/null
@@ -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();
+    }
+}