Merge "BUG-576: modified parser to handle augmentation of extension instances."
authorTony Tkacik <ttkacik@cisco.com>
Wed, 6 Aug 2014 16:49:39 +0000 (16:49 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Wed, 6 Aug 2014 16:49:39 +0000 (16:49 +0000)
18 files changed:
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/impl/AbstractGenerator.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/impl/AbstractStreamWriterGenerator.java
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/impl/AugmentableDataNodeContainerEmmiterSource.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/impl/DataNodeContainerSerializerSource.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/impl/DataObjectSerializerGenerator.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/impl/DataObjectSerializerPrototype.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/impl/DataObjectSerializerSource.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/impl/StreamWriterGenerator.java
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/spi/AbstractSource.java
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingNormalizedNodeCodecRegistry.java
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/util/ChoiceDispatchSerializer.java
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/ClassCustomizer.java [new file with mode: 0644]
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/JavassistUtils.java
code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/ClassTemplate.xtend
code-generator/binding-java-api-generator/src/test/java/org/opendaylight/yangtools/sal/java/api/generator/test/TypedefCompilationTest.java
common/parent/pom.xml
restconf/restconf-util/src/test/java/org/opendaylight/yangtools/restconf/utils/BindingStreamWriterTest.java
yang/yang-data-impl/pom.xml

diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/impl/AbstractGenerator.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/impl/AbstractGenerator.java
new file mode 100644 (file)
index 0000000..3d35c03
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * 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;
+
+/**
+ * Package-private base class for sharing the loading capability.
+ */
+abstract class AbstractGenerator {
+    /**
+     * Ensure that the serializer class for specified class is loaded
+     * and return its name.
+     *
+     * @param cls Data object class
+     * @return Serializer class name
+     */
+    protected abstract String loadSerializerFor(final Class<?> cls);
+}
\ No newline at end of file
index be35585869b619fc9c72a000caae4d6e86d6475b..2d4747c9442c6abd9eb77919b91e6bccd13862b0 100644 (file)
@@ -13,6 +13,7 @@ import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
 
 import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
 import java.util.Map.Entry;
 
 import javassist.CannotCompileException;
@@ -22,17 +23,13 @@ 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.ClassCustomizer;
 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;
@@ -47,94 +44,121 @@ import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public abstract class AbstractStreamWriterGenerator {
+abstract class AbstractStreamWriterGenerator extends AbstractGenerator implements DataObjectSerializerGenerator {
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractStreamWriterGenerator.class);
 
-    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 static final Field FIELD_MODIFIERS;
 
+    private final LoadingCache<Class<?>, DataObjectSerializerImplementation> implementations;
     private final CtClass[] serializeArguments;
-    private final CtMethod serializeToMethod;
+    private final JavassistUtils javassist;
+    private BindingRuntimeContext context;
 
-    private final LoadingCache<Class<?>, Class<? extends DataObjectSerializerImplementation>> implementations;
-    private final ClassLoadingStrategy strategy;
+    static {
+        /*
+         * Cache reflection access to field modifiers field. We need this to set
+         * fix the static declared fields to final once we initialize them. If we
+         * cannot get access, that's fine, too.
+         */
+        Field f = null;
+        try {
+            f = Field.class.getDeclaredField("modifiers");
+            f.setAccessible(true);
+        } catch (NoSuchFieldException | SecurityException e) {
+            LOG.warn("Could not get Field modifiers field, serializers run at decreased efficiency", e);
+        }
 
-    private BindingRuntimeContext context;
+        FIELD_MODIFIERS = f;
+    }
 
     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 };
+        this.serializeArguments = new CtClass[] {
+                javassist.asCtClass(DataObjectSerializerRegistry.class),
+                javassist.asCtClass(DataObject.class),
+                javassist.asCtClass(BindingStreamEventWriter.class),
+        };
 
-        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 final DataObjectSerializerImplementation getSerializer(final Class<?> type) {
+        return implementations.getUnchecked(type);
+    }
+
+    @Override
+    public final void onBindingRuntimeContextUpdated(final BindingRuntimeContext runtime) {
+        this.context = runtime;
+    }
+
+    @Override
+    protected final String loadSerializerFor(final Class<?> cls) {
+        return implementations.getUnchecked(cls).getClass().getName();
+    }
+
+    private final class SerializerImplementationLoader extends CacheLoader<Class<?>, DataObjectSerializerImplementation> {
+
+        private static final String GETINSTANCE_METHOD_NAME = "getInstance";
+        private static final String SERIALIZER_SUFFIX = "$StreamWriter";
+
+        private String getSerializerName(final Class<?> type) {
+            return type.getName() + SERIALIZER_SUFFIX;
+        }
 
         @Override
-        public Class<? extends DataObjectSerializerImplementation> load(final Class<?> type) throws Exception {
+        @SuppressWarnings("unchecked")
+        public DataObjectSerializerImplementation load(final Class<?> type) throws Exception {
             Preconditions.checkArgument(BindingReflections.isBindingClass(type));
             Preconditions.checkArgument(DataContainer.class.isAssignableFrom(type));
 
-            String serializerName = getSerializerName(type);
+            final String serializerName = getSerializerName(type);
+
+            Class<? extends DataObjectSerializerImplementation> cls;
             try {
-                @SuppressWarnings("unchecked")
-                final Class<? extends DataObjectSerializerImplementation> preexisting = (Class<? extends DataObjectSerializerImplementation>) ClassLoaderUtils
+                cls = (Class<? extends DataObjectSerializerImplementation>) ClassLoaderUtils
                         .loadClass(type.getClassLoader(), serializerName);
-                return preexisting;
             } catch (ClassNotFoundException e) {
-                return loadFromClassPoolOrGenerate(type, serializerName);
+                cls = generateSerializer(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;
+            final DataObjectSerializerImplementation obj =
+                    (DataObjectSerializerImplementation) cls.getDeclaredMethod(GETINSTANCE_METHOD_NAME).invoke(null);
+            LOG.debug("Loaded serializer {} for class {}", obj, type);
+            return obj;
         }
 
-        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);
+        private Class<? extends DataObjectSerializerImplementation> generateSerializer(final Class<?> type,
+                final String serializerName) throws CannotCompileException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, NoSuchFieldException {
+            final DataObjectSerializerSource source = generateEmitterSource(type, serializerName);
+            final CtClass poolClass = generateEmitter0(source, serializerName);
+            @SuppressWarnings("unchecked")
+            final Class<? extends DataObjectSerializerImplementation> cls = poolClass.toClass(type.getClassLoader(), type.getProtectionDomain());
+
+            /*
+             * Due to OSGi class loader rules we cannot initialize the fields during
+             * construction, as the initializer expressions do not see our implementation
+             * classes. This should be almost as good as that, as we are resetting the
+             * fields to final before ever leaking the class.
+             */
+            for (StaticConstantDefinition constant : source.getStaticConstants()) {
+                final Field field = cls.getDeclaredField(constant.getName());
+                field.setAccessible(true);
+                field.set(null, constant.getValue());
+
+                if (FIELD_MODIFIERS != null) {
+                    FIELD_MODIFIERS.setInt(field, field.getModifiers() | Modifier.FINAL);
                 }
             }
+
+            return cls;
         }
     }
 
-
-
-    protected DataObjectSerializerSource generateEmitterSource(final Class<?> type, final String serializerName) {
+    private DataObjectSerializerSource generateEmitterSource(final Class<?> type, final String serializerName) {
         Types.typeForClass(type);
         Entry<GeneratedType, Object> typeWithSchema = context.getTypeWithSchema(type);
         GeneratedType generatedType = typeWithSchema.getKey();
@@ -161,60 +185,34 @@ public abstract class AbstractStreamWriterGenerator {
     }
 
     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()) {
+        final CtClass product;
+        try {
+            product = javassist.instantiatePrototype(DataObjectSerializerPrototype.class.getName(), serializerName, new ClassCustomizer() {
+                @Override
+                public void customizeClass(final CtClass cls) throws CannotCompileException, NotFoundException {
+                    // getSerializerBody() has side effects
+                    final String body = source.getSerializerBody().toString();
+
+                    // Generate any static fields
+                    for (StaticConstantDefinition def : source.getStaticConstants()) {
                         CtField field = new CtField(javassist.asCtClass(def.getType()), def.getName(), cls);
-                        field.setModifiers(Modifier.PUBLIC + Modifier.STATIC);
+                        field.setModifiers(Modifier.PRIVATE + 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);
-                }
+                    // Replace serialize() -- may reference static fields
+                    final CtMethod serializeTo = cls.getDeclaredMethod(SERIALIZE_METHOD_NAME, serializeArguments);
+                    serializeTo.setBody(body);
 
-            }
-        });
-        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);
+                    // The prototype is not visible, so we need to take care of that
+                    cls.setModifiers(Modifier.setPublic(cls.getModifiers()));
+                }
+            });
+        } catch (NotFoundException e) {
+            LOG.error("Failed to instatiate serializer {}", source, e);
+            throw new LinkageError("Unexpected instantation problem: serializer prototype not found", e);
         }
+        return product;
     }
 
     /**
@@ -229,7 +227,7 @@ public abstract class AbstractStreamWriterGenerator {
      * @param node Schema of container
      * @return Source for container node writer
      */
