summaryrefslogtreecommitdiffstats
path: root/infra/test-utils/test-tools/src/main/java
diff options
context:
space:
mode:
authorJan Srnicek <jsrnicek@cisco.com>2017-02-10 08:55:55 +0100
committerMarek Gradzki <mgradzki@cisco.com>2017-02-10 08:53:27 +0000
commitde55d1e7c1fa5517ee6eabcd3fa23e5b5136d64b (patch)
tree057cd5f38c18da91852c2d79168ae41c0c6bfed6 /infra/test-utils/test-tools/src/main/java
parent8450b69800c827ba221351eb0c374fcbd9146593 (diff)
HONEYCOMB-334 - List entry injection for yang data
Major changes - mechanism to inject list entries by key - provided processor registry to hide explicit implementations Minor changes - general refactoring Test cases - list in root of model - list under container - list under nested container - list in augmentation Change-Id: I9abe1ce5f9176c132ad88627b135516574e40e06 Signed-off-by: Jan Srnicek <jsrnicek@cisco.com>
Diffstat (limited to 'infra/test-utils/test-tools/src/main/java')
-rw-r--r--infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/AbstractYangContextHolder.java42
-rw-r--r--infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/ContainerNodeDataProcessor.java89
-rw-r--r--infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/HoneycombTestRunner.java47
-rw-r--r--infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/ListNodeDataProcessor.java84
-rw-r--r--infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/YangContextProducer.java16
-rw-r--r--infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/YangDataProcessor.java129
-rw-r--r--infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/YangDataProcessorRegistry.java68
-rw-r--r--infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/annotations/InjectablesProcessor.java33
-rw-r--r--infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/factories/ChildNodeDataFactory.java77
-rw-r--r--infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/factories/RootNodeDataFactory.java42
-rw-r--r--infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/factories/YangDataFactory.java109
11 files changed, 448 insertions, 288 deletions
diff --git a/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/AbstractYangContextHolder.java b/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/AbstractYangContextHolder.java
new file mode 100644
index 000000000..93360d25a
--- /dev/null
+++ b/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/AbstractYangContextHolder.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017 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.test.tools;
+
+import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+import javax.annotation.Nonnull;
+
+abstract class AbstractYangContextHolder {
+
+ private final SchemaContext schemaContext;
+ private final BindingToNormalizedNodeCodec serializer;
+
+ AbstractYangContextHolder(@Nonnull final SchemaContext schemaContext,
+ @Nonnull final BindingToNormalizedNodeCodec serializer){
+ this.schemaContext=schemaContext;
+ this.serializer=serializer;
+ }
+
+ SchemaContext schemaContext() {
+ return schemaContext;
+ }
+
+ BindingToNormalizedNodeCodec serializer() {
+ return serializer;
+ }
+}
diff --git a/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/ContainerNodeDataProcessor.java b/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/ContainerNodeDataProcessor.java
new file mode 100644
index 000000000..089bb43cd
--- /dev/null
+++ b/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/ContainerNodeDataProcessor.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2017 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.test.tools;
+
+import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.Nonnull;
+import java.io.InputStream;
+
+import static com.google.common.base.Preconditions.checkState;
+import static io.fd.honeycomb.translate.util.JsonUtils.readContainerEntryJson;
+import static io.fd.honeycomb.translate.util.JsonUtils.readJson;
+
+final class ContainerNodeDataProcessor extends AbstractYangContextHolder implements YangDataProcessor {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ContainerNodeDataProcessor.class);
+
+ ContainerNodeDataProcessor(@Nonnull SchemaContext schemaContext, @Nonnull BindingToNormalizedNodeCodec serializer) {
+ super(schemaContext, serializer);
+ }
+
+ @Nonnull
+ @Override
+ public DataObject getNodeData(@Nonnull YangInstanceIdentifier yangInstanceIdentifier, @Nonnull String resourcePath) {
+
+ final InputStream resourceStream = this.getClass().getResourceAsStream(resourcePath);
+ final YangInstanceIdentifier nodeParent = getNodeParent(yangInstanceIdentifier).orElse(null);
+ final SchemaNode parentSchema = parentSchema(schemaContext(), serializer(), nodeParent, () -> LOG);
+
+ // to be able to process containers in root of model
+ if (isRoot(yangInstanceIdentifier)) {
+ // if root ,read as root
+ final ContainerNode data = readJson(schemaContext(), resourceStream, parentSchema);
+ checkState(data.getValue().size() == 1, "Single root expected in %s", resourcePath);
+ //then extracts first child
+ final QName rootNodeType = data.getValue().iterator().next().getNodeType();
+ final YangInstanceIdentifier realIdentifier = YangInstanceIdentifier.of(rootNodeType);
+ return nodeBinding(serializer(), realIdentifier, data).getValue();
+ } else {
+ // reads just container
+ final YangInstanceIdentifier.NodeIdentifier nodeIdentifier = containerNodeIdentifier(yangInstanceIdentifier);
+ final ContainerNode data = readContainerEntryJson(schemaContext(), resourceStream, parentSchema, nodeIdentifier);
+ return nodeBinding(serializer(), yangInstanceIdentifier, data.getValue().iterator().next()).getValue();
+ }
+ }
+
+ @Override
+ public boolean canProcess(@Nonnull YangInstanceIdentifier identifier) {
+ return isRoot(identifier) ||
+ isContainer(identifierBinding(serializer(), identifier).getTargetType());
+ }
+
+ private static boolean isContainer(final Class targetType) {
+ return !Identifiable.class.isAssignableFrom(targetType)
+ && !Augmentation.class.isAssignableFrom(targetType);
+ }
+
+ private static YangInstanceIdentifier.NodeIdentifier containerNodeIdentifier(@Nonnull final YangInstanceIdentifier nodeIdentifier) {
+ return java.util.Optional.ofNullable(nodeIdentifier.getLastPathArgument())
+ .filter(pathArgument -> pathArgument instanceof YangInstanceIdentifier.NodeIdentifier)
+ .map(YangInstanceIdentifier.NodeIdentifier.class::cast)
+ .orElseThrow(() -> new IllegalArgumentException(
+ String.format("Unable to create container node identifier from %s", nodeIdentifier)));
+ }
+}
diff --git a/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/HoneycombTestRunner.java b/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/HoneycombTestRunner.java
index 906a5fc87..0f8b1b9af 100644
--- a/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/HoneycombTestRunner.java
+++ b/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/HoneycombTestRunner.java
@@ -17,29 +17,23 @@
package io.fd.honeycomb.test.tools;
import io.fd.honeycomb.test.tools.annotations.InjectablesProcessor;
-import io.fd.honeycomb.test.tools.factories.ChildNodeDataFactory;
-import io.fd.honeycomb.test.tools.factories.RootNodeDataFactory;
-import java.io.IOException;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Parameter;
-import java.util.Arrays;
-import java.util.List;
-import java.util.stream.Collectors;
-import javax.annotation.Nullable;
-import org.apache.commons.lang3.StringUtils;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.Statement;
import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
import org.opendaylight.yangtools.yang.data.util.AbstractModuleStringInstanceIdentifierCodec;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Parameter;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
public class HoneycombTestRunner extends BlockJUnit4ClassRunner implements YangContextProducer, InjectablesProcessor {
private static final Logger LOG = LoggerFactory.getLogger(HoneycombTestRunner.class);
@@ -48,8 +42,7 @@ public class HoneycombTestRunner extends BlockJUnit4ClassRunner implements YangC
private BindingToNormalizedNodeCodec serializer;
private AbstractModuleStringInstanceIdentifierCodec iidParser;
- private ChildNodeDataFactory childNodeDataFactory;
- private RootNodeDataFactory rootNodeDataFactory;
+ private YangDataProcessorRegistry processorRegistry;
public HoneycombTestRunner(final Class<?> klass) throws InitializationError {
super(klass);
@@ -64,12 +57,11 @@ public class HoneycombTestRunner extends BlockJUnit4ClassRunner implements YangC
final ModuleInfoBackedContext ctx = getCheckedModuleInfoContext(test);
schemaContext = ctx.getSchemaContext();
// Create serializer from it in order to later transform NormalizedNodes into BA
- serializer = createSerializer(ctx, schemaContext);
+ serializer = createSerializer(ctx);
// Create InstanceIdentifier Codec in order to later transform string represented IID into YangInstanceIdentifier
iidParser = getIIDCodec(ctx);
- childNodeDataFactory = new ChildNodeDataFactory(schemaContext, serializer, iidParser);
- rootNodeDataFactory = new RootNodeDataFactory(schemaContext, serializer, iidParser);
+ processorRegistry = YangDataProcessorRegistry.create(schemaContext, serializer);
injectFields(test);
return test;
@@ -83,7 +75,7 @@ public class HoneycombTestRunner extends BlockJUnit4ClassRunner implements YangC
/**
* Allows method parameters injection
- * */
+ */
@Override
protected Statement methodInvoker(final FrameworkMethod method, final Object test) {
return new InjectableTestMethodInvoker(method, test, Arrays.stream(method.getMethod().getParameters())
@@ -94,7 +86,7 @@ public class HoneycombTestRunner extends BlockJUnit4ClassRunner implements YangC
private Object injectValueOrNull(final Parameter parameter) {
return isInjectable(parameter)
- ? getData(resourcePath(parameter), instanceIdentifier(parameter).orNull(), parameter.getType())
+ ? processorRegistry.getNodeData(instanceIdentifier(iidParser, parameter), resourcePath(parameter))
: null;
}
@@ -107,22 +99,7 @@ public class HoneycombTestRunner extends BlockJUnit4ClassRunner implements YangC
injectableFields(testInstance.getClass()).forEach(field -> {
LOG.debug("Processing field {}", field);
injectField(field, testInstance,
- getData(resourcePath(field), instanceIdentifier(field).orNull(), field.getType()));
+ processorRegistry.getNodeData(instanceIdentifier(iidParser, field), resourcePath(field)));
});
}
-
- private DataObject getData(final String resourcePath, @Nullable final String identifier,
- final Class<?> injectedType) {
- try {
- if (StringUtils.isNotEmpty(identifier)) {
- LOG.debug("Processing {} as child node {}", injectedType, identifier);
- return childNodeDataFactory.getChildNodeData(identifier, resourcePath);
- } else {
- LOG.debug("Processing {} as root node", injectedType);
- return rootNodeDataFactory.getRootNodeData(getRootInstanceIdentifier(injectedType), resourcePath);
- }
- } catch (DeserializationException | IOException e) {
- throw new IllegalStateException(e);
- }
- }
}
diff --git a/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/ListNodeDataProcessor.java b/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/ListNodeDataProcessor.java
new file mode 100644
index 000000000..375f55307
--- /dev/null
+++ b/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/ListNodeDataProcessor.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2017 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.test.tools;
+
+import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.Nonnull;
+import java.io.InputStream;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static io.fd.honeycomb.translate.util.JsonUtils.readListEntryFromJson;
+
+/**
+ * json --> BA processor for list entry data
+ */
+final class ListNodeDataProcessor extends AbstractYangContextHolder implements YangDataProcessor {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ListNodeDataProcessor.class);
+
+ ListNodeDataProcessor(@Nonnull final SchemaContext schemaContext,
+ @Nonnull final BindingToNormalizedNodeCodec serializer) {
+ super(schemaContext, serializer);
+ }
+
+ @Nonnull
+ @Override
+ public DataObject getNodeData(@Nonnull final YangInstanceIdentifier nodeIdentifier,
+ @Nonnull final String resourcePath) {
+ checkArgument(canProcess(nodeIdentifier), "Cannot process identifier %s", nodeIdentifier);
+ final YangInstanceIdentifier listParent = listNodeParent(nodeIdentifier);
+ final YangInstanceIdentifier.NodeIdentifierWithPredicates keyedNodeIdentifier = listNodeIdentifier(nodeIdentifier);
+ final InputStream resourceStream = this.getClass().getResourceAsStream(resourcePath);
+ final SchemaNode parentSchemaNode = parentSchema(schemaContext(), serializer(), listParent, () -> LOG);
+ final MapEntryNode data = readListEntryFromJson(schemaContext(), resourceStream, parentSchemaNode, keyedNodeIdentifier);
+
+ return nodeBinding(serializer(), nodeIdentifier, data).getValue();
+ }
+
+ @Override
+ public boolean canProcess(@Nonnull final YangInstanceIdentifier identifier) {
+ return !isRoot(identifier) &&
+ Identifiable.class.isAssignableFrom(identifierBinding(serializer(), identifier).getTargetType());
+ }
+
+ private YangInstanceIdentifier listNodeParent(@Nonnull final YangInstanceIdentifier nodeIdentifier) {
+ // if it is list, real parent is second to last
+ return getNodeParent(nodeIdentifier).map(parent -> getNodeParent(parent).orElse(null))
+ .orElseThrow(() -> new IllegalArgumentException(
+ String.format("Unable to get parent for list node from %s", nodeIdentifier)));
+ }
+
+ private static YangInstanceIdentifier.NodeIdentifierWithPredicates listNodeIdentifier(@Nonnull final YangInstanceIdentifier nodeIdentifier) {
+ return java.util.Optional.ofNullable(nodeIdentifier.getLastPathArgument())
+ .filter(pathArgument -> pathArgument instanceof YangInstanceIdentifier.NodeIdentifierWithPredicates)
+ .map(YangInstanceIdentifier.NodeIdentifierWithPredicates.class::cast)
+ .orElseThrow(() -> new IllegalArgumentException(
+ String.format("Unable to create list node identifier from %s", nodeIdentifier)));
+ }
+}
+
+
+
diff --git a/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/YangContextProducer.java b/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/YangContextProducer.java
index 23af9733d..017a68c9f 100644
--- a/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/YangContextProducer.java
+++ b/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/YangContextProducer.java
@@ -16,12 +16,7 @@
package io.fd.honeycomb.test.tools;
-import static com.google.common.base.Preconditions.checkState;
-
import io.fd.honeycomb.test.tools.annotations.SchemaContextProvider;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
import javassist.ClassPool;
import org.apache.commons.lang3.reflect.MethodUtils;
import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
@@ -34,6 +29,12 @@ import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactory;
import org.opendaylight.yangtools.yang.data.util.AbstractModuleStringInstanceIdentifierCodec;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import static com.google.common.base.Preconditions.checkState;
+
/**
* Common logic to initialize serializers/deserializers/etc while working with yang based data
*/
@@ -67,14 +68,13 @@ interface YangContextProducer {
return (AbstractModuleStringInstanceIdentifierCodec) cstr.newInstance(ctx.getSchemaContext(), jsonCodecFactory);
}
- default BindingToNormalizedNodeCodec createSerializer(final ModuleInfoBackedContext moduleInfoBackedContext,
- final SchemaContext schemaContexts) {
+ default BindingToNormalizedNodeCodec createSerializer(final ModuleInfoBackedContext moduleInfoBackedContext) {
final BindingNormalizedNodeCodecRegistry codecRegistry =
new BindingNormalizedNodeCodecRegistry(
StreamWriterGenerator.create(JavassistUtils.forClassPool(ClassPool.getDefault())));
codecRegistry
- .onBindingRuntimeContextUpdated(BindingRuntimeContext.create(moduleInfoBackedContext, schemaContexts));
+ .onBindingRuntimeContextUpdated(BindingRuntimeContext.create(moduleInfoBackedContext, moduleInfoBackedContext.getSchemaContext()));
return new BindingToNormalizedNodeCodec(moduleInfoBackedContext, codecRegistry);
}
}
diff --git a/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/YangDataProcessor.java b/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/YangDataProcessor.java
new file mode 100644
index 000000000..a353e4b3b
--- /dev/null
+++ b/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/YangDataProcessor.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2017 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.test.tools;
+
+import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
+import org.opendaylight.yangtools.sal.binding.generator.impl.BindingSchemaContextUtils;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.slf4j.Logger;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.AbstractMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Supplier;
+
+interface YangDataProcessor {
+
+ /**
+ * Attempts to find data in file specified by <b>resourcePath</b>,<br>
+ * and translate it to BA object
+ *
+ * @param yangInstanceIdentifier identifier of path to read
+ * @param resourcePath path of resource file to load
+ */
+ @Nonnull
+ DataObject getNodeData(@Nonnull final YangInstanceIdentifier yangInstanceIdentifier,
+ @Nonnull final String resourcePath);
+
+ /**
+ * Verifies if provided identifier is identifying node processed by this processor
+ *
+ * @param identifier node identifier
+ */
+ boolean canProcess(@Nonnull final YangInstanceIdentifier identifier);
+
+ default boolean isRoot(@Nonnull final YangInstanceIdentifier identifier) {
+ return identifier.getPathArguments().isEmpty();
+ }
+
+ @Nonnull
+ default Optional<YangInstanceIdentifier> getNodeParent(@Nonnull final YangInstanceIdentifier identifier) {
+ return Optional.ofNullable(identifier.getParent());
+ }
+
+ @Nonnull
+ default SchemaNode parentSchema(@Nonnull final SchemaContext schemaContext,
+ @Nonnull final BindingToNormalizedNodeCodec serializer,
+ @Nullable final YangInstanceIdentifier parentYangId,
+ @Nonnull final Supplier<Logger> logProvider) {
+ // null or root
+ if (parentYangId == null || parentYangId.getPathArguments().size() == 0) {
+ // no parent == use schema context as root context
+ logProvider.get().info("Parent is null, providing schema context as parent node");
+ return schemaContext;
+ }
+
+ final com.google.common.base.Optional<InstanceIdentifier<? extends DataObject>> parentInstanceId;
+ try {
+ parentInstanceId = serializer.toBinding(parentYangId);
+ } catch (DeserializationException e) {
+ throw new IllegalArgumentException(String.format("Unable to deserialize %s", parentYangId));
+ }
+
+ if (!parentInstanceId.isPresent()) {
+ throw new IllegalStateException(String.format("Unable to resolve %s to instance identifier", parentYangId));
+ }
+
+ final com.google.common.base.Optional<DataNodeContainer> dataNodeContainerOptional =
+ BindingSchemaContextUtils.findDataNodeContainer(schemaContext, parentInstanceId.get());
+
+
+ if (!dataNodeContainerOptional.isPresent()) {
+ throw new IllegalArgumentException(String.format("Error finding DataNodeContainer for %s", parentInstanceId.get()));
+ }
+
+ final DataNodeContainer parentNode = dataNodeContainerOptional.get();
+ logProvider.get().info("Parent schema node resolved as {}", parentNode);
+ return (SchemaNode) parentNode;
+ }
+
+ @Nonnull
+ default Map.Entry<InstanceIdentifier<? extends DataObject>, DataObject> nodeBinding(@Nonnull final BindingToNormalizedNodeCodec serializer,
+ @Nonnull final YangInstanceIdentifier identifier,
+ @Nonnull final NormalizedNode<?, ?> data) {
+ try {
+ return serializer.toBinding(new AbstractMap.SimpleImmutableEntry<>(identifier, data))
+ .or(() -> {
+ throw new IllegalArgumentException(String.format("Unable to create node binding for %s|%s", identifier, data));
+ });
+ } catch (DeserializationException e) {
+ throw new IllegalArgumentException(String.format("Unable to deserialize node %s|%s", identifier, data));
+ }
+ }
+
+ @Nonnull
+ default InstanceIdentifier<? extends DataObject> identifierBinding(@Nonnull final BindingToNormalizedNodeCodec serializer,
+ @Nonnull final YangInstanceIdentifier identifier) {
+ try {
+ return serializer.toBinding(identifier)
+ .or(() -> {
+ throw new IllegalArgumentException(String.format("Unable convert %s to binding", identifier));
+ });
+ } catch (DeserializationException e) {
+ throw new IllegalArgumentException(String.format("Unable to deserialize %s", identifier));
+ }
+ }
+}
diff --git a/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/YangDataProcessorRegistry.java b/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/YangDataProcessorRegistry.java
new file mode 100644
index 000000000..d23cd59c1
--- /dev/null
+++ b/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/YangDataProcessorRegistry.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2017 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.test.tools;
+
+import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+import javax.annotation.Nonnull;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static com.google.common.base.Preconditions.checkState;
+
+/**
+ * Process yang data from json to BA Objects
+ */
+final class YangDataProcessorRegistry {
+
+ private final List<YangDataProcessor> processors;
+
+ private YangDataProcessorRegistry(@Nonnull final SchemaContext context,
+ @Nonnull final BindingToNormalizedNodeCodec codec) {
+ // linked should be faster for iteration
+ processors = new LinkedList<>();
+ processors.add(new ListNodeDataProcessor(context, codec));
+ processors.add(new ContainerNodeDataProcessor(context, codec));
+ }
+
+ static YangDataProcessorRegistry create(@Nonnull final SchemaContext context,
+ @Nonnull final BindingToNormalizedNodeCodec codec) {
+ return new YangDataProcessorRegistry(context, codec);
+ }
+
+ @Nonnull
+ DataObject getNodeData(@Nonnull final YangInstanceIdentifier yangInstanceIdentifier,
+ @Nonnull final String resourcePath) {
+ return pickProcessor(yangInstanceIdentifier).getNodeData(yangInstanceIdentifier, resourcePath);
+ }
+
+ private YangDataProcessor pickProcessor(final YangInstanceIdentifier yangInstanceIdentifier) {
+ final List<YangDataProcessor> eligibleProcessors = processors.stream()
+ .filter(processors -> processors.canProcess(yangInstanceIdentifier))
+ .collect(Collectors.toList());
+
+ // canProcess should be exclusive for node type, but just in case
+ checkState(eligibleProcessors.size() == 1,
+ "No single eligible processor found, matches=[%s]", eligibleProcessors);
+
+ return eligibleProcessors.get(0);
+ }
+}
diff --git a/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/annotations/InjectablesProcessor.java b/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/annotations/InjectablesProcessor.java
index c364938ed..216d8353b 100644
--- a/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/annotations/InjectablesProcessor.java
+++ b/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/annotations/InjectablesProcessor.java
@@ -16,22 +16,21 @@
package io.fd.honeycomb.test.tools.annotations;
-import static io.fd.honeycomb.test.tools.annotations.InjectTestData.NO_ID;
-
-import com.google.common.base.Optional;
-import java.lang.reflect.Field;
-import java.lang.reflect.Parameter;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
import org.apache.commons.lang3.reflect.FieldUtils;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.data.rev150105.$YangModuleInfoImpl;
import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.util.AbstractModuleStringInstanceIdentifierCodec;
+
+import javax.annotation.Nonnull;
+import java.lang.reflect.Field;
+import java.lang.reflect.Parameter;
+import java.util.List;
+import java.util.Set;
+
+import static io.fd.honeycomb.test.tools.annotations.InjectTestData.NO_ID;
/**
* Common logic for @InjectTestData
@@ -54,23 +53,23 @@ public interface InjectablesProcessor {
return parameter.getAnnotation(InjectTestData.class).resourcePath();
}
- default Optional<String> instanceIdentifier(final Field field) {
+ default YangInstanceIdentifier instanceIdentifier(@Nonnull final AbstractModuleStringInstanceIdentifierCodec parser, @Nonnull final Field field) {
final String identifier = field.getAnnotation(InjectTestData.class).id();
// == used instead of equals to ensure constant was used
if (NO_ID.equals(identifier)) {
- return Optional.absent();
+ return getRootInstanceIdentifier(field.getType());
} else {
- return Optional.of(identifier);
+ return parser.deserialize(identifier);
}
}
- default Optional<String> instanceIdentifier(final Parameter parameter) {
+ default YangInstanceIdentifier instanceIdentifier(@Nonnull final AbstractModuleStringInstanceIdentifierCodec parser, @Nonnull final Parameter parameter) {
final String identifier = parameter.getAnnotation(InjectTestData.class).id();
// == used instead of equals to ensure constant was used
if (NO_ID.equals(identifier)) {
- return Optional.absent();
+ return getRootInstanceIdentifier(parameter.getType());
} else {
- return Optional.of(identifier);
+ return parser.deserialize(identifier);
}
}
@@ -83,7 +82,7 @@ public interface InjectablesProcessor {
}
}
- default YangInstanceIdentifier getRootInstanceIdentifier(final Class type) {
+ static YangInstanceIdentifier getRootInstanceIdentifier(final Class type) {
try {
return YangInstanceIdentifier.of(QName.class.cast(type.getField("QNAME").get(null)));
} catch (IllegalAccessException e) {
diff --git a/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/factories/ChildNodeDataFactory.java b/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/factories/ChildNodeDataFactory.java
deleted file mode 100644
index 05812123e..000000000
--- a/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/factories/ChildNodeDataFactory.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (c) 2016 Cisco and/or its affiliates.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package io.fd.honeycomb.test.tools.factories;
-
-
-import com.google.common.base.Optional;
-import java.io.IOException;
-import javax.annotation.Nonnull;
-import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
-import org.opendaylight.yangtools.sal.binding.generator.impl.BindingSchemaContextUtils;
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
-import org.opendaylight.yangtools.yang.data.util.AbstractModuleStringInstanceIdentifierCodec;
-import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class ChildNodeDataFactory extends YangDataFactory {
-
- private static final Logger LOG = LoggerFactory.getLogger(ChildNodeDataFactory.class);
-
- public ChildNodeDataFactory(@Nonnull final SchemaContext schemaContext,
- @Nonnull final BindingToNormalizedNodeCodec serializer,
- @Nonnull final AbstractModuleStringInstanceIdentifierCodec iidParser) {
- super(schemaContext, serializer, iidParser);
- }
-
- public DataObject getChildNodeData(final String instanceIdentifier,
- final String resourcePath) throws DeserializationException, IOException {
- // Parse string ID into YangId
- final YangInstanceIdentifier nodeYid = iidParser.deserialize(instanceIdentifier);
- // Look for parent YangId
- final YangInstanceIdentifier parentYid = nodeYid.getParent();
-
- if (parentYid.isEmpty()) {
- throw new IllegalArgumentException(
- "Attempt to process root node as children has been detected,to process root nodes just don't use id in @InjectTestData");
- }
- // Find Schema node for parent of data that's currently being parsed (needed when parsing the data into NormalizedNodes)
- return getDataForNode(nodeYid, resourcePath, getNonRootParentSchema(parentYid));
- }
-
- private DataNodeContainer getNonRootParentSchema(final YangInstanceIdentifier parentYangId)
- throws DeserializationException {
- LOG.debug("Processing parent identifier {}", parentYangId);
- final Optional<InstanceIdentifier<? extends DataObject>> parentInstanceId = serializer.toBinding(parentYangId);
- if (!parentInstanceId.isPresent()) {
- throw new IllegalStateException("Unable to resolve " + parentYangId + " to instance identifier");
- }
-
- final Optional<DataNodeContainer> dataNodeContainerOptional =
- BindingSchemaContextUtils.findDataNodeContainer(schemaContext, parentInstanceId.get());
-
- if (!dataNodeContainerOptional.isPresent()) {
- throw new IllegalArgumentException("Error finding DataNodeContainer for " + parentInstanceId.get());
- }
-
- return dataNodeContainerOptional.get();
- }
-}
diff --git a/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/factories/RootNodeDataFactory.java b/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/factories/RootNodeDataFactory.java
deleted file mode 100644
index 3aacea016..000000000
--- a/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/factories/RootNodeDataFactory.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2016 Cisco and/or its affiliates.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package io.fd.honeycomb.test.tools.factories;
-
-
-import java.io.IOException;
-import javax.annotation.Nonnull;
-import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
-import org.opendaylight.yangtools.yang.data.util.AbstractModuleStringInstanceIdentifierCodec;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-
-public class RootNodeDataFactory extends YangDataFactory {
-
- public RootNodeDataFactory(@Nonnull final SchemaContext schemaContext,
- @Nonnull final BindingToNormalizedNodeCodec serializer,
- @Nonnull final AbstractModuleStringInstanceIdentifierCodec iidParser) {
- super(schemaContext, serializer, iidParser);
- }
-
- public DataObject getRootNodeData(final YangInstanceIdentifier rootInstanceIdentifier,
- final String resourcePath) throws DeserializationException, IOException {
- //entire schema context is parent schema in this case
- return getDataForNode(rootInstanceIdentifier, resourcePath, schemaContext);
- }
-}
diff --git a/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/factories/YangDataFactory.java b/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/factories/YangDataFactory.java
deleted file mode 100644
index ecf556cd2..000000000
--- a/infra/test-utils/test-tools/src/main/java/io/fd/honeycomb/test/tools/factories/YangDataFactory.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (c) 2016 Cisco and/or its affiliates.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package io.fd.honeycomb.test.tools.factories;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.base.Optional;
-import com.google.common.collect.Iterables;
-import io.fd.honeycomb.translate.util.JsonUtils;
-import java.io.IOException;
-import java.util.AbstractMap;
-import java.util.Map;
-import javax.annotation.Nonnull;
-import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
-import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
-import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
-import org.opendaylight.yangtools.yang.data.util.AbstractModuleStringInstanceIdentifierCodec;
-import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.model.api.SchemaNode;
-
-/**
- * Common logic for reading of yang data
- */
-abstract class YangDataFactory {
-
- final SchemaContext schemaContext;
- final BindingToNormalizedNodeCodec serializer;
- final AbstractModuleStringInstanceIdentifierCodec iidParser;
-
- YangDataFactory(@Nonnull final SchemaContext schemaContext,
- @Nonnull final BindingToNormalizedNodeCodec serializer,
- @Nonnull final AbstractModuleStringInstanceIdentifierCodec iidParser) {
- this.schemaContext = checkNotNull(schemaContext, "SchemaContext cannot be null");
- this.serializer = checkNotNull(serializer, "Serializer cannot be null");
- this.iidParser = checkNotNull(iidParser, "Instance identifier parser cannot be null");
- }
-
- DataObject getDataForNode(final YangInstanceIdentifier nodeYangIdentifier,
- final String resourcePath,
- final DataNodeContainer parentSchema)
- throws DeserializationException, IOException {
-
- // Reads resources from provided resource path
- final ContainerNode rootData = getCheckedRootData(resourcePath, parentSchema);
-
- // Now transform the single child from JSON into BA format
- final DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> actualData =
- extractCheckedSingleChild(rootData);
-
- return getCheckedBinding(nodeYangIdentifier, actualData).getValue();
- }
-
- private ContainerNode getCheckedRootData(final String resourcePath, final DataNodeContainer parentSchema)
- throws IOException {
- // TODO the cast to SchemaNode is dangerous and would not work for Augments, Choices and some other nodes maybe. At least check
- // TODO not sure if this is true, while testing this code was working fine event while processing choices/cases,
- // TODO only problem is to find suitable codec that can process cases,etc
- // Transform JSON into NormalizedNode
-
- final ContainerNode rootData = JsonUtils.readJson(schemaContext,
- checkNotNull(this.getClass().getResource(resourcePath), "Unable to find resource %s", resourcePath)
- .openStream(), ((SchemaNode) parentSchema));
-
- checkArgument(rootData.getValue().size() == 1, "Only a single data node is expected in %s, but there were: %s",
- resourcePath, rootData.getValue());
- return rootData;
- }
-
- private DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> extractCheckedSingleChild(
- final ContainerNode rootData) {
- // Now transform the single child from JSON into BA format
- final DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> actualData =
- Iterables.getFirst(rootData.getValue(), null);
-
- checkNotNull(actualData, "Unable to extract single child from %s", rootData);
- return actualData;
- }
-
- private Map.Entry<InstanceIdentifier<? extends DataObject>, DataObject> getCheckedBinding(
- final YangInstanceIdentifier nodeYangIdentifier,
- final DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> actualData)
- throws DeserializationException {
- final Optional<Map.Entry<InstanceIdentifier<? extends DataObject>, DataObject>> ba =
- serializer.toBinding(new AbstractMap.SimpleImmutableEntry<>(nodeYangIdentifier, actualData));
-
- checkArgument(ba.isPresent(), "Unable to convert to binding %s", nodeYangIdentifier);
- return ba.get();
- }
-}