package org.opendaylight.mdsal.binding2.generator.api;
import com.google.common.annotations.Beta;
-import org.opendaylight.mdsal.binding2.spec.YangModuleInfo;
+import org.opendaylight.mdsal.binding2.spec.runtime.YangModuleInfo;
import org.opendaylight.yangtools.concepts.ObjectRegistration;
/**
<groupId>org.opendaylight.mdsal</groupId>
<artifactId>mdsal-binding2-generator-util</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-binding2-util</artifactId>
+ </dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
import java.util.List;
import java.util.Map;
import java.util.Set;
-import org.opendaylight.mdsal.binding2.generator.util.Binding2GeneratorUtil;
-import org.opendaylight.mdsal.binding2.generator.util.Binding2Mapping;
+import org.opendaylight.mdsal.binding2.generator.util.BindingGeneratorUtil;
import org.opendaylight.mdsal.binding2.generator.util.ReferencedTypeImpl;
import org.opendaylight.mdsal.binding2.model.api.Type;
import org.opendaylight.mdsal.binding2.model.api.type.builder.GeneratedTypeBuilder;
+import org.opendaylight.mdsal.binding2.util.BindingMapping;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
Preconditions.checkArgument(module.getName() != null, "Module name cannot be NULL.");
Preconditions.checkState(module.getAugmentations() != null, "Augmentations Set cannot be NULL.");
- final String basePackageName = Binding2Mapping.getRootPackageName(module);
+ final String basePackageName = BindingMapping.getRootPackageName(module);
final List<AugmentationSchema> augmentations = resolveAugmentations(module);
Map<Module, ModuleContext> resultCtx = genCtx;
for (final AugmentationSchema augment : augmentations) {
if (!(targetSchemaNode instanceof ChoiceSchemaNode)) {
String packageName = augmentPackageName;
if (usesNodeParent instanceof SchemaNode) {
- packageName = Binding2GeneratorUtil.packageNameForAugmentedGeneratedType(augmentPackageName,
+ packageName = BindingGeneratorUtil.packageNameForAugmentedGeneratedType(augmentPackageName,
((SchemaNode) usesNodeParent).getPath());
}
generatedCtx = GenHelperUtil.addRawAugmentGenTypeDefinition(module, packageName, augmentPackageName,
for (final DataSchemaNode caseNode : augmentedNodes) {
if (caseNode != null) {
- final String packageName = Binding2GeneratorUtil.packageNameForGeneratedType(basePackageName,
+ final String packageName = BindingGeneratorUtil.packageNameForGeneratedType(basePackageName,
caseNode.getPath());
final GeneratedTypeBuilder caseTypeBuilder = GenHelperUtil.addDefaultInterfaceDefinition(packageName,
caseNode, module, genCtx, schemaContext, verboseClassComments, genTypeBuilders);
import java.util.Map;
import java.util.regex.Pattern;
import org.opendaylight.mdsal.binding2.generator.impl.util.YangTextTemplate;
-import org.opendaylight.mdsal.binding2.generator.util.Binding2GeneratorUtil;
-import org.opendaylight.mdsal.binding2.generator.util.Binding2Mapping;
+import org.opendaylight.mdsal.binding2.generator.util.BindingGeneratorUtil;
import org.opendaylight.mdsal.binding2.generator.util.BindingTypes;
import org.opendaylight.mdsal.binding2.generator.util.Types;
import org.opendaylight.mdsal.binding2.generator.util.generated.type.builder.GeneratedTypeBuilderImpl;
import org.opendaylight.mdsal.binding2.model.api.Type;
import org.opendaylight.mdsal.binding2.model.api.type.builder.GeneratedTypeBuilder;
import org.opendaylight.mdsal.binding2.model.api.type.builder.GeneratedTypeBuilderBase;
+import org.opendaylight.mdsal.binding2.txt.yangTemplateForModule;
+import org.opendaylight.mdsal.binding2.txt.yangTemplateForNode;
+import org.opendaylight.mdsal.binding2.util.BindingMapping;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
import org.opendaylight.yangtools.yang.model.api.UsesNode;
import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
-import org.opendaylight.mdsal.binding2.txt.yangTemplateForModule;
-import org.opendaylight.mdsal.binding2.txt.yangTemplateForNode;
/**
* Helper util class used for generation of types in binding spec v2.
*/
static GeneratedTypeBuilder moduleTypeBuilder(final Module module, final String postfix, final boolean verboseClassComments) {
Preconditions.checkArgument(module != null, "Module reference cannot be NULL.");
- final String packageName = Binding2Mapping.getRootPackageName(module);
- final String moduleName = Binding2Mapping.getClassName(module.getName()) + postfix;
+ final String packageName = BindingMapping.getRootPackageName(module);
+ final String moduleName = BindingMapping.getClassName(module.getName()) + postfix;
final GeneratedTypeBuilderImpl moduleBuilder = new GeneratedTypeBuilderImpl(packageName, moduleName);
moduleBuilder.setDescription(createDescription(module, verboseClassComments));
private static String createDescription(final Module module, final boolean verboseClassComments) {
final StringBuilder sb = new StringBuilder();
- final String moduleDescription = Binding2GeneratorUtil.encodeAngleBrackets(module.getDescription());
+ final String moduleDescription = BindingGeneratorUtil.encodeAngleBrackets(module.getDescription());
final String formattedDescription = YangTextTemplate.formatToParagraph(moduleDescription, 0);
if (!Strings.isNullOrEmpty(formattedDescription)) {
sb.append(NEW_LINE);
sb.append("<pre>");
sb.append(NEW_LINE);
- sb.append(Binding2GeneratorUtil.encodeAngleBrackets(yangTemplateForModule.render(module).body()));
+ sb.append(BindingGeneratorUtil.encodeAngleBrackets(yangTemplateForModule.render(module).body()));
sb.append("</pre>");
}
static Map<Module, ModuleContext> processUsesAugments(final SchemaContext schemaContext, final
DataNodeContainer node, final Module module, Map<Module, ModuleContext> genCtx, Map<String,
Map<String, GeneratedTypeBuilder>> genTypeBuilders, final boolean verboseClassComments) {
- final String basePackageName = Binding2Mapping.getRootPackageName(module);
+ final String basePackageName = BindingMapping.getRootPackageName(module);
for (final UsesNode usesNode : node.getUses()) {
for (final AugmentationSchema augment : usesNode.getAugmentations()) {
genCtx = AugmentToGenType.usesAugmentationToGenTypes(schemaContext, basePackageName, augment, module,
String augTypeName;
if (augIdentifier != null) {
- augTypeName = Binding2Mapping.getClassName(augIdentifier);
+ augTypeName = BindingMapping.getClassName(augIdentifier);
} else {
augTypeName = augGenTypeName(augmentBuilders, targetTypeRef.getName());
}
String genTypeName;
if (prefix == null) {
- genTypeName = Binding2Mapping.getClassName(schemaNodeName);
+ genTypeName = BindingMapping.getClassName(schemaNodeName);
} else {
- genTypeName = prefix + Binding2Mapping.getClassName(schemaNodeName);
+ genTypeName = prefix + BindingMapping.getClassName(schemaNodeName);
}
final GeneratedTypeBuilderImpl newType = new GeneratedTypeBuilderImpl(packageName, genTypeName);
final Module module = SchemaContextUtil.findParentModule(schemaContext, schemaNode);
- qNameConstant(newType, Binding2Mapping.QNAME_STATIC_FIELD_NAME, schemaNode.getQName());
+ qNameConstant(newType, BindingMapping.QNAME_STATIC_FIELD_NAME, schemaNode.getQName());
newType.addComment(schemaNode.getDescription());
newType.setDescription(createDescription(schemaNode, newType.getFullyQualifiedName(), schemaContext, verboseClassComments));
newType.setReference(schemaNode.getReference());
private static String createDescription(final SchemaNode schemaNode, final String fullyQualifiedName,
final SchemaContext schemaContext, final boolean verboseClassComments) {
final StringBuilder sb = new StringBuilder();
- final String nodeDescription = Binding2GeneratorUtil.encodeAngleBrackets(schemaNode.getDescription());
+ final String nodeDescription = BindingGeneratorUtil.encodeAngleBrackets(schemaNode.getDescription());
final String formattedDescription = YangTextTemplate.formatToParagraph(nodeDescription, 0);
if (!Strings.isNullOrEmpty(formattedDescription)) {
sb.append(NEW_LINE);
sb.append("<pre>");
sb.append(NEW_LINE);
- sb.append(Binding2GeneratorUtil.encodeAngleBrackets(yangTemplateForNode.render(schemaNode).body()));
+ sb.append(BindingGeneratorUtil.encodeAngleBrackets(yangTemplateForNode.render(schemaNode).body()));
sb.append("</pre>");
sb.append(NEW_LINE);
sb.append("The schema path to identify an instance is");
import java.util.List;
import java.util.Map;
import org.opendaylight.mdsal.binding2.generator.spi.TypeProvider;
-import org.opendaylight.mdsal.binding2.generator.util.Binding2Mapping;
import org.opendaylight.mdsal.binding2.generator.yang.types.TypeProviderImpl;
import org.opendaylight.mdsal.binding2.model.api.Type;
import org.opendaylight.mdsal.binding2.model.api.type.builder.GeneratedTypeBuilder;
+import org.opendaylight.mdsal.binding2.util.BindingMapping;
import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
if (!module.getChildNodes().isEmpty()) {
final GeneratedTypeBuilder moduleType = GenHelperUtil.moduleToDataType(module, genCtx, verboseClassComments);
genCtx.get(module).addModuleNode(moduleType);
- final String basePackageName = Binding2Mapping.getRootPackageName(module);
+ final String basePackageName = BindingMapping.getRootPackageName(module);
GenHelperUtil.resolveDataSchemaNodes(module, basePackageName, moduleType, moduleType, module
.getChildNodes());
}
<groupId>org.opendaylight.mdsal</groupId>
<artifactId>mdsal-binding2-spec</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-binding2-util</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-parser-impl</artifactId>
import com.google.common.base.CharMatcher;
import com.google.common.collect.Iterables;
import java.util.Iterator;
+import org.opendaylight.mdsal.binding2.util.BindingMapping;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.model.api.SchemaPath;
* class names, attribute names and/or valid JavaDoc comments.
*/
@Beta
-public final class Binding2GeneratorUtil {
+public final class BindingGeneratorUtil {
private static final CharMatcher GT_MATCHER = CharMatcher.is('>');
private static final CharMatcher LT_MATCHER = CharMatcher.is('<');
- private Binding2GeneratorUtil() {
+ private BindingGeneratorUtil() {
throw new UnsupportedOperationException("Utility class");
}
//FIXME: colon or dash in identifier?
builder.append(nodeLocalName);
}
- return Binding2Mapping.normalizePackageName(builder.toString());
+ return BindingMapping.normalizePackageName(builder.toString());
}
/**
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.opendaylight.mdsal.binding2.generator.util.AbstractBaseType;
-import org.opendaylight.mdsal.binding2.generator.util.Binding2Mapping;
import org.opendaylight.mdsal.binding2.model.api.AnnotationType;
import org.opendaylight.mdsal.binding2.model.api.Constant;
import org.opendaylight.mdsal.binding2.model.api.Enumeration;
import org.opendaylight.mdsal.binding2.model.api.Type;
import org.opendaylight.mdsal.binding2.model.api.type.builder.AnnotationTypeBuilder;
import org.opendaylight.mdsal.binding2.model.api.type.builder.EnumBuilder;
+import org.opendaylight.mdsal.binding2.util.BindingMapping;
import org.opendaylight.yangtools.util.LazyCollections;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.model.api.Status;
builder.append(name);
builder.append(", values=");
builder.append(values);
- builder.append("]");
+ builder.append(']');
return builder.toString();
}
final String reference, final Status status) {
this.name = name;
- this.mappedName = Binding2Mapping.getClassName(name);
+ this.mappedName = BindingMapping.getClassName(name);
this.value = value;
this.description = description;
this.reference = reference;
builder.append(getMappedName());
builder.append(", value=");
builder.append(value);
- builder.append("]");
+ builder.append(']');
return builder.toString();
}
}
public String toFormattedString() {
StringBuilder builder = new StringBuilder();
builder.append("public enum");
- builder.append(" ");
+ builder.append(' ');
builder.append(getName());
builder.append(" {");
builder.append("\n");
int i = 0;
for (final Enumeration.Pair valPair : values) {
builder.append("\t");
- builder.append(" ");
+ builder.append(' ');
builder.append(valPair.getMappedName());
builder.append(" (");
builder.append(valPair.getValue());
<groupId>org.opendaylight.mdsal</groupId>
<artifactId>mdsal-binding2-generator-util</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-binding2-util</artifactId>
+ </dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
package org.opendaylight.mdsal.binding2.java.api.generator.renderers;
-import static org.opendaylight.mdsal.binding2.generator.util.Binding2Mapping.MEMBER_PATTERN_LIST;
-import static org.opendaylight.mdsal.binding2.generator.util.Binding2Mapping.PATTERN_CONSTANT_NAME;
import static org.opendaylight.mdsal.binding2.java.api.generator.util.TextTemplateUtil.fieldName;
import static org.opendaylight.mdsal.binding2.java.api.generator.util.TextTemplateUtil.setterMethod;
+import static org.opendaylight.mdsal.binding2.util.BindingMapping.MEMBER_PATTERN_LIST;
+import static org.opendaylight.mdsal.binding2.util.BindingMapping.PATTERN_CONSTANT_NAME;
import com.google.common.base.Preconditions;
import com.google.common.collect.Collections2;
package org.opendaylight.mdsal.binding2.java.api.generator.renderers;
-import static org.opendaylight.mdsal.binding2.generator.util.Binding2Mapping.MODEL_BINDING_PROVIDER_CLASS_NAME;
-import static org.opendaylight.mdsal.binding2.generator.util.Binding2Mapping.getRootPackageName;
+import static org.opendaylight.mdsal.binding2.util.BindingMapping.MODEL_BINDING_PROVIDER_CLASS_NAME;
+import static org.opendaylight.mdsal.binding2.util.BindingMapping.getRootPackageName;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import org.opendaylight.mdsal.binding2.model.api.ParameterizedType;
import org.opendaylight.mdsal.binding2.model.api.Type;
import org.opendaylight.mdsal.binding2.model.api.WildcardType;
-import org.opendaylight.mdsal.binding2.spec.YangModelBindingProvider;
-import org.opendaylight.mdsal.binding2.spec.YangModuleInfo;
+import org.opendaylight.mdsal.binding2.spec.runtime.YangModelBindingProvider;
+import org.opendaylight.mdsal.binding2.spec.runtime.YangModuleInfo;
import org.opendaylight.mdsal.binding2.txt.modelProviderTemplate;
import org.opendaylight.mdsal.binding2.txt.yangModuleInfoTemplate;
import org.opendaylight.yangtools.yang.model.api.Module;
* and is available at http://www.eclipse.org/legal/epl-v10.html
*@
-@import org.opendaylight.mdsal.binding2.generator.util.Binding2Mapping.PATTERN_CONSTANT_NAME
@import org.opendaylight.mdsal.binding2.java.api.generator.util.TextTemplateUtil.asArguments
@import org.opendaylight.mdsal.binding2.java.api.generator.util.TextTemplateUtil.fieldName
@import org.opendaylight.mdsal.binding2.model.api.GeneratedTransferObject
@import org.opendaylight.mdsal.binding2.model.api.GeneratedProperty
+@import org.opendaylight.mdsal.binding2.util.BindingMapping.PATTERN_CONSTANT_NAME
@(genTo: GeneratedTransferObject, allProperties: List[GeneratedProperty], properties: List[GeneratedProperty],
parentProperties: List[GeneratedProperty], importedNames: Map[String, String], argumentsDeclaration: String,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*@
-@import org.opendaylight.mdsal.binding2.generator.util.Binding2Mapping.PATTERN_CONSTANT_NAME
-@import org.opendaylight.mdsal.binding2.generator.util.Binding2Mapping.MEMBER_PATTERN_LIST
+@import org.opendaylight.mdsal.binding2.util.BindingMapping.MEMBER_PATTERN_LIST
+@import org.opendaylight.mdsal.binding2.util.BindingMapping.PATTERN_CONSTANT_NAME
@(patterName: String)
static {
* and is available at http://www.eclipse.org/legal/epl-v10.html
*@
-@import org.opendaylight.mdsal.binding2.generator.util.Binding2Mapping.MODULE_INFO_CLASS_NAME
-@import org.opendaylight.mdsal.binding2.generator.util.Binding2Mapping.MODEL_BINDING_PROVIDER_CLASS_NAME
+@import org.opendaylight.mdsal.binding2.util.BindingMapping.MODEL_BINDING_PROVIDER_CLASS_NAME
+@import org.opendaylight.mdsal.binding2.util.BindingMapping.MODULE_INFO_CLASS_NAME
@(packageName: String, yangModelBindingProviderName: String, yangModuleInfoName: String)
package @{packageName};
* and is available at http://www.eclipse.org/legal/epl-v10.html
*@
-@import org.opendaylight.mdsal.binding2.generator.util.Binding2Mapping.getClassName
-@import org.opendaylight.mdsal.binding2.generator.util.Binding2Mapping.getRootPackageName
-@import org.opendaylight.mdsal.binding2.generator.util.Binding2Mapping.MODULE_INFO_CLASS_NAME
@import org.opendaylight.mdsal.binding2.java.api.generator.util.TextTemplateUtil.getFormattedRevision
@import org.opendaylight.mdsal.binding2.java.api.generator.util.TextTemplateUtil.getSourcePath
@import org.opendaylight.mdsal.binding2.java.api.generator.renderers.YangModuleInfoTemplateRenderer.getSortedQName
+@import org.opendaylight.mdsal.binding2.util.BindingMapping.getClassName
+@import org.opendaylight.mdsal.binding2.util.BindingMapping.getRootPackageName
+@import org.opendaylight.mdsal.binding2.util.BindingMapping.MODULE_INFO_CLASS_NAME
@import org.opendaylight.yangtools.yang.model.api.Module
@import org.opendaylight.yangtools.yang.model.api.SchemaContext
--- /dev/null
+/*
+ * Copyright (c) 2017 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.mdsal.binding2.spec.runtime;
+
+import com.google.common.annotations.Beta;
+import org.opendaylight.yangtools.concepts.Codec;
+
+/**
+ * Base interface for Binding2 encoding/decoding mechanism implementation
+ */
+@Beta
+public interface BindingCodec<P, I> extends BindingSerializer<P, I>, BindingDeserializer<I, P>, Codec<P, I> {
+
+ /**
+ * Produces an object based on input.
+ *
+ * @param input Input object
+ * @return Product derived from input
+ */
+ @Override
+ P serialize(I input);
+
+ /**
+ * Produces an object based on input.
+ *
+ * @param input Input object
+ * @return Product derived from input
+ */
+ @Override
+ I deserialize(P input);
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2017 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.mdsal.binding2.spec.runtime;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * The concept of a deserializer in Binding part, which produces an object from some input.
+ *
+ * @param <P> Product type
+ * @param <I> Input type
+ */
+@Beta
+public interface BindingDeserializer<P, I> {
+
+ /**
+ * Produces an object based on input.
+ *
+ * @param input Input object
+ * @return Product derived from input
+ */
+ P deserialize(I input);
+}
--- /dev/null
+/*
+ * Copyright (c) 2017 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.mdsal.binding2.spec.runtime;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * The concept of a serializer in Binding part, which produces an object from some input.
+ *
+ * @param <P> Product type
+ * @param <I> Input type
+ */
+@Beta
+public interface BindingSerializer<P, I> {
+
+ /**
+ * Produces an object based on input.
+ *
+ * @param input Input object
+ * @return Product derived from input
+ */
+ P serialize(I input);
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2017 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.mdsal.binding2.spec.runtime;
+
+import com.google.common.annotations.Beta;
+import java.io.Closeable;
+import java.io.Flushable;
+import java.io.IOException;
+import org.opendaylight.mdsal.binding2.spec.Augmentation;
+import org.opendaylight.mdsal.binding2.spec.IdentifiableItem;
+import org.opendaylight.mdsal.binding2.spec.Item;
+import org.opendaylight.mdsal.binding2.spec.TreeNode;
+
+/**
+ * Event Stream Writer for Binding version 2 Representation
+ *
+ *
+ * <h3>Emitting Event Stream</h3>
+ *
+ * <ul>
+ * <li><code>container</code> - Container node representation, start event is
+ * emitted using {@link #startContainerNode(Class, int)} and node end event is
+ * emitted using {@link #endNode()}. Container node is implementing
+ * {@link TreeNode} interface.
+ *
+ * <li><code>list</code> - YANG list statement has two representations in event
+ * stream - un-keyed list and map. Un-keyed list is YANG list which didn't
+ * specify key.
+ *
+ * <ul>
+ * <li><code>Map</code> - Map start event is emitted using
+ * {@link #startMapNode(IdentifiableItem, int)} and is ended using {@link #endNode()}. Each map
+ * entry start is emitted using {@link #startMapEntryNode(IdentifiableItem, int)} with Map of keys
+ * and finished using {@link #endNode()}.</li>
+ *
+ * <li><code>UnkeyedList</code> - Un-keyed list represents list without keys,
+ * un-keyed list start is emitted using {@link #startUnkeyedList(Class, int)}, list
+ * end is emitted using {@link #endNode()}. Each list item is emitted using
+ * {@link #startUnkeyedListItem(int)} and ended using {@link #endNode()}.</li>
+ * </ul></li>
+ *
+ * <li><code>leaf</code> - Leaf node event is emitted using
+ * {@link #startleafNode(String, Object)}. {@link #endNode()} MUST NOT be emitted for
+ * leaf node.</li>
+ *
+ * <li><code>leaf-list</code> - Leaf list start is emitted using
+ * {@link #startLeafSet(String, int)}. Leaf list end is emitted using
+ * {@link #endNode()}. Leaf list entries are emitted using
+ * {@link #startleafSetEntryNode(Object)}.
+ *
+ * <li><code>anyxml - Anyxml node event is emitted using
+ * {@link #startAnyxmlNode(String, Object)}. {@link #endNode()} MUST NOT be emitted
+ * for anyxml node.</code></li>
+ *
+ * <li><code>anydata - Anydata node event is emitted using
+ * {@link #startAnydataNode(String, Object)}. {@link #endNode()} MUST NOT be emitted
+ * for anydata node.</code></li>
+ *
+ * <li><code>choice</code> Choice node event is emitted by
+ * {@link #startChoiceNode(Item, int)} event and must be immediately followed by
+ * {@link #startCase(Class, int)} event. Choice node is finished by emitting an
+ * {@link #endNode()} event.</li>
+ *
+ * <li>
+ * <code>case</code> - Case node may be emitted only inside choice node by
+ * invoking {@link #startCase(Class, int)}. Case node is finished be emitting an
+ * {@link #endNode()} event.</li>
+ *
+ * <li>
+ * <code>augment</code> - Represents augmentation, augmentation node is started
+ * by invoking {@link #startAugmentationNode(Class)} and
+ * finished by invoking {@link #endNode()}.</li>
+ *
+ * </ul>
+ *
+ * <h3>Implementation notes</h3> This interface is not intended to be
+ * implemented by users of generated Binding2 DTOs but to be used by utilities,
+ * which needs to emit NormalizedNode model from Binding2 DTOs.
+ * <p>
+ * This interface is intended as API definition of facade for real Event /
+ * Stream Writer, without explicitly requiring stream writer and related
+ * interfaces to be imported by all generated Binding2 DTOs.
+ * <p>
+ * Existence of this interface in runtime Java Binding2 package is required to
+ * support runtime generation of users of this interface in OSGI and OSGI-like
+ * environment, since this package is only package which is imported by all
+ * generated Binding2 DTOs and wired in OSGI.
+ *
+ *
+ */
+@Beta
+public interface BindingStreamEventWriter extends Closeable, Flushable {
+
+ /**
+ * Methods in this interface allow users to hint the underlying
+ * implementation about the sizing of container-like constructors
+ * (leafLists, containers, etc.). These hints may be taken into account by a
+ * particular implementation to improve performance, but clients are not
+ * required to provide hints. This constant should be used by clients who
+ * either do not have the sizing information, or do not wish to divulge it
+ * (for whatever reasons). Implementations are free to ignore these hints
+ * completely, but if they do use them, they are expected to be resilient in
+ * face of missing and mismatched hints, which is to say the user can
+ * specify startLeafSet(..., 1) and then call leafNode() 15 times.
+ * <p>
+ * The acceptable hint values are non-negative integers and this constant,
+ * all other values will result, based on implementation preference, in the
+ * hint being completely ignored or IllegalArgumentException being thrown.
+ */
+ int UNKNOWN_SIZE = -1;
+
+ /**
+ *
+ * Emits a leaf node event with supplied value.
+ *
+ * @param localName
+ * name of node as defined in schema, namespace and revision are
+ * derived from parent node.
+ * @param value
+ * Value of leaf node.
+ * @throws IllegalArgumentException
+ * If emitted leaf node has invalid value in current context or
+ * was emitted multiple times.
+ * @throws IllegalStateException
+ * If node was emitted inside <code>map</code>,
+ * <code>choice</code> <code>unkeyed list</code> node.
+ * @throws IOException if an underlying IO error occurs
+ */
+ void startleafNode(String localName, Object value) throws IOException;
+
+ /**
+ *
+ * Emits a start of leaf set (leaf-list).
+ * <p>
+ * Emits start of leaf set, during writing leaf set event, only
+ * {@link #startleafSetEntryNode(Object)} calls are valid. Leaf set event is
+ * finished by calling {@link #endNode()}.
+ *
+ * @param localName
+ * name of node as defined in schema, namespace and revision are
+ * derived from parent node.
+ * @param childSizeHint
+ * Non-negative count of expected direct child nodes or
+ * {@link #UNKNOWN_SIZE} if count is unknown. This is only hint
+ * and should not fail writing of child events, if there are more
+ * events than count.
+ * @throws IllegalArgumentException
+ * If emitted leaf node is invalid in current context or was
+ * emitted multiple times.
+ * @throws IllegalStateException
+ * If node was emitted inside <code>map</code>,
+ * <code>choice</code> <code>unkeyed list</code> node.
+ * @throws IOException if an underlying IO error occurs
+ */
+ void startLeafSet(String localName, int childSizeHint) throws IOException;
+
+ /**
+ *
+ * Emits a start of leaf set (leaf-list).
+ * <p>
+ * Emits start of leaf set, during writing leaf set event, only
+ * {@link #startleafSetEntryNode(Object)} calls are valid. Leaf set event is
+ * finished by calling {@link #endNode()}.
+ *
+ * @param localName
+ * name of node as defined in schema, namespace and revision are
+ * derived from parent node.
+ * @param childSizeHint
+ * Non-negative count of expected direct child nodes or
+ * {@link #UNKNOWN_SIZE} if count is unknown. This is only hint
+ * and should not fail writing of child events, if there are more
+ * events than count.
+ * @throws IllegalArgumentException
+ * If emitted leaf node is invalid in current context or was
+ * emitted multiple times.
+ * @throws IllegalStateException
+ * If node was emitted inside <code>map</code>,
+ * <code>choice</code> <code>unkeyed list</code> node.
+ * @throws IOException if an underlying IO error occurs
+ */
+ void startOrderedLeafSet(String localName, int childSizeHint) throws IOException;
+
+ /**
+ * Emits a leaf set entry node
+ *
+ * @param value
+ * Value of leaf set entry node.
+ * @throws IllegalArgumentException
+ * If emitted leaf node has invalid value.
+ * @throws IllegalStateException
+ * If node was emitted outside <code>leaf set</code> node.
+ * @throws IOException if an underlying IO error occurs
+ */
+ void startleafSetEntryNode(Object value) throws IOException;
+
+ /**
+ *
+ * Emits start of new container.
+ *
+ * <p>
+ * End of container event is emitted by invoking {@link #endNode()}.
+ *
+ * <p>
+ * Valid sub-events are:
+ * <ul>
+ * <li>{@link #startleafNode(String, Object)}</li>
+ * <li>{@link #startContainerNode(Class, int)}</li>
+ * <li>{@link #startChoiceNode(Item, int)}</li>
+ * <li>{@link #startLeafSet(String, int)}</li>
+ * <li>{@link #startMapNode(IdentifiableItem, int)}</li>
+ * <li>{@link #startUnkeyedList(Class, int)}</li>
+ * <li>{@link #startAugmentationNode(Class)}</li>
+ * </ul>
+ *
+ * @param container
+ * name of node as defined in schema, namespace and revision are
+ * derived from parent node.
+ * @param childSizeHint
+ * Non-negative count of expected direct child nodes or
+ * {@link #UNKNOWN_SIZE} if count is unknown. This is only hint
+ * and should not fail writing of child events, if there are more
+ * events than count.
+ * @throws IllegalArgumentException
+ * If emitted node is invalid in current context or was emitted
+ * multiple times.
+ * @throws IllegalStateException
+ * If node was emitted inside <code>map</code>,
+ * <code>choice</code> <code>unkeyed list</code> node.
+ * @throws IOException if an underlying IO error occurs
+ */
+ void startContainerNode(Class<? extends TreeNode> container, int childSizeHint) throws IOException;
+
+ /**
+ *
+ * Emits start of unkeyed list node event.
+ *
+ * <p>
+ * End of unkeyed list event is emitted by invoking {@link #endNode()}.
+ * Valid sub-event is only {@link #startUnkeyedListItem(int)}. All other
+ * methods will throw {@link IllegalArgumentException}.
+ *
+ * @param localName
+ * name of node as defined in schema, namespace and revision are
+ * derived from parent node.
+ * @param childSizeHint
+ * Non-negative count of expected direct child nodes or
+ * {@link #UNKNOWN_SIZE} if count is unknown. This is only hint
+ * and should not fail writing of child events, if there are more
+ * events than count.
+ * @throws IllegalArgumentException
+ * If emitted node is invalid in current context or was emitted
+ * multiple times.
+ * @throws IllegalStateException
+ * If node was emitted inside <code>map</code>,
+ * <code>choice</code> <code>unkeyed list</code> node.
+ * @throws IOException if an underlying IO error occurs
+ */
+ void startUnkeyedList(Class<? extends TreeNode> localName, int childSizeHint) throws IOException;
+
+ /**
+ * Emits start of new unkeyed list item.
+ *
+ * <p>
+ * Un-keyed list item event is finished by invoking {@link #endNode()}.
+ * <p>
+ * Valid sub-events are:
+ *
+ * <ul>
+ * <li>{@link #startleafNode(String, Object)}</li>
+ * <li>{@link #startContainerNode(Class, int)}</li>
+ * <li>{@link #startChoiceNode(Item, int)}</li>
+ * <li>{@link #startLeafSet(String, int)}</li>
+ * <li>{@link #startMapNode(IdentifiableItem, int)}</li>
+ * <li>{@link #startUnkeyedList(Class, int)}</li>
+ * <li>{@link #startAugmentationNode(Class)}</li>
+ * </ul>
+ *
+ *
+ * @param childSizeHint
+ * Non-negative count of expected direct child nodes or
+ * {@link #UNKNOWN_SIZE} if count is unknown. This is only hint
+ * and should not fail writing of child events, if there are more
+ * events than count.
+ * @throws IllegalStateException
+ * If node was emitted outside <code>unkeyed list</code> node.
+ * @throws IOException if an underlying IO error occurs
+ */
+ void startUnkeyedListItem(int childSizeHint) throws IOException;
+
+ /**
+ *
+ * Emits start of unordered map node event.
+ *
+ * <p>
+ * End of map node event is emitted by invoking {@link #endNode()}. Valid
+ * subevents is only {@link #startMapEntryNode(IdentifiableItem, int)}. All other methods will
+ * throw {@link IllegalArgumentException}.
+ *
+ * @param mapEntryType
+ * Class of list item, which has defined key.
+ * @param childSizeHint
+ * Non-negative count of expected direct child nodes or
+ * {@link #UNKNOWN_SIZE} if count is unknown. This is only hint
+ * and should not fail writing of child events, if there are more
+ * events than count.
+ * @throws IllegalArgumentException
+ * @throws IllegalStateException
+ * If node was emitted inside <code>map</code>,
+ * <code>choice</code> <code>unkeyed list</code> node.
+ * @throws IOException if an underlying IO error occurs
+ */
+ <I extends TreeNode, T> void startMapNode(IdentifiableItem<I, T> mapEntryType, int childSizeHint)
+ throws IOException;
+
+ /**
+ *
+ * Emits start of ordered map node event.
+ *
+ * <p>
+ * End of map node event is emitted by invoking {@link #endNode()}. Valid
+ * sub-event is only {@link #startMapEntryNode(IdentifiableItem, int)}. All other methods will
+ * throw {@link IllegalArgumentException}.
+ *
+ * @param mapEntryType
+ * Class of list item, which has defined key.
+ * @param childSizeHint
+ * Non-negative count of expected direct child nodes or
+ * {@link #UNKNOWN_SIZE} if count is unknown. This is only hint
+ * and should not fail writing of child events, if there are more
+ * events than count.
+ * @throws IllegalArgumentException
+ * @throws IllegalStateException
+ * If node was emitted inside <code>map</code>,
+ * <code>choice</code> <code>unkeyed list</code> node.
+ * @throws IOException if an underlying IO error occurs
+ */
+ <I extends TreeNode, T> void startOrderedMapNode(IdentifiableItem<I, T> mapEntryType, int childSizeHint)
+ throws IOException;
+
+ /**
+ *
+ * Emits start of map entry.
+ *
+ * <p>
+ * End of map entry event is emitted by invoking {@link #endNode()}.
+ *
+ * <p>
+ * Valid sub-events are:
+ * <ul>
+ * <li>{@link #startleafNode(String, Object)}</li>
+ * <li>{@link #startContainerNode(Class, int)}</li>
+ * <li>{@link #startChoiceNode(Item, int)}</li>
+ * <li>{@link #startLeafSet(String, int)}</li>
+ * <li>{@link #startMapNode(IdentifiableItem, int)}</li>
+ * <li>{@link #startUnkeyedList(Class, int)}</li>
+ * <li>{@link #startAugmentationNode(Class)}</li>
+ * </ul>
+ *
+ * @param keyValues
+ * Key of map entry node
+ * @param childSizeHint
+ * Non-negative count of expected direct child nodes or
+ * {@link #UNKNOWN_SIZE} if count is unknown. This is only hint
+ * and should not fail writing of child events, if there are more
+ * events than count.
+ * @throws IllegalArgumentException
+ * If key contains incorrect value.
+ * @throws IllegalStateException
+ * If node was emitted outside <code>map entry</code> node.
+ * @throws IOException if an underlying IO error occurs
+ */
+ <I extends TreeNode, T> void startMapEntryNode(IdentifiableItem<I, T> keyValues, int childSizeHint)
+ throws IOException;
+
+ /**
+ * Emits start of choice node.
+ *
+ * <p>
+ * Valid sub-event is {@link #startCase(Class, int)}, which selects case
+ * which should be written.
+ *
+ * @param choice
+ * Choice class.
+ * @param childSizeHint
+ * Non-negative count of expected direct child nodes or
+ * {@link #UNKNOWN_SIZE} if count is unknown. This is only hint
+ * and should not fail writing of child events, if there are more
+ * events than count.
+ * @throws IllegalArgumentException
+ * @throws IllegalStateException
+ * If node was emitted inside <code>map</code>, <code>choice</code>,
+ * <code>unkeyed list</code> node.
+ * @throws IOException if an underlying IO error occurs
+ */
+ <T extends TreeNode> void startChoiceNode(Item<T> choice, int childSizeHint) throws IOException;
+
+ /**
+ *
+ * Starts a case node.
+ *
+ * <p>
+ * Valid sub-events are:
+ * <ul>
+ * <li>{@link #startleafNode(String, Object)}</li>
+ * <li>{@link #startContainerNode(Class, int)}</li>
+ * <li>{@link #startChoiceNode(Item, int)}</li>
+ * <li>{@link #startLeafSet(String, int)}</li>
+ * <li>{@link #startMapNode(IdentifiableItem, int)}</li>
+ * <li>{@link #startUnkeyedList(Class, int)}</li>
+ * <li>{@link #startAugmentationNode(Class)}</li>
+ * </ul>
+ *
+ * @param caze Case class
+ * @throws IllegalArgumentException
+ * @throws IOException if an underlying IO error occurs
+ */
+ void startCase(Class<? extends TreeNode> caze, int childSizeHint) throws IOException;
+
+ /**
+ * Emits start of augmentation node.
+ *
+ * <p>
+ * End of augmentation event is emitted by invoking {@link #endNode()}.
+ *
+ * <p>
+ * Valid sub-events are:
+ *
+ * <ul>
+ * <li>{@link #startleafNode(String, Object)}</li>
+ * <li>{@link #startContainerNode(Class, int)}</li>
+ * <li>{@link #startChoiceNode(Item, int)}</li>
+ * <li>{@link #startLeafSet(String, int)}</li>
+ * <li>{@link #startMapNode(IdentifiableItem, int)}</li>
+ * <li>{@link #startUnkeyedList(Class, int)}</li>
+ * </ul>
+ *
+ * <p>
+ * Note this is only method, which does not require childSizeHint, since
+ * maximum value is always size of <code>possibleChildren</code>.
+ *
+ * @param augmentationType augmentation class
+ * @throws IllegalArgumentException
+ * If augmentation is invalid in current context.
+ * @throws IOException if an underlying IO error occurs
+ */
+ void startAugmentationNode(Class<? extends Augmentation<?>> augmentationType) throws IOException;
+
+ /**
+ * Emits anyxml node event.
+ *
+ * @param name
+ * @param value
+ * @throws IllegalArgumentException
+ * @throws IllegalStateException
+ * If node was emitted inside <code>map</code>,
+ * <code>choice</code> <code>unkeyed list</code> node.
+ * @throws IOException if an underlying IO error occurs
+ */
+ void startAnyxmlNode(String name, Object value) throws IOException;
+
+ /**
+ * Emits anydata node event.
+ *
+ * @param name
+ * @param value
+ * @throws IllegalStateException
+ * If node was emitted inside <code>map</code>,
+ * <code>choice</code> <code>unkeyed list</code> node.
+ * @throws IOException if an underlying IO error occurs
+ */
+ void startAnydataNode(String name, Object value) throws IOException;
+
+ /**
+ * Emits end event for node.
+ *
+ * @throws IllegalStateException If there is no open node.
+ * @throws IOException if an underlying IO error occurs
+ */
+ void endNode() throws IOException;
+
+ @Override
+ void flush() throws IOException;
+
+ @Override
+ void close() throws IOException;
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2017 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.mdsal.binding2.spec.runtime;
+
+import com.google.common.annotations.Beta;
+import java.io.IOException;
+import org.opendaylight.mdsal.binding2.spec.TreeNode;
+
+/*
+ * A serializer which writes TreeNode to supplied stream event writer.
+ */
+@Beta
+public interface TreeNodeSerializer {
+
+ /**
+ * Writes stream events representing object to supplied stream
+ *
+ * @param obj
+ * Source of stream events
+ * @param stream
+ * Stream to which events should be written.
+ */
+ void serialize(TreeNode obj, BindingStreamEventWriter stream) throws IOException;
+}
\ No newline at end of file
/*
- * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2017 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.mdsal.binding2.spec;
+package org.opendaylight.mdsal.binding2.spec.runtime;
import java.util.ServiceLoader;
/*
- * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2017 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.mdsal.binding2.spec;
+package org.opendaylight.mdsal.binding2.spec.runtime;
import com.google.common.annotations.Beta;
import com.google.common.base.Optional;
-import java.io.IOException;
-import java.io.InputStream;
import java.util.Set;
import org.opendaylight.yangtools.concepts.SemVer;
import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (c) 2017 Cisco Systems, Inc. and others. All rights reserved.
+ ~
+ ~ This program and the accompanying materials are made available under the
+ ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.opendaylight.odlparent</groupId>
+ <artifactId>bundle-parent</artifactId>
+ <version>1.8.0-SNAPSHOT</version>
+ <relativePath/>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-binding2-util</artifactId>
+ <version>0.10.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+ <name>${project.artifactId}</name>
+ <description>${project.artifactId}</description>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yangtools-artifacts</artifactId>
+ <version>1.1.0-SNAPSHOT</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-model-api</artifactId>
+ </dependency>
+ </dependencies>
+
+ <!--
+ Maven Site Configuration
+
+ The following configuration is necessary for maven-site-plugin to
+ correctly identify the correct deployment path for OpenDaylight Maven
+ sites.
+ -->
+ <url>${odl.site.url}/${project.groupId}/${stream}/${project.artifactId}/</url>
+
+ <distributionManagement>
+ <site>
+ <id>opendaylight-site</id>
+ <url>${nexus.site.url}/${project.artifactId}/</url>
+ </site>
+ </distributionManagement>
+
+</project>
\ No newline at end of file
/*
- * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2017 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.mdsal.binding2.generator.util;
+package org.opendaylight.mdsal.binding2.util;
import com.google.common.annotations.Beta;
import com.google.common.base.CharMatcher;
* Standard Util class that provides generated Java related functionality
*/
@Beta
-public final class Binding2Mapping {
+public final class BindingMapping {
public static final Set<String> JAVA_RESERVED_WORDS = ImmutableSet.of("abstract", "assert", "boolean", "break",
"byte", "case", "catch", "char", "class", "const", "continue", "default", "double", "do", "else", "enum",
}
};
- private Binding2Mapping() {
+ private BindingMapping() {
throw new UnsupportedOperationException("Utility class");
}
}
//FIXME: don't use underscore in v2
- if (Character.isDigit(p.charAt(0)) || Binding2Mapping.JAVA_RESERVED_WORDS.contains(p)) {
+ if (Character.isDigit(p.charAt(0)) || BindingMapping.JAVA_RESERVED_WORDS.contains(p)) {
builder.append('_');
}
builder.append(p);
--- /dev/null
+/*
+ * Copyright (c) 2017 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.mdsal.binding2.util;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Throwables;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+import java.lang.invoke.MethodType;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utility class for instantiating value-type generated objects with String being the base type. Unlike the normal
+ * constructor, instances of this class bypass string validation.
+ *
+ * THE USE OF THIS CLASS IS DANGEROUS AND SHOULD ONLY BE USED TO IMPLEMENT WELL-AUDITED AND CORRECT UTILITY METHODS
+ * SHIPPED WITH MODELS TO PROVIDE INSTANTIATION FROM TYPES DIFFERENT THAN STRING.
+ *
+ * APPLICATION CODE <em>MUST NOT</em> USE THIS CLASS DIRECTLY. VIOLATING THIS CONSTRAINT HAS SECURITY AND CORRECTNESS
+ * IMPLICATIONS ON EVERY USER INTERACTING WITH THE RESULTING OBJECTS.
+ *
+ * @param <T> Resulting object type
+ */
+@Beta
+public final class StringValueObjectFactory<T> {
+
+ private static final MethodType CONSTRUCTOR_METHOD_TYPE = MethodType.methodType(Object.class, Object.class);
+ private static final MethodType SETTER_METHOD_TYPE = MethodType.methodType(void.class, Object.class, String.class);
+ private static final Logger LOG = LoggerFactory.getLogger(StringValueObjectFactory.class);
+ private static final Lookup LOOKUP = MethodHandles.lookup();
+
+ private final MethodHandle constructor;
+ private final MethodHandle setter;
+ private final T template;
+
+ private StringValueObjectFactory(final T template, final MethodHandle constructor, final MethodHandle setter) {
+ this.template = Preconditions.checkNotNull(template);
+ this.constructor = constructor.bindTo(template);
+ this.setter = Preconditions.checkNotNull(setter);
+ }
+
+ public static <T> StringValueObjectFactory<T> create(final Class<T> clazz, final String templateString) {
+ final Constructor<T> stringConstructor;
+ try {
+ stringConstructor = clazz.getConstructor(String.class);
+ } catch (NoSuchMethodException e) {
+ throw new IllegalArgumentException(String.format("%s does not have a String constructor", clazz), e);
+ }
+
+ final T template;
+ try {
+ template = stringConstructor.newInstance(templateString);
+ } catch (InstantiationException | InvocationTargetException | IllegalAccessException e) {
+ throw new IllegalArgumentException(String.format("Failed to instantiate template %s for '%s'", clazz,
+ templateString), e);
+ }
+
+ final Constructor<T> copyConstructor;
+ try {
+ copyConstructor = clazz.getConstructor(clazz);
+ } catch (NoSuchMethodException e) {
+ throw new IllegalArgumentException(String.format("%s does not have a copy constructor", clazz), e);
+ }
+
+ final Field f;
+ try {
+ f = clazz.getDeclaredField("_value");
+ } catch (NoSuchFieldException e) {
+ throw new IllegalArgumentException(String.format("%s does not have required internal field", clazz), e);
+ }
+ f.setAccessible(true);
+
+ final StringValueObjectFactory<T> ret;
+ try {
+ ret = new StringValueObjectFactory<>(template,
+ LOOKUP.unreflectConstructor(copyConstructor).asType(CONSTRUCTOR_METHOD_TYPE),
+ LOOKUP.unreflectSetter(f).asType(SETTER_METHOD_TYPE));
+ } catch (IllegalAccessException e) {
+ throw new IllegalStateException("Failed to instantiate method handles", e);
+ }
+
+ // Let us be very defensive and scream loudly if the invocation does not come from the same package. This
+ // is far from perfect, but better than nothing.
+ final Throwable t = new Throwable("Invocation stack");
+ t.fillInStackTrace();
+ if (matchesPackage(clazz.getPackage().getName(), t.getStackTrace())) {
+ LOG.info("Instantiated factory for {}", clazz);
+ } else {
+ LOG.warn("Instantiated factory for {} outside its package", clazz, t);
+ }
+
+ return ret;
+ }
+
+ private static boolean matchesPackage(final String pkg, final StackTraceElement[] stackTrace) {
+ for (StackTraceElement e : stackTrace) {
+ final String sp = e.getClassName();
+ if (sp.startsWith(pkg) && sp.lastIndexOf('.') == pkg.length()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public T newInstance(final String string) {
+ Preconditions.checkNotNull(string, "Argument may not be null");
+
+ try {
+ final T ret = (T) constructor.invokeExact();
+ setter.invokeExact(ret, string);
+ LOG.trace("Instantiated new object {} value {}", ret.getClass(), string);
+ return ret;
+ } catch (Throwable e) {
+ throw Throwables.propagate(e);
+ }
+ }
+
+ public T getTemplate() {
+ return template;
+ }
+}
<module>mdsal-binding2-generator-impl</module>
<module>mdsal-binding2-java-api-generator</module>
<module>mdsal-binding2-generator-util</module>
+ <module>mdsal-binding2-util</module>
</modules>
<!--
<artifactId>mdsal-binding2-generator-util</artifactId>
<version>0.10.0-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-binding2-util</artifactId>
+ <version>0.10.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.mdsal</groupId>
<artifactId>mdsal-eos-common-api</artifactId>