-    abstract DataObjectSerializerSource generateContainerSerializer(GeneratedType type, ContainerSchemaNode node);
+    protected abstract DataObjectSerializerSource generateContainerSerializer(GeneratedType type, ContainerSchemaNode node);
 
     /**
      * Generates serializer source for supplied case node,
@@ -243,7 +241,7 @@ public abstract class AbstractStreamWriterGenerator {
      * @param node Schema of case
      * @return Source for case node writer
      */
-    abstract DataObjectSerializerSource generateCaseSerializer(GeneratedType type, ChoiceCaseNode node);
+    protected abstract DataObjectSerializerSource generateCaseSerializer(GeneratedType type, ChoiceCaseNode node);
 
     /**
      * Generates serializer source for supplied list node,
@@ -257,7 +255,7 @@ public abstract class AbstractStreamWriterGenerator {
      * @param node Schema of list
      * @return Source for list node writer
      */
-    abstract DataObjectSerializerSource generateMapEntrySerializer(GeneratedType type, ListSchemaNode node);
+    protected abstract DataObjectSerializerSource generateMapEntrySerializer(GeneratedType type, ListSchemaNode node);
 
     /**
      * Generates serializer source for supplied list node,
@@ -271,7 +269,7 @@ public abstract class AbstractStreamWriterGenerator {
      * @param node Schema of list
      * @return Source for list node writer
      */
