*
* @param path
* - {@link InstanceIdentifier} path
+ * @param <T> data type
* @return subtree codec
*/
@Nullable
*
* @param childClass
* - child class by Biding Stream navigation
+ * @param <E> data type
* @return context of child
* @throws IllegalArgumentException
* - if supplied child class is not valid in specified context
*
* @param childClass
* - child class by Binding Stream navigation
+ * @param <E> data type
* @return context of child or Optional absent if supplied is not applicable
* in context
*/
* - Binding Instance Identifier pointing to data
* @param data
* - representing Data Tree
+ * @param <T> data type
* @return NormalizedNode representation
* @throws IllegalArgumentException
* - if supplied Instance Identifier is not valid.
--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.mdsal.binding.javav2.dom.codec.generator.spi.generator;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * Base class for sharing the loading capability.
+ */
+@Beta
+public abstract class AbstractGenerator {
+
+ /**
+ * Ensure that the serializer class for specified class is loaded and return
+ * its name.
+ *
+ * @param cls
+ * - data tree class
+ * @return serializer class name
+ */
+ public abstract String loadSerializerFor(final Class<?> cls);
+}
--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.mdsal.binding.javav2.dom.codec.generator.spi.generator;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Supplier;
+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.lang.reflect.InvocationTargetException;
+import java.util.Map.Entry;
+import javassist.CannotCompileException;
+import javassist.CtClass;
+import javassist.CtField;
+import javassist.CtMethod;
+import javassist.Modifier;
+import javassist.NotFoundException;
+import javax.annotation.Nonnull;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.generator.api.TreeNodeSerializerGenerator;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.generator.impl.StaticBindingProperty;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.generator.impl.TreeNodeSerializerPrototype;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.generator.spi.source.AbstractTreeNodeSerializerSource;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.serializer.AugmentableDispatchSerializer;
+import org.opendaylight.mdsal.binding.javav2.generator.impl.util.BindingRuntimeContext;
+import org.opendaylight.mdsal.binding.javav2.generator.impl.util.javassist.JavassistUtils;
+import org.opendaylight.mdsal.binding.javav2.generator.util.Types;
+import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedType;
+import org.opendaylight.mdsal.binding.javav2.spec.base.Instantiable;
+import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
+import org.opendaylight.mdsal.binding.javav2.spec.runtime.BindingStreamEventWriter;
+import org.opendaylight.mdsal.binding.javav2.spec.runtime.TreeNodeSerializerImplementation;
+import org.opendaylight.mdsal.binding.javav2.spec.runtime.TreeNodeSerializerRegistry;
+import org.opendaylight.mdsal.binding.javav2.spec.util.BindingReflections;
+import org.opendaylight.yangtools.util.ClassLoaderUtils;
+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.opendaylight.yangtools.yang.model.api.NotificationDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Beta
+public abstract class AbstractStreamWriterGenerator extends AbstractGenerator implements TreeNodeSerializerGenerator {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractStreamWriterGenerator.class);
+
+ public static final String SERIALIZE_METHOD_NAME = "serialize";
+ protected static final AugmentableDispatchSerializer AUGMENTABLE = new AugmentableDispatchSerializer();
+ private static final Field FIELD_MODIFIERS;
+
+ private final LoadingCache<Class<?>, TreeNodeSerializerImplementation> implementations;
+ private final CtClass[] serializeArguments;
+ private final JavassistUtils javassist;
+
+ private BindingRuntimeContext context;
+
+ 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);
+ }
+
+ FIELD_MODIFIERS = f;
+ }
+
+ protected AbstractStreamWriterGenerator(final JavassistUtils utils) {
+ super();
+ this.javassist = Preconditions.checkNotNull(utils, "JavassistUtils instance is required.");
+ this.serializeArguments = new CtClass[] { javassist.asCtClass(TreeNodeSerializerRegistry.class),
+ javassist.asCtClass(TreeNode.class), javassist.asCtClass(BindingStreamEventWriter.class), };
+ javassist.appendClassLoaderIfMissing(TreeNodeSerializerPrototype.class.getClassLoader());
+ this.implementations = CacheBuilder.newBuilder().weakKeys().build(new SerializerImplementationLoader());
+ }
+
+ @Override
+ public final TreeNodeSerializerImplementation getSerializer(final Class<?> type) {
+ return implementations.getUnchecked(type);
+ }
+
+ @Override
+ public final void onBindingRuntimeContextUpdated(final BindingRuntimeContext runtime) {
+ this.context = runtime;
+ }
+
+ @Override
+ public final String loadSerializerFor(final Class<?> cls) {
+ return implementations.getUnchecked(cls).getClass().getName();
+ }
+
+ private final class SerializerImplementationLoader extends CacheLoader<Class<?>, TreeNodeSerializerImplementation> {
+
+ 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
+ @SuppressWarnings("unchecked")
+ public TreeNodeSerializerImplementation load(@Nonnull final Class<?> type) throws Exception {
+ Preconditions.checkArgument(BindingReflections.isBindingClass(type));
+ Preconditions.checkArgument(Instantiable.class.isAssignableFrom(type),
+ "Instantiable is not assingnable from %s from classloader %s.", type, type.getClassLoader());
+
+ final String serializerName = getSerializerName(type);
+
+ Class<? extends TreeNodeSerializerImplementation> cls;
+ try {
+ cls = (Class<? extends TreeNodeSerializerImplementation>) ClassLoaderUtils
+ .loadClass(type.getClassLoader(), serializerName);
+ } catch (final ClassNotFoundException e) {
+ cls = generateSerializer(type, serializerName);
+ }
+
+ final TreeNodeSerializerImplementation obj =
+ (TreeNodeSerializerImplementation) cls.getDeclaredMethod(GETINSTANCE_METHOD_NAME).invoke(null);
+ LOG.debug("Loaded serializer {} for class {}", obj, type);
+ return obj;
+ }
+
+ @SuppressWarnings("unchecked")
+ private Class<? extends TreeNodeSerializerImplementation> generateSerializer(final Class<?> type,
+ final String serializerName)
+ throws CannotCompileException, IllegalAccessException, IllegalArgumentException,
+ InvocationTargetException, NoSuchMethodException, SecurityException, NoSuchFieldException {
+ final AbstractTreeNodeSerializerSource source = generateEmitterSource(type, serializerName);
+ final CtClass poolClass = generateEmitter0(type, source, serializerName);
+ final Class<? extends TreeNodeSerializerImplementation> 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 (final StaticBindingProperty 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;
+ }
+ }
+
+ private AbstractTreeNodeSerializerSource generateEmitterSource(final Class<?> type, final String serializerName) {
+ Types.typeForClass(type);
+ javassist.appendClassLoaderIfMissing(type.getClassLoader());
+ final Entry<GeneratedType, Object> typeWithSchema = context.getTypeWithSchema(type);
+ final GeneratedType generatedType = typeWithSchema.getKey();
+ final Object schema = typeWithSchema.getValue();
+
+ final AbstractTreeNodeSerializerSource source;
+ if (schema instanceof ContainerSchemaNode) {
+ source = generateContainerSerializer(generatedType, (ContainerSchemaNode) schema);
+ } else if (schema instanceof ListSchemaNode) {
+ final 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 if (schema instanceof NotificationDefinition) {
+ source = generateNotificationSerializer(generatedType, (NotificationDefinition) schema);
+ } else {
+ throw new UnsupportedOperationException("Schema type " + schema.getClass() + " is not supported");
+ }
+ return source;
+ }
+
+ private CtClass generateEmitter0(final Class<?> type, final AbstractTreeNodeSerializerSource source,
+ final String serializerName) {
+ final CtClass product;
+
+ /*
+ * getSerializerBody() has side effects, such as loading classes and
+ * codecs, it should be run in model class loader in order to correctly
+ * reference load child classes.
+ *
+ * Furthermore the fact that getSerializedBody() can trigger other code
+ * generation to happen, we need to take care of this before calling
+ * instantiatePrototype(), as that will call our customizer with the
+ * lock held, hence any code generation will end up being blocked on the
+ * javassist lock.
+ */
+ final String body = ClassLoaderUtils.withClassLoader(type.getClassLoader(),
+ (Supplier<String>) () -> source.getSerializerBody().toString());
+
+ try {
+ product = javassist.instantiatePrototype(TreeNodeSerializerPrototype.class.getName(), serializerName,
+ cls -> {
+ // Generate any static fields
+ for (final StaticBindingProperty def : source.getStaticConstants()) {
+ final CtField field = new CtField(javassist.asCtClass(def.getType()), def.getName(), cls);
+ field.setModifiers(Modifier.PRIVATE + Modifier.STATIC);
+ cls.addField(field);
+ }
+
+ // Replace serialize() -- may reference static fields
+ final CtMethod serializeTo = cls.getDeclaredMethod(SERIALIZE_METHOD_NAME, serializeArguments);
+ serializeTo.setBody(body);
+
+ // The prototype is not visible, so we need to take care
+ // of that
+ cls.setModifiers(Modifier.setPublic(cls.getModifiers()));
+ });
+ } catch (final NotFoundException e) {
+ LOG.error("Failed to instatiate serializer {}", source, e);
+ throw new LinkageError("Unexpected instantation problem: serializer prototype not found", e);
+ }
+ return product;
+ }
+
+ /**
+ * 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
+ */
+ protected abstract AbstractTreeNodeSerializerSource 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
+ */
+ protected abstract AbstractTreeNodeSerializerSource 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
+ */
+ protected abstract AbstractTreeNodeSerializerSource 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
+ */
+ protected abstract AbstractTreeNodeSerializerSource 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 schema - schema of augmentation
+ * @return source for augmentation node writer
+ */
+ protected abstract AbstractTreeNodeSerializerSource generateSerializer(GeneratedType type, AugmentationSchema schema);
+
+ /**
+ * Generates serializer source for notification 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 notification
+ * @param node - schema of notification
+ * @return source for notification node writer
+ */
+ protected abstract AbstractTreeNodeSerializerSource generateNotificationSerializer(GeneratedType type,
+ NotificationDefinition node);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.mdsal.binding.javav2.dom.codec.generator.spi.source;
+
+import com.google.common.annotations.Beta;
+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.mdsal.binding.javav2.dom.codec.generator.impl.StaticBindingProperty;
+import org.opendaylight.mdsal.binding.javav2.model.api.Type;
+
+/**
+ * Base class for preparing types and constants for writer.
+ *
+ */
+@Beta
+abstract class AbstractSource {
+
+ private final Set<StaticBindingProperty> staticConstants = new HashSet<>();
+
+ /**
+ * Create new static constant of specific type with value.
+ *
+ * @param name
+ * - name of constant
+ * @param type
+ * - specific type of constant
+ * @param value
+ * - value of constant
+ * @param <T>
+ * - type of constant
+ */
+ final <T> void staticConstant(final String name, final Class<T> type, final T value) {
+ this.staticConstants.add(new StaticBindingProperty(name, type, value));
+ }
+
+ /**
+ * Get set of static constants.
+ *
+ * @return unmodifiable view of set of static constants
+ */
+ public final Set<StaticBindingProperty> getStaticConstants() {
+ return Collections.unmodifiableSet(this.staticConstants);
+ }
+
+ /**
+ * Prepare common part of invoke of method on object.
+ *
+ * @param object
+ * - object for invoke method
+ * @param methodName
+ * - method name to be invoked
+ * @return base part of invoking method on object as String
+ */
+ private static StringBuilder prepareCommonInvokePart(final CharSequence object, final String methodName) {
+ final StringBuilder sb = new StringBuilder();
+ if (object != null) {
+ sb.append(object);
+ sb.append('.');
+ }
+ return sb.append(methodName).append('(');
+ }
+
+ /**
+ * Prepare invoking method on object with an argument.
+ *
+ * @param object
+ * - object for invoke method
+ * @param methodName
+ * - method name to be invoked
+ * @param arg
+ * - argument of method
+ * @return invoking method on object with an argument as String
+ */
+ static final CharSequence invoke(final CharSequence object, final String methodName, final Object arg) {
+ return prepareCommonInvokePart(object, methodName).append(arg).append(')');
+ }
+
+ /**
+ * Prepare invoking method on object with more arguments.
+ *
+ * @param object
+ * - object for invoke method
+ * @param methodName
+ * - method name to be invoked
+ * @param args
+ * - arguments of method
+ * @return invoking method on object with more arguments as String
+ */
+ static final CharSequence invoke(final CharSequence object, final String methodName,
+ final Object... args) {
+ final StringBuilder sb = prepareCommonInvokePart(object, methodName);
+
+ final UnmodifiableIterator<Object> iterator = Iterators.forArray(args);
+ while (iterator.hasNext()) {
+ sb.append(iterator.next());
+ if (iterator.hasNext()) {
+ sb.append(',');
+ }
+ }
+ return sb.append(')');
+ }
+
+ /**
+ * Assign of value to variable.
+ *
+ * @param var
+ * - name of variable
+ * @param value
+ * - value of variable
+ * @return assigned value to variable as char sequence
+ */
+ static final CharSequence assign(final String var, final CharSequence value) {
+ return assign((String) null, var, value);
+ }
+
+ /**
+ * Assign of value to variable of specific type.
+ *
+ * @param type
+ * - specific type of value
+ * @param var
+ * - name of variable
+ * @param value
+ * - value of variable
+ * @return assigned value to variable of specific type as char sequence, if
+ * type is null then there is not added type to final string of
+ * assigned value
+ */
+ static final CharSequence assign(final String type, final String var, final CharSequence value) {
+ final StringBuilder sb = new StringBuilder();
+ if (type != null) {
+ sb.append(type);
+ sb.append(' ');
+ }
+ return sb.append(var).append(" = ").append(value);
+ }
+
+ /**
+ * Assign of value to variable of specific type.
+ *
+ * @param type
+ * - specific type of value
+ * @param var
+ * - name of variable
+ * @param value
+ * - value of variable
+ * @return assigned value to variable of specific type as char sequence, if
+ * type is null then there is not added type to final string of
+ * assigned value
+ */
+ static final CharSequence assign(final Type type, final String var, final CharSequence value) {
+ return assign(type.getFullyQualifiedName(), var, value);
+ }
+
+ /**
+ * Cast value to specific type.
+ *
+ * @param type
+ * - specific type
+ * @param value
+ * - value for cast
+ * @return casted value to specifc type as char sequence
+ */
+ static final CharSequence cast(final Type type, final CharSequence value) {
+ return cast(type.getFullyQualifiedName(), value);
+ }
+
+ /**
+ * Create loop through iterable object with specific body.
+ *
+ * @param iterable
+ * - iterable object
+ * @param iteratorName
+ * - name of iterator variable of iterable object
+ * @param valueType
+ * - type of iterable item
+ * @param valueName
+ * - name of variable of iterable item
+ * @param body
+ * - specific body for porcess of iterable item
+ * @return loop through iterable object with specific body as String
+ */
+ static final CharSequence forEach(final String iterable, final String iteratorName,
+ final String valueType, final String valueName, final CharSequence body) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append(statement(assign(java.util.Iterator.class.getName(), iteratorName, invoke(iterable, "iterator"))));
+ sb.append("while (").append(invoke(iteratorName, "hasNext")).append(") {\n");
+ sb.append(statement(assign(valueType, valueName, cast(valueType, invoke(iteratorName, "next")))));
+ sb.append(body);
+ return sb.append("\n}\n");
+ }
+
+ /**
+ * Cast value to specific type.
+ *
+ * @param type
+ * - specific type
+ * @param value
+ * - value for cast
+ * @return casted value to specifc type as char sequence
+ */
+ static final CharSequence cast(final String type, final CharSequence value) {
+ return "((" + type + ") " + value + ')';
+ }
+
+ /**
+ * Create new Java statement.
+ *
+ * @param statement
+ * - input for creating new Java statement
+ * @return java statement
+ */
+ static final CharSequence statement(final CharSequence statement) {
+ return new StringBuilder(statement).append(";\n");
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.mdsal.binding.javav2.dom.codec.generator.spi.source;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.generator.spi.generator.AbstractGenerator;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.generator.spi.generator.AbstractStreamWriterGenerator;
+import org.opendaylight.mdsal.binding.javav2.generator.api.ClassLoadingStrategy;
+import org.opendaylight.mdsal.binding.javav2.generator.impl.GeneratedClassLoadingStrategy;
+import org.opendaylight.mdsal.binding.javav2.model.api.Type;
+import org.opendaylight.mdsal.binding.javav2.spec.base.Instantiable;
+import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
+import org.opendaylight.mdsal.binding.javav2.spec.runtime.BindingStreamEventWriter;
+import org.opendaylight.mdsal.binding.javav2.spec.runtime.TreeNodeSerializerRegistry;
+
+@Beta
+public abstract class AbstractTreeNodeSerializerSource extends AbstractSource {
+
+ private static final ClassLoadingStrategy STRATEGY = GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy();
+
+ static final String SERIALIZER = "_serializer";
+ static final String STREAM = "_stream";
+ static final String ITERATOR = "_iterator";
+ static final String CURRENT = "_current";
+ static final String REGISTRY = "_registry";
+
+ private final AbstractGenerator generator;
+
+ /**
+ * Set up generator.
+ *
+ * @param generator
+ * -parent generator
+ */
+ AbstractTreeNodeSerializerSource(final AbstractGenerator generator) {
+ this.generator = Preconditions.checkNotNull(generator);
+ }
+
+ @SuppressWarnings("unchecked")
+ Class<? extends Instantiable<?>> loadClass(final Type childType) {
+ try {
+ return (Class<? extends Instantiable<?>>) STRATEGY.loadClass(childType);
+ } catch (final ClassNotFoundException e) {
+ throw new IllegalStateException("Could not load referenced class ", e);
+ }
+ }
+
+ /**
+ * Returns body of static serialize method.
+ *
+ * <ul>
+ * <li>{@link TreeNodeSerializerRegistry} - registry of serializers
+ * <li>{@link TreeNode} - node to be serialized
+ * <li>{@link BindingStreamEventWriter} - writer to which events should be
+ * serialized
+ * </ul>
+ *
+ * @return valid javassist code describing static serialization body
+ */
+ public abstract CharSequence getSerializerBody();
+
+ /**
+ * Invoking leafNode method of stream with arguments local name and value.
+ *
+ * @param localName
+ * - argument for invoking leafNode
+ * @param value
+ * - argument for invoking leafNode
+ * @return invoking leafNode method as String
+ */
+ static final CharSequence leafNode(final String localName, final CharSequence value) {
+ return invoke(STREAM, "leafNode", escape(localName), value);
+ }
+
+ /**
+ * Invoking startLeafSet method of stream with arguments local name and
+ * expected.
+ *
+ * @param localName
+ * - argument for invoking startLeafSet
+ * @param expected
+ * - argument for invoking startLeafSet
+ * @return invoking startLeafSet method as String
+ */
+ static final CharSequence startLeafSet(final String localName, final CharSequence expected) {
+ return invoke(STREAM, "startLeafSet", escape(localName), expected);
+ }
+
+ /**
+ * Invoking startOrderedLeafSet method of stream with arguments localname
+ * and expected.
+ *
+ * @param localName
+ * - argument for invoking startOrderedLeafSet
+ * @param expected
+ * - argument for invoking startOrderedLeafSet
+ * @return invoking startOrderedLeafSet method as String
+ */
+ static final CharSequence startOrderedLeafSet(final String localName, final CharSequence expected) {
+ return invoke(STREAM, "startOrderedLeafSet", escape(localName), expected);
+ }
+
+ /**
+ * Bound local name by quotes.
+ *
+ * @param localName
+ * - to be bounded
+ * @return bounded local name
+ */
+ static final CharSequence escape(final String localName) {
+ return '"' + localName + '"';
+ }
+
+ /**
+ * Invoking leafSetEntryNode method of stream with argument value.
+ *
+ * @param value
+ * - argument for invoking leafSetEntryNode
+ * @return invoking leafSetEntryNode method as String
+ */
+ static final CharSequence leafSetEntryNode(final CharSequence value) {
+ return invoke(STREAM, "leafSetEntryNode", value);
+ }
+
+ /**
+ * Invoking startContainerNode method of stream with arguments type and
+ * expected.
+ *
+ * @param type
+ * - argument for invoking startContainerNode
+ * @param expected
+ * - argument for invoking startContainerNode
+ * @return invoking startContainerNode method as String
+ */
+ static final CharSequence startContainerNode(final CharSequence type, final CharSequence expected) {
+ return invoke(STREAM, "startContainerNode", type, expected);
+ }
+
+ /**
+ * Invoking startUnkeyedList method of stream with arguments type and
+ * expected.
+ *
+ * @param type
+ * - argument for invoking startUnkeyedList
+ * @param expected
+ * - argument for invoking startUnkeyedList
+ * @return invoking startUnkeyedList method as String
+ */
+ static final CharSequence startUnkeyedList(final CharSequence type, final CharSequence expected) {
+ return invoke(STREAM, "startUnkeyedList", type, expected);
+ }
+
+ /**
+ * Invoking startUnkeyedListItem of stream with argument expected.
+ *
+ * @param expected
+ * - argument for invoking startUnkeyedListItem
+ * @return invoking startUnkeyedListItem method as String
+ */
+ static final CharSequence startUnkeyedListItem(final CharSequence expected) {
+ return invoke(STREAM, "startUnkeyedListItem", expected);
+ }
+
+ /**
+ * Invoking startMapNode method of stream with arguments type and expected.
+ *
+ * @param type
+ * - argument for invoking startMapNode
+ * @param expected
+ * - argument for invoking startMapNode
+ * @return invoking startMapNode method as String
+ */
+ static final CharSequence startMapNode(final CharSequence type, final CharSequence expected) {
+ return invoke(STREAM, "startMapNode", type, expected);
+ }
+
+ /**
+ * Invoking startOrderedMapNode method of stream with arguments type and
+ * expected.
+ *
+ * @param type
+ * - argument for invoking startOrderedMapNode
+ * @param expected
+ * - argument for invoking startOrderedMapNode
+ * @return invoking startOrderedMapNode method as String
+ */
+ static final CharSequence startOrderedMapNode(final CharSequence type, final CharSequence expected) {
+ return invoke(STREAM, "startOrderedMapNode", type, expected);
+ }
+
+ /**
+ * Invoking startMapEntryNode method of stream with arguments key and
+ * expected.
+ *
+ * @param key
+ * - argument for invoking startMapEntryNode
+ * @param expected
+ * - argument for invoking startMapEntryNode
+ * @return invoking startMapEntryNode method as String
+ */
+ static final CharSequence startMapEntryNode(final CharSequence key, final CharSequence expected) {
+ return invoke(STREAM, "startMapEntryNode", key, expected);
+ }
+
+ /**
+ * Invoking startAugmentationNode of stream with argument key.
+ *
+ * @param key
+ * - argument for invoking startAugmentationNode
+ * @return invoking startAugmentationNode method as String
+ */
+ static final CharSequence startAugmentationNode(final CharSequence key) {
+ return invoke(STREAM, "startAugmentationNode", key);
+ }
+
+ /**
+ * Invoking startChoiceNode method of stream with arguments localname and
+ * expected.
+ *
+ * @param localName
+ * - argument for invoking startChoiceNode
+ * @param expected
+ * - argument for invoking startChoiceNode
+ * @return invoking startChoiceNode method as String
+ */
+ static final CharSequence startChoiceNode(final CharSequence localName, final CharSequence expected) {
+ return invoke(STREAM, "startChoiceNode", localName, expected);
+ }
+
+ /**
+ * Invoking startCaseNode method of stream with arguments localname and
+ * expected.
+ *
+ * @param localName
+ * - argument for invoking startCaseNode
+ * @param expected
+ * - argument for invoking startCaseNode
+ * @return invoking startCaseNode method as String
+ */
+ static final CharSequence startCaseNode(final CharSequence localName, final CharSequence expected) {
+ return invoke(STREAM, "startCase", localName, expected);
+ }
+
+ /**
+ * Invoking anyxmlNode method of stream with arguments name and
+ * value.
+ *
+ * @param name
+ * - argument for invoking anyxmlNode
+ * @param value
+ * - argument for invoking anyxmlNode
+ * @return invoking anyxmlNode method as String
+ */
+ static final CharSequence anyxmlNode(final String name, final String value)
+ throws IllegalArgumentException {
+ return invoke(STREAM, "anyxmlNode", escape(name), name);
+ }
+
+ /**
+ * Invoking anydataNode method of stream with arguments name and
+ * value.
+ *
+ * @param name
+ * - argument for invoking anydataNode
+ * @param value
+ * - argument for invoking anydataNode
+ * @return invoking anydataNode method as String
+ */
+ static final CharSequence anydataNode(final String name, final String value)
+ throws IllegalArgumentException {
+ return invoke(STREAM, "anydataNode", escape(name), name);
+ }
+
+ /**
+ * Invoking endNode method of stream without any arguments.
+ *
+ * @return invoking andNode method as String
+ */
+ static final CharSequence endNode() {
+ return invoke(STREAM, "endNode");
+ }
+
+ /**
+ * Prepare loop through iterable object with specific body.
+ *
+ * @param iterable
+ * - name of iterable object
+ * @param valueType
+ * - type of iterate objects
+ * @param body
+ * - specific body of loop
+ * @return loop through iterable object as String
+ */
+ static final CharSequence forEach(final String iterable, final Type valueType, final CharSequence body) {
+ return forEach(iterable, ITERATOR, valueType.getFullyQualifiedName(), CURRENT, body);
+ }
+
+ /**
+ * Returns class reference for type.
+ *
+ * @param type
+ * - type for referencing class
+ * @return referenced class of type
+ */
+ static final CharSequence classReference(final Type type) {
+ return type.getFullyQualifiedName() + ".class";
+ }
+
+ /**
+ * After getting class of childType from class loader, prepare invoking of
+ * serialize() method from instance of reached class of childType with
+ * arguments {@link #REGISTRY}, name and {@link #STREAM}.
+ *
+ * @param childType
+ * - type of child for getting class from classloader
+ * @param name
+ * - argument for invoking serialize method of instance childType
+ * class
+ * @return invoking serialize method with specific arguments as String
+ */
+ final CharSequence staticInvokeEmitter(final Type childType, final String name) {
+ final Class<?> cls;
+ try {
+ cls = STRATEGY.loadClass(childType);
+ } catch (final ClassNotFoundException e) {
+ throw new IllegalStateException("Failed to invoke emitter", e);
+ }
+
+ final String className = this.generator.loadSerializerFor(cls) + ".getInstance()";
+ return invoke(className, AbstractStreamWriterGenerator.SERIALIZE_METHOD_NAME, REGISTRY, name, STREAM);
+ }
+}
+
import com.google.common.annotations.Beta;
import org.opendaylight.mdsal.binding.javav2.generator.api.ClassLoadingStrategy;
import org.opendaylight.mdsal.binding.javav2.model.api.Type;
+import org.opendaylight.yangtools.util.ClassLoaderUtils;
@Beta
public abstract class GeneratedClassLoadingStrategy implements ClassLoadingStrategy {
+ private static final GeneratedClassLoadingStrategy TCCL_STRATEGY = new TCCLClassLoadingStrategy();
+
@Override
- public Class<?> loadClass(Type type) throws ClassNotFoundException {
+ public Class<?> loadClass(final Type type) throws ClassNotFoundException {
return loadClass(type.getFullyQualifiedName());
}
@Override
public abstract Class<?> loadClass(String fqcn) throws ClassNotFoundException;
+
+ public static ClassLoadingStrategy getTCCLClassLoadingStrategy() {
+ return TCCL_STRATEGY;
+ }
+
+ private static final class TCCLClassLoadingStrategy extends GeneratedClassLoadingStrategy {
+ @Override
+ public Class<?> loadClass(final String fullyQualifiedName) throws ClassNotFoundException {
+ return ClassLoaderUtils.loadClassWithTCCL(fullyQualifiedName);
+ }
+ }
}