--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ and is available at http://www.eclipse.org/legal/epl-v10.html
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>binding-generator</artifactId>
+ <version>0.6.2-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>binding-data-codec</artifactId>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.javassist</groupId>
+ <artifactId>javassist</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>binding-generator-impl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-parser-impl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-impl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>binding-generator-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>binding-generator-spi</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>binding-type-provider</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.code.findbugs</groupId>
+ <artifactId>jsr305</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.xtend</groupId>
+ <artifactId>org.eclipse.xtend.lib</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-jar-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+ <Export-Package>
+ org.opendaylight.yangtools.sal.binding.generator.impl.*,
+ org.opendaylight.yangtools.sal.binding.generator.util.*
+ </Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.eclipse.xtend</groupId>
+ <artifactId>xtend-maven-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+</project>
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.api;
+
+import java.util.Map;
+import java.util.Map.Entry;
+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;
+
+/**
+ * Serialization service, which provides two-way serialization between
+ * Java Binding Data representation and NormalizedNode representation.
+ *
+ */
+public interface BindingNormalizedNodeSerializer {
+
+ /**
+ * Translates supplied Binding Instance Identifier into NormalizedNode instance identifier.
+ *
+ * @param binding Binding Instance Identifier
+ * @return DOM Instance Identifier
+ */
+ YangInstanceIdentifier toYangInstanceIdentifier(final InstanceIdentifier<?> binding);
+
+ /**
+ * Translates supplied YANG Instance Identifier into Binding instance identifier.
+ *
+ * @param dom YANG Instance Identifier
+ * @return Binding Instance Identifier
+ */
+ InstanceIdentifier<?> fromYangInstanceIdentifier(final YangInstanceIdentifier dom);
+
+ /**
+ * Translates supplied Binding Instance Identifier and data into NormalizedNode representatoin.
+ *
+ * @param path Binding Instance Identifier pointing to data
+ * @param data Data object representing data
+ * @return NormalizedNode representation
+ */
+ <T extends DataObject> Entry<YangInstanceIdentifier,NormalizedNode<?,?>> toNormalizedNode(final InstanceIdentifier<T> path, final T data);
+
+ /**
+ * Translates supplied YANG Instance Identifier and NormalizedNode into Binding data.
+ *
+ * @param path Binding Instance Identifier
+ * @param data NormalizedNode representing data
+ * @return DOM Instance Identifier
+ */
+ Entry<InstanceIdentifier<?>,DataObject> fromNormalizedNode(final YangInstanceIdentifier path, NormalizedNode<?, ?> data);
+
+ /**
+ * Returns map view which contains translated set of entries to normalized nodes.
+ * Returned set will not contain representation of leaf nodes.
+ *
+ * @param dom Map of YANG Instance Identifier to Data
+ * @return Map of Binding Instance Identifier to data.
+ */
+ Map<InstanceIdentifier<?>,DataObject> fromNormalizedNodes(Map<YangInstanceIdentifier,NormalizedNode<?,?>> dom);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.api;
+
+import java.util.Map.Entry;
+import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+
+/**
+ *
+ * Factory for {@link BindingStreamEventWriter}, which provides stream writers
+ * which translates data and delegates calls to
+ * {@link NormalizedNodeStreamWriter}.
+ *
+ */
+public interface BindingNormalizedNodeWriterFactory {
+
+ /**
+ *
+ * Creates a {@link BindingStreamEventWriter} for data tree path which will
+ * translate to NormalizedNode model and invoke proper events on supplied
+ * {@link NormalizedNodeStreamWriter}.
+ * <p>
+ * Also provides translation of supplied Instance Identifier to
+ * {@link YangInstanceIdentifier} so client code, does not need to translate
+ * that separately.
+ * <p>
+ * If {@link YangInstanceIdentifier} is not needed, please use
+ * {@link #newWriter(InstanceIdentifier, NormalizedNodeStreamWriter)}
+ * method to conserve resources.
+ *
+ * @param path
+ * Binding Path in conceptual data tree, for which writer should
+ * be instantiated
+ * @param domWriter
+ * Stream writer on which events will be invoked.
+ * @return Instance Identifier and {@link BindingStreamEventWriter}
+ * which will write to supplied {@link NormalizedNodeStreamWriter}.
+ */
+ public Entry<YangInstanceIdentifier, BindingStreamEventWriter> newWriterAndIdentifier(final InstanceIdentifier<?> path,
+ final NormalizedNodeStreamWriter domWriter);
+
+ /**
+ *
+ * Creates a {@link BindingStreamEventWriter} for data tree path which will
+ * translate to NormalizedNode model and invoke proper events on supplied
+ * {@link NormalizedNodeStreamWriter}.
+ * <p>
+ *
+ * This variation does not provide YANG instance identifier and is useful
+ * for use-cases, where {@link InstanceIdentifier} translation is done
+ * in other way, or YANG instance identifier is unnecessary (e.g. notifications, RPCs).
+ *
+ * @param path Binding Path in conceptual data tree, for which writer should
+ * be instantiated
+ * @param domWriter Stream writer on which events will be invoked.
+ * @return {@link BindingStreamEventWriter}
+ * which will write to supplied {@link NormalizedNodeStreamWriter}.
+ */
+ public BindingStreamEventWriter newWriter(final InstanceIdentifier<?> path,
+ final NormalizedNodeStreamWriter domWriter);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.gen.impl;
+
+import com.google.common.base.Preconditions;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+
+import java.lang.reflect.Field;
+import java.util.Map.Entry;
+
+import javassist.CannotCompileException;
+import javassist.CtClass;
+import javassist.CtField;
+import javassist.CtMethod;
+import javassist.Modifier;
+import javassist.NotFoundException;
+
+import org.opendaylight.yangtools.binding.data.codec.gen.spi.AbstractSource;
+import org.opendaylight.yangtools.binding.data.codec.gen.spi.StaticConstantDefinition;
+import org.opendaylight.yangtools.binding.data.codec.util.AugmentableDispatchSerializer;
+import org.opendaylight.yangtools.binding.generator.util.Types;
+import org.opendaylight.yangtools.sal.binding.generator.api.ClassLoadingStrategy;
+import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
+import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
+import org.opendaylight.yangtools.sal.binding.generator.util.ClassGenerator;
+import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
+import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType;
+import org.opendaylight.yangtools.sal.binding.model.api.Type;
+import org.opendaylight.yangtools.util.ClassLoaderUtils;
+import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializerImplementation;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializerRegistry;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class AbstractStreamWriterGenerator {
+
+ protected static final String SERIALIZER_SUFFIX = "$StreamWriter";
+ protected static final String STATIC_SERIALIZE_METHOD_NAME = "staticSerialize";
+ protected static final String SERIALIZE_METHOD_NAME = "serialize";
+
+ protected static final AugmentableDispatchSerializer AUGMENTABLE = new AugmentableDispatchSerializer();
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractStreamWriterGenerator.class);
+
+ private final JavassistUtils javassist;
+ private final CtClass serializerCt;
+ private final CtClass dataObjectCt;
+ private final CtClass writerCt;
+ private final CtClass voidCt;
+ private final CtClass registryCt;
+
+ private final CtClass[] serializeArguments;
+ private final CtMethod serializeToMethod;
+
+ private final LoadingCache<Class<?>, Class<? extends DataObjectSerializerImplementation>> implementations;
+ private final ClassLoadingStrategy strategy;
+
+ private BindingRuntimeContext context;
+
+ protected AbstractStreamWriterGenerator(final JavassistUtils utils) {
+ super();
+ this.javassist = Preconditions.checkNotNull(utils,"JavassistUtils instance is required.");
+ this.serializerCt = javassist.asCtClass(DataObjectSerializerImplementation.class);
+ this.registryCt = javassist.asCtClass(DataObjectSerializerRegistry.class);
+ this.writerCt = javassist.asCtClass(BindingStreamEventWriter.class);
+ this.dataObjectCt = javassist.asCtClass(DataObject.class);
+ this.voidCt = javassist.asCtClass(Void.class);
+ this.serializeArguments = new CtClass[] { registryCt,dataObjectCt, writerCt };
+
+ try {
+ this.serializeToMethod = serializerCt.getDeclaredMethod(SERIALIZE_METHOD_NAME, serializeArguments);
+ } catch (NotFoundException e) {
+ throw new IllegalStateException("Required method " + SERIALIZE_METHOD_NAME + "was not found in class " + BindingStreamEventWriter.class ,e);
+ }
+ this.implementations = CacheBuilder.newBuilder().weakKeys().build(new SerializerImplementationLoader());
+ strategy = GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy();
+ }
+
+ private final class SerializerImplementationLoader extends
+ CacheLoader<Class<?>, Class<? extends DataObjectSerializerImplementation>> {
+
+ @Override
+ public Class<? extends DataObjectSerializerImplementation> load(final Class<?> type) throws Exception {
+ Preconditions.checkArgument(BindingReflections.isBindingClass(type));
+ Preconditions.checkArgument(DataContainer.class.isAssignableFrom(type));
+
+ String serializerName = getSerializerName(type);
+ try {
+ @SuppressWarnings("unchecked")
+ final Class<? extends DataObjectSerializerImplementation> preexisting = (Class<? extends DataObjectSerializerImplementation>) ClassLoaderUtils
+ .loadClass(type.getClassLoader(), serializerName);
+ return preexisting;
+ } catch (ClassNotFoundException e) {
+ return loadFromClassPoolOrGenerate(type, serializerName);
+ }
+ }
+
+ private Class<? extends DataObjectSerializerImplementation> loadFromClassPoolOrGenerate(final Class<?> type,
+ final String serializerName) throws CannotCompileException {
+ CtClass poolClass;
+ DataObjectSerializerSource source = generateEmitterSource(type, serializerName);
+ poolClass = generateEmitter0(source, serializerName);
+ @SuppressWarnings("unchecked")
+ Class<? extends DataObjectSerializerImplementation> cls = poolClass.toClass(type.getClassLoader(), type.getProtectionDomain());
+ initStaticConstants(cls,source);
+ return cls;
+ }
+
+ private void initStaticConstants(final Class<? extends DataObjectSerializerImplementation> cls, final DataObjectSerializerSource source) {
+ for(StaticConstantDefinition constant : source.getStaticConstants()) {
+ try {
+ Field field = cls.getDeclaredField(constant.getName());
+ field.set(null, constant.getValue());
+ } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
+ throw new IllegalStateException("Could not initialize expected constant",e);
+ }
+ }
+ }
+ }
+
+
+
+ protected DataObjectSerializerSource generateEmitterSource(final Class<?> type, final String serializerName) {
+ Types.typeForClass(type);
+ Entry<GeneratedType, Object> typeWithSchema = context.getTypeWithSchema(type);
+ GeneratedType generatedType = typeWithSchema.getKey();
+ Object schema = typeWithSchema.getValue();
+
+ final DataObjectSerializerSource source;
+ if (schema instanceof ContainerSchemaNode) {
+ source = generateContainerSerializer(generatedType, (ContainerSchemaNode) schema);
+ } else if (schema instanceof ListSchemaNode){
+ ListSchemaNode casted = (ListSchemaNode) schema;
+ if (casted.getKeyDefinition().isEmpty()) {
+ source = generateUnkeyedListEntrySerializer(generatedType, casted);
+ } else {
+ source = generateMapEntrySerializer(generatedType, casted);
+ }
+ } else if(schema instanceof AugmentationSchema) {
+ source = generateSerializer(generatedType,(AugmentationSchema) schema);
+ } else if(schema instanceof ChoiceCaseNode) {
+ source = generateCaseSerializer(generatedType,(ChoiceCaseNode) schema);
+ } else {
+ throw new UnsupportedOperationException("Schema type " + schema.getClass() + " is not supported");
+ }
+ return source;
+ }
+
+ private CtClass generateEmitter0(final DataObjectSerializerSource source, final String serializerName) {
+ CtClass product = javassist.createClass(serializerName, serializerCt, new ClassGenerator() {
+
+ @Override
+ public void process(final CtClass cls) {
+ final String staticBody = source.getStaticSerializeBody().toString();
+ try {
+
+ for(StaticConstantDefinition def : source.getStaticConstants()) {
+ CtField field = new CtField(javassist.asCtClass(def.getType()), def.getName(), cls);
+ field.setModifiers(Modifier.PUBLIC + Modifier.STATIC);
+ cls.addField(field);
+ }
+
+ CtMethod staticSerializeTo = new CtMethod(voidCt, STATIC_SERIALIZE_METHOD_NAME, serializeArguments, cls);
+ staticSerializeTo.setModifiers(Modifier.PUBLIC + Modifier.FINAL + Modifier.STATIC);
+ staticSerializeTo.setBody(staticBody);
+ cls.addMethod(staticSerializeTo);
+
+
+ CtMethod serializeTo = new CtMethod(serializeToMethod,cls,null);
+ serializeTo.setModifiers(Modifier.PUBLIC + Modifier.FINAL);
+ serializeTo.setBody(
+ new StringBuilder().append('{')
+ .append(STATIC_SERIALIZE_METHOD_NAME).append("($$);\n")
+ .append("return null;")
+ .append('}')
+ .toString()
+ );
+ cls.addMethod(serializeTo);
+ } catch (CannotCompileException e) {
+ LOG.error("Can not compile body of codec for {}.",serializerName,e);
+ throw new IllegalStateException(e);
+ }
+
+ }
+ });
+ return product;
+ }
+
+ @SuppressWarnings("unchecked")
+ protected Class<? extends DataContainer> loadClass(final Type childType) {
+ try {
+ return (Class<? extends DataContainer>) strategy.loadClass(childType);
+ } catch (ClassNotFoundException e) {
+ throw new IllegalStateException("Could not load referenced class ",e);
+ }
+ }
+
+ public DataObjectSerializerImplementation getSerializer(final Class<?> type) {
+ try {
+ return implementations.getUnchecked(type).newInstance();
+ } catch (InstantiationException | IllegalAccessException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ /**
+ * Generates serializer source code for supplied container node,
+ * which will read supplied binding type and invoke proper methods
+ * on supplied {@link BindingStreamEventWriter}.
+ * <p>
+ * Implementation is required to recursively invoke events
+ * for all reachable binding objects.
+ *
+ * @param type Binding type of container
+ * @param node Schema of container
+ * @return Source for container node writer
+ */
+ abstract DataObjectSerializerSource generateContainerSerializer(GeneratedType type, ContainerSchemaNode node);
+
+ /**
+ * Generates serializer source for supplied case node,
+ * which will read supplied binding type and invoke proper methods
+ * on supplied {@link BindingStreamEventWriter}.
+ * <p>
+ * Implementation is required to recursively invoke events
+ * for all reachable binding objects.
+ *
+ * @param type Binding type of case
+ * @param node Schema of case
+ * @return Source for case node writer
+ */
+ abstract DataObjectSerializerSource generateCaseSerializer(GeneratedType type, ChoiceCaseNode node);
+
+ /**
+ * Generates serializer source for supplied list node,
+ * which will read supplied binding type and invoke proper methods
+ * on supplied {@link BindingStreamEventWriter}.
+ * <p>
+ * Implementation is required to recursively invoke events
+ * for all reachable binding objects.
+ *
+ * @param type Binding type of list
+ * @param node Schema of list
+ * @return Source for list node writer
+ */
+ abstract DataObjectSerializerSource generateMapEntrySerializer(GeneratedType type, ListSchemaNode node);
+
+ /**
+ * Generates serializer source for supplied list node,
+ * which will read supplied binding type and invoke proper methods
+ * on supplied {@link BindingStreamEventWriter}.
+ * <p>
+ * Implementation is required to recursively invoke events
+ * for all reachable binding objects.
+ *
+ * @param type Binding type of list
+ * @param node Schema of list
+ * @return Source for list node writer
+ */
+ abstract DataObjectSerializerSource generateUnkeyedListEntrySerializer(GeneratedType type, ListSchemaNode node);
+
+ /**
+ * Generates serializer source for supplied augmentation node,
+ * which will read supplied binding type and invoke proper methods
+ * on supplied {@link BindingStreamEventWriter}.
+ * <p>
+ * Implementation is required to recursively invoke events
+ * for all reachable binding objects.
+ *
+ * @param type Binding type of augmentation
+ * @param node Schema of augmentation
+ * @return Source for augmentation node writer
+ */
+ abstract DataObjectSerializerSource generateSerializer(GeneratedType type, AugmentationSchema schema);
+
+ protected static String getSerializerName(final Class<?> type) {
+ return type.getName() + SERIALIZER_SUFFIX;
+ }
+
+ protected abstract class DataObjectSerializerSource extends AbstractSource {
+
+ protected static final String STREAM = "_stream";
+ protected static final String ITERATOR = "_iterator";
+ protected static final String CURRENT = "_current";
+ protected static final String REGISTRY = "_registry";
+
+ /**
+ * Returns body of static serialize method.
+ *
+ * <ul>
+ * <li> {@link DataObjectSerializerRegistry} - registry of serializers
+ * <li> {@link DataObject} - object to be serialized
+ * <li> {@link BindingStreamEventWriter} - writer to which events should be serialized.
+ * </ul>
+ *
+ * @return Valid javassist code describing static serialization body.
+ */
+ protected abstract CharSequence getStaticSerializeBody();
+
+ protected final CharSequence leafNode(final String localName, final CharSequence value) {
+ return invoke(STREAM, "leafNode", escape(localName), value);
+ }
+
+ protected final CharSequence startLeafSet(final String localName,final CharSequence expected) {
+ return invoke(STREAM, "startLeafSet", escape(localName),expected);
+ }
+
+ protected final CharSequence leafSetEntryNode(final CharSequence value) {
+ return invoke(STREAM, "leafSetEntryNode", value);
+
+ }
+
+ protected final CharSequence startContainerNode(final CharSequence type, final CharSequence expected) {
+ return invoke(STREAM, "startContainerNode", (type),expected);
+ }
+
+ protected final CharSequence escape(final String localName) {
+ return '"'+localName+'"';
+ }
+
+ protected final CharSequence startUnkeyedList(final CharSequence type, final CharSequence expected) {
+ return invoke(STREAM, "startUnkeyedList", (type),expected);
+ }
+
+ protected final CharSequence startUnkeyedListItem(final CharSequence expected) {
+ return invoke(STREAM, "startUnkeyedListItem",expected);
+ }
+
+ protected final CharSequence startMapNode(final CharSequence type,final CharSequence expected) {
+ return invoke(STREAM, "startMapNode", (type),expected);
+ }
+
+ protected final CharSequence startOrderedMapNode(final CharSequence type,final CharSequence expected) {
+ return invoke(STREAM, "startOrderedMapNode", (type),expected);
+ }
+
+ protected final CharSequence startMapEntryNode(final CharSequence key, final CharSequence expected) {
+ return invoke(STREAM,"startMapEntryNode",key,expected);
+
+ }
+
+ protected final CharSequence startAugmentationNode(final CharSequence key) {
+ return invoke(STREAM,"startAugmentationNode",key);
+
+ }
+
+ protected final CharSequence startChoiceNode(final CharSequence localName,final CharSequence expected) {
+ return invoke(STREAM, "startChoiceNode", (localName),expected);
+ }
+
+ protected final CharSequence startCaseNode(final CharSequence localName,final CharSequence expected) {
+ return invoke(STREAM, "startCase", (localName),expected);
+ }
+
+
+ protected final CharSequence anyxmlNode(final String name, final String value) throws IllegalArgumentException {
+ return invoke(STREAM,"anyxmlNode",escape(name),name);
+ }
+
+ protected final CharSequence endNode() {
+ return invoke(STREAM, "endNode");
+ }
+
+ protected final CharSequence forEach(final String iterable,final Type valueType,final CharSequence body) {
+ return forEach(iterable,ITERATOR,valueType.getFullyQualifiedName(),CURRENT,body);
+ }
+
+ protected final CharSequence classReference(final Type type) {
+ return new StringBuilder().append(type.getFullyQualifiedName()).append(".class");
+ }
+
+ protected final CharSequence staticInvokeEmitter(final Type childType, final String name) {
+ Class<?> cls;
+ try {
+ cls = strategy.loadClass(childType);
+ String className = implementations.getUnchecked(cls).getName();
+ return invoke(className, STATIC_SERIALIZE_METHOD_NAME,REGISTRY, name,STREAM);
+ } catch (ClassNotFoundException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ }
+
+ public void onBindingRuntimeContextUpdated(final BindingRuntimeContext runtime) {
+ this.context = runtime;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.gen.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.opendaylight.yangtools.binding.data.codec.util.AugmentableDispatchSerializer;
+import org.opendaylight.yangtools.binding.data.codec.util.ChoiceDispatchSerializer;
+import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
+import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType;
+import org.opendaylight.yangtools.sal.binding.model.api.MethodSignature;
+import org.opendaylight.yangtools.sal.binding.model.api.ParameterizedType;
+import org.opendaylight.yangtools.sal.binding.model.api.Type;
+import org.opendaylight.yangtools.yang.binding.BindingMapping;
+import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializerImplementation;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializerRegistry;
+import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
+
+/**
+ *
+ * Concrete implementation of {@link AbstractStreamWriterGenerator}
+ * which in runtime generates classes implementing {@link DataObjectSerializerImplementation}
+ * interface and are used to serialize Binding {@link DataObject}.
+ *
+ * Actual implementation of codecs is done via static methods, which allows
+ * for static wiring of codecs. Choice codec and Augmentable codecs
+ * are static properties of parent codec and stateless implementations
+ * are used ( {@link ChoiceDispatchSerializer}, {@link AugmentableDispatchSerializer},
+ * which uses registry to dispatch to concrete item codec.
+ *
+ */
+public class StreamWriterGenerator extends AbstractStreamWriterGenerator {
+
+ public StreamWriterGenerator(final JavassistUtils utils) {
+ super(utils);
+ }
+
+ private abstract class DataNodeContainerSerializerSource extends DataObjectSerializerSource {
+
+ protected static final String INPUT = "_input";
+ protected static final String CHOICE_SERIALIZER = "CHOICE_SERIALIZER";
+ protected static final String AUGMENTABLE_SERIALIZER = "AUGMENTABLE_SERIALIZER";
+
+ GeneratedType dtoType;
+ DataNodeContainer schemaNode;
+
+ public DataNodeContainerSerializerSource(final GeneratedType type, final DataNodeContainer node) {
+ this.dtoType = type;
+ this.schemaNode = node;
+ customize();
+ }
+
+ protected void customize() {
+ // Intentionally NOOP
+ }
+
+ public abstract CharSequence emitStartEvent();
+
+ @Override
+ protected CharSequence getStaticSerializeBody() {
+ StringBuilder b = new StringBuilder();
+ b.append("{\n");
+ b.append(statement(assign(DataObjectSerializerRegistry.class.getName(), REGISTRY, "$1")));
+ b.append(statement(assign(dtoType.getFullyQualifiedName(), INPUT,
+ cast(dtoType.getFullyQualifiedName(), "$2"))));
+ b.append(statement(assign(BindingStreamEventWriter.class.getName(), STREAM, cast(BindingStreamEventWriter.class.getName(), "$3"))));
+ b.append(statement(emitStartEvent()));
+
+ emitBody(b);
+ emitAfterBody(b);
+ b.append(statement(endNode()));
+ b.append(statement("return null"));
+ b.append("}");
+ return b;
+ }
+
+ /**
+ * Allows for customization of emitting code, which is processed after
+ * normal DataNodeContainer body. Ideal for augmentations or others.
+ */
+ protected void emitAfterBody(final StringBuilder b) {
+ //
+ }
+
+ private void emitBody(final StringBuilder b) {
+ Map<String, Type> getterToType = collectAllProperties(dtoType, new HashMap<String, Type>());
+ for (DataSchemaNode schemaChild : schemaNode.getChildNodes()) {
+ if (!schemaChild.isAugmenting()) {
+ String getter = getGetterName(schemaChild);
+ Type childType = getterToType.get(getter);
+ emitChild(b, getter, childType, schemaChild);
+ }
+ }
+ }
+
+ private void emitChild(final StringBuilder b, final String getterName, final Type childType,
+ final DataSchemaNode schemaChild) {
+ b.append(statement(assign(childType, getterName, cast(childType, invoke(INPUT, getterName)))));
+
+ b.append("if (").append(getterName).append(" != null) {\n");
+ emitChildInner(b, getterName, childType, schemaChild);
+ b.append("}\n");
+ }
+
+ private void emitChildInner(final StringBuilder b, final String getterName, final Type childType,
+ final DataSchemaNode child) {
+ if (child instanceof LeafSchemaNode) {
+ b.append(statement(leafNode(child.getQName().getLocalName(), getterName)));
+ } else if (child instanceof AnyXmlSchemaNode) {
+ b.append(statement(anyxmlNode(child.getQName().getLocalName(), getterName)));
+ } else if (child instanceof LeafListSchemaNode) {
+ b.append(statement(startLeafSet(child.getQName().getLocalName(),invoke(getterName, "size"))));
+ Type valueType = ((ParameterizedType) childType).getActualTypeArguments()[0];
+ b.append(forEach(getterName, valueType, statement(leafSetEntryNode(CURRENT))));
+ b.append(statement(endNode()));
+ } else if (child instanceof ListSchemaNode) {
+ Type valueType = ((ParameterizedType) childType).getActualTypeArguments()[0];
+ ListSchemaNode casted = (ListSchemaNode) child;
+ emitList(b, getterName, valueType, casted);
+ } else if (child instanceof ContainerSchemaNode) {
+ b.append(statement(staticInvokeEmitter(childType, getterName)));
+ } else if (child instanceof ChoiceNode) {
+ String propertyName = "CHOICE_" + childType.getName();
+ staticConstant(propertyName, DataObjectSerializerImplementation.class, ChoiceDispatchSerializer.from(loadClass(childType)));
+ b.append(statement(invoke(propertyName, SERIALIZE_METHOD_NAME, REGISTRY, cast(DataObject.class.getName(),getterName), STREAM)));
+ }
+ }
+
+ private void emitList(final StringBuilder b, final String getterName, final Type valueType,
+ final ListSchemaNode child) {
+ final CharSequence startEvent;
+
+ b.append(statement(assign("int", "_count", invoke(getterName, "size"))));
+ if (child.getKeyDefinition().isEmpty()) {
+ startEvent = startUnkeyedList(classReference(valueType), "_count");
+ } else if (child.isUserOrdered()) {
+ startEvent = startOrderedMapNode(classReference(valueType), "_count");
+ } else {
+ startEvent = startMapNode(classReference(valueType), "_count");
+ }
+ b.append(statement(startEvent));
+ b.append(forEach(getterName, valueType, statement(staticInvokeEmitter(valueType, CURRENT))));
+ b.append(statement(endNode()));
+ }
+ }
+
+ protected abstract class AugmentableDataNodeContainerEmmiterSource extends DataNodeContainerSerializerSource {
+
+ public AugmentableDataNodeContainerEmmiterSource(final GeneratedType type, final DataNodeContainer node) {
+ super(type, node);
+ staticConstant(AUGMENTABLE_SERIALIZER, DataObjectSerializerImplementation.class,AUGMENTABLE);
+ }
+
+ @Override
+ protected void emitAfterBody(final StringBuilder b) {
+ b.append(statement(invoke(AUGMENTABLE_SERIALIZER, "serialize",REGISTRY, INPUT, STREAM)));
+ }
+ }
+
+ private static Map<String, Type> collectAllProperties(final GeneratedType type, final Map<String, Type> hashMap) {
+ for (MethodSignature definition : type.getMethodDefinitions()) {
+ hashMap.put(definition.getName(), definition.getReturnType());
+ }
+ for (Type parent : type.getImplements()) {
+ if (parent instanceof GeneratedType) {
+ collectAllProperties((GeneratedType) parent, hashMap);
+ }
+ }
+ return hashMap;
+ }
+
+
+
+ private CharSequence getChildSizeFromSchema(final DataNodeContainer node) {
+ return Integer.toString(node.getChildNodes().size());
+ }
+
+ @Override
+ DataObjectSerializerSource generateContainerSerializer(final GeneratedType type, final ContainerSchemaNode node) {
+
+ return new DataNodeContainerSerializerSource(type, node) {
+ @Override
+ public CharSequence emitStartEvent() {
+ return startContainerNode(classReference(type), getChildSizeFromSchema(node));
+ }
+ };
+ }
+
+ protected static final String getGetterName(final DataSchemaNode node) {
+ final TypeDefinition<?> type ;
+ if (node instanceof LeafSchemaNode) {
+ type = ((LeafSchemaNode) node).getType();
+ } else if(node instanceof LeafListSchemaNode) {
+ type = ((LeafListSchemaNode) node).getType();
+ } else {
+ type = null;
+ }
+ String prefix = "get";
+ if(type != null) {
+ TypeDefinition<?> rootType = type;
+ while (rootType.getBaseType() != null) {
+ rootType = rootType.getBaseType();
+ }
+ if(rootType instanceof BooleanTypeDefinition) {
+ prefix = "is";
+ }
+ }
+
+ return prefix + BindingMapping.getClassName(node.getQName().getLocalName());
+ }
+
+ @Override
+ DataObjectSerializerSource generateCaseSerializer(final GeneratedType type, final ChoiceCaseNode node) {
+ return new AugmentableDataNodeContainerEmmiterSource(type, node) {
+ @Override
+ public CharSequence emitStartEvent() {
+ return startCaseNode(classReference(type),getChildSizeFromSchema(node));
+ }
+ };
+ }
+
+ @Override
+ DataObjectSerializerSource generateUnkeyedListEntrySerializer(final GeneratedType type, final ListSchemaNode node) {
+ return new AugmentableDataNodeContainerEmmiterSource(type, node) {
+
+ @Override
+ public CharSequence emitStartEvent() {
+ return startUnkeyedListItem(getChildSizeFromSchema(schemaNode));
+ }
+ };
+ }
+
+ @Override
+ DataObjectSerializerSource generateSerializer(final GeneratedType type, final AugmentationSchema schema) {
+ return new DataNodeContainerSerializerSource(type,schema) {
+
+ @Override
+ public CharSequence emitStartEvent() {
+ return startAugmentationNode(classReference(type));
+ }
+ };
+ }
+
+ @Override
+ DataObjectSerializerSource generateMapEntrySerializer(final GeneratedType type, final ListSchemaNode node) {
+ return new AugmentableDataNodeContainerEmmiterSource(type, node) {
+
+ @Override
+ public CharSequence emitStartEvent() {
+ return startMapEntryNode(invoke(INPUT, "getKey"), getChildSizeFromSchema(node));
+ }
+ };
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.gen.spi;
+
+import com.google.common.collect.Iterators;
+import com.google.common.collect.UnmodifiableIterator;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import org.opendaylight.yangtools.sal.binding.model.api.Type;
+
+public abstract class AbstractSource {
+
+ private final Set<StaticConstantDefinition> staticConstants = new HashSet<>();
+
+ public final <T> void staticConstant(final String name, final Class<T> type, final T value) {
+ staticConstants.add(new StaticConstantDefinition(name, type, value));
+ }
+
+ public final Set<StaticConstantDefinition> getStaticConstants() {
+ return Collections.unmodifiableSet(staticConstants);
+ }
+
+ protected final CharSequence invoke(final CharSequence object, final String methodName, final Object... args) {
+ StringBuilder builder = new StringBuilder();
+ if (object != null) {
+ builder.append(object);
+ builder.append(".");
+ }
+ builder.append(methodName);
+ builder.append('(');
+
+ UnmodifiableIterator<Object> iterator = Iterators.forArray(args);
+ while (iterator.hasNext()) {
+ builder.append(iterator.next());
+ if (iterator.hasNext()) {
+ builder.append(',');
+ }
+ }
+ builder.append(')');
+ return builder;
+ }
+
+ protected final CharSequence assign(final String var, final CharSequence value) {
+ return assign((String) null, var, value);
+ }
+
+ protected final CharSequence assign(final String type, final String var, final CharSequence value) {
+ StringBuilder builder = new StringBuilder();
+ if(type != null) {
+ builder.append(type);
+ builder.append(' ');
+ }
+ builder.append(var);
+ builder.append(" = ");
+ builder.append(value);
+ return builder;
+ }
+
+ protected final CharSequence assign(final Type type, final String var, final CharSequence value) {
+ return assign(type.getFullyQualifiedName(), var, value);
+ }
+
+ protected final CharSequence cast(final Type type, final CharSequence value) {
+ return cast(type.getFullyQualifiedName(), value);
+ }
+
+ protected final CharSequence forEach(final String iterable,final String iteratorName, final String valueType,final String valueName, final CharSequence body) {
+ StringBuilder b = new StringBuilder();
+ b.append(statement(assign(java.util.Iterator.class.getName(), iteratorName,invoke(iterable, "iterator"))));
+ b.append("while (").append(invoke(iteratorName, "hasNext")).append(") {\n");
+ b.append(statement(assign(valueType, valueName,cast(valueType, invoke(iteratorName, "next")))));
+ b.append(body);
+ b.append("\n}\n");
+ return b;
+ }
+
+ protected final CharSequence statement(final CharSequence statement) {
+ return new StringBuilder().append(statement).append(";\n");
+ }
+
+ protected final CharSequence cast(final String type, final CharSequence value) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("((");
+ builder.append(type);
+ builder.append(')');
+ builder.append(' ');
+ builder.append(value);
+ builder.append(')');
+ return builder;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.gen.spi;
+
+import com.google.common.base.Preconditions;
+
+/**
+ *
+ * Definition of static property for generated class
+ * <p>
+ * This definition consists of
+ * <ul>
+ * <li>name - property name</li>
+ * <li>type - Java type for property</li>
+ * <li>value - value to which property should be initialized</li>
+ *
+ */
+public class StaticConstantDefinition {
+
+ private final String name;
+ private final Class<?> type;
+ private final Object value;
+
+ public StaticConstantDefinition(final String name, final Class<?> type, final Object value) {
+ super();
+ this.name = Preconditions.checkNotNull(name);
+ this.type = Preconditions.checkNotNull(type);
+ this.value = Preconditions.checkNotNull(value);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Class<?> getType() {
+ return type;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + name.hashCode();
+ return result;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ StaticConstantDefinition other = (StaticConstantDefinition) obj;
+ if (!name.equals(other.name)) {
+ return false;
+ }
+ return true;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+
+public class AugmentationNode extends DataObjectCodecContext<AugmentationSchema> {
+
+ private final YangInstanceIdentifier.PathArgument yangIdentifier;
+
+ public AugmentationNode(final Class<?> cls, final QNameModule namespace,
+ final AugmentationIdentifier identifier, final AugmentationSchema nodeSchema,
+ final CodecContextFactory loader) {
+ super(cls, namespace, nodeSchema, loader);
+ this.yangIdentifier = identifier;
+ }
+
+ @Override
+ public YangInstanceIdentifier.PathArgument getDomPathArgument() {
+ return yangIdentifier;
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.AbstractMap.SimpleEntry;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.opendaylight.yangtools.binding.data.codec.impl.NodeCodecContext.CodecContextFactory;
+import org.opendaylight.yangtools.concepts.Codec;
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
+import org.opendaylight.yangtools.util.ClassLoaderUtils;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.BindingMapping;
+import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
+
+class BindingCodecContext implements CodecContextFactory, Immutable {
+
+ private static final String GETTER_PREFIX = "get";
+ private final SchemaRootCodecContext root;
+ private final BindingRuntimeContext context;
+ private final Codec<YangInstanceIdentifier,InstanceIdentifier<?>> instanceIdentifierCodec;
+ private final Codec<QName,Class<?>> identityCodec;
+
+ public BindingCodecContext(final BindingRuntimeContext context) {
+ this.context = Preconditions.checkNotNull(context, "Bidning Runtime Context is required.");
+ this.root = SchemaRootCodecContext.create(this);
+ this.instanceIdentifierCodec = new InstanceIdentifierCodec();
+ this.identityCodec = new IdentityCodec();
+ }
+
+ @Override
+ public BindingRuntimeContext getRuntimeContext() {
+ return context;
+ }
+
+ public Codec<YangInstanceIdentifier,InstanceIdentifier<?>> getInstanceIdentifierCodec() {
+ return instanceIdentifierCodec;
+ }
+
+ public Codec<QName, Class<?>> getIdentityCodec() {
+ return identityCodec;
+ }
+
+ public Entry<YangInstanceIdentifier, BindingStreamEventWriter> newWriter(final InstanceIdentifier<?> path,
+ final NormalizedNodeStreamWriter domWriter) {
+ LinkedList<YangInstanceIdentifier.PathArgument> yangArgs = new LinkedList<>();
+ DataContainerCodecContext<?> codecContext = getCodecContextNode(path, yangArgs);
+ BindingStreamEventWriter writer = new BindingToNormalizedStreamWriter(codecContext, domWriter);
+ return new SimpleEntry<>(YangInstanceIdentifier.create(yangArgs), writer);
+ }
+
+ public BindingStreamEventWriter newWriterWithoutIdentifier(final InstanceIdentifier<?> path,
+ final NormalizedNodeStreamWriter domWriter) {
+ return new BindingToNormalizedStreamWriter(getCodecContextNode(path, null), domWriter);
+ }
+
+ public DataContainerCodecContext<?> getCodecContextNode(final InstanceIdentifier<?> binding,
+ final List<YangInstanceIdentifier.PathArgument> builder) {
+ DataContainerCodecContext<?> currentNode = root;
+ for (InstanceIdentifier.PathArgument bindingArg : binding.getPathArguments()) {
+ currentNode = currentNode.getIdentifierChild(bindingArg, builder);
+ }
+ return currentNode;
+ }
+
+ public NodeCodecContext getCodecContextNode(final YangInstanceIdentifier dom,
+ final List<InstanceIdentifier.PathArgument> builder) {
+ NodeCodecContext currentNode = root;
+ ListNodeCodecContext currentList = null;
+ for (YangInstanceIdentifier.PathArgument domArg : dom.getPathArguments()) {
+ Preconditions.checkArgument(currentNode instanceof DataContainerCodecContext<?>);
+ DataContainerCodecContext<?> previous = (DataContainerCodecContext<?>) currentNode;
+ NodeCodecContext nextNode = previous.getYangIdentifierChild(domArg);
+ /*
+ * List representation in YANG Instance Identifier consists of two
+ * arguments: first is list as a whole, second is list as an item so
+ * if it is /list it means list as whole, if it is /list/list - it
+ * is wildcarded and if it is /list/list[key] it is concrete item,
+ * all this variations are expressed in Binding Aware Instance
+ * Identifier as Item or IdentifiableItem
+ */
+ if (currentList != null) {
+
+ if (currentList == nextNode) {
+
+ // We entered list, so now we have all information to emit
+ // list
+ // path using second list argument.
+ builder.add(currentList.getBindingPathArgument(domArg));
+ currentList = null;
+ currentNode = nextNode;
+ } else {
+ throw new IllegalArgumentException(
+ "List should be referenced two times in YANG Instance Identifier");
+ }
+ } else if (nextNode instanceof ListNodeCodecContext) {
+ // We enter list, we do not update current Node yet,
+ // since we need to verify
+ currentList = (ListNodeCodecContext) nextNode;
+ } else if (nextNode instanceof ChoiceNodeCodecContext) {
+ // We do not add path argument for choice, since
+ // it is not supported by binding instance identifier.
+ currentNode = nextNode;
+ }else if (nextNode instanceof DataContainerCodecContext<?>) {
+ builder.add(((DataContainerCodecContext<?>) nextNode).getBindingPathArgument(domArg));
+ currentNode = nextNode;
+ } else if (nextNode instanceof LeafNodeCodecContext) {
+ Preconditions.checkArgument(builder == null,"Instance Identifier for leaf is not representable.");
+ }
+ }
+ // Algorithm ended in list as whole representation
+ // we sill need to emit identifier for list
+ if (currentList != null) {
+ builder.add(currentList.getBindingPathArgument(null));
+ return currentList;
+ }
+ return currentNode;
+ }
+
+ @Override
+ public ImmutableMap<String, LeafNodeCodecContext> getLeafNodes(final Class<?> parentClass, final DataNodeContainer childSchema) {
+ HashMap<String, DataSchemaNode> getterToLeafSchema = new HashMap<>();
+ for (DataSchemaNode leaf : childSchema.getChildNodes()) {
+ final TypeDefinition<?> typeDef;
+ if (leaf instanceof LeafSchemaNode) {
+ typeDef = ((LeafSchemaNode) leaf).getType();
+ } else if (leaf instanceof LeafListSchemaNode) {
+ typeDef = ((LeafListSchemaNode) leaf).getType();
+ } else {
+ continue;
+ }
+
+ String getterName = getGetterName(leaf.getQName(),typeDef);
+ getterToLeafSchema.put(getterName, leaf);
+ }
+ return getLeafNodesUsingReflection(parentClass, getterToLeafSchema);
+ }
+
+ private String getGetterName(final QName qName, TypeDefinition<?> typeDef) {
+ String suffix = BindingMapping.getClassName(qName);
+
+ while(typeDef.getBaseType() != null) {
+ typeDef = typeDef.getBaseType();
+ }
+ if(typeDef instanceof BooleanTypeDefinition) {
+ return "is" + suffix;
+ }
+ return GETTER_PREFIX + suffix;
+ }
+
+ private ImmutableMap<String, LeafNodeCodecContext> getLeafNodesUsingReflection(final Class<?> parentClass,
+ final Map<String, DataSchemaNode> getterToLeafSchema) {
+ Map<String, LeafNodeCodecContext> leaves = new HashMap<>();
+ for (Method method : parentClass.getMethods()) {
+ if (method.getParameterTypes().length == 0) {
+ DataSchemaNode schema = getterToLeafSchema.get(method.getName());
+ final LeafNodeCodecContext leafNode;
+ if (schema instanceof LeafSchemaNode) {
+ leafNode = leafNodeFrom(method.getReturnType(), schema);
+
+ } else {
+ // FIXME: extract inner list value
+ leafNode = null;
+ }
+ if (leafNode != null) {
+ leaves.put(schema.getQName().getLocalName(), leafNode);
+ }
+ }
+ }
+ return ImmutableMap.copyOf(leaves);
+ }
+
+
+ private LeafNodeCodecContext leafNodeFrom(final Class<?> returnType, final DataSchemaNode schema) {
+ return new LeafNodeCodecContext(schema, getCodec(returnType,schema));
+ }
+
+ private Codec<Object, Object> getCodec(final Class<?> returnType, final DataSchemaNode schema) {
+ if(Class.class.equals(returnType)) {
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ final Codec<Object,Object>casted = (Codec) identityCodec;
+ return casted;
+ } else if(InstanceIdentifier.class.equals(returnType)) {
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ final Codec<Object,Object>casted = (Codec) instanceIdentifierCodec;
+ return casted;
+ } else if(BindingReflections.isBindingClass(returnType)) {
+ final TypeDefinition<?> instantiatedType;
+ if(schema instanceof LeafSchemaNode) {
+ instantiatedType = ((LeafSchemaNode) schema).getType();
+ } else if(schema instanceof LeafListSchemaNode) {
+ instantiatedType = ((LeafListSchemaNode) schema).getType();
+ } else {
+ instantiatedType = null;
+ }
+ if(instantiatedType != null) {
+ return getCodec(returnType,instantiatedType);
+ }
+ }
+ return ValueTypeCodec.NOOP_CODEC;
+ }
+
+ private Codec<Object, Object> getCodec(final Class<?> returnType, final TypeDefinition<?> instantiatedType) {
+ @SuppressWarnings("rawtypes")
+ TypeDefinition rootType = instantiatedType;
+ while(rootType.getBaseType() != null) {
+ rootType = rootType.getBaseType();
+ }
+ if (rootType instanceof IdentityrefTypeDefinition) {
+ return ValueTypeCodec.encapsulatedValueCodecFor(returnType,identityCodec);
+ } else if (rootType instanceof InstanceIdentifierTypeDefinition) {
+ return ValueTypeCodec.encapsulatedValueCodecFor(returnType,instanceIdentifierCodec);
+ } else if(rootType instanceof UnionTypeDefinition) {
+ // FIXME: Return union codec
+ return ValueTypeCodec.NOOP_CODEC;
+ }
+ return ValueTypeCodec.getCodecFor(returnType, instantiatedType);
+ }
+
+ private class InstanceIdentifierCodec implements Codec<YangInstanceIdentifier,InstanceIdentifier<?>> {
+
+ @Override
+ public YangInstanceIdentifier serialize(final InstanceIdentifier<?> input) {
+ List<YangInstanceIdentifier.PathArgument> domArgs = new LinkedList<>();
+ getCodecContextNode(input, domArgs);
+ return YangInstanceIdentifier.create(domArgs);
+ }
+
+ @Override
+ public InstanceIdentifier<?> deserialize(final YangInstanceIdentifier input) {
+ List<InstanceIdentifier.PathArgument> builder = new LinkedList<>();
+ getCodecContextNode(input, builder);
+ return InstanceIdentifier.create(builder);
+ }
+ }
+
+ private class IdentityCodec implements Codec<QName,Class<?>> {
+
+
+ @Override
+ public Class<?> deserialize(final QName input) {
+ Preconditions.checkArgument(input != null, "Input must not be null.");
+ return context.getIdentityClass(input);
+ }
+
+ @Override
+ public QName serialize(final Class<?> input) {
+ Preconditions.checkArgument(BaseIdentity.class.isAssignableFrom(input));
+ return BindingReflections.findQName(input);
+ }
+ }
+
+ private static class ValueContext {
+
+ Method getter;
+ Codec<Object,Object> codec;
+
+ public ValueContext(final Class<?> identifier, final LeafNodeCodecContext leaf) {
+ final String getterName = GETTER_PREFIX + BindingMapping.getClassName(leaf.getDomPathArgument().getNodeType());
+ try {
+ getter =identifier.getMethod(getterName);
+ } catch (NoSuchMethodException | SecurityException e) {
+ throw new IllegalStateException(e);
+ }
+ codec = leaf.getValueCodec();
+ }
+
+ public Object getAndSerialize(final Object obj) {
+ try {
+ Object value = getter.invoke(obj);
+ return codec.serialize(value);
+ } catch (IllegalAccessException | InvocationTargetException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ public Object deserialize(final Object obj) {
+ return codec.deserialize(obj);
+ }
+
+ }
+
+ private class IdentifiableItemCodec implements Codec<NodeIdentifierWithPredicates, IdentifiableItem<?, ?>> {
+
+ private final Class<? extends Identifier<?>> keyClass;
+ private final ImmutableMap<QName, ValueContext> keyValueContexts;
+ private final QName name;
+ private final Constructor<? extends Identifier<?>> constructor;
+ private final Class<?> identifiable;
+
+ public IdentifiableItemCodec(final QName name,final Class<? extends Identifier<?>> keyClass,final Class<?> identifiable,final Map<QName, ValueContext> keyValueContexts) {
+ this.name = name;
+ this.identifiable = identifiable;
+ this.keyClass = keyClass;
+ this.keyValueContexts = ImmutableMap.copyOf(keyValueContexts);
+ this.constructor = getConstructor(keyClass);
+ }
+
+ @Override
+ public IdentifiableItem<?,?> deserialize(final NodeIdentifierWithPredicates input) {
+ ArrayList<Object> bindingValues = new ArrayList<>();
+ for(Entry<QName, Object> yangEntry : input.getKeyValues().entrySet()) {
+ QName yangName = yangEntry.getKey();
+ Object yangValue = yangEntry.getValue();
+ bindingValues.add(keyValueContexts.get(yangName).deserialize(yangValue));
+ }
+ try {
+ Identifier<?> identifier = constructor.newInstance(bindingValues.toArray());
+ return new IdentifiableItem(identifiable, identifier);
+ } catch (InstantiationException | IllegalAccessException
+ | InvocationTargetException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override
+ public NodeIdentifierWithPredicates serialize(final IdentifiableItem<?, ?> input) {
+ Object value = input.getKey();
+
+ Map<QName,Object> values = new HashMap<>();
+ for(Entry<QName, ValueContext> valueCtx : keyValueContexts.entrySet()) {
+ values.put(valueCtx.getKey(), valueCtx.getValue().getAndSerialize(value));
+ }
+ return new NodeIdentifierWithPredicates(name, values);
+ }
+
+ }
+
+ private static Constructor<? extends Identifier<?>> getConstructor(final Class<? extends Identifier<?>> clazz) {
+ for(Constructor constr : clazz.getConstructors()) {
+ Class<?>[] parameters = constr.getParameterTypes();
+ if (!clazz.equals(parameters[0])) {
+ // It is not copy constructor;
+ return constr;
+ }
+ }
+ throw new IllegalArgumentException("Supplied class " + clazz +"does not have required constructor.");
+ }
+
+
+ @Override
+ public Codec<NodeIdentifierWithPredicates, IdentifiableItem<?, ?>> getPathArgumentCodec(final Class<?> listClz,
+ final ListSchemaNode schema) {
+ Class<? extends Identifier<?>> identifier =ClassLoaderUtils.findFirstGenericArgument(listClz, Identifiable.class);
+ Map<QName, ValueContext> valueCtx = new HashMap<>();
+ for(LeafNodeCodecContext leaf : getLeafNodes(identifier, schema).values()) {
+ QName name = leaf.getDomPathArgument().getNodeType();
+ valueCtx.put(name, new ValueContext(identifier,leaf));
+ }
+ return new IdentifiableItemCodec(schema.getQName(), identifier, listClz, valueCtx);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import com.google.common.base.Preconditions;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import java.util.AbstractMap.SimpleEntry;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
+import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeWriterFactory;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.AbstractStreamWriterGenerator;
+import org.opendaylight.yangtools.concepts.Delegator;
+import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
+import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializer;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializerImplementation;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializerRegistry;
+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.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
+
+public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerRegistry, BindingNormalizedNodeWriterFactory, BindingNormalizedNodeSerializer {
+
+ private final AbstractStreamWriterGenerator generator;
+ private final LoadingCache<Class<? extends DataObject>, DataObjectSerializer> serializers;
+ private BindingCodecContext codecContext;
+
+ public BindingNormalizedNodeCodecRegistry(final AbstractStreamWriterGenerator generator) {
+ this.generator = Preconditions.checkNotNull(generator);
+ this.serializers = CacheBuilder.newBuilder().weakKeys().build(new GeneratorLoader());
+ }
+
+ @Override
+ public DataObjectSerializer getSerializer(final Class<? extends DataObject> type) {
+ return serializers.getUnchecked(type);
+ }
+
+ public BindingCodecContext getCodecContext() {
+ return codecContext;
+ }
+
+ public void onBindingRuntimeContextUpdated(final BindingRuntimeContext context) {
+ codecContext = new BindingCodecContext(context);
+ generator.onBindingRuntimeContextUpdated(context);
+ }
+
+
+ @Override
+ public YangInstanceIdentifier toYangInstanceIdentifier(final InstanceIdentifier<?> binding) {
+ List<YangInstanceIdentifier.PathArgument> builder = new LinkedList<>();
+ codecContext.getCodecContextNode(binding, builder);
+ return codecContext.getInstanceIdentifierCodec().serialize(binding);
+ }
+
+ @Override
+ public InstanceIdentifier<?> fromYangInstanceIdentifier(final YangInstanceIdentifier dom) {
+ return codecContext.getInstanceIdentifierCodec().deserialize(dom);
+ }
+
+ @Override
+ public <T extends DataObject> Entry<YangInstanceIdentifier,NormalizedNode<?,?>> toNormalizedNode(final InstanceIdentifier<T> path, final T data) {
+ NormalizedNodeResult result = new NormalizedNodeResult();
+ // We create dom stream writer which produces normalized nodes
+ NormalizedNodeStreamWriter domWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+
+ // We create Binding Stream Writer wchich translates from Binding to Normalized Nodes
+ Entry<YangInstanceIdentifier, BindingStreamEventWriter> writeCtx = codecContext.newWriter(path, domWriter);
+
+ // We get serializer which reads binding data and uses Binding To NOrmalized Node writer to write result
+ getSerializer(path.getTargetType()).serialize(data, writeCtx.getValue());
+ return new SimpleEntry<YangInstanceIdentifier,NormalizedNode<?,?>>(writeCtx.getKey(),result.getResult());
+ }
+
+ @Override
+ public Entry<InstanceIdentifier<?>, DataObject> fromNormalizedNode(final YangInstanceIdentifier path,
+ final NormalizedNode<?, ?> data) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ @Override
+ public Map<InstanceIdentifier<?>, DataObject> fromNormalizedNodes(
+ final Map<YangInstanceIdentifier, NormalizedNode<?, ?>> dom) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ @Override
+ public Entry<YangInstanceIdentifier, BindingStreamEventWriter> newWriterAndIdentifier(final InstanceIdentifier<?> path, final NormalizedNodeStreamWriter domWriter) {
+ return codecContext.newWriter(path, domWriter);
+ }
+
+ @Override
+ public BindingStreamEventWriter newWriter(final InstanceIdentifier<?> path, final NormalizedNodeStreamWriter domWriter) {
+ return codecContext.newWriterWithoutIdentifier(path, domWriter);
+ }
+
+ private class GeneratorLoader extends CacheLoader<Class<? extends DataObject>, DataObjectSerializer> {
+
+ @Override
+ public DataObjectSerializer load(final Class<? extends DataObject> key) throws Exception {
+ DataObjectSerializerImplementation prototype = generator.getSerializer(key);
+ return new DataObjectSerializerProxy(prototype);
+ }
+ }
+
+ private class DataObjectSerializerProxy implements DataObjectSerializer,
+ Delegator<DataObjectSerializerImplementation> {
+
+ private final DataObjectSerializerImplementation delegate;
+
+ DataObjectSerializerProxy(final DataObjectSerializerImplementation delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public DataObjectSerializerImplementation getDelegate() {
+ return delegate;
+ }
+
+ @Override
+ public void serialize(final DataObject obj, final BindingStreamEventWriter stream) {
+ delegate.serialize(BindingNormalizedNodeCodecRegistry.this, obj, stream);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import com.google.common.base.Preconditions;
+
+import java.util.AbstractMap;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.opendaylight.yangtools.concepts.Delegator;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
+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.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+
+class BindingToNormalizedStreamWriter implements BindingStreamEventWriter, Delegator<NormalizedNodeStreamWriter> {
+
+ private final NormalizedNodeStreamWriter delegate;
+ private final Deque<NodeCodecContext> schema = new ArrayDeque<>();
+ private final NodeCodecContext rootNodeSchema;
+
+ public BindingToNormalizedStreamWriter(final NodeCodecContext schema, final NormalizedNodeStreamWriter delegate) {
+ this.delegate = Preconditions.checkNotNull(delegate, "Delegate must not be null");
+ this.rootNodeSchema = Preconditions.checkNotNull(schema);
+
+ }
+
+ private NodeCodecContext current() {
+ return schema.peek();
+ }
+
+ private NodeIdentifier duplicateSchemaEnter() {
+ final NodeCodecContext next;
+ if (current() == null) {
+ // Entry of first node
+ next = rootNodeSchema;
+ } else {
+ next = current();
+ }
+ this.schema.push(next);
+ return (NodeIdentifier) current().getDomPathArgument();
+ }
+
+ private <T extends YangInstanceIdentifier.PathArgument> T enter(final Class<?> name, final Class<T> identifier) {
+ final NodeCodecContext next;
+ if (current() == null) {
+ // Entry of first node
+ next = rootNodeSchema;
+ } else {
+ Preconditions.checkArgument((current() instanceof DataContainerCodecContext), "Could not start node %s",
+ name);
+ next = ((DataContainerCodecContext<?>) current()).getStreamChild(name);
+ }
+ this.schema.push(next);
+ @SuppressWarnings("unchecked")
+ T arg = (T) next.getDomPathArgument();
+ return arg;
+ }
+
+ private <T extends YangInstanceIdentifier.PathArgument> T enter(final String localName, final Class<T> identifier) {
+ NodeCodecContext current = current();
+ NodeCodecContext next = ((DataObjectCodecContext<?>) current).getLeafChild(localName);
+ this.schema.push(next);
+ @SuppressWarnings("unchecked")
+ T arg = (T) next.getDomPathArgument();
+ return arg;
+ }
+
+ @Override
+ public void endNode() {
+ NodeCodecContext left = schema.pop();
+ // NormalizedNode writer does not have entry into case, but into choice
+ // so for leaving case, we do not emit endNode.
+ if (!(left instanceof CaseNodeCodecContext)) {
+ getDelegate().endNode();
+ }
+ }
+
+ @Override
+ public NormalizedNodeStreamWriter getDelegate() {
+ return delegate;
+ }
+
+ private Map.Entry<NodeIdentifier, Object> serializeLeaf(final String localName, final Object value) {
+ Preconditions.checkArgument(current() instanceof DataObjectCodecContext<?>);
+
+ DataObjectCodecContext<?> currentCasted = (DataObjectCodecContext<?>) current();
+ LeafNodeCodecContext leafContext = currentCasted.getLeafChild(localName);
+
+ NodeIdentifier domArg = (NodeIdentifier) leafContext.getDomPathArgument();
+ Object domValue = leafContext.getValueCodec().serialize(value);
+ return new AbstractMap.SimpleEntry<>(domArg, domValue);
+ }
+
+ @Override
+ public void leafNode(final String localName, final Object value) throws IllegalArgumentException {
+ Entry<NodeIdentifier, Object> dom = serializeLeaf(localName, value);
+ getDelegate().leafNode(dom.getKey(), dom.getValue());
+ };
+
+ @Override
+ public void anyxmlNode(final String name, final Object value) throws IllegalArgumentException {
+ Entry<NodeIdentifier, Object> dom = serializeLeaf(name, value);
+ getDelegate().anyxmlNode(dom.getKey(), dom.getValue());
+ }
+
+ @Override
+ public void leafSetEntryNode(final Object value) throws IllegalArgumentException {
+ LeafNodeCodecContext ctx = (LeafNodeCodecContext) current();
+ getDelegate().leafSetEntryNode(ctx.getValueCodec().serialize(value));
+ }
+
+ @Override
+ public void startAugmentationNode(final Class<? extends Augmentation<?>> augmentationType)
+ throws IllegalArgumentException {
+ getDelegate().startAugmentationNode(enter(augmentationType, AugmentationIdentifier.class));
+ }
+
+ @Override
+ public void startCase(final Class<? extends DataObject> caze, final int childSizeHint)
+ throws IllegalArgumentException {
+ enter(caze, NodeIdentifier.class);
+ };
+
+ @Override
+ public void startChoiceNode(final Class<? extends DataContainer> type, final int childSizeHint)
+ throws IllegalArgumentException {
+ getDelegate().startChoiceNode(enter(type, NodeIdentifier.class), childSizeHint);
+ }
+
+ @Override
+ public void startContainerNode(final Class<? extends DataObject> object, final int childSizeHint)
+ throws IllegalArgumentException {
+ getDelegate().startContainerNode(enter(object, NodeIdentifier.class), childSizeHint);
+ }
+
+ @Override
+ public void startLeafSet(final String localName, final int childSizeHint) throws IllegalArgumentException {
+ getDelegate().startLeafSet(enter(localName, NodeIdentifier.class), childSizeHint);
+ };
+
+ @Override
+ public void startMapEntryNode(final Identifier<?> key, final int childSizeHint) throws IllegalArgumentException {
+ duplicateSchemaEnter();
+ NodeIdentifierWithPredicates identifier = ((ListNodeCodecContext) current()).serialize(key);
+ getDelegate().startMapEntryNode(identifier, childSizeHint);
+ };
+
+ @Override
+ public <T extends DataObject & Identifiable<?>> void startMapNode(final Class<T> mapEntryType,
+ final int childSizeHint) throws IllegalArgumentException {
+ getDelegate().startMapNode(enter(mapEntryType, NodeIdentifier.class), childSizeHint);
+ };
+
+ @Override
+ public <T extends DataObject & Identifiable<?>> void startOrderedMapNode(final Class<T> mapEntryType,
+ final int childSizeHint) throws IllegalArgumentException {
+ getDelegate().startOrderedMapNode(enter(mapEntryType, NodeIdentifier.class), childSizeHint);
+ };
+
+ @Override
+ public void startUnkeyedList(final Class<? extends DataObject> obj, final int childSizeHint)
+ throws IllegalArgumentException {
+ getDelegate().startUnkeyedList(enter(obj, NodeIdentifier.class), childSizeHint);
+ };
+
+ @Override
+ public void startUnkeyedListItem(final int childSizeHint) throws IllegalStateException {
+ getDelegate().startUnkeyedListItem(duplicateSchemaEnter(), childSizeHint);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableSortedMap;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.HashSet;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.concurrent.Callable;
+import org.opendaylight.yangtools.yang.binding.BindingMapping;
+import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition.Bit;
+
+class BitsCodec extends ReflectionBasedCodec {
+
+ private final ImmutableSortedMap<String, Method> valueGetters;
+ private final Constructor<?> constructor;
+
+ private BitsCodec(final Class<?> typeClass, final SortedMap<String, Method> valueGetters,
+ final Constructor<?> constructor) {
+ super(typeClass);
+ this.valueGetters = ImmutableSortedMap.copyOf(valueGetters);
+ this.constructor = constructor;
+ }
+
+ static Callable<ReflectionBasedCodec> loader(final Class<?> returnType,
+ final BitsTypeDefinition rootType) {
+ return new Callable<ReflectionBasedCodec>() {
+
+ @Override
+ public ReflectionBasedCodec call() throws Exception {
+ try {
+ SortedMap<String, Method> valueGetters = new TreeMap<>();
+ for (Bit bit : rootType.getBits()) {
+ String bindingName = BindingMapping.getClassName(bit.getName());
+ Method valueGetter = returnType.getMethod("is" + bindingName);
+ valueGetters.put(bit.getName(), valueGetter);
+
+ }
+ Constructor<?> constructor = null;
+ for (Constructor<?> cst : returnType.getConstructors()) {
+ if (cst.getParameterTypes()[0].equals(returnType)) {
+ continue;
+ }
+ constructor = cst;
+ }
+
+ return new BitsCodec(returnType, valueGetters, constructor);
+ } catch (IllegalArgumentException | NoSuchMethodException | SecurityException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ };
+ }
+
+ @Override
+ public Object deserialize(final Object input) {
+ Preconditions.checkArgument(input instanceof Set);
+ @SuppressWarnings("unchecked")
+ Set<String> casted = (Set<String>) input;
+
+ Object args[] = new Object[valueGetters.size()];
+ int currentArg = 0;
+ for (String value : valueGetters.keySet()) {
+ if (casted.contains(value)) {
+ args[currentArg] = Boolean.TRUE;
+ } else {
+ args[currentArg] = Boolean.FALSE;
+ }
+ currentArg++;
+ }
+
+ try {
+ return constructor.newInstance(args);
+ } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override
+ public Object serialize(final Object input) {
+ Set<String> result = new HashSet<>();
+ for (Entry<String, Method> valueGet : valueGetters.entrySet()) {
+ try {
+ Boolean value = (Boolean) valueGet.getValue().invoke(input);
+ if (value) {
+ result.add(valueGet.getKey());
+ }
+ } catch (IllegalAccessException | InvocationTargetException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+ return result;
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import java.util.List;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+
+class CaseNodeCodecContext extends DataObjectCodecContext<ChoiceCaseNode> {
+
+ private final YangInstanceIdentifier.PathArgument yangIdentifier;
+
+ CaseNodeCodecContext(final Class<?> cls, final ChoiceCaseNode nodeSchema,
+ final CodecContextFactory runtimeContext) {
+ super(cls, nodeSchema.getQName().getModule(), nodeSchema, runtimeContext);
+ this.yangIdentifier = (new YangInstanceIdentifier.NodeIdentifier(nodeSchema.getQName()));
+ }
+
+ @Override
+ protected YangInstanceIdentifier.PathArgument getDomPathArgument() {
+ return yangIdentifier;
+ }
+
+ @Override
+ protected void addYangPathArgument(final PathArgument arg,
+ final List<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument> builder) {
+ // NOOP
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import java.util.HashMap;
+import java.util.Map;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+class ChoiceNodeCodecContext extends DataContainerCodecContext<ChoiceNode> {
+
+ private final YangInstanceIdentifier.PathArgument yangArgument;
+ private final ImmutableMap<QName, ChoiceCaseNode> caseChildToCase;
+
+ ChoiceNodeCodecContext(final Class<?> cls, final ChoiceNode nodeSchema, final CodecContextFactory context) {
+ super(cls, nodeSchema.getQName().getModule(), nodeSchema, context);
+ Map<QName, ChoiceCaseNode> childToCase = new HashMap<>();
+ yangArgument = new YangInstanceIdentifier.NodeIdentifier(nodeSchema.getQName());
+ for (ChoiceCaseNode caseNode : nodeSchema.getCases()) {
+ for (DataSchemaNode caseChild : caseNode.getChildNodes()) {
+ childToCase.put(caseChild.getQName(), caseNode);
+ }
+ }
+ caseChildToCase = ImmutableMap.copyOf(childToCase);
+ }
+
+ @Override
+ protected YangInstanceIdentifier.PathArgument getDomPathArgument() {
+ return yangArgument;
+ }
+
+ @Override
+ protected DataContainerCodecContext<?> loadChild(final Class<?> childClass) {
+
+ ChoiceCaseNode childSchema = factory.getRuntimeContext().getCaseSchemaDefinition(schema, childClass);
+ return new CaseNodeCodecContext(childClass, childSchema, factory);
+ }
+
+ @Override
+ protected NodeCodecContext getYangIdentifierChild(final YangInstanceIdentifier.PathArgument arg) {
+
+ QName childQName = arg.getNodeType();
+ ChoiceCaseNode caze = caseChildToCase.get(childQName);
+ Preconditions.checkArgument(caze != null, "Argument %s is not valid child of %s", arg, schema);
+ ;
+ Class<?> cazeClass = factory.getRuntimeContext().getClassForSchema(caze);
+ return getStreamChild(cazeClass).getYangIdentifierChild(arg);
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import org.opendaylight.yangtools.concepts.Codec;
+
+class CompositeValueCodec extends ValueTypeCodec {
+
+ private final ValueTypeCodec bindingToSimpleType;
+ @SuppressWarnings("rawtypes")
+ private final Codec bindingToDom;
+
+ CompositeValueCodec(final ValueTypeCodec extractor,
+ @SuppressWarnings("rawtypes") final Codec delegate) {
+ this.bindingToSimpleType = extractor;
+ this.bindingToDom = delegate;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Object deserialize(final Object input) {
+ return bindingToSimpleType.deserialize(bindingToDom.deserialize(input));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Object serialize(final Object input) {
+ return bindingToDom.serialize(bindingToSimpleType.serialize(input));
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+
+class ContainerNodeCodecContext extends DataObjectCodecContext<ContainerSchemaNode> {
+
+ private final YangInstanceIdentifier.PathArgument yangIdentifier;
+
+ protected ContainerNodeCodecContext(final Class<?> cls, final ContainerSchemaNode nodeSchema,
+ final CodecContextFactory loader) {
+ super(cls, nodeSchema.getQName().getModule(), nodeSchema, loader);
+ this.yangIdentifier = (new YangInstanceIdentifier.NodeIdentifier(nodeSchema.getQName()));
+ }
+
+ @Override
+ protected YangInstanceIdentifier.PathArgument getDomPathArgument() {
+ return yangIdentifier;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import java.util.List;
+import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+abstract class DataContainerCodecContext<T> extends NodeCodecContext {
+
+ protected final T schema;
+ protected final QNameModule namespace;
+ protected final CodecContextFactory factory;
+ protected final Class<?> bindingClass;
+ protected final InstanceIdentifier.Item<?> bindingArg;
+
+ protected final LoadingCache<Class<?>, DataContainerCodecContext<?>> containerChild;
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ protected DataContainerCodecContext(final Class<?> cls, final QNameModule namespace, final T nodeSchema,
+ final CodecContextFactory factory) {
+ super();
+ this.schema = nodeSchema;
+ this.factory = factory;
+ this.namespace = namespace;
+ this.bindingClass = cls;
+ this.bindingArg = new InstanceIdentifier.Item(bindingClass);
+
+ this.containerChild = CacheBuilder.newBuilder().build(new CacheLoader<Class<?>, DataContainerCodecContext<?>>() {
+ @Override
+ public DataContainerCodecContext<?> load(final Class<?> key) throws Exception {
+ return loadChild(key);
+ }
+ });
+ }
+
+ static DataContainerCodecContext<?> from(final Class<?> cls, final DataSchemaNode schema,
+ final CodecContextFactory loader) {
+ if (schema instanceof ContainerSchemaNode) {
+ return new ContainerNodeCodecContext(cls, (ContainerSchemaNode) schema, loader);
+ } else if (schema instanceof ListSchemaNode) {
+ return new ListNodeCodecContext(cls, (ListSchemaNode) schema, loader);
+ } else if (schema instanceof ChoiceNode) {
+ return new ChoiceNodeCodecContext(cls, (ChoiceNode) schema, loader);
+ }
+ throw new IllegalArgumentException("Not supported type " + cls + " " + schema);
+ }
+
+ protected T getSchema() {
+ return schema;
+ }
+
+ /**
+ * Returns nested node context using supplied YANG Instance Identifier
+ *
+ * @param arg Yang Instance Identifier Argument
+ * @return Context of child
+ * @throws IllegalArgumentException If supplied argument does not represent valid child.
+ */
+ protected abstract NodeCodecContext getYangIdentifierChild(final YangInstanceIdentifier.PathArgument arg);
+
+ /**
+ * Returns nested node context using supplied Binding Instance Identifier
+ * and adds YANG instance identifiers to supplied list.
+ *
+ * @param arg Binding Instance Identifier Argument
+ * @return Context of child
+ * @throws IllegalArgumentException If supplied argument does not represent valid child.
+ */
+ protected DataContainerCodecContext<?> getIdentifierChild(final InstanceIdentifier.PathArgument arg,
+ final List<YangInstanceIdentifier.PathArgument> builder) {
+ final DataContainerCodecContext<?> child = getStreamChild(arg.getType());
+ if (builder != null) {
+ child.addYangPathArgument(arg,builder);
+ }
+ return child;
+ }
+
+ /**
+ *
+ * Returns deserialized Binding Path Argument from YANG instance identifier.
+ *
+ * @param domArg
+ * @return
+ */
+ protected PathArgument getBindingPathArgument(final YangInstanceIdentifier.PathArgument domArg) {
+ return bindingArg;
+ }
+
+ /**
+ *
+ * Returns child context as if it was walked by
+ * {@link BindingStreamEventWriter}. This means that to enter case, one
+ * must issue getChild(ChoiceClass).getChild(CaseClass).
+ *
+ * @param childClass
+ * @return Context of child
+ */
+ protected DataContainerCodecContext<?> getStreamChild(final Class<?> childClass) {
+ return containerChild.getUnchecked(childClass);
+ }
+
+ /**
+ * Loads children identified by supplied class. If children is not
+ * valid, throws {@link IllegalArgumentException}.
+ *
+ * @param childClass
+ * @return Context of child
+ */
+ protected abstract DataContainerCodecContext<?> loadChild(final Class<?> childClass);
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + " [" + bindingClass + "]";
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+
+import java.util.List;
+import java.util.Map.Entry;
+
+import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl;
+import org.opendaylight.yangtools.sal.binding.generator.api.ClassLoadingStrategy;
+import org.opendaylight.yangtools.sal.binding.model.api.Type;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.util.SchemaNodeUtils;
+
+abstract class DataObjectCodecContext<T extends DataNodeContainer> extends DataContainerCodecContext<T> {
+
+ protected final ImmutableMap<String, LeafNodeCodecContext> leafChild;
+ protected final ImmutableMap<Type, Entry<Type, Type>> choiceCaseChildren;
+ protected final ImmutableMap<AugmentationIdentifier, Type> augIdentifierToType;
+
+ protected DataObjectCodecContext(final Class<?> cls, final QNameModule namespace, final T nodeSchema,
+ final CodecContextFactory loader) {
+ super(cls, namespace, nodeSchema, loader);
+ this.leafChild = loader.getLeafNodes(cls, nodeSchema);
+ this.choiceCaseChildren = factory.getRuntimeContext().getChoiceCaseChildren(schema);
+ this.augIdentifierToType = factory.getRuntimeContext().getAvailableAugmentationTypes(nodeSchema);
+ }
+
+ @Override
+ protected DataContainerCodecContext<?> getIdentifierChild(final InstanceIdentifier.PathArgument arg,
+ final List<YangInstanceIdentifier.PathArgument> builder) {
+ if (choiceCaseChildren.isEmpty()) {
+ return super.getIdentifierChild(arg, builder);
+ }
+ // Lookup in choiceCase
+ Class<? extends DataObject> argument = arg.getType();
+ ReferencedTypeImpl ref = new ReferencedTypeImpl(argument.getPackage().getName(), argument.getSimpleName());
+ Entry<Type, Type> cazeId = choiceCaseChildren.get(ref);
+ if (cazeId == null) {
+ return super.getIdentifierChild(arg, builder);
+ }
+ ClassLoadingStrategy loader = factory.getRuntimeContext().getStrategy();
+ try {
+ Class<?> choice = loader.loadClass(cazeId.getKey());
+ Class<?> caze = loader.loadClass(cazeId.getValue());
+ ChoiceNodeCodecContext choiceNode = (ChoiceNodeCodecContext) getStreamChild(choice);
+ choiceNode.addYangPathArgument(arg, builder);
+ CaseNodeCodecContext cazeNode = (CaseNodeCodecContext) choiceNode.getStreamChild(caze);
+ cazeNode.addYangPathArgument(arg, builder);
+ return cazeNode.getIdentifierChild(arg, builder);
+
+ } catch (ClassNotFoundException e) {
+ throw new IllegalArgumentException("Required class not found.", e);
+ }
+
+ }
+
+ @Override
+ protected NodeCodecContext getYangIdentifierChild(final YangInstanceIdentifier.PathArgument arg) {
+ if (arg instanceof YangInstanceIdentifier.AugmentationIdentifier) {
+ return getChildByAugmentationIdentifier((YangInstanceIdentifier.AugmentationIdentifier) arg);
+ }
+
+ QName childQName = arg.getNodeType();
+ DataSchemaNode childSchema = schema.getDataChildByName(childQName);
+ Preconditions.checkArgument(childSchema != null, "Argument %s is not valid child of %s", arg, schema);
+ if (childSchema instanceof DataNodeContainer || childSchema instanceof ChoiceNode) {
+ Class<?> childCls = factory.getRuntimeContext().getClassForSchema(childSchema);
+ DataContainerCodecContext<?> childNode = getStreamChild(childCls);
+ return childNode;
+ } else {
+ return getLeafChild(childQName.getLocalName());
+ }
+ }
+
+ protected NodeCodecContext getChildByAugmentationIdentifier(final YangInstanceIdentifier.AugmentationIdentifier arg) {
+ final Type augType = augIdentifierToType.get(arg);
+ try {
+ Class<?> augClass = factory.getRuntimeContext().getStrategy().loadClass(augType);
+ return getStreamChild(augClass);
+ } catch (ClassNotFoundException e) {
+ throw new IllegalStateException("Unable to load referenced augmentation.", e);
+ }
+ }
+
+ protected final LeafNodeCodecContext getLeafChild(final String name) {
+ final LeafNodeCodecContext value = leafChild.get(name);
+ Preconditions.checkArgument(value != null, "Leaf %s is not valid for %s", name, bindingClass);
+ return value;
+ }
+
+ @Override
+ protected DataContainerCodecContext<?> loadChild(final Class<?> childClass) {
+ if (Augmentation.class.isAssignableFrom(childClass)) {
+ return loadAugmentation(childClass);
+ }
+
+ DataSchemaNode origDef = factory.getRuntimeContext().getSchemaDefinition(childClass);
+ // Direct instantiation or use in same module in which grouping
+ // was defined.
+ DataSchemaNode sameName = schema.getDataChildByName(origDef.getQName());
+ final DataSchemaNode childSchema;
+ if (sameName != null) {
+ // Exactly same schema node
+ if (origDef.equals(sameName)) {
+ childSchema = sameName;
+ // We check if instantiated node was added via uses
+ // statement and is an instantiation of same grouping
+ } else if (origDef.equals(SchemaNodeUtils.getRootOriginalIfPossible(sameName))) {
+ childSchema = sameName;
+ } else {
+ // Node has same name, but clearly is different
+ childSchema = null;
+ }
+ } else {
+ // We are looking for instantiation via uses in other module
+ QName instantiedName = QName.create(namespace, origDef.getQName().getLocalName());
+ DataSchemaNode potential = schema.getDataChildByName(instantiedName);
+ // We check if it is really instantiated from same
+ // definition
+ // as class was derived
+ if (potential != null && origDef.equals(SchemaNodeUtils.getRootOriginalIfPossible(potential))) {
+ childSchema = potential;
+ } else {
+ childSchema = null;
+ }
+ }
+ Preconditions
+ .checkArgument(childSchema != null, "Node %s does not have child named %s", schema, childClass);
+ return DataContainerCodecContext.from(childClass, childSchema, factory);
+ }
+
+ @SuppressWarnings("rawtypes")
+ private AugmentationNode loadAugmentation(final Class childClass) {
+ Preconditions.checkArgument(schema instanceof AugmentationTarget);
+ @SuppressWarnings("unchecked")
+ Entry<AugmentationIdentifier, AugmentationSchema> augSchema = factory.getRuntimeContext()
+ .getResolvedAugmentationSchema(schema, childClass);
+ QNameModule namespace = Iterables.getFirst(augSchema.getKey().getPossibleChildNames(), null).getModule();
+ return new AugmentationNode(childClass, namespace, augSchema.getKey(), augSchema.getValue(), factory);
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.concurrent.Callable;
+
+/**
+ *
+ * Derived YANG types are just immutable value holders for simple value
+ * types, which are same as in NormalizedNode model.
+ *
+ */
+class EncapsulatedValueCodec extends ReflectionBasedCodec {
+
+ private final Method getter;
+ private final Constructor<?> constructor;
+
+ EncapsulatedValueCodec(final Class<?> typeClz) {
+ super(typeClz);
+ try {
+ this.getter = typeClz.getMethod("getValue");
+ this.constructor = typeClz.getConstructor(getter.getReturnType());
+ } catch (NoSuchMethodException | SecurityException e) {
+ throw new IllegalStateException("Could not resolve required method.", e);
+ }
+ }
+
+ static Callable<ReflectionBasedCodec> loader(final Class<?> typeClz) {
+ return new Callable<ReflectionBasedCodec>() {
+ @Override
+ public ReflectionBasedCodec call() throws Exception {
+ return new EncapsulatedValueCodec(typeClz);
+ }
+ };
+ }
+
+ @Override
+ public Object deserialize(final Object input) {
+ try {
+ return constructor.newInstance(input);
+ } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override
+ public Object serialize(final Object input) {
+ try {
+ return getter.invoke(input);
+ } catch (IllegalAccessException | InvocationTargetException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableBiMap;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Callable;
+
+import org.opendaylight.yangtools.yang.binding.BindingMapping;
+import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair;
+
+class EnumerationCodec extends ReflectionBasedCodec {
+
+ ImmutableBiMap<String, Enum<?>> yangValueToBinding;
+
+ public EnumerationCodec(final Class<? extends Enum<?>> enumeration, final Map<String, Enum<?>> schema) {
+ super(enumeration);
+ yangValueToBinding = ImmutableBiMap.copyOf(schema);
+ }
+
+ static Callable<ReflectionBasedCodec> loader(final Class<?> returnType,
+ final EnumTypeDefinition enumSchema) {
+ Preconditions.checkArgument(Enum.class.isAssignableFrom(returnType));
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ final Class<? extends Enum<?>> enumType = (Class) returnType;
+ return new Callable<ReflectionBasedCodec>() {
+ @Override
+ public ReflectionBasedCodec call() throws Exception {
+
+ Map<String, Enum<?>> nameToValue = new HashMap<>();
+ for (Enum<?> enumValue : enumType.getEnumConstants()) {
+ nameToValue.put(enumValue.toString(), enumValue);
+ }
+ Map<String, Enum<?>> yangNameToBinding = new HashMap<>();
+ for (EnumPair yangValue : enumSchema.getValues()) {
+ final String bindingName = BindingMapping.getClassName(yangValue.getName());
+ final Enum<?> bindingVal = nameToValue.get(bindingName);
+ yangNameToBinding.put(yangValue.getName(), bindingVal);
+ }
+ return new EnumerationCodec(enumType, yangNameToBinding);
+ }
+ };
+ }
+
+
+ @Override
+ public Object deserialize(final Object input) {
+ Enum<?> value = yangValueToBinding.get(input);
+ Preconditions.checkArgument(value != null, "Invalid enumeration value %s. Valid values are %s", input,
+ yangValueToBinding.keySet());
+ return value;
+ }
+
+ @Override
+ public Object serialize(final Object input) {
+ Preconditions.checkArgument(typeClass.isInstance(input), "Input must be instance of %s", typeClass);
+ return yangValueToBinding.inverse().get(input);
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import org.opendaylight.yangtools.concepts.Codec;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+class LeafNodeCodecContext extends NodeCodecContext {
+
+ private final YangInstanceIdentifier.PathArgument yangIdentifier;
+ private final Codec<Object, Object> valueCodec;
+
+ LeafNodeCodecContext(final DataSchemaNode node, final Codec<Object, Object> codec) {
+ this.yangIdentifier = new YangInstanceIdentifier.NodeIdentifier(node.getQName());
+ this.valueCodec = codec;
+ }
+
+ @Override
+ protected YangInstanceIdentifier.PathArgument getDomPathArgument() {
+ return (yangIdentifier);
+ }
+
+ protected Codec<Object, Object> getValueCodec() {
+ return valueCodec;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import java.util.List;
+
+import org.opendaylight.yangtools.concepts.Codec;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+class ListNodeCodecContext extends DataObjectCodecContext<ListSchemaNode> {
+
+ private final YangInstanceIdentifier.PathArgument yangIdentifier;
+ private final Codec<NodeIdentifierWithPredicates, IdentifiableItem<?, ?>> codec;
+
+ ListNodeCodecContext(final Class<?> cls, final ListSchemaNode nodeSchema, final CodecContextFactory loader) {
+ super(cls, nodeSchema.getQName().getModule(), nodeSchema, loader);
+ this.yangIdentifier = new YangInstanceIdentifier.NodeIdentifier(nodeSchema.getQName());
+ if (Identifiable.class.isAssignableFrom(cls)) {
+ this.codec = loader.getPathArgumentCodec(cls,nodeSchema);
+ } else {
+ this.codec = null;
+ }
+ }
+
+ @Override
+ public YangInstanceIdentifier.PathArgument getDomPathArgument() {
+ return yangIdentifier;
+ }
+
+ @Override
+ public void addYangPathArgument(final InstanceIdentifier.PathArgument arg, final List<YangInstanceIdentifier.PathArgument> builder) {
+
+ /*
+ * DOM Instance Identifier for list is always represent by two
+ * entries one for map and one for children. This is also true for
+ * wildcarded instance identifiers
+ */
+ if (builder == null) {
+ return;
+ }
+ super.addYangPathArgument(arg, builder);
+ if (arg instanceof IdentifiableItem<?, ?>) {
+ builder.add(codec.serialize((IdentifiableItem<?, ?>) arg));
+ } else {
+ // Adding wildcarded
+ super.addYangPathArgument(arg, builder);
+ }
+ }
+
+ @Override
+ public InstanceIdentifier.PathArgument getBindingPathArgument(
+ final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument domArg) {
+ if(domArg instanceof NodeIdentifierWithPredicates) {
+ return codec.deserialize((NodeIdentifierWithPredicates) domArg);
+ }
+ return super.getBindingPathArgument(domArg);
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ public NodeIdentifierWithPredicates serialize(final Identifier<?> key) {
+ return codec.serialize(new IdentifiableItem(bindingClass, key));
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import com.google.common.collect.ImmutableMap;
+import java.util.List;
+import org.opendaylight.yangtools.concepts.Codec;
+import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+/**
+ *
+ * Location specific context for schema nodes, which contains codec specific
+ * information to properly serialize / deserialize from Java YANG Binding data
+ * to NormalizedNode data.
+ *
+ * Two core subtypes of codec context are available:
+ * <ul>
+ * <li>{@link LeafNodeCodecContext} - Context for nodes, which does not contain
+ * any nested YANG modeled substructures.</li>
+ * <li>{@link DataObjectCodecContext} - Context for nodes, which does contain
+ * nested YANG modeled substructures. This context nodes contains context
+ * for children nodes.</li>
+ * </ul>
+ *
+ */
+abstract class NodeCodecContext {
+
+ /**
+ * Returns Yang Instance Identifier Path Argument of current node
+ *
+ * @return DOM Path Argument of node
+ */
+ protected abstract YangInstanceIdentifier.PathArgument getDomPathArgument();
+
+ /**
+ *
+ * Immutable factory, which provides access to runtime context,
+ * create leaf nodes and provides path argument codecs.
+ * <p>
+ * During lifetime of factory all calls for same arguments to method must return
+ * equal result (not necessary same instance of result).
+ *
+ */
+ protected interface CodecContextFactory {
+
+ /**
+ * Returns immutable runtime context associated with this factory.
+ * @return runtime context
+ */
+ BindingRuntimeContext getRuntimeContext();
+
+ /**
+ * Returns leaf nodes for supplied data container and parent class.
+ *
+ * @param type Binding type for which leaves should be loaded.
+ * @param schema Instantiated schema of binding type.
+ * @return Map of local name to leaf node context.
+ */
+ ImmutableMap<String, LeafNodeCodecContext> getLeafNodes(Class<?> type, DataNodeContainer schema);
+
+ /**
+ * Returns Path argument codec for list item
+ *
+ * @param type Type of list item
+ * @param schema Schema of list item
+ * @return Path argument codec for supplied list item.
+ */
+ Codec<NodeIdentifierWithPredicates, IdentifiableItem<?, ?>> getPathArgumentCodec(Class<?> type,
+ ListSchemaNode schema);
+
+ }
+
+ /**
+ *
+ * Serializes supplied Binding Path Argument
+ * and adds all necessary YANG instance identifiers to supplied list.
+ *
+ * @param arg Bidning Path Argument
+ * @param builder DOM Path argument.
+ */
+ protected void addYangPathArgument(final InstanceIdentifier.PathArgument arg,
+ final List<YangInstanceIdentifier.PathArgument> builder) {
+ if (builder != null) {
+ builder.add(getDomPathArgument());
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+abstract class ReflectionBasedCodec extends ValueTypeCodec {
+
+ protected final Class<?> typeClass;
+
+ public ReflectionBasedCodec(final Class<?> typeClass) {
+ super();
+ this.typeClass = typeClass;
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import com.google.common.base.Preconditions;
+
+import org.opendaylight.yangtools.util.ClassLoaderUtils;
+import org.opendaylight.yangtools.yang.binding.ChildOf;
+import org.opendaylight.yangtools.yang.binding.DataRoot;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+class SchemaRootCodecContext extends DataContainerCodecContext<SchemaContext> {
+
+ private SchemaRootCodecContext(final CodecContextFactory factory) {
+ super(SchemaRootCodecContext.class, null, factory.getRuntimeContext().getSchemaContext(), factory);
+ }
+
+ /**
+ * Creates RootNode from supplied CodecContextFactory.
+ *
+ * @param factory
+ * CodecContextFactory
+ * @return
+ */
+ static SchemaRootCodecContext create(final CodecContextFactory factory) {
+ return new SchemaRootCodecContext(factory);
+ }
+
+ @Override
+ protected DataContainerCodecContext<?> loadChild(final Class<?> childClass) {
+ Class<Object> parent = ClassLoaderUtils.findFirstGenericArgument(childClass, ChildOf.class);
+ Preconditions.checkArgument(DataRoot.class.isAssignableFrom(parent));
+
+ QName qname = BindingReflections.findQName(childClass);
+ DataSchemaNode childSchema = getSchema().getDataChildByName(qname);
+ return DataContainerCodecContext.from(childClass, childSchema, factory);
+ }
+
+ @Override
+ protected YangInstanceIdentifier.PathArgument getDomPathArgument() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected NodeCodecContext getYangIdentifierChild(final YangInstanceIdentifier.PathArgument arg) {
+
+ QName childQName = arg.getNodeType();
+ DataSchemaNode childSchema = schema.getDataChildByName(childQName);
+ Preconditions.checkArgument(childSchema != null, "Argument %s is not valid child of %s", arg, schema);
+ if (childSchema instanceof DataNodeContainer || childSchema instanceof ChoiceNode) {
+ Class<?> childCls = factory.getRuntimeContext().getClassForSchema(childSchema);
+ DataContainerCodecContext<?> childNode = getStreamChild(childCls);
+ return childNode;
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import org.opendaylight.yangtools.concepts.Codec;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
+
+/**
+ * Value codec, which serializes / deserializes values from DOM simple values.
+ *
+ */
+abstract class ValueTypeCodec implements Codec<Object, Object> {
+
+ private static final Cache<Class<?>, ReflectionBasedCodec> REFLECTION_CODECS = CacheBuilder.newBuilder().weakKeys()
+ .build();
+
+ /**
+ *
+ * No-op Codec, Java YANG Binding uses same types as NormalizedNode model
+ * for base YANG types, representing numbers, binary and strings.
+ *
+ *
+ */
+ public static final ValueTypeCodec NOOP_CODEC = new ValueTypeCodec() {
+
+ @Override
+ public Object serialize(final Object input) {
+ return input;
+ }
+
+ @Override
+ public Object deserialize(final Object input) {
+ return input;
+ }
+ };
+
+ public static ValueTypeCodec getCodecFor(final Class<?> typeClz, final TypeDefinition<?> def) {
+ if (BindingReflections.isBindingClass(typeClz)) {
+ return getReflectionCodec(typeClz, getCodecLoader(typeClz, def));
+ }
+ return NOOP_CODEC;
+ }
+
+ private static ValueTypeCodec getReflectionCodec(final Class<?> typeClz, final Callable<ReflectionBasedCodec> loader) {
+ try {
+ return REFLECTION_CODECS.get(typeClz, loader);
+ } catch (ExecutionException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ private static Callable<ReflectionBasedCodec> getCodecLoader(final Class<?> typeClz, final TypeDefinition<?> def) {
+
+ TypeDefinition<?> rootType = def;
+ while (rootType.getBaseType() != null) {
+ rootType = rootType.getBaseType();
+ }
+ if (rootType instanceof EnumTypeDefinition) {
+ return EnumerationCodec.loader(typeClz, (EnumTypeDefinition) rootType);
+ } else if (rootType instanceof BitsTypeDefinition) {
+ return BitsCodec.loader(typeClz, (BitsTypeDefinition) rootType);
+ }
+ return EncapsulatedValueCodec.loader(typeClz);
+ }
+
+ @SuppressWarnings("rawtypes")
+ static ValueTypeCodec encapsulatedValueCodecFor(final Class<?> typeClz, final Codec delegate) {
+ ValueTypeCodec extractor = getReflectionCodec(typeClz, EncapsulatedValueCodec.loader(typeClz));
+ return new CompositeValueCodec(extractor, delegate);
+ }
+
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.util;
+
+import com.google.common.base.Preconditions;
+import java.util.Map;
+import java.util.Map.Entry;
+import org.opendaylight.yangtools.yang.binding.Augmentable;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializer;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializerImplementation;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializerRegistry;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AugmentableDispatchSerializer implements DataObjectSerializerImplementation {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AugmentableDispatchSerializer.class);
+
+ @Override
+ public void serialize(final DataObjectSerializerRegistry reg, final DataObject obj,
+ final BindingStreamEventWriter stream) {
+ if (obj instanceof Augmentable<?>) {
+ Map<Class<? extends Augmentation<?>>, Augmentation<?>> augmentations = BindingReflections
+ .getAugmentations((Augmentable<?>) obj);
+ for (Entry<Class<? extends Augmentation<?>>, Augmentation<?>> aug : augmentations.entrySet()) {
+ emitAugmentation(aug.getKey(), aug.getValue(), stream, reg);
+ }
+ }
+ }
+
+ @SuppressWarnings("rawtypes")
+ private void emitAugmentation(final Class type, final Augmentation<?> value, final BindingStreamEventWriter stream,
+ final DataObjectSerializerRegistry registry) {
+ Preconditions.checkArgument(value instanceof DataObject);
+ @SuppressWarnings("unchecked")
+ DataObjectSerializer serializer = registry.getSerializer(type);
+ if (serializer != null) {
+ serializer.serialize((DataObject) value, stream);
+ } else {
+ LOG.warn("DataObjectSerializer is not present for {} in registry {}", type, registry);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.util;
+
+import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializer;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializerImplementation;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializerRegistry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ChoiceDispatchSerializer implements DataObjectSerializerImplementation {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ChoiceDispatchSerializer.class);
+
+ @SuppressWarnings("rawtypes")
+ private final Class choiceClass;
+
+ @SuppressWarnings("rawtypes")
+ private ChoiceDispatchSerializer(final Class choiceClass) {
+ super();
+ this.choiceClass = choiceClass;
+ }
+
+ public static final ChoiceDispatchSerializer from(final Class<? extends DataContainer> choiceClass) {
+ return new ChoiceDispatchSerializer(choiceClass);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void serialize(final DataObjectSerializerRegistry reg, final DataObject obj, final BindingStreamEventWriter stream) {
+ @SuppressWarnings("rawtypes")
+ Class cazeClass = obj.getImplementedInterface();
+ stream.startChoiceNode(choiceClass, BindingStreamEventWriter.UNKNOWN_SIZE);
+ DataObjectSerializer caseSerializer = reg.getSerializer(cazeClass);
+ if (caseSerializer != null) {
+ caseSerializer.serialize(obj, stream);
+ } else {
+ LOG.warn("No serializer for case {} is available in registry {}", cazeClass, reg);
+ }
+ stream.endNode();
+ }
+}
import com.google.common.collect.Multimap;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
-
import java.net.URI;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
-
import javassist.ClassPool;
-
import javax.annotation.concurrent.GuardedBy;
-
import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil;
import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl;
import org.opendaylight.yangtools.binding.generator.util.Types;
import org.opendaylight.yangtools.yang.binding.RpcService;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.api.Node;
import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl;
import org.opendaylight.yangtools.yang.data.impl.codec.AugmentationCodec;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Multimap;
+
import java.util.AbstractMap;
import java.util.AbstractMap.SimpleEntry;
import java.util.Collection;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
+
import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl;
import org.opendaylight.yangtools.concepts.Immutable;
import org.opendaylight.yangtools.sal.binding.generator.api.ClassLoadingStrategy;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.AugmentationSchemaProxy;
import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
private final BiMap<Type, Object> typeToDefiningSchema = HashBiMap.create();
private final Multimap<Type, Type> augmentableToAugmentations = HashMultimap.create();
private final Multimap<Type, Type> choiceToCases = HashMultimap.create();
+ private final Map<QName, Type> identities = new HashMap<>();
private BindingRuntimeContext(final ClassLoadingStrategy strategy, final SchemaContext schema) {
this.strategy = strategy;
generator.generateTypes(schema);
Map<Module, ModuleContext> modules = generator.getModuleContexts();
- for (Entry<Module, ModuleContext> entry : modules.entrySet()) {
- ModuleContext ctx = entry.getValue();
+ for (ModuleContext ctx : modules.values()) {
augmentationToSchema.putAll(ctx.getTypeToAugmentation());
typeToDefiningSchema.putAll(ctx.getTypeToSchema());
augmentableToAugmentations.putAll(ctx.getAugmentableToAugmentations());
choiceToCases.putAll(ctx.getChoiceToCases());
+ identities.putAll(ctx.getIdentities());
}
}
*
* @param augClass Augmentation class
* @return Schema of augmentation
- * @throws IllegalArgumentException If supplied class is not an augmentation or current context does not contain schema for augmenation.
+ * @throws IllegalArgumentException If supplied class is not an augmentation or current context does not contain schema for augmentation.
*/
public AugmentationSchema getAugmentationDefinition(final Class<?> augClass) throws IllegalArgumentException {
- Preconditions.checkArgument(Augmentation.class.isAssignableFrom(augClass),"Class {} does not represent augmentation",augClass);
+ Preconditions.checkArgument(Augmentation.class.isAssignableFrom(augClass), "Class {} does not represent augmentation", augClass);
final AugmentationSchema ret = augmentationToSchema.get(referencedType(augClass));
- Preconditions.checkArgument(ret != null, "Supplied augmentation {} is not valid in current context",augClass);
+ Preconditions.checkArgument(ret != null, "Supplied augmentation {} is not valid in current context", augClass);
return ret;
}
* @return Schema node, from which class was generated.
*/
public DataSchemaNode getSchemaDefinition(final Class<?> cls) {
- Preconditions.checkArgument(Augmentation.class.isAssignableFrom(cls));
+ Preconditions.checkArgument(!Augmentation.class.isAssignableFrom(cls),"Supplied class must not be augmentation");
return (DataSchemaNode) typeToDefiningSchema.get(referencedType(cls));
}
public ImmutableMap<Type, Entry<Type, Type>> getChoiceCaseChildren(final DataNodeContainer schema) {
Map<Type,Entry<Type,Type>> childToCase = new HashMap<>();;
- for(ChoiceNode choice : FluentIterable.from(schema.getChildNodes()).filter(ChoiceNode.class)) {
+ for (ChoiceNode choice : FluentIterable.from(schema.getChildNodes()).filter(ChoiceNode.class)) {
ChoiceNode originalChoice = getOriginalSchema(choice);
Type choiceType = referencedType(typeToDefiningSchema.inverse().get(originalChoice));
Collection<Type> cases = choiceToCases.get(choiceType);
- for(Type caze : cases) {
+ for (Type caze : cases) {
Entry<Type,Type> caseIdentifier = new SimpleEntry<>(choiceType,caze);
HashSet<Type> caseChildren = new HashSet<>();
- if(caze instanceof GeneratedTypeBuilder) {
+ if (caze instanceof GeneratedTypeBuilder) {
caze = ((GeneratedTypeBuilder) caze).toInstance();
}
collectAllContainerTypes((GeneratedType) caze, caseChildren);
- for(Type caseChild : caseChildren) {
+ for (Type caseChild : caseChildren) {
childToCase.put(caseChild, caseIdentifier);
}
}
}
return ImmutableMap.copyOf(childToCase);
+ }
+
+ public Class<?> getClassForSchema(final DataSchemaNode childSchema) {
+ DataSchemaNode origSchema = getOriginalSchema(childSchema);
+ Type clazzType = typeToDefiningSchema.inverse().get(origSchema);
+ try {
+ return strategy.loadClass(clazzType);
+ } catch (ClassNotFoundException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ public ImmutableMap<AugmentationIdentifier,Type> getAvailableAugmentationTypes(final DataNodeContainer container) {
+ Map<AugmentationIdentifier,Type> identifierToType = new HashMap<>();
+ if (container instanceof AugmentationTarget) {
+ Set<AugmentationSchema> augments = ((AugmentationTarget) container).getAvailableAugmentations();
+ for (AugmentationSchema augment : augments) {
+ // Augmentation must have child nodes if is to be used with Binding classes
+ if (!augment.getChildNodes().isEmpty()) {
+ Type augType = typeToDefiningSchema.inverse().get(augment);
+ if (augType != null) {
+ identifierToType.put(getAugmentationIdentifier(augment),augType);
+ }
+ }
+ }
+ }
+ return ImmutableMap.copyOf(identifierToType);
}
+ private AugmentationIdentifier getAugmentationIdentifier(final AugmentationSchema augment) {
+ Set<QName> childNames = new HashSet<>();
+ for (DataSchemaNode child : augment.getChildNodes()) {
+ childNames.add(child.getQName());
+ }
+ return new AugmentationIdentifier(childNames);
+ }
+
private static Type referencedType(final Type type) {
if(type instanceof ReferencedTypeImpl) {
return type;
private static final <T extends SchemaNode> T getOriginalSchema(final T choice) {
@SuppressWarnings("unchecked")
T original = (T) SchemaNodeUtils.getRootOriginalIfPossible(choice);
- if(original != null) {
+ if (original != null) {
return original;
}
return choice;
}
+ public Class<?> getIdentityClass(final QName input) {
+ Type identityType = identities.get(input);
+ Preconditions.checkArgument(identityType != null, "Supplied QName is not valid identity");
+ try {
+ return strategy.loadClass(identityType);
+ } catch (ClassNotFoundException e) {
+ throw new IllegalArgumentException("Required class " + identityType + "was not found.",e);
+ }
+ }
+
}
<module>binding-java-api-generator</module>
<module>binding-type-provider</module>
<module>maven-sal-api-gen-plugin</module>
+ <module>binding-data-codec</module>
</modules>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>restconf-client-api</artifactId>
<artifactId>binding-generator-impl</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>binding-data-codec</artifactId>
+ <version>0.6.2-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>bug527-test-model</artifactId>
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.restconf.utils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+import java.util.Map.Entry;
+import javassist.ClassPool;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.topology.unix.rev131222.network.topology.topology.node.path.computation.client.reported.lsp.lsp.tlvs.vs.tlv.vendor.payload.unix.UnixSubTlvs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.topology.unix.rev131222.network.topology.topology.node.path.computation.client.reported.lsp.lsp.tlvs.vs.tlv.vendor.payload.unix.UnixSubTlvsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.ReportedLsp1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.ReportedLsp1Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.lsp.object.Lsp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.lsp.object.LspBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.lsp.object.lsp.Tlvs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.lsp.object.lsp.TlvsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.network.topology.topology.node.path.computation.client.reported.lsp.lsp.tlvs.vs.tlv.vendor.payload.LinuxBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.network.topology.topology.node.path.computation.client.reported.lsp.lsp.tlvs.vs.tlv.vendor.payload.linux.LinuxSubTlvsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.vs.tlv.VsTlv;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.vs.tlv.VsTlvBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.Node1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.PathComputationClient;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.PathComputationClientBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.path.computation.client.ReportedLsp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.path.computation.client.ReportedLspBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.path.computation.client.ReportedLspKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator;
+import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
+import org.opendaylight.yangtools.sal.binding.generator.impl.BindingSchemaContextUtils;
+import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
+import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl;
+import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
+import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+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.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+public class BindingStreamWriterTest {
+
+ private static final InstanceIdentifier<PathComputationClient> PATH_TO_CLIENT = InstanceIdentifier
+ .builder(NetworkTopology.class).child(Topology.class, new TopologyKey(new TopologyId("foo"))).child(Node.class,new NodeKey(new NodeId("test"))).augmentation(Node1.class)
+ .child(PathComputationClient.class).build();
+
+
+ private static final InstanceIdentifier<Tlvs> PATH_TO_TLVS = PATH_TO_CLIENT.child(ReportedLsp.class, new ReportedLspKey("test")).augmentation(ReportedLsp1.class).child(Lsp.class).child(Tlvs.class);
+ private static final InstanceIdentifier<UnixSubTlvs> PATH_TO_UNIX = PATH_TO_TLVS.child(VsTlv.class).child(UnixSubTlvs.class);
+
+ private static final ReportedLspKey LSP1_KEY = new ReportedLspKey("one");
+ private static final ReportedLspKey LSP2_KEY = new ReportedLspKey("two");
+
+ private RuntimeGeneratedMappingServiceImpl mappingService;
+ private Optional<SchemaContext> schemaContext;
+ private org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator generator;
+ private BindingNormalizedNodeCodecRegistry registry;
+ private DataSchemaNode schema;
+ private BindingRuntimeContext runtimeContext;
+
+ @Before
+ public void setup() {
+ this.mappingService = new RuntimeGeneratedMappingServiceImpl(ClassPool.getDefault());
+
+ final ModuleInfoBackedContext moduleInfo = ModuleInfoBackedContext.create();
+ moduleInfo.addModuleInfos(BindingReflections.loadModuleInfos());
+ schemaContext = moduleInfo.tryToCreateSchemaContext();
+ this.mappingService.onGlobalContextUpdated(moduleInfo.tryToCreateSchemaContext().get());
+ JavassistUtils utils = JavassistUtils.forClassPool(ClassPool.getDefault());
+ generator = new StreamWriterGenerator(utils);
+ registry = new BindingNormalizedNodeCodecRegistry(generator);
+ runtimeContext = BindingRuntimeContext.create(moduleInfo, schemaContext.get());
+ registry.onBindingRuntimeContextUpdated(runtimeContext);
+
+ schema = (DataSchemaNode) BindingSchemaContextUtils.findDataNodeContainer(schemaContext.get(), PATH_TO_CLIENT)
+ .get();
+ }
+
+
+ @Test
+ public void instanceIdentifierCodec() {
+
+ }
+
+ @Test
+ public void writeWithStreamAPI() {
+ Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> result = registry.toNormalizedNode(PATH_TO_CLIENT, createTestData());
+ NormalizedNode<?, ?> output = result.getValue();
+ assertNotNull(output);
+ assertTrue(output instanceof ContainerNode);
+
+ Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> unixResult = registry.toNormalizedNode(PATH_TO_UNIX, new UnixSubTlvsBuilder().setUnixValue((short) 10).build());
+ assertNotNull(unixResult);
+ }
+
+ @Test
+ public void testInstanceIdentifier() {
+ YangInstanceIdentifier yang = registry.toYangInstanceIdentifier(PATH_TO_UNIX);
+ assertNotNull(yang);
+ InstanceIdentifier<?> binding = registry.fromYangInstanceIdentifier(yang);
+ assertEquals(PATH_TO_UNIX,binding);
+ }
+
+ @Test
+ @Ignore
+ public void testPerformance() {
+ for (int i = 1; i < 5; i++) {
+ int repetitions = (int) Math.pow(10, i);
+ measure("streamAPI: " + repetitions, repetitions, new Runnable() {
+ @Override
+ public void run() {
+ writeWithStreamAPI();
+ }
+ });
+ }
+ }
+
+ private void measure(final String name, final int repetitions, final Runnable runnable) {
+ runnable.run(); // WARM UP
+ long start = System.nanoTime();
+ // TODO Auto-generated method stub
+ for (int i = 0; i < repetitions; i++) {
+ runnable.run();
+ }
+ long finish = System.nanoTime();
+ // To Miliseconds
+ System.out.println(String.format("Type: %s Time: %f", name, (finish - start) / 1000000.d));
+ }
+
+ PathComputationClient createTestData() {
+ return new PathComputationClientBuilder().setReportedLsp(
+ ImmutableList.<ReportedLsp> builder().add(reportedLsp(LSP1_KEY)).add(reportedLsp(LSP2_KEY)).build())
+ .build();
+ }
+
+ private ReportedLsp reportedLsp(final ReportedLspKey lspKey) {
+ return new ReportedLspBuilder()
+ .setKey(lspKey)
+ .addAugmentation(
+ ReportedLsp1.class,
+ new ReportedLsp1Builder().setLsp(
+ new LspBuilder().setTlvs(
+ new TlvsBuilder().setVsTlv(
+ new VsTlvBuilder().setVendorPayload(
+ new LinuxBuilder().setLinuxSubTlvs(
+ new LinuxSubTlvsBuilder().setLinuxValue((short) 50)
+ .build()).build()).build()).build()).build())
+ .build()).build();
+ }
+
+}
/**
*
- * Emits start of map node event.
+ * Emits start of unordered map node event.
*
* <p>
* End of map node event is emitted by invoking {@link #endNode()}. Valid
<T extends DataObject & Identifiable<?>> void startMapNode(Class<T> mapEntryType, int childSizeHint)
throws IllegalArgumentException;
+
+ /**
+ *
+ * Emits start of ordered map node event.
+ *
+ * <p>
+ * End of map node event is emitted by invoking {@link #endNode()}. Valid
+ * subevents is only {@link #startMapEntryNode(Identifier, int)}. All other methods will
+ * throw {@link IllegalArgumentException}.
+ *
+ * @param mapEntryType
+ * Class of list item, which has defined key.
+ * @param childSizeHint
+ * Non-negative count of expected direct child nodes or
+ * {@link #UNKNOWN_SIZE} if count is unknown. This is only hint
+ * and should not fail writing of child events, if there are more
+ * events than count.
+ * @throws IllegalArgumentException
+ * @throws IllegalStateException
+ * If node was emitted inside <code>map</code>,
+ * <code>choice</code> <code>unkeyed list</code> node.
+ */
+ <T extends DataObject & Identifiable<?>> void startOrderedMapNode(Class<T> mapEntryType, int childSizeHint)
+ throws IllegalArgumentException;
+
/**
*
* Emits start of map entry.
import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableAugmentationNodeBuilder;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetNodeBuilder;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableOrderedMapNodeBuilder;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableUnkeyedListNodeBuilder;
/**
@Override
public void startMapEntryNode(final NodeIdentifierWithPredicates identifier,final int childSizeHint) throws IllegalArgumentException {
- Preconditions.checkArgument(getCurrent() instanceof ImmutableMapNodeBuilder);
+ if(!(getCurrent() instanceof NormalizedNodeResultBuilder)) {
+ Preconditions.checkArgument(getCurrent() instanceof ImmutableMapNodeBuilder);
+ }
enter(Builders.mapEntryBuilder().withNodeIdentifier(identifier));
}
@Override
public void startOrderedMapNode(final NodeIdentifier name,final int childSizeHint) throws IllegalArgumentException {
- checkDataNodeContainer();
+ if(!(getCurrent() instanceof NormalizedNodeResultBuilder)) {
+ Preconditions.checkArgument(getCurrent() instanceof ImmutableOrderedMapNodeBuilder);
+ }
enter(Builders.mapBuilder().withNodeIdentifier(name));
}