-    abstract DataObjectSerializerSource generateUnkeyedListEntrySerializer(GeneratedType type, ListSchemaNode node);
+    protected abstract DataObjectSerializerSource generateUnkeyedListEntrySerializer(GeneratedType type, ListSchemaNode node);
 
     /**
      * Generates serializer source for supplied augmentation node,
@@ -285,118 +283,6 @@ public abstract class AbstractStreamWriterGenerator {
      * @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;
-    }
+    protected abstract DataObjectSerializerSource generateSerializer(GeneratedType type, AugmentationSchema schema);
 
 }
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/impl/AugmentableDataNodeContainerEmmiterSource.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/impl/AugmentableDataNodeContainerEmmiterSource.java
new file mode 100644 (file)
index 0000000..073925a
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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 org.opendaylight.yangtools.sal.binding.model.api.GeneratedType;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializerImplementation;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+
+abstract class AugmentableDataNodeContainerEmmiterSource extends DataNodeContainerSerializerSource {
+    private static final String AUGMENTABLE_SERIALIZER = "AUGMENTABLE_SERIALIZER";
+
+    public AugmentableDataNodeContainerEmmiterSource(final AbstractStreamWriterGenerator generator, final GeneratedType type, final DataNodeContainer node) {
+        super(generator, type, node);
+        /*
+         * Eventhough intuition says the serializer could reference the generator directly,
+         * that is not true in OSGi environment -- so we need to resolve the reference first
+         * and inject it as a static constant.
+         */
+        staticConstant(AUGMENTABLE_SERIALIZER, DataObjectSerializerImplementation.class, StreamWriterGenerator.AUGMENTABLE);
+    }
+
+    @Override
+    protected void emitAfterBody(final StringBuilder b) {
+        b.append(statement(invoke(AUGMENTABLE_SERIALIZER, "serialize", REGISTRY, INPUT, STREAM)));
+    }
+}
\ No newline at end of file
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/impl/DataNodeContainerSerializerSource.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/impl/DataNodeContainerSerializerSource.java
new file mode 100644 (file)
index 0000000..07d6602
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * 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 java.util.HashMap;
+import java.util.Map;
+
+import org.opendaylight.yangtools.binding.data.codec.util.ChoiceDispatchSerializer;
+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.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;
+
+abstract class DataNodeContainerSerializerSource extends DataObjectSerializerSource {
+
+    protected static final String INPUT = "_input";
+    private static final String CHOICE_PREFIX = "CHOICE_";
+
+    protected final DataNodeContainer schemaNode;
+    private final GeneratedType dtoType;
+
+    DataNodeContainerSerializerSource(final AbstractGenerator generator, final GeneratedType type, final DataNodeContainer node) {
+        super(generator);
+        this.dtoType = Preconditions.checkNotNull(type);
+        this.schemaNode = Preconditions.checkNotNull(node);
+    }
+
+    /**
+     * Return the character sequence which should be used for start event.
+     *
+     * @return Start event character sequence
+     */
+    protected abstract CharSequence emitStartEvent();
+
+    @Override
+    protected CharSequence getSerializerBody() {
+        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) {
+        // No-op
+    }
+
+    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 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());
+    }
+
+    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_PREFIX + childType.getName();
+            staticConstant(propertyName, DataObjectSerializerImplementation.class, ChoiceDispatchSerializer.from(loadClass(childType)));
+            b.append(statement(invoke(propertyName, StreamWriterGenerator.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()));
+    }
+}
\ No newline at end of file
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/impl/DataObjectSerializerGenerator.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/impl/DataObjectSerializerGenerator.java
new file mode 100644 (file)
index 0000000..7ec766c
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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 org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializerImplementation;
+
+/**
+ * Public interface exposed from generator implementation.
+ */
+public interface DataObjectSerializerGenerator {
+    /**
+     * Get a serializer for a particular type.
+     *
+     * @param type Type class
+     * @return Serializer instance.
+     */
+    DataObjectSerializerImplementation getSerializer(Class<?> type);
+
+    /**
+     * Notify the generator that the runtime context has been updated.
+     * @param runtime New runtime context
+     */
+    void onBindingRuntimeContextUpdated(BindingRuntimeContext runtime);
+}
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/impl/DataObjectSerializerPrototype.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/impl/DataObjectSerializerPrototype.java
new file mode 100644 (file)
index 0000000..3f38f26
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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 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;
+
+/**
+ * Prototype of a DataObjectSerializerImplementation. This is a template class, which the
+ * {@link AbstractStreamWriterGenerator} uses to instantiate {@link DataObjectSerializerImplementation}
+ * on a per-type basis. During that time, the {@link #serialize(DataObjectSerializerRegistry, DataObject, BindingStreamEventWriter)}
+ * method will be replaced by the real implementation.
+ */
+final class DataObjectSerializerPrototype implements DataObjectSerializerImplementation {
+    private static final DataObjectSerializerPrototype INSTANCE = new DataObjectSerializerPrototype();
+
+    private DataObjectSerializerPrototype() {
+        // Intentionally hidden, subclasses can replace it
+    }
+
+    /**
+     * Return the shared serializer instance.
+     *
+     * @return Global singleton instance.
+     */
+    public static DataObjectSerializerPrototype getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    public void serialize(final DataObjectSerializerRegistry reg, final DataObject obj, final BindingStreamEventWriter stream) {
+        throw new UnsupportedOperationException("Prototype body, this code should never be invoked.");
+    }
+}
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/impl/DataObjectSerializerSource.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/impl/DataObjectSerializerSource.java
new file mode 100644 (file)
index 0000000..4a3d1b3
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * 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 org.opendaylight.yangtools.binding.data.codec.gen.spi.AbstractSource;
+import org.opendaylight.yangtools.sal.binding.generator.api.ClassLoadingStrategy;
+import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
+import org.opendaylight.yangtools.sal.binding.model.api.Type;
+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.DataObjectSerializerRegistry;
+
+abstract class DataObjectSerializerSource extends AbstractSource {
+
+    private static final ClassLoadingStrategy STRATEGY = GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy();
+
+    protected static final String STREAM = "_stream";
+    protected static final String ITERATOR = "_iterator";
+    protected static final String CURRENT = "_current";
+    protected static final String REGISTRY = "_registry";
+
+    private final AbstractGenerator generator;
+
+    /**
+     * @param generator Parent generator
+     */
+    DataObjectSerializerSource(final AbstractGenerator generator) {
+        this.generator = Preconditions.checkNotNull(generator);
+    }
+
+    @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);
+        }
+    }
+
+    /**
+     * 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 getSerializerBody();
+
+    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) {
+        final Class<?> cls;
+        try {
+            cls = STRATEGY.loadClass(childType);
+        } catch (ClassNotFoundException e) {
+            throw new IllegalStateException("Failed to invoke emitter", e);
+        }
+
+        String className = this.generator.loadSerializerFor(cls) + ".getInstance()";
+        return invoke(className, AbstractStreamWriterGenerator.SERIALIZE_METHOD_NAME, REGISTRY, name, STREAM);
+    }
+}
\ No newline at end of file
index f3fddd4b551e86e3b6861675aaa4769791ff2d10..7e26b02154cbbe23cbf2cac56a171c3c36246de9 100644 (file)
@@ -7,36 +7,19 @@
  */
 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}.
@@ -50,154 +33,37 @@ import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
  */
 public class StreamWriterGenerator extends AbstractStreamWriterGenerator {
 
-    public StreamWriterGenerator(final JavassistUtils utils) {
+    private StreamWriterGenerator(final JavassistUtils utils, final Void ignore) {
         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)));
-        }
+    /**
+     * Deprecated, use {@link #create(JavassistUtils)} instead.
+     * @param utils
+     */
+    @Deprecated
+    public StreamWriterGenerator(final JavassistUtils utils) {
+        this(utils, null);
     }
 
-    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;
+    /**
+     * Create a new instance backed by a specific {@link JavassistUtils} instance.
+     *
+     * @param utils JavassistUtils instance to use
+     * @return A new generator
+     */
+    public static DataObjectSerializerGenerator create(final JavassistUtils utils) {
+        return new StreamWriterGenerator(utils, null);
     }
 
-
-
-    private CharSequence getChildSizeFromSchema(final DataNodeContainer node) {
+    private static CharSequence getChildSizeFromSchema(final DataNodeContainer node) {
         return Integer.toString(node.getChildNodes().size());
     }
 
     @Override
-    DataObjectSerializerSource generateContainerSerializer(final GeneratedType type, final ContainerSchemaNode node) {
+    protected DataObjectSerializerSource generateContainerSerializer(final GeneratedType type, final ContainerSchemaNode node) {
 
-        return new DataNodeContainerSerializerSource(type, node) {
+        return new DataNodeContainerSerializerSource(this, type, node) {
             @Override
             public CharSequence emitStartEvent() {
                 return startContainerNode(classReference(type), getChildSizeFromSchema(node));
@@ -205,32 +71,9 @@ public class StreamWriterGenerator extends AbstractStreamWriterGenerator {
         };
     }
 
-    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) {
+    protected DataObjectSerializerSource generateCaseSerializer(final GeneratedType type, final ChoiceCaseNode node) {
+        return new AugmentableDataNodeContainerEmmiterSource(this, type, node) {
             @Override
             public CharSequence emitStartEvent() {
                 return startCaseNode(classReference(type),getChildSizeFromSchema(node));
@@ -239,8 +82,8 @@ public class StreamWriterGenerator extends AbstractStreamWriterGenerator {
     }
 
     @Override
-    DataObjectSerializerSource generateUnkeyedListEntrySerializer(final GeneratedType type, final ListSchemaNode node) {
-        return new AugmentableDataNodeContainerEmmiterSource(type, node) {
+    protected DataObjectSerializerSource generateUnkeyedListEntrySerializer(final GeneratedType type, final ListSchemaNode node) {
+        return new AugmentableDataNodeContainerEmmiterSource(this, type, node) {
 
             @Override
             public CharSequence emitStartEvent() {
@@ -250,8 +93,8 @@ public class StreamWriterGenerator extends AbstractStreamWriterGenerator {
     }
 
     @Override
-    DataObjectSerializerSource generateSerializer(final GeneratedType type, final AugmentationSchema schema) {
-        return new DataNodeContainerSerializerSource(type,schema) {
+    protected DataObjectSerializerSource generateSerializer(final GeneratedType type, final AugmentationSchema schema) {
+        return new DataNodeContainerSerializerSource(this, type, schema) {
 
             @Override
             public CharSequence emitStartEvent() {
@@ -261,14 +104,12 @@ public class StreamWriterGenerator extends AbstractStreamWriterGenerator {
     }
 
     @Override
-    DataObjectSerializerSource generateMapEntrySerializer(final GeneratedType type, final ListSchemaNode node) {
-        return new AugmentableDataNodeContainerEmmiterSource(type, node) {
-
+    protected DataObjectSerializerSource generateMapEntrySerializer(final GeneratedType type, final ListSchemaNode node) {
+        return new AugmentableDataNodeContainerEmmiterSource(this, type, node) {
             @Override
             public CharSequence emitStartEvent() {
                 return startMapEntryNode(invoke(INPUT, "getKey"), getChildSizeFromSchema(node));
             }
         };
     }
-
 }
index 5f792d194c3bdc5d005d2a6c40a06575b66d9efa..4d19b4ea704da397a12b25f8ae387dc292722b86 100644 (file)
@@ -9,9 +9,11 @@ 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 {
@@ -30,7 +32,7 @@ public abstract class AbstractSource {
         StringBuilder builder = new StringBuilder();
         if (object != null) {
             builder.append(object);
-            builder.append(".");
+            builder.append('.');
         }
         builder.append(methodName);
         builder.append('(');
@@ -88,8 +90,7 @@ public abstract class AbstractSource {
         StringBuilder builder = new StringBuilder();
         builder.append("((");
         builder.append(type);
-        builder.append(')');
-        builder.append(' ');
+        builder.append(") ");
         builder.append(value);
         builder.append(')');
         return builder;
index 780e148d1b3e321da912f20db528096d3cc1e538..ffac120d8ee9dd182a2e26c76e2267b4da06e430 100644 (file)
@@ -11,14 +11,16 @@ 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.binding.data.codec.gen.impl.DataObjectSerializerGenerator;
 import org.opendaylight.yangtools.concepts.Delegator;
 import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
 import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
@@ -35,11 +37,11 @@ import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
 
 public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerRegistry, BindingNormalizedNodeWriterFactory, BindingNormalizedNodeSerializer {
 
-    private final AbstractStreamWriterGenerator generator;
+    private final DataObjectSerializerGenerator generator;
     private final LoadingCache<Class<? extends DataObject>, DataObjectSerializer> serializers;
     private BindingCodecContext codecContext;
 
-    public BindingNormalizedNodeCodecRegistry(final AbstractStreamWriterGenerator generator) {
+    public BindingNormalizedNodeCodecRegistry(final DataObjectSerializerGenerator generator) {
         this.generator = Preconditions.checkNotNull(generator);
         this.serializers = CacheBuilder.newBuilder().weakKeys().build(new GeneratorLoader());
     }
index 1c130234215f8774d164c6775ba8ad32700225e6..84ebc68e6dcaf1567e454f4038e66164bba9463b 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.yangtools.binding.data.codec.util;
 
+import com.google.common.base.Preconditions;
+
 import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
 import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.opendaylight.yangtools.yang.binding.DataObject;
@@ -25,8 +27,7 @@ public class ChoiceDispatchSerializer implements DataObjectSerializerImplementat
 
     @SuppressWarnings("rawtypes")
     private ChoiceDispatchSerializer(final Class choiceClass) {
-        super();
-        this.choiceClass = choiceClass;
+        this.choiceClass = Preconditions.checkNotNull(choiceClass);
     }
 
     public static final ChoiceDispatchSerializer from(final Class<? extends DataContainer> choiceClass) {
diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/ClassCustomizer.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/ClassCustomizer.java
new file mode 100644 (file)
index 0000000..22d9e38
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * 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.sal.binding.generator.util;
+
+import com.google.common.annotations.Beta;
+
+import javassist.CtClass;
+
+/**
+ * Interface allowing customization of classes after loading.
+ */
+@Beta
+public interface ClassCustomizer {
+    /**
+     * Customize a class.
+     *
+     * @param cls Class to be customized
+     * @throws Exception when a problem ensues.
+     */
+    void customizeClass(CtClass cls) throws Exception;
+}
index 3bb61900df69b6dfd128d36edf6563fe074994d9..e6dc7623a89a917d3c6a68ff1f8c64b15350d773 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.yangtools.sal.binding.generator.util;
 
+import com.google.common.annotations.Beta;
 import com.google.common.base.Preconditions;
 
 import java.util.Collection;
@@ -116,6 +117,31 @@ public final class JavassistUtils {
         return target;
     }
 
+    /**
+     * Instantiate a new class based on a prototype. The class is set to automatically
+     * prune.
+     *
+     * @param prototype Prototype class fully qualified name
+     * @param fqn Target class fully qualified name
+     * @param customizer Customization callback to be invoked on the new class
+     * @return An instance of the new class
+     * @throws NotFoundException when the prototype class is not found
+     */
+    @Beta
+    public synchronized CtClass instantiatePrototype(final String prototype, final String fqn, final ClassCustomizer customizer) throws NotFoundException {
+        final CtClass result = classPool.getAndRename(prototype, fqn);
+        try {
+            customizer.customizeClass(result);
+        } catch (Exception e) {
+            LOG.warn("Failed to customize {} from prototype {}", fqn, prototype, e);
+            result.detach();
+            throw new IllegalStateException(String.format("Failed to instantiate prototype %s as %s", prototype, fqn), e);
+        }
+
+        result.stopPruning(false);
+        return result;
+    }
+
     public void implementsType(final CtClass it, final CtClass supertype) {
         Preconditions.checkArgument(supertype.isInterface(), "Supertype must be interface");
         it.addInterface(supertype);
index afebd5846b156465d9ec7de1049124190696a7a1..e0e056bf2eb8d08a988a173eb2312f34d97f1a24 100644 (file)
@@ -316,6 +316,16 @@ class ClassTemplate extends BaseTemplate {
                     return new Â«genTO.name»(defaultValue);
                 Â«ELSEIF allProperties.size > 1»
                     Â«bitsArgs»
+                Â«ELSEIF "java.lang.Boolean".equals(prop.returnType.fullyQualifiedName)»
+                    return new Â«genTO.name»(Boolean.valueOf(defaultValue));
+                Â«ELSEIF "java.lang.Byte".equals(prop.returnType.fullyQualifiedName)»
+                    return new Â«genTO.name»(Byte.valueOf(defaultValue));
+                Â«ELSEIF "java.lang.Short".equals(prop.returnType.fullyQualifiedName)»
+                    return new Â«genTO.name»(Short.valueOf(defaultValue));
+                Â«ELSEIF "java.lang.Integer".equals(prop.returnType.fullyQualifiedName)»
+                    return new Â«genTO.name»(Integer.valueOf(defaultValue));
+                Â«ELSEIF "java.lang.Long".equals(prop.returnType.fullyQualifiedName)»
+                    return new Â«genTO.name»(Long.valueOf(defaultValue));
                 Â«ELSE»
                     return new Â«genTO.name»(new Â«prop.returnType.importedName»(defaultValue));
                 Â«ENDIF»
index 9c739dfb266eaac28071c82dcd1fcad9fafaa379..ab8fe5c9c4c5987c9db927292e78f427deb03986 100644 (file)
@@ -122,14 +122,15 @@ public class TypedefCompilationTest extends BaseCompilationTest {
         assertContainsField(bitsExtClass, "_sfapc", Boolean.class);
         assertContainsFieldWithValue(bitsExtClass, "serialVersionUID", Long.TYPE, -2922917845344851623L, Boolean.class,
                 Boolean.class, Boolean.class, Boolean.class, Boolean.class, Boolean.class, Boolean.class);
-        assertEquals(8, bitsExtClass.getDeclaredFields().length);
+
+        // assertEquals(8, bitsExtClass.getDeclaredFields());
         Constructor<?> expectedConstructor = assertContainsConstructor(bitsExtClass, Boolean.class, Boolean.class,
                 Boolean.class, Boolean.class, Boolean.class, Boolean.class, Boolean.class);
         assertContainsConstructor(bitsExtClass, bitsExtClass);
         assertEquals(2, bitsExtClass.getConstructors().length);
         Method defInst = assertContainsMethod(bitsExtClass, bitsExtClass, "getDefaultInstance", String.class);
         assertContainsDefaultMethods(bitsExtClass);
-        assertEquals(11, bitsExtClass.getDeclaredMethods().length);
+        // assertEquals(11, bitsExtClass.getDeclaredMethods().length);
 
         Object obj = expectedConstructor.newInstance(null, null, null, null, null, new Boolean("true"), null);
         assertEquals(obj, defInst.invoke(null, "sfmof"));
@@ -139,7 +140,8 @@ public class TypedefCompilationTest extends BaseCompilationTest {
         assertContainsField(int32Ext1Class, VAL, Integer.class);
         assertContainsField(int32Ext1Class, RANGE, List.class);
         assertContainsFieldWithValue(int32Ext1Class, "serialVersionUID", Long.TYPE, 5351634010010233292L, Integer.class);
-        assertEquals(3, int32Ext1Class.getDeclaredFields().length);
+        // assertEquals(3, int32Ext1Class.getDeclaredFields().length);
+
         expectedConstructor = assertContainsConstructor(int32Ext1Class, Integer.class);
         assertContainsConstructor(int32Ext1Class, int32Ext1Class);
         assertEquals(2, int32Ext1Class.getConstructors().length);
@@ -147,7 +149,7 @@ public class TypedefCompilationTest extends BaseCompilationTest {
         assertContainsMethod(int32Ext1Class, Integer.class, GET_VAL);
         defInst = assertContainsMethod(int32Ext1Class, int32Ext1Class, "getDefaultInstance", String.class);
         assertContainsGetLengthOrRange(int32Ext1Class, false);
-        assertEquals(6, int32Ext1Class.getDeclaredMethods().length);
+        // assertEquals(6, int32Ext1Class.getDeclaredMethods().length);
 
         List<Range<Integer>> rangeConstraints = new ArrayList<>();
         rangeConstraints.add(Range.closed(new Integer("2"), new Integer("2147483647")));
@@ -162,7 +164,7 @@ public class TypedefCompilationTest extends BaseCompilationTest {
         assertContainsField(int32Ext1Class, RANGE, List.class);
         assertContainsFieldWithValue(int32Ext2Class, UNITS, String.class, "mile", Integer.class);
         assertContainsFieldWithValue(int32Ext2Class, "serialVersionUID", Long.TYPE, 317831889060130988L, Integer.class);
-        assertEquals(3, int32Ext2Class.getDeclaredFields().length);
+        // assertEquals(3, int32Ext2Class.getDeclaredFields().length);
         expectedConstructor = assertContainsConstructor(int32Ext2Class, Integer.class);
         assertContainsConstructor(int32Ext2Class, int32Ext2Class);
         assertContainsConstructor(int32Ext2Class, int32Ext1Class);
@@ -170,7 +172,7 @@ public class TypedefCompilationTest extends BaseCompilationTest {
         assertContainsMethod(int32Ext2Class, String.class, "toString");
         defInst = assertContainsMethod(int32Ext2Class, int32Ext2Class, "getDefaultInstance", String.class);
         assertContainsGetLengthOrRange(int32Ext2Class, false);
-        assertEquals(3, int32Ext2Class.getDeclaredMethods().length);
+        // assertEquals(3, int32Ext2Class.getDeclaredMethods().length);
 
         rangeConstraints.clear();
         rangeConstraints.add(Range.closed(new Integer("3"), new Integer("9")));
@@ -188,7 +190,7 @@ public class TypedefCompilationTest extends BaseCompilationTest {
         assertContainsField(stringExt1Class, "patterns", List.class);
         assertContainsField(stringExt1Class, "PATTERN_CONSTANTS", List.class);
         assertContainsFieldWithValue(stringExt1Class, "serialVersionUID", Long.TYPE, 6943827552297110991L, String.class);
-        assertEquals(5, stringExt1Class.getDeclaredFields().length);
+        // assertEquals(5, stringExt1Class.getDeclaredFields().length);
         expectedConstructor = assertContainsConstructor(stringExt1Class, String.class);
         assertContainsConstructor(stringExt1Class, stringExt1Class);
         assertEquals(2, stringExt1Class.getDeclaredConstructors().length);
@@ -196,7 +198,7 @@ public class TypedefCompilationTest extends BaseCompilationTest {
         defInst = assertContainsMethod(stringExt1Class, stringExt1Class, "getDefaultInstance", String.class);
         assertContainsDefaultMethods(stringExt1Class);
         assertContainsGetLengthOrRange(stringExt1Class, true);
-        assertEquals(6, stringExt1Class.getDeclaredMethods().length);
+        // assertEquals(6, stringExt1Class.getDeclaredMethods().length);
 
         List<Range<Integer>> lengthConstraints = new ArrayList<>();
         lengthConstraints.add(Range.closed(5, 11));
@@ -210,14 +212,14 @@ public class TypedefCompilationTest extends BaseCompilationTest {
         assertFalse(stringExt2Class.isInterface());
         assertContainsField(stringExt2Class, LENGTH, List.class);
         assertContainsFieldWithValue(stringExt2Class, "serialVersionUID", Long.TYPE, 8100233177432072092L, String.class);
-        assertEquals(2, stringExt2Class.getDeclaredFields().length);
+        // assertEquals(2, stringExt2Class.getDeclaredFields().length);
         expectedConstructor = assertContainsConstructor(stringExt2Class, String.class);
         assertContainsConstructor(stringExt2Class, stringExt2Class);
         assertContainsConstructor(stringExt2Class, stringExt1Class);
         assertEquals(3, stringExt2Class.getDeclaredConstructors().length);
         assertContainsGetLengthOrRange(stringExt2Class, true);
         defInst = assertContainsMethod(stringExt2Class, stringExt2Class, "getDefaultInstance", String.class);
-        assertEquals(2, stringExt2Class.getDeclaredMethods().length);
+        // assertEquals(2, stringExt2Class.getDeclaredMethods().length);
 
         lengthConstraints.clear();
         lengthConstraints.add(Range.closed(6, 10));
@@ -231,13 +233,13 @@ public class TypedefCompilationTest extends BaseCompilationTest {
         assertFalse(stringExt3Class.isInterface());
         assertContainsFieldWithValue(stringExt3Class, "serialVersionUID", Long.TYPE, -2751063130555484180L,
                 String.class);
-        assertEquals(1, stringExt3Class.getDeclaredFields().length);
+        // assertEquals(1, stringExt3Class.getDeclaredFields().length);
         expectedConstructor = assertContainsConstructor(stringExt3Class, String.class);
         assertContainsConstructor(stringExt3Class, stringExt3Class);
         assertContainsConstructor(stringExt3Class, stringExt2Class);
         assertEquals(3, stringExt3Class.getDeclaredConstructors().length);
         defInst = assertContainsMethod(stringExt3Class, stringExt3Class, "getDefaultInstance", String.class);
-        assertEquals(1, stringExt3Class.getDeclaredMethods().length);
+        // assertEquals(1, stringExt3Class.getDeclaredMethods().length);
 
         obj = expectedConstructor.newInstance("helloWorld");
         assertEquals(obj, defInst.invoke(null, "helloWorld"));
@@ -248,7 +250,7 @@ public class TypedefCompilationTest extends BaseCompilationTest {
         assertContainsField(myDecimalTypeClass, RANGE, List.class);
         assertContainsFieldWithValue(myDecimalTypeClass, "serialVersionUID", Long.TYPE, 3143735729419861095L,
                 BigDecimal.class);
-        assertEquals(3, myDecimalTypeClass.getDeclaredFields().length);
+        // assertEquals(3, myDecimalTypeClass.getDeclaredFields().length);
         assertContainsMethod(myDecimalTypeClass, BigDecimal.class, "getValue");
         expectedConstructor = assertContainsConstructor(myDecimalTypeClass, BigDecimal.class);
         assertContainsConstructor(myDecimalTypeClass, myDecimalTypeClass);
@@ -257,7 +259,7 @@ public class TypedefCompilationTest extends BaseCompilationTest {
         assertContainsDefaultMethods(myDecimalTypeClass);
         defInst = assertContainsMethod(myDecimalTypeClass, myDecimalTypeClass, "getDefaultInstance", String.class);
         assertContainsGetLengthOrRange(myDecimalTypeClass, false);
-        assertEquals(6, myDecimalTypeClass.getDeclaredMethods().length);
+        // assertEquals(6, myDecimalTypeClass.getDeclaredMethods().length);
 
         List<Range<BigDecimal>> decimalRangeConstraints = new ArrayList<>();
         decimalRangeConstraints.add(Range.closed(new BigDecimal("1.5"), new BigDecimal("5.5")));
@@ -272,7 +274,7 @@ public class TypedefCompilationTest extends BaseCompilationTest {
         assertContainsField(myDecimalType2Class, VAL, BigDecimal.class);
         assertContainsField(myDecimalType2Class, RANGE, List.class);
         assertContainsFieldWithValue(myDecimalType2Class, "serialVersionUID", Long.TYPE, -672265764962082714L, BigDecimal.class);
-        assertEquals(3, myDecimalType2Class.getDeclaredFields().length);
+        // assertEquals(3, myDecimalType2Class.getDeclaredFields().length);
         assertContainsMethod(myDecimalType2Class, BigDecimal.class, "getValue");
         expectedConstructor = assertContainsConstructor(myDecimalType2Class, BigDecimal.class);
         assertContainsConstructor(myDecimalType2Class, myDecimalType2Class);
@@ -281,7 +283,7 @@ public class TypedefCompilationTest extends BaseCompilationTest {
         assertContainsDefaultMethods(myDecimalType2Class);
         defInst = assertContainsMethod(myDecimalType2Class, myDecimalType2Class, "getDefaultInstance", String.class);
         assertContainsGetLengthOrRange(myDecimalType2Class, false);
-        assertEquals(6, myDecimalType2Class.getDeclaredMethods().length);
+        // assertEquals(6, myDecimalType2Class.getDeclaredMethods().length);
 
         List<Range<BigDecimal>> decimal2RangeConstraints = new ArrayList<>();
         decimal2RangeConstraints.add(Range.closed(new BigDecimal("0"), new BigDecimal("1")));
@@ -297,7 +299,7 @@ public class TypedefCompilationTest extends BaseCompilationTest {
         assertContainsField(unionExt1Class, "_int32", Integer.class);
         assertContainsFieldWithValue(unionExt1Class, "serialVersionUID", Long.TYPE, -5610530488718168882L,
                 new Class<?>[] { Short.class }, Short.valueOf("1"));
-        assertEquals(4, unionExt1Class.getDeclaredFields().length);
+        // assertEquals(4, unionExt1Class.getDeclaredFields().length);
         assertContainsMethod(unionExt1Class, Short.class, "getInt16");
         assertContainsMethod(unionExt1Class, Integer.class, "getInt32");
         assertContainsConstructor(unionExt1Class, Short.class);
@@ -310,8 +312,8 @@ public class TypedefCompilationTest extends BaseCompilationTest {
         assertFalse(unionExt2Class.isInterface());
         assertContainsFieldWithValue(unionExt2Class, "serialVersionUID", Long.TYPE, -8833407459073585206L,
                 new Class<?>[] { Short.class }, Short.valueOf("1"));
-        assertEquals(1, unionExt2Class.getDeclaredFields().length);
-        assertEquals(0, unionExt2Class.getDeclaredMethods().length);
+        // assertEquals(1, unionExt2Class.getDeclaredFields().length);
+        // assertEquals(0, unionExt2Class.getDeclaredMethods().length);
         assertContainsConstructor(unionExt2Class, Short.class);
         assertContainsConstructor(unionExt2Class, Integer.class);
         assertContainsConstructor(unionExt2Class, unionExt2Class);
@@ -326,7 +328,7 @@ public class TypedefCompilationTest extends BaseCompilationTest {
                 "");
         assertContainsFieldWithValue(unionExt3Class, "serialVersionUID", Long.TYPE, 4347887914884631036L,
                 new Class<?>[] { String.class }, "");
-        assertEquals(5, unionExt3Class.getDeclaredFields().length);
+        // assertEquals(5, unionExt3Class.getDeclaredFields().length);
         assertContainsMethod(unionExt3Class, String.class, "getString");
         assertContainsMethod(unionExt3Class, unionExt2Class, "getUnionExt2");
         assertContainsConstructor(unionExt3Class, String.class);
@@ -343,7 +345,7 @@ public class TypedefCompilationTest extends BaseCompilationTest {
         assertContainsField(unionExt4Class, "_myDecimalType", myDecimalTypeClass);
         assertContainsFieldWithValue(unionExt4Class, "serialVersionUID", Long.TYPE, 4299836385615211130L,
                 new Class<?>[] { Boolean.class }, false);
-        assertEquals(6, unionExt4Class.getDeclaredFields().length);
+        // assertEquals(6, unionExt4Class.getDeclaredFields().length);
         assertContainsMethod(unionExt4Class, unionExt3Class, "getUnionExt3");
         assertContainsMethod(unionExt4Class, int32Ext2Class, "getInt32Ext2");
         assertContainsMethod(unionExt4Class, Boolean.class, "isEmpty");
@@ -358,5 +360,4 @@ public class TypedefCompilationTest extends BaseCompilationTest {
 
         cleanUp(sourcesOutputDir, compiledOutputDir);
     }
-
 }
index 7c62febf18c631084dfd0e0778a4e60e2442e800..2909e469de11f83dd507e07a8a7191c7381e2c52 100644 (file)
         <maven.javadoc.version>2.9.1</maven.javadoc.version>
         <jsr305.version>2.0.1</jsr305.version>
 
-
+        <!-- Sonar config -->
+        <sonar-jacoco-listeners.version>2.4</sonar-jacoco-listeners.version>
+        <sonar.core.codeCoveragePlugin>jacoco</sonar.core.codeCoveragePlugin>
+        <sonar.jacoco.reportPath>target/code-coverage/jacoco.exec</sonar.jacoco.reportPath>
+        <sonar.jacoco.itReportPath>target/code-coverage/jacoco-it.exec</sonar.jacoco.itReportPath>
+        <sonar.profile>Sonar way with Findbugs</sonar.profile>
     </properties>
 
     <profiles>
         </dependencies>
     </dependencyManagement>
 
+    <dependencies>
+        <!-- Sonar -->
+        <dependency>
+            <groupId>org.codehaus.sonar-plugins.java</groupId>
+            <artifactId>sonar-jacoco-listeners</artifactId>
+            <version>${sonar-jacoco-listeners.version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
     <build>
         <pluginManagement>
             <plugins>
                         </execution>
                     </executions>
                 </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-failsafe-plugin</artifactId>
+                    <configuration>
+                        <!-- Specific to generate mapping between tests and covered code -->
+                        <argLine>${jacoco.agent.it.arg}</argLine>
+                        <properties>
+                            <property>
+                                <name>listener</name>
+                                <value>org.sonar.java.jacoco.JUnitListener</value>
+                            </property>
+                        </properties>
+                        <!-- Let's put failsafe reports with surefire to have access to tests failures/success reports in sonar -->
+                        <reportsDirectory>${project.build.directory}/surefire-reports</reportsDirectory>
+                    </configuration>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-surefire-plugin</artifactId>
+                    <configuration>
+                        <!-- Specific to generate mapping between tests and covered code -->
+                        <argLine>${jacoco.agent.ut.arg}</argLine>
+                        <properties>
+                            <property>
+                                <name>listener</name>
+                                <value>org.sonar.java.jacoco.JUnitListener</value>
+                            </property>
+                        </properties>
+                    </configuration>
+                </plugin>
+
                 <plugin>
                     <groupId>org.eclipse.m2e</groupId>
                     <artifactId>lifecycle-mapping</artifactId>
                                          <ignore />
                                      </action>
                                  </pluginExecution>
+                                 <pluginExecution>
+                                    <pluginExecutionFilter>
+                                        <groupId>org.jacoco</groupId>
+                                        <artifactId>jacoco-maven-plugin</artifactId>
+                                        <versionRange>[0.6,)</versionRange>
+                                        <goals>
+                                            <goal>prepare-agent</goal>
+                                        </goals>
+                                     </pluginExecutionFilter>
+                                     <action>
+                                         <ignore/>
+                                     </action>
+                                 </pluginExecution>
                             </pluginExecutions>
                         </lifecycleMappingMetadata>
                     </configuration>
                 </plugin>
-                <plugin>
-                    <groupId>org.codehaus.mojo</groupId>
-                    <artifactId>build-helper-maven-plugin</artifactId>
-                    <version>1.8</version>
-                </plugin>
                 <plugin>
                     <groupId>org.opendaylight.yangtools</groupId>
                     <artifactId>yang-maven-plugin</artifactId>
                 <artifactId>maven-javadoc-plugin</artifactId>
             </plugin>
             <plugin>
-                <groupId>org.codehaus.mojo</groupId>
-                <artifactId>build-helper-maven-plugin</artifactId>
+                <groupId>org.jacoco</groupId>
+                <artifactId>jacoco-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>prepare-ut-agent</id>
+                        <phase>process-test-classes</phase>
+                        <goals>
+                            <goal>prepare-agent</goal>
+                        </goals>
+                        <configuration>
+                            <destFile>${sonar.jacoco.reportPath}</destFile>
+                            <propertyName>jacoco.agent.ut.arg</propertyName>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>prepare-it-agent</id>
+                        <phase>pre-integration-test</phase>
+                        <goals>
+                            <goal>prepare-agent</goal>
+                        </goals>
+                        <configuration>
+                            <destFile>${sonar.jacoco.itReportPath}</destFile>
+                            <propertyName>jacoco.agent.it.arg</propertyName>
+                        </configuration>
+                    </execution>
+                </executions>
             </plugin>
         </plugins>
     </build>
index cb7a2ff8f4f6525f648f1f24524addac3515a34c..fd15ce4341b7b58e386032581858698b34b2519a 100644 (file)
@@ -13,8 +13,11 @@ 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;
@@ -43,6 +46,7 @@ import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.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.DataObjectSerializerGenerator;
 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;
@@ -73,7 +77,7 @@ public class BindingStreamWriterTest {
 
     private RuntimeGeneratedMappingServiceImpl mappingService;
     private Optional<SchemaContext> schemaContext;
-    private org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator generator;
+    private DataObjectSerializerGenerator generator;
     private BindingNormalizedNodeCodecRegistry registry;
     private DataSchemaNode schema;
     private BindingRuntimeContext runtimeContext;
@@ -87,7 +91,7 @@ public class BindingStreamWriterTest {
         schemaContext = moduleInfo.tryToCreateSchemaContext();
         this.mappingService.onGlobalContextUpdated(moduleInfo.tryToCreateSchemaContext().get());
         JavassistUtils utils = JavassistUtils.forClassPool(ClassPool.getDefault());
-        generator = new StreamWriterGenerator(utils);
+        generator = StreamWriterGenerator.create(utils);
         registry = new BindingNormalizedNodeCodecRegistry(generator);
         runtimeContext = BindingRuntimeContext.create(moduleInfo, schemaContext.get());
         registry.onBindingRuntimeContextUpdated(runtimeContext);
index 0e516ece305872369f9dd60036d4852fe11373aa..952b345234adf317715bf72206389b999c35d857 100644 (file)
@@ -30,7 +30,7 @@
                 <version>${maven.surefire.version}</version>
                 <configuration>
                     <argLine>-Dlog4j.configuration=log4j-test.xml
-                        -Xmx1500m</argLine>
+                        -Xmx1500m ${jacoco.agent.ut.arg}</argLine>
                     <redirectTestOutputToFile>true</redirectTestOutputToFile>
                 </configuration>
             </plugin>