import org.opendaylight.yangtools.sal.binding.model.api.type.builder.AnnotationTypeBuilder
import org.opendaylight.yangtools.yang.model.api.ModuleImport
import org.opendaylight.yangtools.yang.binding.DataContainer
-import org.opendaylight.yangtools.yang.model.api.AugmentationTarget
import org.opendaylight.yangtools.yang.model.api.NotificationDefinition
import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil
import org.opendaylight.yangtools.sal.binding.model.api.Restrictions
import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilderBase
import com.google.common.collect.Sets
-import java.net.URI
-import java.util.Date
public class BindingGeneratorImpl implements BindingGenerator {
targetSchemaNode = findDataSchemaNode(schemaContext, targetPath);
if (targetSchemaNode instanceof DataSchemaNode && (targetSchemaNode as DataSchemaNode).isAddedByUses()) {
- targetSchemaNode = findOriginal(targetSchemaNode as DataSchemaNode);
+ targetSchemaNode = findOriginal(targetSchemaNode as DataSchemaNode, schemaContext);
if (targetSchemaNode == null) {
throw new NullPointerException(
"Failed to find target node from grouping in augmentation " + augSchema + " in module " +
}
}
- /**
- * Utility method which search for original node defined in grouping.
- */
- private def DataSchemaNode findOriginal(DataSchemaNode node) {
- var DataSchemaNode result = findCorrectTargetFromGrouping(node);
- if (result == null) {
- result = findCorrectTargetFromAugment(node);
- if (result != null) {
- if (result.addedByUses) {
- result = findOriginal(result);
- }
- }
- }
- return result;
- }
-
- private def DataSchemaNode findCorrectTargetFromAugment(DataSchemaNode node) {
- if (!node.augmenting) {
- return null
- }
-
- var QName currentName = node.QName
- var Object currentNode = node
- var Object parent = node;
- val tmpPath = new ArrayList<QName>()
- val tmpTree = new ArrayList<SchemaNode>()
-
- var AugmentationSchema augment = null;
- do {
- val SchemaPath sp = (parent as SchemaNode).path
- val List<QName> names = sp.path
- val List<QName> newNames = new ArrayList(names)
- newNames.remove(newNames.size - 1)
- val SchemaPath newSp = new SchemaPath(newNames, sp.absolute)
- parent = findDataSchemaNode(schemaContext, newSp)
- if (parent instanceof AugmentationTarget) {
- tmpPath.add(currentName);
- tmpTree.add(currentNode as SchemaNode)
- augment = findNodeInAugment((parent as AugmentationTarget).availableAugmentations, currentName);
- if (augment == null) {
- currentName = (parent as DataSchemaNode).QName
- currentNode = parent
- }
- }
- } while ((parent as DataSchemaNode).augmenting && augment == null);
-
- if (augment == null) {
- return null;
- } else {
- Collections.reverse(tmpPath);
- Collections.reverse(tmpTree);
- var Object actualParent = augment;
- var DataSchemaNode result = null;
- for (name : tmpPath) {
- if (actualParent instanceof DataNodeContainer) {
- result = (actualParent as DataNodeContainer).getDataChildByName(name.localName);
- actualParent = (actualParent as DataNodeContainer).getDataChildByName(name.localName);
- } else {
- if (actualParent instanceof ChoiceNode) {
- result = (actualParent as ChoiceNode).getCaseNodeByName(name.localName);
- actualParent = (actualParent as ChoiceNode).getCaseNodeByName(name.localName);
- }
- }
- }
-
- if (result.addedByUses) {
- result = findCorrectTargetFromAugmentGrouping(result, augment, tmpTree);
- }
-
- return result;
- }
- }
-
- private def AugmentationSchema findNodeInAugment(Collection<AugmentationSchema> augments, QName name) {
- for (augment : augments) {
- val DataSchemaNode node = augment.getDataChildByName(name);
- if (node != null) {
- return augment;
- }
- }
- return null;
- }
-
- private def DataSchemaNode findCorrectTargetFromGrouping(DataSchemaNode node) {
- if (node.path.path.size == 1) {
- // uses is under module statement
- val Module m = findParentModule(schemaContext, node);
- var DataSchemaNode result = null;
- for (u : m.uses) {
- var SchemaNode targetGrouping = findNodeInSchemaContext(schemaContext, u.groupingPath.path);
- if (!(targetGrouping instanceof GroupingDefinition)) {
- throw new IllegalArgumentException("Failed to generate code for augment in " + u);
- }
- var gr = targetGrouping as GroupingDefinition;
- result = gr.getDataChildByName(node.QName.localName);
- }
- if (result == null) {
- throw new IllegalArgumentException("Failed to generate code for augment")
- }
- return result
- } else {
- var DataSchemaNode result = null;
- var QName currentName = node.QName
- var tmpPath = new ArrayList<QName>()
- var Object parent = null
-
- val SchemaPath sp = node.path
- val List<QName> names = sp.path
- val List<QName> newNames = new ArrayList(names)
- newNames.remove(newNames.size - 1)
- val SchemaPath newSp = new SchemaPath(newNames, sp.absolute)
- parent = findDataSchemaNode(schemaContext, newSp)
-
- do {
- tmpPath.add(currentName);
- if (parent instanceof DataNodeContainer) {
- val dataNodeParent = parent as DataNodeContainer;
- for (u : dataNodeParent.uses) {
- if (result == null) {
- result = getResultFromUses(u, currentName.localName)
- }
- }
- }
- if (result == null) {
- currentName = (parent as SchemaNode).QName
- if (parent instanceof SchemaNode) {
- val SchemaPath nodeSp = (parent as SchemaNode).path
- val List<QName> nodeNames = nodeSp.path
- val List<QName> nodeNewNames = new ArrayList(nodeNames)
- nodeNewNames.remove(nodeNewNames.size - 1)
- if (nodeNewNames.empty) {
- parent = getParentModule(parent as SchemaNode)
- } else {
- val SchemaPath nodeNewSp = new SchemaPath(nodeNewNames, nodeSp.absolute)
- parent = findDataSchemaNode(schemaContext, nodeNewSp)
- }
- } else {
- throw new IllegalArgumentException("Failed to generate code for augment")
- }
- }
- } while (result == null && !(parent instanceof Module));
-
- if (result != null) {
- result = getTargetNode(tmpPath, result)
- }
- return result;
- }
- }
-
- private def DataSchemaNode findCorrectTargetFromAugmentGrouping(DataSchemaNode node, AugmentationSchema parentNode,
- List<SchemaNode> dataTree) {
-
- var DataSchemaNode result = null;
- var QName currentName = node.QName
- var tmpPath = new ArrayList<QName>()
- tmpPath.add(currentName)
- var int i = 1;
- var Object parent = null
-
- do {
- if (dataTree.size < 2 || dataTree.size == i) {
- parent = parentNode
- } else {
- parent = dataTree.get(dataTree.size - (i+1))
- tmpPath.add((parent as SchemaNode).QName)
- }
-
- val dataNodeParent = parent as DataNodeContainer;
- for (u : dataNodeParent.uses) {
- if (result == null) {
- result = getResultFromUses(u, currentName.localName)
- }
- }
- if (result == null) {
- i = i + 1
- currentName = (parent as SchemaNode).QName
- }
- } while (result == null);
-
- if (result != null) {
- result = getTargetNode(tmpPath, result)
- }
- return result;
- }
-
- private def getResultFromUses(UsesNode u, String currentName) {
- var SchemaNode targetGrouping = findNodeInSchemaContext(schemaContext, u.groupingPath.path)
- if (!(targetGrouping instanceof GroupingDefinition)) {
- throw new IllegalArgumentException("Failed to generate code for augment in " + u)
- }
- var gr = targetGrouping as GroupingDefinition
- return gr.getDataChildByName(currentName)
- }
-
- private def getTargetNode(List<QName> tmpPath, DataSchemaNode node) {
- var DataSchemaNode result = node
- if (tmpPath.size == 1) {
- if (result != null && result.addedByUses) {
- result = findOriginal(result);
- }
- return result;
- } else {
- var DataSchemaNode newParent = result;
- Collections.reverse(tmpPath);
-
- tmpPath.remove(0);
- for (name : tmpPath) {
- // searching by local name is must, because node has different namespace in its original location
- if (newParent instanceof DataNodeContainer) {
- newParent = (newParent as DataNodeContainer).getDataChildByName(name.localName);
- } else {
- newParent = (newParent as ChoiceNode).getCaseNodeByName(name.localName);
- }
- }
- if (newParent != null && newParent.addedByUses) {
- newParent = findOriginal(newParent);
- }
- return newParent;
- }
- }
-
-
/**
* Convenient method to find node added by uses statement.
*/
var targetSchemaNode = findDataSchemaNode(schemaContext, targetPath)
if (targetSchemaNode instanceof DataSchemaNode &&
(targetSchemaNode as DataSchemaNode).isAddedByUses()) {
- targetSchemaNode = findOriginal(targetSchemaNode as DataSchemaNode);
+ targetSchemaNode = findOriginal(targetSchemaNode as DataSchemaNode, schemaContext);
if (targetSchemaNode == null) {
throw new NullPointerException(
"Failed to find target node from grouping for augmentation " + augSchema +
* <li>true - in other cases</li>
* </ul>
*/
- private def boolean resolveLeafSchemaNodeAsMethod(GeneratedTypeBuilder typeBuilder, LeafSchemaNode leaf) {
+ private def Type resolveLeafSchemaNodeAsMethod(GeneratedTypeBuilder typeBuilder, LeafSchemaNode leaf) {
+ var Type returnType = null;
if ((leaf !== null) && (typeBuilder !== null)) {
val leafName = leaf.QName.localName;
var String leafDesc = leaf.description;
if (leafName !== null && !leaf.isAddedByUses()) {
val TypeDefinition<?> typeDef = leaf.type;
- var Type returnType = null;
var GeneratedTOBuilder genTOBuilder;
if (typeDef instanceof EnumTypeDefinition) {
returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf);
if (returnType !== null) {
val MethodSignatureBuilder getter = constructGetter(typeBuilder, leafName, leafDesc, returnType);
processContextRefExtension(leaf, getter, parentModule);
- return true;
}
}
}
- return false;
+ return returnType;
}
private def void processContextRefExtension(LeafSchemaNode leaf, MethodSignatureBuilder getter, Module module) {
return null;
}
- /**
- * Converts <code>leaf</code> schema node to property of generated TO
- * builder.
- *
- * @param toBuilder
- * generated TO builder to which is <code>leaf</code> added as
- * property
- * @param leaf
- * leaf schema node which is added to <code>toBuilder</code> as
- * property
- * @param isReadOnly
- * boolean value which says if leaf property is|isn't read only
- * @return boolean value
- * <ul>
- * <li>false - if <code>leaf</code>, <code>toBuilder</code> or leaf
- * name equals null or if leaf is added by <i>uses</i>.</li>
- * <li>true - other cases</li>
- * </ul>
- */
private def boolean resolveLeafSchemaNodeAsProperty(GeneratedTOBuilder toBuilder, LeafSchemaNode leaf,
boolean isReadOnly, Module module) {
if ((leaf !== null) && (toBuilder !== null)) {
} else {
returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf);
}
-
- if (returnType !== null) {
- val propBuilder = toBuilder.addProperty(parseToValidParamName(leafName));
- propBuilder.setReadOnly(isReadOnly);
- propBuilder.setReturnType(returnType);
- propBuilder.setComment(leafDesc);
- toBuilder.addEqualsIdentity(propBuilder);
- toBuilder.addHashIdentity(propBuilder);
- toBuilder.addToStringProperty(propBuilder);
- return true;
- }
+ return resolveLeafSchemaNodeAsProperty(toBuilder, leaf, returnType, isReadOnly)
}
}
return false;
}
+ /**
+ * Converts <code>leaf</code> schema node to property of generated TO
+ * builder.
+ *
+ * @param toBuilder
+ * generated TO builder to which is <code>leaf</code> added as
+ * property
+ * @param leaf
+ * leaf schema node which is added to <code>toBuilder</code> as
+ * property
+ * @param returnType property type
+ * @param isReadOnly
+ * boolean value which says if leaf property is|isn't read only
+ * @return boolean value
+ * <ul>
+ * <li>false - if <code>leaf</code>, <code>toBuilder</code> or leaf
+ * name equals null or if leaf is added by <i>uses</i>.</li>
+ * <li>true - other cases</li>
+ * </ul>
+ */
+ private def resolveLeafSchemaNodeAsProperty(GeneratedTOBuilder toBuilder, LeafSchemaNode leaf, Type returnType,
+ boolean isReadOnly) {
+ if (returnType == null) {
+ return false;
+ }
+ val leafName = leaf.QName.localName
+ val leafDesc = leaf.description
+ val propBuilder = toBuilder.addProperty(parseToValidParamName(leafName));
+ propBuilder.setReadOnly(isReadOnly);
+ propBuilder.setReturnType(returnType);
+ propBuilder.setComment(leafDesc);
+ toBuilder.addEqualsIdentity(propBuilder);
+ toBuilder.addHashIdentity(propBuilder);
+ toBuilder.addToStringProperty(propBuilder);
+ return true;
+ }
+
/**
* Converts <code>node</code> leaf list schema node to getter method of
* <code>typeBuilder</code>.
if (schemaNode instanceof LeafSchemaNode) {
val leaf = schemaNode as LeafSchemaNode;
val leafName = leaf.QName.localName;
- resolveLeafSchemaNodeAsMethod(typeBuilder, leaf);
+ val Type type = resolveLeafSchemaNodeAsMethod(typeBuilder, leaf);
if (listKeys.contains(leafName)) {
- resolveLeafSchemaNodeAsProperty(genTOBuilder, leaf, true, module)
+ if (type == null) {
+ resolveLeafSchemaNodeAsProperty(genTOBuilder, leaf, true, module)
+ } else {
+ resolveLeafSchemaNodeAsProperty(genTOBuilder, leaf, type, true)
+ }
}
} else if (!schemaNode.addedByUses) {
if (schemaNode instanceof LeafListSchemaNode) {
return null
}
- private def Module getParentModule(SchemaNode node) {
- val QName qname = node.getPath().getPath().get(0);
- val URI namespace = qname.getNamespace();
- val Date revision = qname.getRevision();
- return schemaContext.findModuleByNamespaceAndRevision(namespace, revision);
- }
-
public def getModuleContexts() {
genCtx;
}
Field instanceIdField;
try {
instanceIdField = obj.getField(INSTANCE_IDENTIFIER_CODEC);
- if(obj != null) {
+ if (instanceIdField != null) {
instanceIdField.set(null, codec);
}
} catch (NoSuchFieldException e) {
}
}
-
public static void setIdentityRefCodec(Class<?> obj,IdentityCodec<?> codec) {
Field instanceIdField;
try {
instanceIdField = obj.getField(IDENTITYREF_CODEC);
- if(obj != null) {
+ if (instanceIdField != null) {
instanceIdField.set(null, codec);
}
} catch (NoSuchFieldException e) {
*/
package org.opendaylight.yangtools.sal.binding.generator.impl
+import com.google.common.collect.ImmutableList
+import java.util.ArrayList
+import java.util.Collections
+import java.util.HashMap
+import java.util.List
+import java.util.Map
+import java.util.WeakHashMap
+import java.util.concurrent.ConcurrentHashMap
+import org.opendaylight.yangtools.yang.binding.Augmentation
+import org.opendaylight.yangtools.yang.binding.DataObject
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yangtools.yang.data.impl.codec.CodecRegistry
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem
-import org.opendaylight.yangtools.yang.common.QName
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item
-import java.util.Map
-import java.util.WeakHashMap
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections
+import org.opendaylight.yangtools.yang.common.QName
+import org.opendaylight.yangtools.yang.data.api.CompositeNode
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
-import java.util.ArrayList
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument
+import org.opendaylight.yangtools.yang.data.api.Node
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
+import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
+import org.opendaylight.yangtools.yang.data.impl.codec.CodecRegistry
+import org.opendaylight.yangtools.yang.data.impl.codec.IdentifierCodec
import org.opendaylight.yangtools.yang.data.impl.codec.InstanceIdentifierCodec
import org.opendaylight.yangtools.yang.data.impl.codec.ValueWithQName
-import java.util.HashMap
import org.slf4j.LoggerFactory
-import java.util.List
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yangtools.yang.data.impl.codec.IdentifierCodec
-import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
-import org.opendaylight.yangtools.yang.data.api.Node
-import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
-import org.opendaylight.yangtools.yang.data.api.CompositeNode
-import org.opendaylight.yangtools.yang.binding.Augmentable
-import com.google.common.collect.ImmutableList
-import org.opendaylight.yangtools.yang.binding.Augmentation
-import java.util.concurrent.ConcurrentHashMap
-import org.opendaylight.yangtools.yang.binding.util.BindingReflections
-import java.util.Collections
class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec {
var Class<?> baType = null
val biArgs = input.path
val scannedPath = new ArrayList<QName>(biArgs.size);
- val baArgs = new ArrayList<org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument>(biArgs.size)
+ val baArgs = new ArrayList<InstanceIdentifier.PathArgument>(biArgs.size)
for(biArg : biArgs) {
scannedPath.add(biArg.nodeType);
val baArg = deserializePathArgument(biArg,scannedPath)
return ret;
}
- private def dispatch org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument deserializePathArgument(NodeIdentifier argument,List<QName> processedPath) {
+ private def dispatch InstanceIdentifier.PathArgument deserializePathArgument(NodeIdentifier argument,List<QName> processedPath) {
val Class cls = codecRegistry.getClassForPath(processedPath);
return new Item(cls);
}
- private def dispatch org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument deserializePathArgument(NodeIdentifierWithPredicates argument,List<QName> processedPath) {
+ private def dispatch InstanceIdentifier.PathArgument deserializePathArgument(NodeIdentifierWithPredicates argument,List<QName> processedPath) {
val Class type = codecRegistry.getClassForPath(processedPath);
val IdentifierCodec codec = codecRegistry.getIdentifierCodecForIdentifiable(type);
val value = codec.deserialize(argument.toCompositeNode())?.value;
return new CompositeNodeTOImpl(predicates.nodeType,null,values);
}
- override serialize(InstanceIdentifier input) {
+ override serialize(InstanceIdentifier<?> input) {
var Class<?> previousAugmentation = null
- val pathArgs = input.path as List<org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument>
+ val pathArgs = input.path as List<InstanceIdentifier.PathArgument>
var QName previousQName = null;
val components = new ArrayList<PathArgument>(pathArgs.size);
val qnamePath = new ArrayList<QName>(pathArgs.size);
previousAugmentation = null;
} else {
- previousQName = codecRegistry.getQNameForAugmentation(baArg.type as Class);
+ previousQName = codecRegistry.getQNameForAugmentation(baArg.type as Class<?>);
previousAugmentation = baArg.type;
}
}
classToPreviousAugment.get(class1).put(list,augmentation);
}
- private def dispatch PathArgument serializePathArgument(Item argument, QName previousQname) {
+ private def dispatch PathArgument serializePathArgument(Item<?> argument, QName previousQname) {
val type = argument.type;
val qname = BindingReflections.findQName(type);
if(previousQname == null || (BindingReflections.isAugmentationChild(argument.type))) {
}
private void tryToCreateCasesCodecs(ChoiceNode schema) {
- for (ChoiceCaseNode caseNode : schema.getCases()) {
+ for (ChoiceCaseNode choiceCase : schema.getCases()) {
+ ChoiceCaseNode caseNode = choiceCase;
+ if (caseNode.isAddedByUses()) {
+ DataSchemaNode origCaseNode = SchemaContextUtil.findOriginal(caseNode, currentSchema);
+ if (origCaseNode instanceof ChoiceCaseNode) {
+ caseNode = (ChoiceCaseNode) origCaseNode;
+ }
+ }
SchemaPath path = caseNode.getPath();
+
GeneratedTypeBuilder type;
if (path != null && (type = pathToType.get(path)) != null) {
ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName());
private static class ChoiceCaseCodecImpl<T extends DataContainer> implements ChoiceCaseCodec<T>, //
Delegator<BindingCodec> {
private boolean augmenting;
+ private boolean uses;
private BindingCodec delegate;
private Set<String> validNames;
validNames.add(qname.getLocalName());
}
augmenting = caseNode.isAugmenting();
+ uses = caseNode.isAddedByUses();
}
public ChoiceCaseCodecImpl() {
@Override
public boolean isAcceptable(Node<?> input) {
if (input instanceof CompositeNode) {
- if (augmenting) {
+ if (augmenting && !uses) {
return checkAugmenting((CompositeNode) input);
} else {
return checkLocal((CompositeNode) input);
if (typeSpecBuilder == null) {
typeSpecBuilder = pathToType.get(node.path);
}
- var schemaNode = typeToSchemaNode.get(ref);
- if (schemaNode === null) {
- schemaNode = node;
- }
+
checkState(typeSpecBuilder !== null, "Could not find TypeDefinition for %s, $s", inputType.name, node);
val typeSpec = typeSpecBuilder.toInstance();
- val newret = generateTransformerFor(inputType, typeSpec, schemaNode);
+ val newret = generateTransformerFor(inputType, typeSpec, node);
listener.onClassProcessed(inputType);
return newret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
]
final File compiledOutputDir = new File(COMPILER_OUTPUT_PATH + FS + "list-gen");
assertTrue("Failed to create test file '" + compiledOutputDir + "'", compiledOutputDir.mkdir());
- final List<File> sourceFiles = getSourceFiles("/compilation/list-gen");
- final Set<Module> modulesToBuild = parser.parseYangModels(sourceFiles);
- final SchemaContext context = parser.resolveSchemaContext(modulesToBuild);
- final List<Type> types = bindingGenerator.generateTypes(context);
- final GeneratorJavaFile generator = new GeneratorJavaFile(new HashSet<>(types));
- generator.generateToFile(sourcesOutputDir);
+ generateTestSources("/compilation/list-gen", sourcesOutputDir);
// Test if all sources are generated
File parent = new File(sourcesOutputDir, NS_TEST);
final File compiledOutputDir = new File(COMPILER_OUTPUT_PATH + FS + "augment-under-uses");
assertTrue("Failed to create test file '" + compiledOutputDir + "'", compiledOutputDir.mkdir());
- final List<File> sourceFiles = getSourceFiles("/compilation/augment-under-uses");
- final Set<Module> modulesToBuild = parser.parseYangModels(sourceFiles);
- final SchemaContext context = parser.resolveSchemaContext(modulesToBuild);
- final List<Type> types = bindingGenerator.generateTypes(context);
- final GeneratorJavaFile generator = new GeneratorJavaFile(new HashSet<>(types));
- generator.generateToFile(sourcesOutputDir);
+ generateTestSources("/compilation/augment-under-uses", sourcesOutputDir);
// Test if all sources were generated from 'module foo'
File parent = new File(sourcesOutputDir, NS_FOO);
final File compiledOutputDir = new File(COMPILER_OUTPUT_PATH + FS + "aug-of-aug");
assertTrue("Failed to create test file '" + compiledOutputDir + "'", compiledOutputDir.mkdir());
- final List<File> sourceFiles = getSourceFiles("/compilation/augment-of-augment");
- final Set<Module> modulesToBuild = parser.parseYangModels(sourceFiles);
- final SchemaContext context = parser.resolveSchemaContext(modulesToBuild);
- final List<Type> types = bindingGenerator.generateTypes(context);
- final GeneratorJavaFile generator = new GeneratorJavaFile(new HashSet<>(types));
- generator.generateToFile(sourcesOutputDir);
+ generateTestSources("/compilation/augment-of-augment", sourcesOutputDir);
// Test if all sources were generated from 'module foo'
File parent = new File(sourcesOutputDir, NS_FOO);
final File compiledOutputDir = new File(COMPILER_OUTPUT_PATH + FS + "leaf-return-types");
assertTrue("Failed to create test file '" + compiledOutputDir + "'", compiledOutputDir.mkdir());
- final List<File> sourceFiles = getSourceFiles("/compilation/leaf-return-types");
- final Set<Module> modulesToBuild = parser.parseYangModels(sourceFiles);
- final SchemaContext context = parser.resolveSchemaContext(modulesToBuild);
- final List<Type> types = bindingGenerator.generateTypes(context);
- final GeneratorJavaFile generator = new GeneratorJavaFile(new HashSet<>(types));
- generator.generateToFile(sourcesOutputDir);
+ generateTestSources("/compilation/leaf-return-types", sourcesOutputDir);
File parent = new File(sourcesOutputDir, NS_TEST);
assertTrue(new File(parent, "TestData.java").exists());
final File compiledOutputDir = new File(COMPILER_OUTPUT_PATH + FS + "context-reference");
assertTrue("Failed to create test file '" + compiledOutputDir + "'", compiledOutputDir.mkdir());
- final List<File> sourceFiles = getSourceFiles("/compilation/context-reference");
- final Set<Module> modulesToBuild = parser.parseYangModels(sourceFiles);
- final SchemaContext context = parser.resolveSchemaContext(modulesToBuild);
- final List<Type> types = bindingGenerator.generateTypes(context);
- final GeneratorJavaFile generator = new GeneratorJavaFile(new HashSet<>(types));
- generator.generateToFile(sourcesOutputDir);
+ generateTestSources("/compilation/context-reference", sourcesOutputDir);
// Test if all sources are generated
File fooParent = new File(sourcesOutputDir, NS_FOO);
final File compiledOutputDir = new File(COMPILER_OUTPUT_PATH + FS + "yang");
assertTrue("Failed to create test file '" + compiledOutputDir + "'", compiledOutputDir.mkdir());
- final List<File> sourceFiles = getSourceFiles("/yang");
- final Set<Module> modulesToBuild = parser.parseYangModels(sourceFiles);
- final SchemaContext context = parser.resolveSchemaContext(modulesToBuild);
- final List<Type> types = bindingGenerator.generateTypes(context);
- final GeneratorJavaFile generator = new GeneratorJavaFile(new HashSet<>(types));
- generator.generateToFile(sourcesOutputDir);
+ generateTestSources("/yang", sourcesOutputDir);
// Test if sources are compilable
testCompilation(sourcesOutputDir, compiledOutputDir);
cleanUp(sourcesOutputDir, compiledOutputDir);
}
+ @Test
+ public void bug586Test() throws Exception {
+ final File sourcesOutputDir = new File(GENERATOR_OUTPUT_PATH + FS + "bug586");
+ assertTrue("Failed to create test file '" + sourcesOutputDir + "'", sourcesOutputDir.mkdir());
+ final File compiledOutputDir = new File(COMPILER_OUTPUT_PATH + FS + "bug586");
+ assertTrue("Failed to create test file '" + compiledOutputDir + "'", compiledOutputDir.mkdir());
+
+ generateTestSources("/compilation/bug586", sourcesOutputDir);
+
+ // Test if sources are compilable
+ testCompilation(sourcesOutputDir, compiledOutputDir);
+
+ cleanUp(sourcesOutputDir, compiledOutputDir);
+ }
+
+ private void generateTestSources(String resourceDirPath, File sourcesOutputDir) throws Exception {
+ final List<File> sourceFiles = getSourceFiles(resourceDirPath);
+ final Set<Module> modulesToBuild = parser.parseYangModels(sourceFiles);
+ final SchemaContext context = parser.resolveSchemaContext(modulesToBuild);
+ final List<Type> types = bindingGenerator.generateTypes(context);
+ final GeneratorJavaFile generator = new GeneratorJavaFile(new HashSet<>(types));
+ generator.generateToFile(sourcesOutputDir);
+ }
private void testReturnTypeIdentityref(Class<?> clazz, String methodName, String returnTypeStr) throws Exception {
Method method;
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+module foo {
+ yang-version 1;
+ namespace "urn:yang.foo";
+ prefix "foo";
+
+ revision "2014-03-28" {
+ }
+
+
+ container services {
+ list service {
+ key "permission";
+
+ leaf permission {
+ type enumeration {
+ enum permit;
+ enum deny;
+ }
+ }
+ }
+ }
+
+}
import org.slf4j.Logger
import java.util.List
import org.opendaylight.yangtools.yang.common.QName
-import org.opendaylight.yangtools.yang.model.api.RpcDefinition
import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition
import java.util.ArrayList
import java.util.Map
import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode\rimport java.util.HashMap
import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode
+import org.opendaylight.yangtools.yang.model.api.UsesNode
+import org.opendaylight.yangtools.yang.model.api.GroupingDefinition
+import org.opendaylight.yangtools.yang.model.api.AugmentationTarget
class GeneratorImpl {
static val Logger LOG = LoggerFactory.getLogger(GeneratorImpl)
static val BuildContext CTX = new DefaultBuildContext();
var Module currentModule;
-
+ val Map<String, String> imports = new HashMap();
+ var SchemaContext ctx;
def generate(SchemaContext context, File targetPath, Set<Module> modulesToGen) throws IOException {
path = targetPath;
def generateDocumentation(Module module, SchemaContext ctx) {
val destination = new File(path, '''«module.name».html''')
+ this.ctx = ctx;
+ module.imports.forEach[importModule | this.imports.put(importModule.prefix, importModule.moduleName)]
try {
val fw = new OutputStreamWriter(CTX.newFileOutputStream(destination))
val bw = new BufferedWriter(fw)
def body(Module module, SchemaContext ctx) '''
«header(module)»
+ «typeDefinitionsSummary(module)»
+ «identitiesSummary(module)»
+ «groupingsSummary(module)»
+ «augmentationsSummary(module, ctx)»
+ «objectsSummary(module)»
+ «notificationsSummary(module)»
+ «rpcsSummary(module)»
+ «extensionsSummary(module)»
+ «featuresSummary(module)»
+
«typeDefinitions(module)»
«identities(module)»
'''
+ private def typeDefinitionsSummary(Module module) {
+ val Set<TypeDefinition<?>> typedefs = module.typeDefinitions
+ if (typedefs.empty) {
+ return '';
+ }
+ return '''
+ <div>
+ <h3>Type Definitions Summary</h3>
+ <table>
+ <tr>
+ <th>Name</th>
+ <th>Description</th>
+ </tr>
+ «FOR typedef : typedefs»
+ <tr>
+ <td>
+ «anchorLink(typedef.QName.localName, strong(typedef.QName.localName))»
+ </td>
+ <td>
+ «typedef.description»
+ </td>
+ </tr>
+ «ENDFOR»
+ </table>
+ </div>
+ '''
+ }
+
def typeDefinitions(Module module) {
val Set<TypeDefinition<?>> typedefs = module.typeDefinitions
if (typedefs.empty) {
<ul>
«FOR typedef : typedefs»
<li>
- «strong("typedef " + typedef.QName.localName)»
+ <h3 id="«typedef.QName.localName»">«typedef.QName.localName»</h3>
<ul>
«typedef.descAndRefLi»
«typedef.restrictions»
<ul>
«FOR identity : module.identities»
<li>
- «strong("identity " + identity.QName.localName)»
+ <h3 id="«identity.QName.localName»">«identity.QName.localName»</h3>
<ul>
«identity.descAndRefLi»
- «IF identity.baseIdentity != null»
+ «IF identity.baseIdentity !== null»
«listItem("base", identity.baseIdentity.QName.localName)»
«ENDIF»
</ul>
'''
}
+ private def identitiesSummary(Module module) {
+ if (module.identities.empty) {
+ return '';
+ }
+ return '''
+ <h3>Identities Summary</h3>
+ <table>
+ <tr>
+ <th>Name</th>
+ <th>Description</th>
+ </tr>
+ «FOR identity : module.identities»
+ <tr>
+ <td>
+ «anchorLink(identity.QName.localName, strong(identity.QName.localName))»
+ </td>
+ <td>
+ «identity.description»
+ </td>
+ </tr>
+ «ENDFOR»
+ </table>
+ '''
+ }
+
private def groupings(Module module) {
if (module.groupings.empty) {
return '';
<ul>
«FOR grouping : module.groupings»
<li>
- «strong("grouping " + grouping.QName.localName)»
+ <h3 id="«grouping.QName.localName»">«grouping.QName.localName»</h3>
<ul>
«grouping.descAndRefLi»
+ «FOR childNode : grouping.childNodes»
+ «childNode.printSchemaNodeInfo»
+ «ENDFOR»
</ul>
</li>
«ENDFOR»
'''
}
+ private def groupingsSummary(Module module) {
+ if (module.groupings.empty) {
+ return '';
+ }
+ return '''
+ <h3>Groupings Summary</h3>
+ <table>
+ <tr>
+ <th>Name</th>
+ <th>Description</th>
+ </tr>
+ «FOR grouping : module.groupings»
+ <tr>
+ <td>
+ «anchorLink(grouping.QName.localName, strong(grouping.QName.localName))»
+ </td>
+ <td>
+ «grouping.description»
+ </td>
+ </tr>
+ «ENDFOR»
+ </table>
+ '''
+ }
+
def dataStore(Module module) {
if (module.childNodes.empty) {
return '';
<ul>
«FOR augment : module.augmentations»
<li>
- <h3>Target [«schemaPathAsRestconfPath(module, augment.targetPath, context)»]</h3>
+ <h3 id="«schemaPathToString(module, augment.targetPath, context, augment)»">
+ Target [«typeAnchorLink(augment.targetPath,schemaPathToString(module, augment.targetPath, context, augment))»]</h3>
«augment.description»
«IF augment.reference !== null»
Reference «augment.reference»
«IF augment.whenCondition !== null»
When «augment.whenCondition.toString»
«ENDIF»
- «augment.childNodes.printChildren(3,InstanceIdentifier.builder().toInstance())»
+ «FOR childNode : augment.childNodes»
+ «childNode.printSchemaNodeInfo»
+ «ENDFOR»
</li>
«ENDFOR»
</ul>
'''
}
+ private def augmentationsSummary(Module module, SchemaContext context) {
+ if (module.augmentations.empty) {
+ return '';
+ }
+ return '''
+ <h3>Augmentations Summary</h3>
+ <table>
+ <tr>
+ <th>Target</th>
+ <th>Description</th>
+ </tr>
+ «FOR augment : module.augmentations»
+ <tr>
+ <td>
+ «anchorLink(schemaPathToString(module, augment.targetPath, context, augment),
+ strong(schemaPathToString(module, augment.targetPath, context, augment)))»
+ </td>
+ <td>
+ «augment.description»
+ </td>
+ </tr>
+ «ENDFOR»
+ </table>
+ '''
+ }
+
def notifications(Module module) {
val Set<NotificationDefinition> notificationdefs = module.notifications
if (notificationdefs.empty) {
<h2>Notifications</h2>
«FOR notificationdef : notificationdefs»
- <h3>«notificationdef.nodeName»</h3>
+ <h3 id="«notificationdef.path.schemaPathToId»">«notificationdef.nodeName»</h3>
«notificationdef.descAndRef»
- «notificationdef.childNodes.printChildren(3,InstanceIdentifier.builder().toInstance())»
+ «FOR childNode : notificationdef.childNodes»
+ «childNode.printSchemaNodeInfo»
+ «ENDFOR»
+ «ENDFOR»
+ '''
+ }
+
+ private def notificationsSummary(Module module) {
+ if (module.notifications.empty) {
+ return '';
+ }
+ return '''
+ <h3>Notifications Summary</h3>
+ <table>
+ <tr>
+ <th>Name</th>
+ <th>Description</th>
+ </tr>
+ «FOR notification : module.notifications»
+ <tr>
+ <td>
+ «anchorLink(notification.path.schemaPathToId, strong(notification.QName.localName))»
+ </td>
+ <td>
+ «notification.description»
+ </td>
+ </tr>
«ENDFOR»
+ </table>
'''
}
return '''
<h2>RPC Definitions</h2>
«FOR rpc : module.rpcs»
- <h3>«rpc.nodeName»</h3>
- «rpc.rpcInfo(InstanceIdentifier.builder().node(rpc.QName).toInstance())»
+ <h3 id="«rpc.QName.localName»">«rpc.nodeName»</h3>
+ <ul>
+ «rpc.descAndRefLi»
+ «rpc.input.printSchemaNodeInfo»
+ «rpc.output.printSchemaNodeInfo»
+ </ul>
«ENDFOR»
</ul>
'''
}
+ private def rpcsSummary(Module module) {
+ if (module.rpcs.empty) {
+ return '';
+ }
+ return '''
+ <h3>RPCs Summary</h3>
+ <table>
+ <tr>
+ <th>Name</th>
+ <th>Description</th>
+ </tr>
+ «FOR rpc : module.rpcs»
+ <tr>
+ <td>
+ «anchorLink(rpc.QName.localName, strong(rpc.QName.localName))»
+ </td>
+ <td>
+ «rpc.description»
+ </td>
+ </tr>
+ «ENDFOR»
+ </table>
+ '''
+ }
+
def extensions(Module module) {
if (module.extensionSchemaNodes.empty) {
return '';
<h2>Extensions</h2>
«FOR ext : module.extensionSchemaNodes»
<li>
- <h3>«ext.nodeName»</h3>
+ <h3 id="«ext.QName.localName»">«ext.nodeName»</h3>
</li>
«extensionInfo(ext)»
«ENDFOR»
'''
}
+ private def extensionsSummary(Module module) {
+ if (module.extensionSchemaNodes.empty) {
+ return '';
+ }
+ return '''
+ <h3>Extensions Summary</h3>
+ <table>
+ <tr>
+ <th>Name</th>
+ <th>Description</th>
+ </tr>
+ «FOR ext : module.extensionSchemaNodes»
+ <tr>
+ <td>
+ «anchorLink(ext.QName.localName, strong(ext.QName.localName))»
+ </td>
+ <td>
+ «ext.description»
+ </td>
+ </tr>
+ «ENDFOR»
+ </table>
+ '''
+ }
+
def features(Module module) {
if (module.features.empty) {
return '';
<ul>
«FOR feature : module.features»
<li>
- «strong("feature " + feature.QName.localName)»
+ <h3 id="«feature.QName.localName»">«feature.QName.localName»</h3>
<ul>
«feature.descAndRefLi»
</ul>
'''
}
- def header(Module module) '''
+ private def featuresSummary(Module module) {
+ if (module.features.empty) {
+ return '';
+ }
+ return '''
+ <h3>Features Summary</h3>
+ <table>
+ <tr>
+ <th>Name</th>
+ <th>Description</th>
+ </tr>
+ «FOR feature : module.features»
+ <tr>
+ <td>
+ «anchorLink(feature.QName.localName, strong(feature.QName.localName))»
+ </td>
+ <td>
+ «feature.description»
+ </td>
+ </tr>
+ «ENDFOR»
+ </table>
+ '''
+ }
+
+ private def objectsSummary(Module module) {
+ if (module.childNodes.empty) {
+ return '';
+ }
+ return '''
+ <h3>Child Nodes Summary</h3>
+ <table>
+ <tr>
+ <th>Name</th>
+ <th>Description</th>
+ </tr>
+ «FOR childNode : module.childNodes»
+ <tr>
+ <td>
+ «anchorLink(childNode.QName.localName, strong(childNode.QName.localName))»
+ </td>
+ <td>
+ «childNode.description»
+ </td>
+ </tr>
+ «ENDFOR»
+ </table>
+ '''
+ }
+
+ def header(Module module)
+ '''
<h1>«module.name»</h1>
<h2>Base Information</h2>
- <dl>
- <dt>Prefix</dt>
- <dd>«pre(module.prefix)»</dd>
- <dt>Namespace</dt>
- <dd>«pre(module.namespace.toString)»</dd>
- <dt>Revision</dt>
- <dd>«pre(REVISION_FORMAT.format(module.revision))»</dd>
-
- «FOR imp : module.imports BEFORE "<dt>Imports</dt>" »
- <dd>«code(imp.prefix)» = «code(imp.moduleName)»</dd>
- «ENDFOR»
- </dl>
+ <table>
+ <tr>
+ <td>«strong("prefix")»</td>
+ <td>«module.prefix»</td>
+ </tr>
+ <tr>
+ <td>«strong("namespace")»</td>
+ <td>«module.namespace»</td>
+ </tr>
+ <tr>
+ <td>«strong("revision")»</td>
+ <td>«REVISION_FORMAT.format(module.revision)»</td>
+ </tr>
+ <tr>
+ <td>«strong("description")»</td>
+ <td>«module.description»</td>
+ </tr>
+ <tr>
+ <td>«strong("yang-version")»</td>
+ <td>«module.yangVersion»</td>
+ </tr>
+ <tr>
+ «FOR imp : module.imports BEFORE '''<td>«strong("imports")»</td><td>''' AFTER '''</td>'''»
+ «imp.prefix»:«imp.moduleName»«IF imp.revision !== null» «REVISION_FORMAT.format(imp.revision)»«ENDIF»;
+ «ENDFOR»
+ </tr>
+ </table>
'''
+ def CharSequence schemaPathToId(SchemaPath path) {
+ if(path !== null) {
+ return '''«FOR qName : path.path SEPARATOR "/"»«qName.localName»«ENDFOR»'''
+ }
+ }
+
def code(String string) '''<code>«string»</code>'''
def process(Module module) {
}
def CharSequence tree(Module module) '''
- «strong("module " + module.name)»
+ «strong(module.name)»
«module.childNodes.treeSet(InstanceIdentifier.builder.toInstance())»
'''
def CharSequence childNodes(Module module) '''
«val childNodes = module.childNodes»
- «IF childNodes !== null && !childNodes.empty»
+ «IF !childNodes.nullOrEmpty»
<h2>Child nodes</h2>
«childNodes.printChildren(3,InstanceIdentifier.builder().toInstance())»
«ENDIF»
'''
+ def CharSequence printSchemaNodeInfo(DataSchemaNode node) {
+ return '''
+ <ul>
+ «node.printBaseInfo»
+ «IF node instanceof DataNodeContainer»
+ «val dataNode = node as DataNodeContainer»
+ <ul>
+ «FOR usesNode : dataNode.uses»
+ «usesNode.printUses»
+ «ENDFOR»
+ </ul>
+ <ul>
+ «FOR typeDef : dataNode.typeDefinitions»
+ «typeDef.restrictions»
+ «ENDFOR»
+ </ul>
+ <ul>
+ «FOR grouping : dataNode.groupings»
+ «grouping.printGrouping»
+ «ENDFOR»
+ </ul>
+ <ul>
+ «FOR child : dataNode.childNodes»
+ «child.printSchemaNodeInfo»
+ «ENDFOR»
+ </ul>
+ «ENDIF»
+ </ul>
+ '''
+ }
+
+ def String typeAnchorLink(SchemaPath path, CharSequence text) {
+ if(path !== null) {
+ val prefix = path.path.last.prefix
+ if(prefix == this.currentModule.prefix) {
+ return '''<a href="#«path.schemaPathToId»">«text»</a>'''
+ } else if(!prefix.nullOrEmpty){
+ val String module = imports.get(prefix)
+ if(!module.nullOrEmpty) {
+ return '''«prefix»:«text»'''
+ //to enable external (import) links
+ //return '''<a href="«module».html#«path.schemaPathToId»">«prefix»:«text»</a>'''
+ }
+ }
+ return text.toString
+ }
+ }
+
+ def CharSequence printBaseInfo(SchemaNode node) {
+ if(node instanceof LeafSchemaNode) {
+ val LeafSchemaNode leafNode = (node as LeafSchemaNode)
+ return '''
+ «printInfo(node, "leaf")»
+ «listItem("type", typeAnchorLink(leafNode.type?.path, leafNode.type.QName.localName))»
+ «listItem("units", leafNode.units)»
+ «listItem("default", leafNode.^default)»
+ </ul>
+ '''
+ } else if(node instanceof LeafListSchemaNode) {
+ val LeafListSchemaNode leafListNode = (node as LeafListSchemaNode)
+ return '''
+ «printInfo(node, "leaf-list")»
+ «listItem("type", leafListNode.type?.QName.localName)»
+ </ul>
+ '''
+ } else if(node instanceof ListSchemaNode) {
+ val ListSchemaNode listNode = (node as ListSchemaNode)
+ return '''
+ «printInfo(node, "list")»
+ «FOR keyDef : listNode.keyDefinition»
+ «listItem("key definition", keyDef.localName)»
+ «ENDFOR»
+ </ul>
+ '''
+ } else if(node instanceof ChoiceNode) {
+ val ChoiceNode choiceNode = (node as ChoiceNode)
+ return '''
+ «printInfo(node, "choice")»
+ «listItem("default case", choiceNode.defaultCase)»
+ «FOR caseNode : choiceNode.cases»
+ «caseNode.printSchemaNodeInfo»
+ «ENDFOR»
+ </ul>
+ '''
+ } else if(node instanceof ChoiceCaseNode) {
+ return '''
+ «printInfo(node, "case")»
+ </ul>
+ '''
+ } else if(node instanceof ContainerSchemaNode) {
+ return '''
+ «printInfo(node, "container")»
+ </ul>
+ '''
+ } else if(node instanceof AnyXmlSchemaNode) {
+ return '''
+ «printInfo(node, "anyxml")»
+ </ul>
+ '''
+ }
+ }
+
+ def CharSequence printInfo(SchemaNode node, String nodeType) {
+ return '''
+ «IF node instanceof AugmentationTarget»
+ «IF node !== null»
+ <strong>
+ <li id="«node.path.schemaPathToId»">
+ «nodeType»: «node.QName.localName»
+ </li>
+ </strong>
+ «ENDIF»
+ «ELSE»
+ «strong(listItem(nodeType, node.QName.localName))»
+ «ENDIF»
+ <ul>
+ «listItem("description", node.description)»
+ «listItem("reference", node.reference)»
+ «IF node instanceof DataSchemaNode»
+ «listItem("when condition", (node as DataSchemaNode).constraints.whenCondition?.toString)»
+ «listItem("min elements", (node as DataSchemaNode).constraints.minElements?.toString)»
+ «listItem("max elements", (node as DataSchemaNode).constraints.maxElements?.toString)»
+ «ENDIF»
+ '''
+ }
+
+ def CharSequence printUses(UsesNode usesNode) {
+ return '''
+ «strong(listItem("uses", typeAnchorLink(usesNode.groupingPath, usesNode.groupingPath.path.last.localName)))»
+ <ul>
+ <li>refines:
+ <ul>
+ «FOR sp : usesNode.refines.keySet»
+ «listItem("node name", usesNode.refines.get(sp).QName.localName)»
+ «ENDFOR»
+ </ul>
+ </li>
+ «FOR augment : usesNode.augmentations»
+ «typeAnchorLink(augment.targetPath,schemaPathToString(currentModule, augment.targetPath, ctx, augment))»
+ «ENDFOR»
+ </ul>
+ '''
+ }
+
+ def CharSequence printGrouping(GroupingDefinition grouping) {
+ return '''
+ «strong(listItem("grouping", grouping.QName.localName))»
+ '''
+ }
+
def CharSequence printChildren(Set<DataSchemaNode> nodes, int level, InstanceIdentifier path) {
- val anyxmlNodes = nodes.filter(AnyXmlSchemaNode)
- val leafNodes = nodes.filter(LeafSchemaNode)
- val leafListNodes = nodes.filter(LeafListSchemaNode)
- val choices = nodes.filter(ChoiceNode)
- val cases = nodes.filter(ChoiceCaseNode)
- val containers = nodes.filter(ContainerSchemaNode)
- val lists = nodes.filter(ListSchemaNode)
- return '''
- «IF ((anyxmlNodes.size + leafNodes.size + leafListNodes.size + containers.size + lists.size) > 0)»
- <h3>Direct children</h3>
- <ul>
- «FOR childNode : anyxmlNodes»
- «childNode.printShortInfo(level,path)»
- «ENDFOR»
- «FOR childNode : leafNodes»
- «childNode.printShortInfo(level,path)»
- «ENDFOR»
- «FOR childNode : leafListNodes»
- «childNode.printShortInfo(level,path)»
- «ENDFOR»
- «FOR childNode : containers»
- «childNode.printShortInfo(level,path)»
- «ENDFOR»
- «FOR childNode : lists»
- «childNode.printShortInfo(level,path)»
- «ENDFOR»
- </ul>
- «ENDIF»
+ val anyxmlNodes = nodes.filter(AnyXmlSchemaNode)
+ val leafNodes = nodes.filter(LeafSchemaNode)
+ val leafListNodes = nodes.filter(LeafListSchemaNode)
+ val choices = nodes.filter(ChoiceNode)
+ val cases = nodes.filter(ChoiceCaseNode)
+ val containers = nodes.filter(ContainerSchemaNode)
+ val lists = nodes.filter(ListSchemaNode)
+ return '''
+ «IF ((anyxmlNodes.size + leafNodes.size + leafListNodes.size + containers.size + lists.size) > 0)»
+ <h3>Direct children</h3>
+ <ul>
+ «FOR childNode : anyxmlNodes»
+ «childNode.printShortInfo(level,path)»
+ «ENDFOR»
+ «FOR childNode : leafNodes»
+ «childNode.printShortInfo(level,path)»
+ «ENDFOR»
+ «FOR childNode : leafListNodes»
+ «childNode.printShortInfo(level,path)»
+ «ENDFOR»
+ «FOR childNode : containers»
+ «childNode.printShortInfo(level,path)»
+ «ENDFOR»
+ «FOR childNode : lists»
+ «childNode.printShortInfo(level,path)»
+ «ENDFOR»
+ </ul>
+ «ENDIF»
- «IF !path.path.empty»
- <h3>XML example</h3>
- «nodes.xmlExample(path.path.last.nodeType,path)»
- </h3>
- «ENDIF»
- «FOR childNode : containers»
- «childNode.printInfo(level,path)»
- «ENDFOR»
- «FOR childNode : lists»
- «childNode.printInfo(level,path)»
- «ENDFOR»
- «FOR childNode : choices»
- «childNode.printInfo(level,path)»
- «ENDFOR»
- «FOR childNode : cases»
- «childNode.printInfo(level,path)»
- «ENDFOR»
-
- '''
+ «IF !path.path.empty»
+ <h3>XML example</h3>
+ «nodes.xmlExample(path.path.last.nodeType,path)»
+ </h3>
+ «ENDIF»
+ «FOR childNode : containers»
+ «childNode.printInfo(level,path)»
+ «ENDFOR»
+ «FOR childNode : lists»
+ «childNode.printInfo(level,path)»
+ «ENDFOR»
+ «FOR childNode : choices»
+ «childNode.printInfo(level,path)»
+ «ENDFOR»
+ «FOR childNode : cases»
+ «childNode.printInfo(level,path)»
+ «ENDFOR»
+ '''
}
def CharSequence xmlExample(Set<DataSchemaNode> nodes, QName name,InstanceIdentifier path) '''
'''
}
+ def CharSequence anchorLink(CharSequence anchor, CharSequence text) {
+ return '''
+ <a href="#«anchor»">«text»</a>
+ '''
+ }
+
def CharSequence localLink(InstanceIdentifier identifier, CharSequence text) '''
<a href="#«FOR cmp : identifier.path SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»">«text»</a>
'''
private def dispatch InstanceIdentifier append(InstanceIdentifier identifier, ListSchemaNode node) {
val pathArguments = new ArrayList(identifier.path)
val keyValues = new LinkedHashMap<QName,Object>();
- if(node.keyDefinition != null) {
+ if(node.keyDefinition !== null) {
for(definition : node.keyDefinition) {
keyValues.put(definition,new Object);
}
return it.toString;
}
- private def String schemaPathAsRestconfPath(Module module, SchemaPath schemaPath, SchemaContext ctx) {
- val Map<String, String> imports = new HashMap();
- for (mImport : module.imports) {
- imports.put(mImport.prefix, mImport.moduleName)
- }
-
- val List<QName> path = schemaPath.path
+ private def String schemaPathToString(Module module, SchemaPath schemaPath, SchemaContext ctx, DataNodeContainer dataNode) {
+ val List<QName> path = schemaPath.path
val StringBuilder pathString = new StringBuilder()
if (schemaPath.absolute) {
pathString.append("/")
}
}
- if (!(node instanceof ChoiceNode) && !(node instanceof ChoiceCaseNode)) {
- var String prefix = name.prefix
- var String moduleName
- if (prefix == null || "".equals(prefix) || prefix.equals(module.prefix)) {
- moduleName = module.name
- } else {
- moduleName = imports.get(prefix)
+ var String prefix = name.prefix
+ var String moduleName
+ if (prefix == null || "".equals(prefix) || prefix.equals(module.prefix)) {
+ moduleName = module.name
+ } else {
+ moduleName = imports.get(prefix)
+ }
+ pathString.append(moduleName)
+ pathString.append(":")
+ pathString.append(name.localName)
+ pathString.append("/")
+ if(node instanceof ChoiceNode && dataNode !== null) {
+ val DataSchemaNode caseNode = dataNode.childNodes.findFirst[DataSchemaNode e | e instanceof ChoiceCaseNode];
+ if(caseNode !== null) {
+ pathString.append("(case)");
+ pathString.append(caseNode.QName.localName);
}
- pathString.append(moduleName)
- pathString.append(":")
- pathString.append(name.localName)
- pathString.append("/")
}
parent = node
- } else if (parent instanceof ChoiceNode) {
- parent = (parent as ChoiceNode).getCaseNodeByName(qname.localName)
}
}
return pathString.toString;
[«FOR key : node.keyDefinition SEPARATOR " "»«key.localName»«ENDFOR»]
'''
- private def CharSequence rpcInfo(RpcDefinition rpc,InstanceIdentifier path) '''
- <ul>
- «rpc.descAndRefLi»
- <li>
- «rpc.input.tree(path)»
- </li>
- <li>
- «rpc.output.tree(path)»
- </li>
- </ul>
- '''
-
private def CharSequence extensionInfo(ExtensionDefinition ext) '''
<ul>
«ext.descAndRefLi»
/* #################### RESTRICTIONS #################### */
private def restrictions(TypeDefinition<?> type) '''
+ «type.baseType.toBaseStmt»
«type.toLength»
«type.toRange»
'''
def toLengthStmt(Collection<LengthConstraint> lengths) '''
«IF lengths != null && !lengths.empty»
- «listItem("Length restrictions")»
+ «listItem("Length restrictions:")»
<ul>
«FOR length : lengths»
<li>
def toRangeStmt(Collection<RangeConstraint> ranges) '''
«IF ranges != null && !ranges.empty»
- «listItem("Range restrictions")»
+ «listItem("Range restrictions:")»
<ul>
«FOR range : ranges»
<li>
«ENDIF»
'''
+ def toBaseStmt(TypeDefinition<?> baseType) '''
+ «IF baseType != null»
+ «listItem("Base type", typeAnchorLink(baseType?.path, baseType.QName.localName))»
+ «ENDIF»
+ '''
+
/* #################### UTILITY #################### */
private def String strong(CharSequence str) '''<strong>«str»</strong>'''
private def italic(CharSequence str) '''<i>«str»</i>'''
- private def pre(CharSequence str) '''<pre>«str»</pre>'''
def CharSequence descAndRefLi(SchemaNode node) '''
- «listItem(node.description)»
+ «listItem("Description", node.description)»
«listItem("Reference", node.reference)»
'''
«node.QName.localName»«node.addedByInfo»
«ENDIF»
'''
-
+
private def dispatch nodeName(ContainerSchemaNode node) '''
«IF node.isAddedBy»
«strong(italic(node.QName.localName))»«node.addedByInfo»
import java.io.File;
import java.io.IOException;
import java.util.Collection;
-import java.util.Collections;
import java.util.Map;
import java.util.Set;
@Override
public Collection<File> generateSources(SchemaContext arg0, File arg1, Set<Module> arg2) throws IOException {
// TODO Auto-generated method stub
- generate(arg0, arg1, arg2);
- return Collections.emptySet();
+ return generate(arg0, arg1, arg2);
}
@Override
*/
package org.opendaylight.yangtools.yang.unified.doc.generator.maven;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.List;
import java.util.Set;
final Set<Module> modulesToBuild = parser.parseYangModels(sourceFiles);
final SchemaContext context = parser.resolveSchemaContext(modulesToBuild);
final CodeGenerator generator = new DocumentationGeneratorImpl();
- generator.generateSources(context, GENERATOR_OUTPUT_DIR, modulesToBuild);
+ Collection<File> generatedFiles = generator.generateSources(context, GENERATOR_OUTPUT_DIR, modulesToBuild);
+ assertEquals(4, generatedFiles.size());
}
private static List<File> getSourceFiles(String path) throws Exception {
*/
package org.opendaylight.yangtools.yang.wadl.generator.maven;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.FileNotFoundException;
--- /dev/null
+// vi: set smarttab et sw=4 tabstop=4:
+module config {
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:config";
+ prefix "config";
+
+
+ description
+ "This module contains the base YANG definitions for NS-OS
+ configuration subsystem. The system modeled revolves around two
+ major concepts: modules and services.";
+
+ revision "2013-04-05" {
+ description
+ "Reworked to give modules their own space.";
+ }
+
+ revision "2013-04-03" {
+ description
+ "Initial revision.";
+ }
+
+ extension java-class {
+ description
+ "YANG language extension carrying the fully-qualified name of
+ a Java class. Code generation tools use the provided reference
+ to tie a specific construct to its Java representation.";
+
+ argument "name";
+ }
+
+ extension required-identity {
+ description
+ "YANG language extension which indicates that a particular
+ leafref, which points to a identityref, should additionally
+ require the target node is actually set to a descendant to
+ of a particular identity.
+
+ This is a workaround to two YANG deficiencies:
+ 1) not being able to leafref instances of identityref
+ 2) not being able to refine an identityref
+
+ This extension takes one argument, name, which MUST be the name
+ of an identity. Furthermore, that identity MUST be based,
+ directly or indirectly, on the identity, which is referenced by
+ the leaf reference, which is annotated with this extension.";
+
+ argument "name";
+ }
+
+ extension inner-state-bean {
+ description
+ "YANG language extension which indicates that a particular
+ list located under module's state should be treated as a list
+ of child state beans instead of just an ordinary list attribute";
+ }
+
+ extension provided-service {
+ description
+ "YANG language extension which indicates that a particular
+ module provides certain service. This extension can be placed
+ on identities that are based on module-type. Zero or more services
+ can be provided.
+ This extension takes one argument - name - which MUST be the name
+ of an identity. Furthermore, this identity MUST be based on
+ service-type.";
+
+ argument "name";
+ }
+
+ extension java-name-prefix {
+ description
+ "YANG language extension carrying java simple class name prefix
+ that will be taken into account when generating java code from
+ identities that are based on module-type.";
+ argument "java-prefix";
+ }
+
+ identity module-type {
+ description
+ "Module identity base type. All module identities must be derived
+ from this type. A module type uniquely defines a single atomic
+ component, such as an application. Each such component is assumed
+ to have its unique, stable and versioned configuration structure.";
+ }
+
+ identity service-type {
+ description
+ "Service identity base type. All service identities must be
+ derived from this type. A service type uniquely defines a single
+ atomic API contract, such as a Java interface, a set of C
+ function declarations, or similar.
+
+ If the service type has a corresponding Java interface, the name
+ of that interface should be attached to the derived identity MUST
+ include a java-class keyword, whose name argument points to that
+ interface.";
+ }
+
+ typedef service-type-ref {
+ description
+ "Internal type of references to service type identity.";
+
+ type identityref {
+ base service-type;
+ }
+ }
+
+ grouping service-ref {
+ description
+ "Type of references to a particular service instance. This type
+ can be used when defining module configuration to refer to a
+ particular service instance. Containers using this grouping
+ should not define anything else. The run-time implementation
+ is expected to inject a reference to the service as the value
+ of the container.";
+
+ leaf type {
+ description
+ "Type of the service being referenced. Users of this grouping
+ should refine this leaf with required-identity pointing to
+ the actual service-type which is actually required.";
+
+ mandatory true;
+ type service-type-ref;
+ }
+
+ leaf name {
+ mandatory true;
+ type leafref {
+ path "/config:services/config:service[config:type=current()/../type]/config:instance/config:name";
+ }
+ }
+ }
+
+ container modules {
+ description
+ "Top level container encapsulating configuration of all modules.";
+
+ list module {
+ key "name";
+ leaf name {
+ description "Unique module instance name";
+ type string;
+ mandatory true;
+ }
+
+ leaf type {
+ type identityref {
+ base module-type;
+ }
+ mandatory true;
+ }
+
+ choice configuration {
+ mandatory true;
+ config true;
+ }
+
+ choice state {
+ config false;
+ }
+ }
+ }
+
+
+ container services {
+ list service {
+ key "type";
+ leaf type {
+ type service-type-ref;
+ }
+ list instance {
+ key "name";
+ leaf name {
+ type string;
+ }
+
+ leaf provider {
+ mandatory true;
+ type leafref {
+ path "/modules/module/name";
+ }
+ }
+ }
+ }
+ }
+
+
+}
--- /dev/null
+// vi: set smarttab et sw=4 tabstop=4:
+module netty {
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:netty";
+ prefix "netty";
+
+ import config { prefix config; revision-date 2013-04-05; }
+
+ organization "Cisco Systems, Inc.";
+
+ contact "Milos Fabian <milfabia@cisco.com>";
+
+ description
+ "This module contains the base YANG definitions for
+ netty services.
+
+ Copyright (c)2013 Cisco Systems, Inc. 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";
+
+ revision "2013-11-19" {
+ description
+ "Initial revision.";
+ }
+
+ identity netty-threadgroup {
+ description
+ "Configuration wrapper around netty's threadgroup";
+
+ base "config:service-type";
+ config:java-class "io.netty.channel.EventLoopGroup";
+ }
+
+ identity netty-event-executor {
+ description
+ "Configuration wrapper around netty's event executor";
+
+ base "config:service-type";
+ config:java-class "io.netty.util.concurrent.EventExecutor";
+ }
+
+ identity netty-timer {
+ description
+ "Configuration wrapper around netty's timer";
+
+ base "config:service-type";
+ config:java-class "io.netty.util.Timer";
+ }
+}
\ No newline at end of file
--- /dev/null
+// vi: set smarttab et sw=4 tabstop=4:
+module protocol-framework {
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:protocol:framework";
+ prefix "pf";
+
+ import config { prefix config; revision-date 2013-04-05; }
+ import netty { prefix netty; revision-date 2013-11-19; }
+
+ organization "Cisco Systems, Inc.";
+
+ contact "Milos Fabian <milfabia@cisco.com>";
+
+ description
+ "This module contains the base YANG definitions for
+ protocol framework.
+
+ Copyright (c)2013 Cisco Systems, Inc. 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";
+
+ revision "2014-03-13" {
+ description
+ "Changed reconnect-strategy to reconnect-strategy-factory - represents ReconnectStrategyFactory.
+ reconnect-strategy-factory modules provides reconnect-strategy-factory service.";
+ }
+
+ revision "2013-11-09" {
+ description
+ "Initial revision";
+ }
+
+ identity reconnect-strategy-factory {
+ description
+ "Service representing a reconnect strategy factory.";
+
+ base "config:service-type";
+ config:java-class "org.opendaylight.protocol.framework.ReconnectStrategyFactory";
+ }
+
+ identity never-reconnect-strategy-factory {
+ base config:module-type;
+ config:provided-service reconnect-strategy-factory;
+ config:java-name-prefix NeverReconnectStrategyFactory;
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case never-reconnect-strategy-factory {
+ when "/config:modules/config:module/config:type = 'never-reconnect-strategy-factory'";
+
+ leaf timeout {
+ mandatory true;
+ type int32;
+ }
+
+ container executor {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity netty:netty-event-executor;
+ }
+ }
+ }
+ }
+ }
+
+ identity reconnect-immediately-strategy-factory {
+ base config:module-type;
+ config:provided-service reconnect-strategy-factory;
+ config:java-name-prefix ReconnectImmediatelyStrategyFactory;
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case reconnect-immediately-strategy-factory {
+ when "/config:modules/config:module/config:type = 'reconnect-immediately-strategy-factory'";
+
+ leaf timeout {
+ mandatory true;
+ type int32;
+ }
+
+ container executor {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity netty:netty-event-executor;
+ }
+ }
+ }
+ }
+ }
+
+ identity timed-reconnect-strategy-factory {
+ base config:module-type;
+ config:provided-service reconnect-strategy-factory;
+ config:java-name-prefix TimedReconnectStrategyFactory;
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case timed-reconnect-strategy-factory {
+ when "/config:modules/config:module/config:type = 'timed-reconnect-strategy-factory'";
+
+ leaf deadline {
+ type int64;
+ units "epoch nanoseconds";
+ }
+
+ leaf max-attempts {
+ mandatory true;
+ type int64;
+ }
+
+ leaf max-sleep {
+ mandatory true;
+ type int64;
+ units "milliseconds";
+ }
+
+ leaf min-sleep {
+ mandatory true;
+ type int64;
+ units "milliseconds";
+ }
+
+ leaf sleep-factor {
+ mandatory true;
+ type decimal64 {
+ fraction-digits 2;
+ }
+ }
+
+ leaf connect-time {
+ mandatory true;
+ type int32;
+ units "milliseconds";
+ }
+
+ container executor {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity netty:netty-event-executor;
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
<parent>
<groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yangtools</artifactId>
+ <artifactId>common-parent</artifactId>
<version>0.6.2-SNAPSHOT</version>
</parent>
<packaging>bundle</packaging>
<modelVersion>4.0.0</modelVersion>
<artifactId>concepts</artifactId>
<name>${project.artifactId}</name>
- <description>Java binding for YANG</description>
+ <description>Common concepts</description>
<build>
<plugins>
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.concepts;
+
+/**
+ * An extension of the {@link Builder} concept which allows an implementation
+ * of this interface to be used in collections instead of the product. Given
+ * the mutable nature of Builders, this has to be done very carefully.
+ *
+ * @param <P> Product type
+ */
+public interface ProductAwareBuilder<P> extends Builder<P> {
+ /**
+ * Return the hash code of the product. This has to be equivalent
+ * of calling {@link #toInstance()}.{@link #hashCode()}.
+ *
+ * @return the hash code of the product.
+ */
+ int productHashCode();
+
+ /**
+ * Check whether an instance of the product that would be created
+ * by the builder is equal to an existing instance. This has to
+ * be equivalent of calling {@link #toInstance()}.{@link #equals(Object)}.
+ *
+ * @param product Product instance
+ * @return Return true if the product is equal to the would-be
+ * product of the builder.
+ */
+ boolean productEquals(Object product);
+}
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
import org.opendaylight.yangtools.concepts.Immutable;
import org.opendaylight.yangtools.concepts.Mutable;
/**
* Determines if object is known to be immutable
- *
+ *
* Note: This method may return false to immutable objects which
* immutability is not known, was defined not using concepts term.
- *
+ *
* @param o
* Reference to check
* @return true if object is known to be immutable false otherwise.
return false;
}
- private static boolean isNumberImmutable(Number o) {
- if(o instanceof AtomicInteger) {
- return false;
- } else if(o instanceof AtomicLong) {
- return false;
- } else if(o instanceof Short) {
- return true;
- }
- return false;
- }
-
@SafeVarargs
private static <E> Set<E> asHashSet(E... list) {
HashSet<E> ret = new HashSet<>();
<parent>
<groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yangtools</artifactId>
+ <artifactId>common-parent</artifactId>
<version>0.6.2-SNAPSHOT</version>
</parent>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>common-parent</artifactId>
+ <version>0.6.2-SNAPSHOT</version>
+ </parent>
+ <packaging>bundle</packaging>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>object-cache-api</artifactId>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>concepts</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.code.findbugs</groupId>
+ <artifactId>jsr305</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>process-classes</phase>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <configuration>
+ <tasks>
+ <!-- This is necessary to remove the impl package and
+ make static binding work with the implementation -->
+ <delete dir="${project.build.outputDirectory}/org/opendaylight/yangtools/objcache/impl"/>
+ </tasks>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.objcache;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.concepts.ProductAwareBuilder;
+
+/**
+ * A cache of objects. Caches are useful for reducing memory overhead
+ * stemming from multiple copies of identical objects -- by putting
+ * a cache in the instantiation path, one can expend some memory on
+ * indexes and spend some CPU cycles on walking the index to potentially
+ * end up with a reused object.
+ *
+ * Note that the cached objects should really be semantically {@link Immutable}.
+ * This interface does not enforce that interface contract simply because
+ * there are third-party objects which fulfill this contract.
+ */
+public interface ObjectCache {
+ /**
+ * Get a reference for an object which is equal to specified object.
+ * The cache is free return either a cached instance, or retain the
+ * object and return it back.
+ *
+ * @param object Requested object, may be null
+ * @return Reference to an object which is equal to the one passed in.
+ * If @object was @null, this method returns @null.
+ */
+ <T> T getReference(@Nullable T object);
+
+ /**
+ * Get a reference to an object equal to the product of a builder.
+ * The builder is expected to remain constant while this method
+ * executes. Unlike {@link #getReference(Object)}, this method has
+ * the potential of completely eliding the product instantiation.
+ *
+ * @param builder Builder instance, may not be null
+ * @return Result of builder's toInstance() product, or an equal
+ * object.
+ */
+ <B extends ProductAwareBuilder<P>, P> P getProduct(@Nonnull B builder);
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.objcache;
+
+import javax.annotation.Nonnull;
+
+import org.opendaylight.yangtools.objcache.impl.StaticObjectCacheBinder;
+import org.opendaylight.yangtools.objcache.spi.IObjectCacheFactory;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * Point of entry for acquiring an {@link ObjectCache} instance.
+ */
+public final class ObjectCacheFactory {
+ private static IObjectCacheFactory FACTORY;
+
+ private static synchronized IObjectCacheFactory initialize() {
+ // Double-check under lock
+ if (FACTORY != null) {
+ return FACTORY;
+ }
+
+ final IObjectCacheFactory f = StaticObjectCacheBinder.getInstance().getProductCacheFactory();
+ FACTORY = f;
+ return f;
+ }
+
+ public static synchronized void reset() {
+ FACTORY = null;
+ }
+
+ /**
+ * Get an ObjectCache for caching a particular object class. Note
+ * that it may be shared for multiple classes.
+ *
+ * @param objClass Class of objects which are to be cached
+ * @return Object cache instance.
+ */
+ public static ObjectCache getObjectCache(@Nonnull final Class<?> objClass) {
+ IObjectCacheFactory f = FACTORY;
+ if (f == null) {
+ f = initialize();
+ }
+
+ return f.getObjectCache(Preconditions.checkNotNull(objClass));
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.objcache.impl;
+
+import org.opendaylight.yangtools.objcache.spi.AbstractObjectCacheBinder;
+
+/*
+ * This is a dummy placeholder implementation. The API package is bound to
+ * it at compile-time, but it is not packaged and thus not present at run-time.
+ */
+public final class StaticObjectCacheBinder extends AbstractObjectCacheBinder {
+ private StaticObjectCacheBinder() {
+ super(null);
+ }
+
+ public static StaticObjectCacheBinder getInstance() {
+ throw new IllegalStateException("This class should have been replaced");
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+/**
+ * Static binding implementation package. The API package is bound at compile-time
+ * to this package. Implementations are expected to supply this package.
+ */
+package org.opendaylight.yangtools.objcache.impl;
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+/**
+ *
+ */
+package org.opendaylight.yangtools.objcache;
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.objcache.spi;
+
+import org.opendaylight.yangtools.concepts.ProductAwareBuilder;
+import org.opendaylight.yangtools.objcache.ObjectCache;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.FinalizableReferenceQueue;
+import com.google.common.base.FinalizableSoftReference;
+import com.google.common.base.Preconditions;
+import com.google.common.cache.Cache;
+
+/**
+ * Abstract object cache implementation. This implementation takes care
+ * of interacting with the user and manages interaction with the Garbage
+ * Collector (via soft references). Subclasses are expected to provide
+ * a backing {@link Cache} instance and provide the
+ */
+public abstract class AbstractObjectCache implements ObjectCache {
+ /**
+ * Key used when looking up a ProductAwareBuilder product. We assume
+ * the builder is not being modified for the duration of the lookup,
+ * anything else is the user's fault.
+ */
+ private static final class BuilderKey {
+ private final ProductAwareBuilder<?> builder;
+
+ private BuilderKey(final ProductAwareBuilder<?> builder) {
+ this.builder = Preconditions.checkNotNull(builder);
+ }
+
+ @Override
+ public int hashCode() {
+ return builder.productHashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ /*
+ * We can tolerate null objects coming our way, but we need
+ * to be on the lookout for WeakKeys, as we cannot pass them
+ * directly to productEquals().
+ */
+ if (obj != null && obj instanceof SoftKey) {
+ obj = ((SoftKey)obj).get();
+ }
+
+ return builder.productEquals(obj);
+ }
+ }
+
+ /**
+ * Key used in the underlying map. It is essentially a soft reference, with
+ * slightly special properties.
+ *
+ * It acts as a proxy for the object it refers to and essentially delegates
+ * to it. There are three exceptions here:
+ *
+ * 1) This key needs to have a cached hash code. The requirement is that the
+ * key needs to be able to look itself up after the reference to the object
+ * has been cleared (and thus we can no longer look it up from there). One
+ * typical container where we are stored are HashMaps -- and they need it
+ * to be constant.
+ * 2) This key does not tolerate checks to see if its equal to null. While we
+ * could return false, we want to catch offenders who try to store nulls
+ * in the cache.
+ * 3) This key inverts the check for equality, e.g. it calls equals() on the
+ * object which was passed to its equals(). Instead of supplying itself,
+ * it supplies the referent. If the soft reference is cleared, such check
+ * will return false, which is fine as it prevents normal lookup from
+ * seeing the cleared key. Removal is handled by the explicit identity
+ * check.
+ */
+ private static abstract class SoftKey extends FinalizableSoftReference<Object> {
+ private final int hashCode;
+
+ public SoftKey(final Object referent, final FinalizableReferenceQueue q) {
+ super(Preconditions.checkNotNull(referent), q);
+ hashCode = referent.hashCode();
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ Preconditions.checkState(obj != null);
+
+ // Order is important: we do not want to call equals() on ourselves!
+ return this == obj || obj.equals(get());
+ }
+
+ @Override
+ public int hashCode() {
+ return hashCode;
+ }
+ }
+
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractObjectCache.class);
+ private final FinalizableReferenceQueue queue;
+ private final Cache<Object, Object> cache;
+
+ protected AbstractObjectCache(final Cache<Object, Object> cache, final FinalizableReferenceQueue queue) {
+ this.queue = Preconditions.checkNotNull(queue);
+ this.cache = Preconditions.checkNotNull(cache);
+ }
+
+ private <T> T put(final T object) {
+ /*
+ * This may look like a race (having a soft reference and not have
+ * it in the cache). In fact this is protected by the fact we still
+ * have a strong reference on the object in our arguments and that
+ * reference survives past method return since we return it.
+ */
+ final Object key = new SoftKey(object, queue) {
+ @Override
+ public void finalizeReferent() {
+ /*
+ * NOTE: while it may be tempting to add "object" into this
+ * trace message, do not ever do that: it would retain
+ * a strong reference, preventing collection.
+ */
+ LOG.trace("Invalidating key {} for object {}", this);
+ cache.invalidate(this);
+ }
+ };
+ cache.put(key, object);
+ LOG.debug("Cached key {} to object {}", key, object);
+ return object;
+ }
+
+ @Override
+ public final <B extends ProductAwareBuilder<P>, P> P getProduct(final B builder) {
+ LOG.debug("Looking up product for {}", builder);
+
+ @SuppressWarnings("unchecked")
+ final P ret = (P) cache.getIfPresent(new BuilderKey(builder));
+ return ret == null ? put(Preconditions.checkNotNull(builder.toInstance())) : ret;
+ }
+
+ @Override
+ public final <T> T getReference(final T object) {
+ LOG.debug("Looking up reference for {}", object);
+ if (object == null) {
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ final T ret = (T) cache.getIfPresent(object);
+ return ret == null ? put(object) : ret;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.objcache.spi;
+
+import javax.annotation.Nonnull;
+
+import com.google.common.base.Preconditions;
+
+public abstract class AbstractObjectCacheBinder implements ObjectCacheFactoryBinder {
+ private final IObjectCacheFactory factory;
+
+ protected AbstractObjectCacheBinder(@Nonnull final IObjectCacheFactory factory) {
+ this.factory = Preconditions.checkNotNull(factory);
+ }
+
+ @Override
+ public final IObjectCacheFactory getProductCacheFactory() {
+ return factory;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.objcache.spi;
+
+import javax.annotation.Nonnull;
+
+import org.opendaylight.yangtools.objcache.ObjectCache;
+
+public interface IObjectCacheFactory {
+ ObjectCache getObjectCache(@Nonnull Class<?> objClass);
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.objcache.spi;
+
+import org.opendaylight.yangtools.concepts.ProductAwareBuilder;
+import org.opendaylight.yangtools.objcache.ObjectCache;
+
+/**
+ * No-operation implementation of an Object Cache. This implementation
+ * does not do any caching, so it only returns the request object.
+ */
+public final class NoopObjectCache implements ObjectCache {
+ private static final NoopObjectCache INSTANCE = new NoopObjectCache();
+
+ private NoopObjectCache() {
+
+ }
+
+ /**
+ * Get the cache instance. Since the cache does not have any state,
+ * this method always returns a singleton instance.
+ *
+ * @return Cache instance.
+ */
+ public static NoopObjectCache getInstance() {
+ return INSTANCE;
+ }
+
+ @Override
+ public <T> T getReference(final T object) {
+ return object;
+ }
+
+ @Override
+ public <B extends ProductAwareBuilder<P>, P> P getProduct(final B builder) {
+ return builder.toInstance();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.objcache.spi;
+
+/**
+ * Interface binding an implementation into ObjectCacheFactory.
+ */
+public interface ObjectCacheFactoryBinder {
+ /**
+ * Get the implementation-specific cache factory.
+ *
+ * @return Implementation-specific factory.
+ */
+ IObjectCacheFactory getProductCacheFactory();
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+/**
+ * Service Provider Interface for Object Cache. Object cache implementations
+ * use classes contained in this package to implement their functionality.
+ */
+package org.opendaylight.yangtools.objcache.spi;
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>common-parent</artifactId>
+ <version>0.6.2-SNAPSHOT</version>
+ </parent>
+ <packaging>bundle</packaging>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>object-cache-guava</artifactId>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>object-cache-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+</project>
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.objcache.guava;
+
+import org.opendaylight.yangtools.objcache.spi.AbstractObjectCache;
+
+import com.google.common.base.FinalizableReferenceQueue;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheBuilderSpec;
+
+final class GuavaObjectCache extends AbstractObjectCache {
+ public GuavaObjectCache(final FinalizableReferenceQueue queue, final CacheBuilderSpec spec) {
+ super(CacheBuilder.from(spec).softValues().build(), queue);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.objcache.guava;
+
+import org.opendaylight.yangtools.objcache.ObjectCache;
+import org.opendaylight.yangtools.objcache.spi.IObjectCacheFactory;
+
+import com.google.common.base.FinalizableReferenceQueue;
+
+public final class GuavaObjectCacheFactory implements IObjectCacheFactory {
+ private static final GuavaObjectCacheFactory INSTANCE = new GuavaObjectCacheFactory();
+ private final FinalizableReferenceQueue queue = new FinalizableReferenceQueue();
+ private final ObjectCache cache;
+
+ private GuavaObjectCacheFactory() {
+ // FIXME: make this more dynamic
+ this.cache = new GuavaObjectCache(queue, null);
+ }
+
+ @Override
+ public void finalize() throws Throwable {
+ try {
+ queue.close();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ @Override
+ public ObjectCache getObjectCache(final Class<?> objClass) {
+ return cache;
+ }
+
+ public static GuavaObjectCacheFactory getInstance() {
+ return INSTANCE;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+/**
+ *
+ */
+package org.opendaylight.yangtools.objcache.guava;
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.objcache.impl;
+
+import org.opendaylight.yangtools.objcache.guava.GuavaObjectCacheFactory;
+import org.opendaylight.yangtools.objcache.spi.AbstractObjectCacheBinder;
+
+public final class StaticObjectCacheBinder extends AbstractObjectCacheBinder {
+ private static final StaticObjectCacheBinder INSTANCE = new StaticObjectCacheBinder();
+
+ private StaticObjectCacheBinder() {
+ super(GuavaObjectCacheFactory.getInstance());
+ }
+
+ public static StaticObjectCacheBinder getInstance() {
+ return INSTANCE;
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>common-parent</artifactId>
+ <version>0.6.2-SNAPSHOT</version>
+ </parent>
+ <packaging>bundle</packaging>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>object-cache-noop</artifactId>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>object-cache-api</artifactId>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+</project>
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.objcache.impl;
+
+import org.opendaylight.yangtools.objcache.ObjectCache;
+import org.opendaylight.yangtools.objcache.spi.AbstractObjectCacheBinder;
+import org.opendaylight.yangtools.objcache.spi.IObjectCacheFactory;
+import org.opendaylight.yangtools.objcache.spi.NoopObjectCache;
+
+public final class StaticObjectCacheBinder extends AbstractObjectCacheBinder {
+ private static final StaticObjectCacheBinder INSTANCE = new StaticObjectCacheBinder();
+
+ private StaticObjectCacheBinder() {
+ super(new IObjectCacheFactory() {
+ @Override
+ public ObjectCache getObjectCache(final Class<?> objClass) {
+ return NoopObjectCache.getInstance();
+ }
+ });
+ }
+
+ public static StaticObjectCacheBinder getInstance() {
+ return INSTANCE;
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yangtools</artifactId>
+ <version>0.6.2-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>common-parent</artifactId>
+ <packaging>pom</packaging>
+
+ <modules>
+ <module>concepts</module>
+ <module>mockito-configuration</module>
+ <module>object-cache-api</module>
+ <module>object-cache-guava</module>
+ <module>object-cache-noop</module>
+ </modules>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>object-cache-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>object-cache-guava</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>object-cache-noop</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+</project>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!-- Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ and is available at http://www.eclipse.org/legal/epl-v10.html -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.opendaylight.yangtools.model</groupId>
+ <artifactId>model-parent</artifactId>
+ <version>0.6.2-SNAPSHOT</version>
+ <relativePath>../../model/pom.xml</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>bug527-test-model</artifactId>
+ <name>${project.artifactId}</name>
+ <description>${project.artifactId}</description>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-jar-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
+
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+module bar {
+ yang-version 1;
+ namespace "urn:yang:bar";
+ prefix "bar";
+
+ revision "2014-03-21" {
+ }
+
+ container alpha {
+ container beta {
+ }
+ }
+
+ grouping group-a {
+ container xcont {
+ choice xchoice {
+ }
+ }
+ }
+
+ grouping group-b {
+ uses group-a {
+ augment "xcont/xchoice" {
+ case xcase {
+ leaf idx {
+ type string;
+ }
+ }
+ }
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+module foo {
+ yang-version 1;
+ namespace "urn:yang:foo";
+ prefix "foo";
+
+ import bar {
+ prefix bar;
+ }
+
+ revision "2014-03-21" {
+ }
+
+
+
+ augment "/bar:alpha/bar:beta" {
+ uses bar:group-b;
+ }
+
+}
+
<packaging>pom</packaging>
<modules>
+ <module>bug527-test-model</module>
<module>regression-test-model</module>
<module>yang-runtime-tests</module>
</modules>
<!-- Build Plugin Versions -->
<maven.bundle.version>2.4.0</maven.bundle.version>
- <maven.jar.version>2.4</maven.jar.version>
+ <maven.jar.version>2.3.2</maven.jar.version>
<maven.javadoc.version>2.9.1</maven.javadoc.version>
<maven.release.version>2.4.2</maven.release.version>
<maven.source.version>2.2.1</maven.source.version>
</scm>
<modules>
- <module>concepts</module>
- <module>yang</module>
<module>code-generator</module>
+ <module>common</module>
+ <module>integration-test</module>
<module>model</module>
<module>restconf</module>
- <module>integration-test</module>
- <module>mockito-configuration</module>
<module>websocket</module>
+ <module>yang</module>
<!-- module>third-party</module -->
</modules>
<artifactId>commons-lang3</artifactId>
<version>${commons.lang.version}</version>
</dependency>
+ <dependency>
+ <groupId>com.google.code.findbugs</groupId>
+ <artifactId>jsr305</artifactId>
+ <version>2.0.3</version>
+ </dependency>
<!-- Plugin integration -->
<dependency>
<artifactId>concepts</artifactId>
<version>${project.version}</version>
</dependency>
- <dependency>
- <groupId>org.glassfish.jersey.ext</groupId>
- <artifactId>jersey-proxy-client</artifactId>
- <version>2.0</version>
- </dependency>
- <dependency>
- <groupId>org.glassfish.jersey.core</groupId>
- <artifactId>jersey-client</artifactId>
- <version>2.0</version>
- </dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
- <version>2.0-m01</version>
+ <version>2.0</version>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<version>1.1.1</version>
</dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.ext</groupId>
+ <artifactId>jersey-proxy-client</artifactId>
+ <version>2.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.core</groupId>
+ <artifactId>jersey-client</artifactId>
+ <version>2.0</version>
+ </dependency>
+
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-model-util</artifactId>
</pluginManagement>
</build>
-</project>
\ No newline at end of file
+</project>
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">
- <modelVersion>4.0.0</modelVersion>
- <artifactId>restconf-client-api</artifactId>
- <packaging>bundle</packaging>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>restconf-client-api</artifactId>
+ <packaging>bundle</packaging>
<parent>
<groupId>org.opendaylight.yangtools</groupId>
<version>0.6.2-SNAPSHOT</version>
</parent>
<dependencies>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>concepts</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-binding</artifactId>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
- <artifactId>concepts</artifactId>
+ <artifactId>yang-common</artifactId>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
- <artifactId>restconf-jaxrs-api</artifactId>
+ <artifactId>yang-data-impl</artifactId>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
- <artifactId>binding-generator-impl</artifactId>
+ <artifactId>yang-model-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
</dependency>
</dependencies>
<build>
*/
package org.opendaylight.yangtools.restconf.client;
-import com.google.common.base.Function;
-import com.google.common.base.Optional;
-import com.sun.jersey.api.client.ClientResponse;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
+
import org.opendaylight.yangtools.restconf.client.to.RestRpcError;
import org.opendaylight.yangtools.restconf.client.to.RestRpcResult;
import org.opendaylight.yangtools.restconf.common.ResourceUri;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSSerializer;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.sun.jersey.api.client.ClientResponse;
+
public class BindingToRestRpc implements InvocationHandler {
private final RestconfClientImpl client;
private final SchemaContext schcemaContext;
private final Module module;
- public BindingToRestRpc(Class proxiedInterface,BindingIndependentMappingService mappingService,RestconfClientImpl client,SchemaContext schemaContext) throws Exception {
+ public BindingToRestRpc(Class<?> proxiedInterface,BindingIndependentMappingService mappingService,RestconfClientImpl client,SchemaContext schemaContext) throws Exception {
this.mappingService = mappingService;
this.client = client;
this.schcemaContext = schemaContext;
*/
package org.opendaylight.yangtools.restconf.client;
-import com.google.common.base.Charsets;
-import com.google.common.base.Function;
-import com.google.common.base.Optional;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.common.util.concurrent.MoreExecutors;
-import com.sun.jersey.api.client.ClientResponse;
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
+
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
+
import javax.ws.rs.core.MediaType;
+
import org.opendaylight.yangtools.concepts.AbstractListenerRegistration;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.restconf.client.api.event.EventStreamInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.base.Charsets;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.sun.jersey.api.client.ClientResponse;
+
<artifactId>restconf-parent</artifactId>
<version>0.6.2-SNAPSHOT</version>
</parent>
+
<artifactId>restconf-common</artifactId>
- <packaging>jar</packaging>
+ <packaging>bundle</packaging>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
</project>
-->
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>restconf-parent</artifactId>
- <version>0.6.2-SNAPSHOT</version>
- </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>restconf-parent</artifactId>
+ <version>0.6.2-SNAPSHOT</version>
+ </parent>
- <artifactId>restconf-jaxrs-api</artifactId>
- <name>restconf-jaxrs-api</name>
+ <artifactId>restconf-jaxrs-api</artifactId>
+ <name>restconf-jaxrs-api</name>
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.glassfish.jersey.ext</groupId>
- <artifactId>jersey-proxy-client</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-data-api</artifactId>
- </dependency>
-
- </dependencies>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>javax.ws.rs</groupId>
+ <artifactId>javax.ws.rs-api</artifactId>
+ </dependency>
+ </dependencies>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<!-- vi: set et smarttab sw=4 tabstop=4: -->
-<!--
- Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
-
- This program and the accompanying materials are made available under the
- terms of the Eclipse Public License v1.0 which accompanies this distribution,
- and is available at http://www.eclipse.org/legal/epl-v10.html
--->
+<!-- Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. This
+ program and the accompanying materials are made available under the terms of the
+ Eclipse Public License v1.0 which accompanies this distribution, and is available
+ at http://www.eclipse.org/legal/epl-v10.html -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>restconf-util</artifactId>
<packaging>jar</packaging>
- <dependencies>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>restconf-jaxrs-api</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-data-api</artifactId>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-data-api</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-data-impl</artifactId>
- </dependency>
- <dependency>
- <groupId>com.sun.jersey</groupId>
- <artifactId>jersey-client</artifactId>
- <version>1.17</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>restconf-client-api</artifactId>
- </dependency>
- <dependency>
- <groupId>commons-io</groupId>
- <artifactId>commons-io</artifactId>
- </dependency>
- <dependency>
- <groupId>xml-apis</groupId>
- <artifactId>xml-apis</artifactId>
- <version>2.0.2</version>
- </dependency>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools.model</groupId>
- <artifactId>ietf-topology-isis</artifactId>
- <version>2013.10.21.2-SNAPSHOT</version>
- <scope>test</scope>
- </dependency>
- </dependencies>
+ <dependencies>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>restconf-client-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>restconf-jaxrs-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-binding</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-common</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-impl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-model-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>javax.ws.rs</groupId>
+ <artifactId>javax.ws.rs-api</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>com.sun.jersey</groupId>
+ <artifactId>jersey-client</artifactId>
+ <version>1.17</version>
+ </dependency>
+ <dependency>
+ <groupId>xml-apis</groupId>
+ <artifactId>xml-apis</artifactId>
+ <version>2.0.2</version>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools.model</groupId>
+ <artifactId>ietf-topology-isis</artifactId>
+ <version>2013.10.21.2-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>binding-generator-impl</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>bug527-test-model</artifactId>
+ <version>0.6.2-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
</project>
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
-import org.eclipse.xtend2.lib.StringConcatenation;
-import org.eclipse.xtext.xbase.lib.Functions;
-import org.eclipse.xtext.xbase.lib.IterableExtensions;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.RpcService;
import org.opendaylight.yangtools.yang.common.QName;
import com.google.common.base.Preconditions;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
+import com.google.common.collect.Iterables;
public class RestconfUtils {
private static final Logger logger = LoggerFactory.getLogger(RestconfUtils.class);
- private static final BiMap<URI,String> uriToModuleName = new Functions.Function0<BiMap<URI,String>>() {
- @Override
- public BiMap<URI,String> apply() {
- HashBiMap<URI,String> _create = HashBiMap.<URI, String>create();
- return _create;
- }
- }.apply();
-
+ private static final BiMap<URI,String> uriToModuleName = HashBiMap.<URI, String>create();
public static Entry<String,DataSchemaNode> toRestconfIdentifier(org.opendaylight.yangtools.yang.binding.InstanceIdentifier<?> bindingIdentifier, BindingIndependentMappingService mappingService, SchemaContext schemaContext) {
InstanceIdentifier domIdentifier = mappingService.toDataDom(bindingIdentifier);
final List<InstanceIdentifier.PathArgument> elements = xmlInstanceIdentifier.getPath();
final StringBuilder ret = new StringBuilder();
- InstanceIdentifier.PathArgument _head = IterableExtensions.<InstanceIdentifier.PathArgument>head(elements);
- final QName startQName = _head.getNodeType();
+ final QName startQName = elements.iterator().next().getNodeType();
URI _namespace = startQName.getNamespace();
Date _revision = startQName.getRevision();
final Module initialModule = schemaContext.findModuleByNamespaceAndRevision(_namespace, _revision);
}
private static CharSequence convertContainerToRestconfIdentifier(final InstanceIdentifier.NodeIdentifier argument, final ContainerSchemaNode node, SchemaContext schemaContext) {
- StringConcatenation _builder = new StringConcatenation();
- _builder.append("/");
- QName _nodeType = argument.getNodeType();
- CharSequence _restconfIdentifier = toRestconfIdentifier(_nodeType,schemaContext);
- _builder.append(_restconfIdentifier, "");
- return _builder;
+ return "/" + toRestconfIdentifier(argument.getNodeType(), schemaContext);
}
+
private static CharSequence convertListToRestconfIdentifier(final InstanceIdentifier.NodeIdentifierWithPredicates argument, final ListSchemaNode node,SchemaContext schemaContext) {
QName _nodeType = argument.getNodeType();
final CharSequence nodeIdentifier = toRestconfIdentifier(_nodeType,schemaContext);
final Map<QName,Object> keyValues = argument.getKeyValues();
- StringConcatenation _builder = new StringConcatenation();
- _builder.append("/");
- _builder.append(nodeIdentifier, "");
- _builder.append("/");
+
+ StringBuilder sb = new StringBuilder("/");
+ sb.append(nodeIdentifier);
+ sb.append('/');
{
List<QName> _keyDefinition = node.getKeyDefinition();
boolean _hasElements = false;
if (!_hasElements) {
_hasElements = true;
} else {
- _builder.appendImmediate("/", "");
+ sb.append('/');
}
Object _get = keyValues.get(key);
- String _uriString = toUriString(_get);
- _builder.append(_uriString, "");
+ sb.append(toUriString(_get));
}
}
- return _builder;
+ return sb.toString();
}
private static String toUriString(final Object object) {
boolean _tripleEquals = (object == null);
String _name_1 = moduleSchema.getName();
module = _name_1;
}
- StringConcatenation _builder = new StringConcatenation();
- _builder.append(module, "");
- _builder.append(":");
- String _localName = qname.getLocalName();
- _builder.append(_localName, "");
- return _builder;
+
+ return module + ':' + qname.getLocalName();
}
private static CharSequence convertToRestconfIdentifier(final InstanceIdentifier.PathArgument argument, final DataNodeContainer node, SchemaContext schemaContext) {
if (argument instanceof InstanceIdentifier.NodeIdentifier
}
private static Module filterLatestModule(final Iterable<Module> modules) {
- Module latestModule = IterableExtensions.<Module>head(modules);
+ Module latestModule = Iterables.getFirst(modules, null);
for (final Module module : modules) {
Date _revision = module.getRevision();
Date _revision_1 = latestModule.getRevision();
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.restconf.utils;
+
+import static junit.framework.Assert.assertNotNull;
+import static org.junit.Assert.*;
+
+import java.io.InputStream;
+
+import javassist.ClassPool;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.yang.bar.rev140321.Alpha;
+import org.opendaylight.yang.gen.v1.urn.yang.bar.rev140321.alpha.Beta;
+import org.opendaylight.yang.gen.v1.urn.yang.bar.rev140321.group.a.xcont.Xchoice;
+import org.opendaylight.yang.gen.v1.urn.yang.bar.rev140321.group.b.xcont.xchoice.Xcase;
+import org.opendaylight.yang.gen.v1.urn.yang.foo.rev140321.Beta1;
+import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
+import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+public class Bug527Test {
+
+ private RuntimeGeneratedMappingServiceImpl mappingService;
+
+ @Before
+ public void setup() {
+ this.mappingService = new RuntimeGeneratedMappingServiceImpl();
+ this.mappingService.setPool(new ClassPool());
+ this.mappingService.init();
+
+ final ModuleInfoBackedContext moduleInfo = ModuleInfoBackedContext.create();
+ moduleInfo.addModuleInfos(BindingReflections.loadModuleInfos());
+ this.mappingService.onGlobalContextUpdated(moduleInfo.tryToCreateSchemaContext().get());
+ }
+
+ @Test
+ public void testToDataObjectMappingWithNestedAugmentations() {
+ InstanceIdentifier<Alpha> alphaId = InstanceIdentifier.builder(Alpha.class).toInstance();
+ InputStream is = this.getClass().getClassLoader().getResourceAsStream("topology-bug527.xml");
+ DataSchemaNode dataSchema = RestconfUtils.toRestconfIdentifier(alphaId, mappingService,
+ mappingService.getSchemaContext()).getValue();
+ Alpha alpha = (Alpha) RestconfUtils.dataObjectFromInputStream(alphaId, is, mappingService.getSchemaContext(),
+ mappingService, dataSchema);
+ assertNotNull(alpha);
+
+ Beta beta = alpha.getBeta();
+ Beta1 beta1 = beta.getAugmentation(Beta1.class);
+
+ Xchoice xchoice = beta1.getXcont().getXchoice();
+ assertNotNull(xchoice);
+
+ Xcase acase = (Xcase) xchoice;
+ assertEquals("idx2", acase.getIdx());
+ }
+
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!-- Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. This
+ program and the accompanying materials are made available under the terms of the
+ Eclipse Public License v1.0 which accompanies this distribution, and is available
+ at http://www.eclipse.org/legal/epl-v10.html -->
+<alpha xmlns="urn:yang:bar">
+ <beta>
+ <xcont xmlns="urn:yang:foo">
+ <idx>idx2</idx>
+ </xcont>
+ </beta>
+</alpha>
<packaging>jar</packaging>
<dependencies>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec-http</artifactId>
*/
package org.opendaylight.yangtools.websocket;
-import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
import java.net.URI;
import java.net.URISyntaxException;
+
import org.junit.Before;
import org.junit.Test;
-import org.opendaylight.yangtools.websocket.client.WebSocketIClient;
-import org.opendaylight.yangtools.websocket.server.WebSocketServer;
+import org.junit.Assert;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.opendaylight.yangtools.websocket.client.WebSocketIClient;
+import org.opendaylight.yangtools.websocket.server.WebSocketServer;
+
+import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
+
+import com.google.common.util.concurrent.SettableFuture;
+
public class WebSocketClientTest {
private static final Logger logger = LoggerFactory.getLogger(WebSocketClientTest.class.toString());
private static final String MESSAGE = "Take me to your leader!";
- private static final int port = 8080;
private Thread webSocketServerThread;
+ /**
+ * Tracks if the message from the server has been received
+ */
+ private SettableFuture<Boolean> messageReceived = SettableFuture.<Boolean>create();
+
+ /**
+ * Tracks the port on which the server is listening
+ */
+ private int port = 0;
@Before
public void startWebSocketServer(){
try {
- WebSocketServer webSocketServer = new WebSocketServer(port);
+ WebSocketServer webSocketServer = new WebSocketServer(0);
webSocketServerThread = new Thread(webSocketServer);
webSocketServerThread.setDaemon(false);
webSocketServerThread.start();
+ port = webSocketServer.getPort().get();
} catch (Exception e) {
logger.trace("Error starting websocket server");
}
}
+
@Test
public void connectAndSendData(){
URI uri = null;
try {
- uri = new URI("ws://localhost:8080/websocket");
+ uri = new URI(String.format("ws://localhost:%d/websocket", port));
+ logger.info("CLIENT: " + uri);
ClientMessageCallback messageCallback = new ClientMessageCallback();
WebSocketIClient wsClient = new WebSocketIClient(uri,messageCallback);
try {
wsClient.connect();
wsClient.writeAndFlush(MESSAGE);
wsClient.writeAndFlush(new CloseWebSocketFrame());
+
+ /*
+ * Wait for up to 5 seconds for the message to be received. If
+ * after that time, the message has not been received then
+ * consider this a failed test.
+ */
+ messageReceived.get(5, TimeUnit.SECONDS);
+
webSocketServerThread.interrupt();
} catch (InterruptedException e) {
- logger.info("WebSocket client couldn't connect to : "+uri);
+ logger.info("WebSocket client couldn't connect to : " + uri);
+ Assert.fail("WebSocker client could not connect to : " + uri);
+ } catch (ExecutionException | TimeoutException toe) {
+ logger.info("Message not received");
+ Assert.fail(toe.toString());
}
} catch (URISyntaxException e) {
logger.info("There is an error in URL sytnax {}",e);
+ Assert.fail("There is an error in URL sytnax");
}
}
private class ClientMessageCallback implements org.opendaylight.yangtools.websocket.client.callback.ClientMessageCallback {
@Override
public void onMessageReceived(Object message) {
- logger.info("received message {}",message);
- System.out.println("received message : " + message);
+ logger.info("received message {}",message);
+ messageReceived.set(true);
}
}
}
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.net.SocketAddress;
+import java.net.InetSocketAddress;
+
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+
+import com.google.common.util.concurrent.SettableFuture;
+
/**
* A HTTP server which serves Web Socket requests at:
*
*/
public class WebSocketServer implements Runnable {
- private final int port;
+ /**
+ * Utilized to get the port on which the server listens. This is a future as
+ * the port is selected dynamically from available ports, thus until the
+ * server is started the value will not be established.
+ */
+ private final SettableFuture<Integer> port;
+
+ /**
+ * Maintains the port number with which the class was initialized.
+ */
+ private final int inPort;
private final ServerBootstrap bootstrap = new ServerBootstrap();
private final EventLoopGroup bossGroup = new NioEventLoopGroup();
private final EventLoopGroup workerGroup = new NioEventLoopGroup();
private static final Logger logger = LoggerFactory.getLogger(WebSocketServer.class.toString());
- public WebSocketServer(int port) {
- this.port = port;
+
+ public WebSocketServer(int inPort) {
+ this.inPort = inPort;
+ port = SettableFuture.<Integer>create();
}
- /**
- * Tries to start web socket server.
- */
public void run(){
try {
startServer();
logger.info("Exception occured while starting webSocket server {}",e);
}
}
-
- /**
- * Start web socket server at {@link #port}.
- * @throws Exception
- */
+
+ public Future<Integer> getPort() {
+ return port;
+ }
+
public void startServer() throws Exception {
try {
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new WebSocketServerInitializer());
- Channel ch = bootstrap.bind(port).sync().channel();
- logger.info("Web socket server started at port " + port + '.');
- logger.info("Open your browser and navigate to http://localhost:" + port + '/');
+ Channel ch = bootstrap.bind(inPort).sync().channel();
+ SocketAddress localSocket = ch.localAddress();
+ try {
+ port.set(((InetSocketAddress) localSocket).getPort());
+ } catch (ClassCastException cce) {
+ throw new ExecutionException("Unknown socket address type", cce);
+ }
+ logger.info("Web socket server started at port " + port.get() + '.');
+ logger.info("Open your browser and navigate to http://localhost:" + port.get() + '/');
- ch.closeFuture().sync();
+ try {
+ ch.closeFuture().sync();
+ } catch (InterruptedException ie) {
+ // No op, sometimes the server is shutdown hard
+ }
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
-
-
}
<module>yang-data-api</module>
<module>yang-data-util</module>
<module>yang-data-impl</module>
+ <module>yang-data-operations</module>
<module>yang-model-api</module>
<module>yang-maven-plugin</module>
<module>yang-maven-plugin-it</module>
<module>yang-model-util</module>
<module>yang-parser-api</module>
<module>yang-parser-impl</module>
+ <module>yang-data-json</module>
</modules>
<properties>
<artifactId>yang-data-api</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-impl</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-json</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-data-util</artifactId>
import com.google.common.collect.Iterables;
/**
- * Uniquely identifies data location in the overall of data tree
- * modeled by YANG.
*
+ * This instance identifier uniquely identifies a specific DataObject in the data tree modeled by YANG.
+ *
+ * For Example let's say you were trying to refer to a node in inventory which was modeled in YANG as follows,
+ *
+ * <pre>
+ * module opendaylight-inventory {
+ * ....
+ *
+ * container nodes {
+ * list node {
+ * key "id";
+ * ext:context-instance "node-context";
+ *
+ * uses node;
+ * }
+ * }
+ *
+ * }
+ * </pre>
+ *
+ * You could create an instance identifier as follows to get to a node with id "openflow:1"
+ *
+ * InstanceIdentifierBuilder.builder(Nodes.class).child(Node.class, new NodeKey(new NodeId("openflow:1")).build();
+ *
+ * This would be the same as using a path like so, "/nodes/node/openflow:1" to refer to the openflow:1 node
*
*/
public final class InstanceIdentifier<T extends DataObject> implements Path<InstanceIdentifier<? extends DataObject>>,Immutable {
private final List<PathArgument> path;
private final Class<T> targetType;
+ /**
+ * Create an instance identifier for a very specific object type.
+ *
+ * For example
+ * <pre>
+ * new InstanceIdentifier(Nodes.class)
+ * </pre>
+ * would create an InstanceIdentifier for an object of type Nodes
+ *
+ * @param type The type of the object which this instance identifier represents
+ */
public InstanceIdentifier(Class<T> type) {
- path = Collections.<PathArgument> singletonList(new Item<>(type));
- this.targetType = type;
+ this(Collections.<PathArgument> singletonList(new Item<>(type)), type);
}
+ /**
+ * Create an instance identifier for a very specific object type.
+ *
+ * Example
+ * <pre>
+ * List<PathArgument> path = Arrays.asList(new Item(Nodes.class))
+ * new InstanceIdentifier(path, Nodes.class);
+ * </pre>
+ *
+ * @param path The path to a specific node in the data tree
+ * @param type The type of the object which this instance identifier represents
+ */
public InstanceIdentifier(List<PathArgument> path, Class<T> type) {
this.path = ImmutableList.copyOf(path);
this.targetType = type;
/**
*
- * @return path
+ * @return A list of the elements of the path
*/
public List<PathArgument> getPath() {
return getPathArguments();
}
+ /**
+ *
+ * @return A list of the elements of the path
+ */
+
public List<PathArgument> getPathArguments() {
return this.path;
}
+ /**
+ *
+ * @return The target type of this instance identifier
+ */
public Class<T> getTargetType() {
return this.targetType;
}
* Return an instance identifier trimmed at the first occurrence of a
* specific component type.
*
+ * For example let's say an instance identifier was built like so,
+ * <pre>
+ * identifier = InstanceIdentifierBuilder.builder(Nodes.class).child(Node.class, new NodeKey(new NodeId("openflow:1")).build();
+ * </pre>
+ *
+ * And you wanted to obtain the Instance identifier which represented Nodes you would do it like so,
+ *
+ * <pre>
+ * identifier.firstIdentifierOf(Nodes.class)
+ * </pre>
+ *
* @param type component type
* @return trimmed instance identifier, or null if the component type
* is not present.
Class<? extends DataObject> getType();
}
+
+ /**
+ * An Item represents an object that probably is only one of it's kind. For example a Nodes object is only one of
+ * a kind. In YANG terms this would probably represent a container.
+ *
+ * @param <T>
+ */
public static final class Item<T extends DataObject> implements PathArgument {
private final Class<T> type;
}
}
+ /**
+ * An IdentifiableItem represents a object that is usually present in a collection and can be identified uniquely
+ * by a key. In YANG terms this would probably represent an item in a list.
+ *
+ * @param <I> An object that is identifiable by an identifier
+ * @param <T> The identifier of the object
+ */
public static final class IdentifiableItem<I extends Identifiable<T> & DataObject, T extends Identifier<I>> implements
PathArgument {
<N extends Identifiable<K> & DataObject, K extends Identifier<N>> InstanceIdentifierBuilder<N> node(
Class<N> listItem, K listKey);
+ /**
+ * Append the specified container as a child of the current InstanceIdentifier referenced by the builder.
+ *
+ * This method should be used when you want to build an instance identifier by appending top-level
+ * elements
+ *
+ * Example,
+ * <pre>
+ * InstanceIdentifier.builder().child(Nodes.class).build();
+ *
+ * </pre>
+ *
+ * NOTE :- The above example is only for illustration purposes InstanceIdentifier.builder() has been deprecated
+ * and should not be used. Use InstanceIdentifier.builder(Nodes.class) instead
+ *
+ * @param container
+ * @param <N>
+ * @return
+ */
<N extends ChildOf<? super T>> InstanceIdentifierBuilder<N> child(Class<N> container);
+ /**
+ * Append the specified listItem as a child of the current InstanceIdentifier referenced by the builder.
+ *
+ * This method should be used when you want to build an instance identifier by appending a specific list element
+ * to the identifier
+ *
+ * @param listItem
+ * @param listKey
+ * @param <N>
+ * @param <K>
+ * @return
+ */
<N extends Identifiable<K> & ChildOf<? super T>, K extends Identifier<N>> InstanceIdentifierBuilder<N> child(
Class<N> listItem, K listKey);
+ /**
+ * Build an identifier which refers to a specific augmentation of the current InstanceIdentifier referenced by
+ * the builder
+ *
+ * @param container
+ * @param <N>
+ * @return
+ */
<N extends DataObject & Augmentation<? super T>> InstanceIdentifierBuilder<N> augmentation(Class<N> container);
+ /**
+ * Build the instance identifier.
+ *
+ * @return
+ */
InstanceIdentifier<T> build();
}
return new BuilderImpl();
}
+ /**
+ * Create an InstanceIdentifierBuilder for a specific type of InstanceIdentifier as specified by container
+ *
+ * @param container
+ * @param <T>
+ * @return
+ */
public static <T extends ChildOf<? extends DataRoot>> InstanceIdentifierBuilder<T> builder(Class<T> container) {
return new BuilderImpl<T>().addNode(container);
}
+ /**
+ * Create an InstanceIdentifierBuilder for a specific type of InstanceIdentifier which represents an IdentifiableItem
+ *
+ * @param listItem
+ * @param listKey
+ * @param <N>
+ * @param <K>
+ * @return
+ */
public static <N extends Identifiable<K> & ChildOf<? extends DataRoot>, K extends Identifier<N>> InstanceIdentifierBuilder<N> builder(
Class<N> listItem, K listKey) {
return new BuilderImpl<N>().addNode(listItem, listKey);
}
+ /**
+ * Create a new InstanceIdentifierBuilder given a base InstanceIdentifier
+ *
+ * @param basePath
+ * @param <T>
+ * @return
+ */
public static <T extends DataObject> InstanceIdentifierBuilder<T> builder(InstanceIdentifier<T> basePath) {
return new BuilderImpl<T>(basePath.path,basePath.targetType);
}
return true;
}
+ /**
+ * The contains method checks if the other identifier is fully contained within the current identifier. It does this
+ * by looking at only the types of the path arguments and not by comparing the path arguments themselse.
+ * If you want to compare path arguments you must use containsWildcarded
+ *
+ * To illustrate here is an example which explains the working of this api.
+ *
+ * Let's say you have two instance identifiers as follows,
+ *
+ * this = /nodes/node/openflow:1
+ * other = /nodes/node/openflow:2
+ *
+ * then this.contains(other) will return true. To ensure that this and other are compared properly you must use
+ * containsWildcarded
+ *
+ * @param other
+ * @return
+ */
@Override
public boolean contains(final InstanceIdentifier<?> other) {
if(other == null) {
return true;
}
+ /**
+ * The containsWildcarded method checks if the other identifier is fully contained within the current identifier.
+ * It does this by looking at both the type and identity of the path arguments.
+ *
+ * @param other
+ * @return
+ */
public boolean containsWildcarded(final InstanceIdentifier<?> other) {
if(other == null) {
throw new IllegalArgumentException("other should not be null");
*/
package org.opendaylight.yangtools.yang.binding.test;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@Test
public void constructWithPredicates() {
-
+
InstanceIdentifier<Nodes> nodes = InstanceIdentifier.builder(Nodes.class).toInstance();
-
+
assertNotNull(nodes);
assertEquals(Nodes.class, nodes.getTargetType());
-
-
- InstanceIdentifier<Node> node = InstanceIdentifier.builder(nodes).node(Node.class).toInstance();
-
+
+
+ InstanceIdentifier<Node> node = InstanceIdentifier.builder(nodes).child(Node.class).toInstance();
+
assertNotNull(node);
assertEquals(Node.class, node.getTargetType());
-
+
assertTrue(nodes.contains(node));
}
assertTrue(nodes.contains(node));
}
-
-
+
+
@Test
public void negativeContains() {
InstanceIdentifier<FooChild> fooChild = InstanceIdentifier.builder(Nodes.class).child(InstantiatedFoo.class).child(FooChild.class).build();
-
+
InstanceIdentifier<Node> nodeTen = InstanceIdentifier.builder(Nodes.class) //
.child(Node.class,new NodeKey(10)).toInstance();
InstanceIdentifier<Node> nodeOne = InstanceIdentifier.builder(Nodes.class) //
.child(Node.class,new NodeKey(1)).toInstance();
InstanceIdentifier<Nodes> nodes = InstanceIdentifier.builder(Nodes.class).toInstance();
-
+
assertFalse(fooChild.contains(nodeTen));
assertFalse(nodeTen.contains(nodes));
-
+
assertFalse(nodeOne.contains(nodes));
assertTrue(nodes.contains(nodeOne));
}
-
+
@Test
public void containsWildcarded() {
InstanceIdentifier<Nodes> nodes = InstanceIdentifier.builder(Nodes.class).toInstance();
InstanceIdentifier<NodeChild> wildcardedChildren = InstanceIdentifier.builder(Nodes.class) //
.child(Node.class) //
.child(NodeChild.class).build();
-
+
assertTrue(wildcarded.isWildcarded());
assertTrue(wildcardedChildren.isWildcarded());
-
-
+
+
InstanceIdentifier<Node> nodeTen = InstanceIdentifier.builder(Nodes.class) //
.child(Node.class,new NodeKey(10)).toInstance();
InstanceIdentifier<Node> nodeOne = InstanceIdentifier.builder(Nodes.class) //
.child(Node.class,new NodeKey(1)).toInstance();
-
+
assertFalse(nodeTen.isWildcarded());
assertFalse(nodeOne.isWildcarded());
assertTrue(nodes.containsWildcarded(nodeOne));
assertTrue(wildcarded.containsWildcarded(nodeOne));
assertTrue(wildcarded.containsWildcarded(nodeTen));
-
-
+
+
InstanceIdentifier<NodeChild> nodeTenChildWildcarded = InstanceIdentifier.builder(Nodes.class) //
.child(Node.class,new NodeKey(10)).child(NodeChild.class).toInstance();
-
+
assertTrue(nodeTenChildWildcarded.isWildcarded());
-
+
InstanceIdentifier<NodeChild> nodeTenChild = InstanceIdentifier.builder(Nodes.class) //
.child(Node.class,new NodeKey(10)).child(NodeChild.class, new NodeChildKey(10)).toInstance();
InstanceIdentifier<NodeChild> nodeOneChild = InstanceIdentifier.builder(Nodes.class) //
.child(Node.class,new NodeKey(1)).child(NodeChild.class, new NodeChildKey(1)).toInstance();
-
+
assertFalse(nodeTenChildWildcarded.containsWildcarded(nodeOneChild));
assertTrue(nodeTenChildWildcarded.containsWildcarded(nodeTenChild));
-
+
}
-
-
+
+
void childOfTest() {
InstanceIdentifier.builder(Nodes.class).child(InstantiatedFoo.class).child(FooChild.class);
}
public class NodeChildKey implements //
Identifier<NodeChild> {
-
- private final int id;
+ private static final long serialVersionUID = 1L;
+ private final int id;
public NodeChildKey(int id) {
super();
public class NodeKey implements //
Identifier<Node> {
-
- private final int id;
+ private static final long serialVersionUID = 1L;
+ private final int id;
public NodeKey(int id) {
super();
*
*
*/
-public final class QName implements Immutable,Serializable {
+public final class QName implements Immutable, Serializable, Comparable<QName> {
private static final long serialVersionUID = 5398411242927766414L;
public boolean isEqualWithoutRevision(QName other) {
return localName.equals(other.getLocalName()) && Objects.equals(namespace, other.getNamespace());
}
+
+ @Override
+ public int compareTo(QName other) {
+ // compare mandatory localName parameter
+ int result = localName.compareTo(other.localName);
+ if (result != 0) {
+ return result;
+ }
+
+ // compare nullable namespace parameter
+ if (namespace == null) {
+ if (other.namespace != null) {
+ return -1;
+ }
+ } else {
+ if (other.namespace == null) {
+ return 1;
+ }
+ result = namespace.compareTo(other.namespace);
+ if (result != 0) {
+ return result;
+ }
+ }
+
+ // compare nullable revision parameter
+ if (revision == null) {
+ if (other.revision != null) {
+ return -1;
+ }
+ } else {
+ if (other.revision == null) {
+ return 1;
+ }
+ result = revision.compareTo(other.revision);
+ if (result != 0) {
+ return result;
+ }
+ }
+
+ return result;
+ }
+
}
import java.net.URI;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
+import static org.junit.Assert.*;
public class QNameTest {
private final String namespace = "urn:foo", revision = "2013-12-24", localName = "bar";
assertLocalNameFails("&");
}
+ @Test
+ public void testCompareTo() throws Exception {
+ String A = "a";
+ String B = "b";
+
+ QName a = QName.create(A);
+ QName b = QName.create(A);
+ assertTrue(a.compareTo(b) == 0);
+ assertTrue(b.compareTo(a) == 0);
+
+ // compare with localName
+ a = QName.create(A);
+ b = QName.create(B);
+ assertTrue(a.compareTo(b) < 0);
+ assertTrue(b.compareTo(a) > 0);
+
+ // compare with namespace
+ a = QName.create(A, revision, A);
+ b = QName.create(B, revision, A);
+ assertTrue(a.compareTo(b) < 0);
+ assertTrue(b.compareTo(a) > 0);
+
+ // compare with 1 null namespace
+ a = new QName(null, QName.parseRevision(revision), A);
+ b = new QName(URI.create(A), QName.parseRevision(revision), A);
+ assertTrue(a.compareTo(b) < 0);
+ assertTrue(b.compareTo(a) > 0);
+
+ // compare with both null namespace
+ b = new QName(null, QName.parseRevision(revision), A);
+ assertTrue(a.compareTo(b) == 0);
+ assertTrue(b.compareTo(a) == 0);
+
+ // compare with revision
+ a = QName.create(A, "2013-12-24", A);
+ b = QName.create(A, "2013-12-25", A);
+ assertTrue(a.compareTo(b) < 0);
+ assertTrue(b.compareTo(a) > 0);
+
+ // compare with 1 null revision
+ a = new QName(URI.create(A), null, A);
+ b = new QName(URI.create(A), QName.parseRevision(revision), A);
+ assertTrue(a.compareTo(b) < 0);
+ assertTrue(b.compareTo(a) > 0);
+
+ // compare with both null revision
+ b = new QName(URI.create(A), null, A);
+ assertTrue(a.compareTo(b) == 0);
+ assertTrue(b.compareTo(a) == 0);
+ }
+
private void assertLocalNameFails(String localName) {
try {
new QName((URI)null, localName);
return childNames;
}
+ @Override
+ public String toString() {
+ final StringBuffer sb = new StringBuffer("AugmentationIdentifier{");
+ sb.append("childNames=").append(childNames);
+ sb.append('}');
+ return sb.toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof AugmentationIdentifier)) return false;
+
+ AugmentationIdentifier that = (AugmentationIdentifier) o;
+
+ if (childNames != null ? !childNames.equals(that.childNames) : that.childNames != null) return false;
+ if (nodeType != null ? !nodeType.equals(that.nodeType) : that.nodeType != null) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = nodeType != null ? nodeType.hashCode() : 0;
+ result = 31 * result + (childNames != null ? childNames.hashCode() : 0);
+ return result;
+ }
}
private static class BuilderImpl implements InstanceIdentifierBuilder {
*/
package org.opendaylight.yangtools.yang.data.api.schema;
+import org.opendaylight.yangtools.yang.data.api.AttributesContainer;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
import com.google.common.base.Optional;
public interface ContainerNode extends //
+ AttributesContainer,
DataContainerNode<NodeIdentifier>,
DataContainerChild<NodeIdentifier, Iterable<DataContainerChild<? extends PathArgument, ?>>> {
*/
package org.opendaylight.yangtools.yang.data.api.schema;
+import org.opendaylight.yangtools.yang.data.api.AttributesContainer;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
public interface LeafNode<T> extends //
+ AttributesContainer,
DataContainerChild<NodeIdentifier, T> {
@Override
*/
package org.opendaylight.yangtools.yang.data.api.schema;
+import org.opendaylight.yangtools.yang.data.api.AttributesContainer;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeWithValue;
-public interface LeafSetEntryNode<T> extends NormalizedNode<NodeWithValue, T> {
+public interface LeafSetEntryNode<T> extends
+ AttributesContainer,
+ NormalizedNode<NodeWithValue, T> {
@Override
public NodeWithValue getIdentifier();
*/
package org.opendaylight.yangtools.yang.data.api.schema;
+import org.opendaylight.yangtools.yang.data.api.AttributesContainer;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
-public interface MapEntryNode extends DataContainerNode<NodeIdentifierWithPredicates> {
+public interface MapEntryNode extends
+ AttributesContainer,
+ DataContainerNode<NodeIdentifierWithPredicates> {
@Override
public NodeIdentifierWithPredicates getIdentifier();
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
- <artifactId>yang-binding</artifactId>
+ <artifactId>yang-model-api</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
- <artifactId>yang-parser-impl</artifactId>
- <exclusions>
- <exclusion>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-simple</artifactId>
- </exclusion>
- </exclusions>
+ <artifactId>yang-model-util</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>yang-binding</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<version>1.5</version>
<scope>test</scope>
</dependency>
- <dependency>
- <groupId>commons-lang</groupId>
- <artifactId>commons-lang</artifactId>
- <version>2.6</version>
- </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>yang-parser-impl</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>commons-lang</groupId>
+ <artifactId>commons-lang</artifactId>
+ <version>2.6</version>
+ </dependency>
</dependencies>
</project>
import com.google.common.io.BaseEncoding;
public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> implements DataStringCodec<J> {
-
+
private static final Pattern intPattern = Pattern.compile("[+-]?[1-9][0-9]*$");
private static final Pattern hexPattern = Pattern.compile("[+-]?0[xX][0-9a-fA-F]+");
private static final Pattern octalPattern = Pattern.compile("[+-]?0[1-7][0-7]*$");
-
+
private final Optional<T> typeDefinition;
private final Class<J> inputClass;
-
+
private static final int provideBase(final String integer) {
if (integer == null) {
throw new IllegalArgumentException("String representing integer number cannot be NULL!");
}
-
+
if ((integer.length() == 1) && (integer.charAt(0) == '0')) {
return 10;
}
-
+
final Matcher intMatcher = intPattern.matcher(integer);
if (intMatcher.matches()) {
return 10;
if (octMatcher.matches()) {
return 8;
} else {
- throw new NumberFormatException("Incorrect lexical representation of Integer value!"
+ throw new NumberFormatException("Incorrect lexical representation of Integer value: " + integer
+ "The Integer value can be defined as Integer Number, Hexadecimal Number or"
+ "Octal Number. The sign vlues are allowed. "
+ "Spaces between digits are NOT allowed!");
}
}
}
-
+
private static String normalizeHexadecimal(final String hexInt) {
if (hexInt == null) {
throw new IllegalArgumentException(
}
return normalizedString;
}
-
+
public static final BinaryCodecStringImpl BINARY_DEFAULT_CODEC = new BinaryCodecStringImpl(
Optional.<BinaryTypeDefinition> absent());
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
-import com.google.common.collect.Maps;
import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.*;
+import org.opendaylight.yangtools.yang.data.api.AttributesContainer;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeWithValue;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.ModifyAction;
import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.api.SimpleNode;
import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl;
import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec;
import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.w3c.dom.*;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
import com.google.common.base.Function;
import com.google.common.base.Objects;
package org.opendaylight.yangtools.yang.data.impl.schema;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.*;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.*;
-import org.opendaylight.yangtools.yang.model.api.*;
-
-public class Builders {
-
- public static <T> NormalizedNodeBuilder<InstanceIdentifier.NodeIdentifier, T, LeafNode<T>> leafBuilder() {
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableAugmentationNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableAugmentationNodeSchemaAwareBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableChoiceNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableChoiceNodeSchemaAwareBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeSchemaAwareBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafNodeSchemaAwareBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetEntryNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetEntryNodeSchemaAwareBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetNodeSchemaAwareBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapEntryNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapEntryNodeSchemaAwareBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeSchemaAwareBuilder;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+public final class Builders {
+
+ private Builders() {
+ throw new UnsupportedOperationException("Utilities class should not be instantiated");
+ }
+
+ public static <T> NormalizedNodeAttrBuilder<InstanceIdentifier.NodeIdentifier, T, LeafNode<T>> leafBuilder() {
return ImmutableLeafNodeBuilder.create();
}
- public static <T> NormalizedNodeBuilder<InstanceIdentifier.NodeIdentifier, T, LeafNode<T>> leafBuilder(
- LeafSchemaNode schema) {
+ public static <T> NormalizedNodeAttrBuilder<InstanceIdentifier.NodeIdentifier, T, LeafNode<T>> leafBuilder(
+ final LeafSchemaNode schema) {
return ImmutableLeafNodeSchemaAwareBuilder.create(schema);
}
- public static <T> NormalizedNodeBuilder<InstanceIdentifier.NodeWithValue, T, LeafSetEntryNode<T>> leafSetEntryBuilder() {
+ public static <T> NormalizedNodeAttrBuilder<InstanceIdentifier.NodeWithValue, T, LeafSetEntryNode<T>> leafSetEntryBuilder() {
return ImmutableLeafSetEntryNodeBuilder.create();
}
- public static <T> NormalizedNodeBuilder<InstanceIdentifier.NodeWithValue, T, LeafSetEntryNode<T>> leafSetEntryBuilder(
- LeafListSchemaNode schema) {
+ public static <T> NormalizedNodeAttrBuilder<InstanceIdentifier.NodeWithValue, T, LeafSetEntryNode<T>> leafSetEntryBuilder(
+ final LeafListSchemaNode schema) {
return ImmutableLeafSetEntryNodeSchemaAwareBuilder.create(schema);
}
- public static <T> ListNodeBuilder<T, LeafSetEntryNode<T>> leafSetBuilder() {
+ public static <T> ListNodeBuilder<T,LeafSetEntryNode<T>> leafSetBuilder() {
return ImmutableLeafSetNodeBuilder.create();
}
- public static <T> ListNodeBuilder<T, LeafSetEntryNode<T>> leafSetBuilder(LeafListSchemaNode schema) {
- return ImmutableLeafSetNodeSchemaAwareBuilder.create(schema);
+ public static <T> ListNodeBuilder<T,LeafSetEntryNode<T>> leafSetBuilder(final LeafSetNode<T> node) {
+ return ImmutableLeafSetNodeBuilder.create(node);
+ }
+
+ public static <T> ListNodeBuilder<T,LeafSetEntryNode<T>> leafSetBuilder(final LeafListSchemaNode schema) {
+ return ImmutableLeafSetNodeSchemaAwareBuilder.<T>create(schema);
}
- public static DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifier, ContainerNode> containerBuilder() {
+ public static <T> ListNodeBuilder<T,LeafSetEntryNode<T>> leafSetBuilder(final LeafListSchemaNode schema, final LeafSetNode<T> node) {
+ return ImmutableLeafSetNodeSchemaAwareBuilder.<T>create(schema, node);
+ }
+
+ public static DataContainerNodeAttrBuilder<InstanceIdentifier.NodeIdentifier, ContainerNode> containerBuilder() {
return ImmutableContainerNodeBuilder.create();
}
- public static DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifier, ContainerNode> containerBuilder(
- ContainerSchemaNode schema) {
+ public static DataContainerNodeAttrBuilder<InstanceIdentifier.NodeIdentifier, ContainerNode> containerBuilder(final ContainerNode node) {
+ return ImmutableContainerNodeBuilder.create(node);
+ }
+
+ public static DataContainerNodeAttrBuilder<InstanceIdentifier.NodeIdentifier, ContainerNode> containerBuilder(
+ final ContainerSchemaNode schema) {
return ImmutableContainerNodeSchemaAwareBuilder.create(schema);
}
- public static DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder() {
+ public static DataContainerNodeAttrBuilder<InstanceIdentifier.NodeIdentifier, ContainerNode> containerBuilder(
+ final ContainerSchemaNode schema, final ContainerNode node) {
+ return ImmutableContainerNodeSchemaAwareBuilder.create(schema, node);
+ }
+
+ public static DataContainerNodeAttrBuilder<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder() {
return ImmutableMapEntryNodeBuilder.create();
}
- public static DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder(
- ListSchemaNode schema) {
+ public static DataContainerNodeAttrBuilder<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder(
+ final ListSchemaNode schema) {
return ImmutableMapEntryNodeSchemaAwareBuilder.create(schema);
}
return ImmutableMapNodeBuilder.create();
}
- public static CollectionNodeBuilder<MapEntryNode, MapNode> mapBuilder(ListSchemaNode schema) {
+ public static CollectionNodeBuilder<MapEntryNode, MapNode> mapBuilder(final MapNode node) {
+ return ImmutableMapNodeBuilder.create(node);
+ }
+
+ public static CollectionNodeBuilder<MapEntryNode, MapNode> mapBuilder(final ListSchemaNode schema) {
return ImmutableMapNodeSchemaAwareBuilder.create(schema);
}
+ public static CollectionNodeBuilder<MapEntryNode, MapNode> mapBuilder(final ListSchemaNode schema, final MapNode node) {
+ return ImmutableMapNodeSchemaAwareBuilder.create(schema, node);
+ }
+
public static DataContainerNodeBuilder<InstanceIdentifier.AugmentationIdentifier, AugmentationNode> augmentationBuilder() {
return ImmutableAugmentationNodeBuilder.create();
}
- public static DataContainerNodeBuilder<InstanceIdentifier.AugmentationIdentifier, AugmentationNode> augmentationBuilder(AugmentationSchema schema) {
+ public static DataContainerNodeBuilder<InstanceIdentifier.AugmentationIdentifier, AugmentationNode> augmentationBuilder(final AugmentationSchema schema) {
return ImmutableAugmentationNodeSchemaAwareBuilder.create(schema);
}
return ImmutableChoiceNodeBuilder.create();
}
- public static DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifier, ChoiceNode> choiceBuilder(org.opendaylight.yangtools.yang.model.api.ChoiceNode schema) {
+ public static DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifier, ChoiceNode> choiceBuilder(final org.opendaylight.yangtools.yang.model.api.ChoiceNode schema) {
return ImmutableChoiceNodeSchemaAwareBuilder.create(schema);
}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapEntryNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeBuilder;
+
+public final class ImmutableNodes {
+
+ private ImmutableNodes() {
+ throw new UnsupportedOperationException("Utilities class should not be instantiated");
+ }
+
+ public static final CollectionNodeBuilder<MapEntryNode, MapNode> mapNodeBuilder() {
+ return ImmutableMapNodeBuilder.create();
+ }
+
+ public static final CollectionNodeBuilder<MapEntryNode, MapNode> mapNodeBuilder(final QName name) {
+ return ImmutableMapNodeBuilder.create().withNodeIdentifier(new NodeIdentifier(name));
+ }
+
+ public static final <T> LeafNode<T> leafNode(final QName name,final T value) {
+ return ImmutableLeafNodeBuilder.<T>create()
+ .withNodeIdentifier(new NodeIdentifier(name))
+ .withValue(value)
+ .build();
+ }
+
+ public static DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder(final QName nodeName,final QName keyName,final Object keyValue) {
+ return ImmutableMapEntryNodeBuilder.create()
+ .withNodeIdentifier(new NodeIdentifierWithPredicates(nodeName, keyName,keyValue))
+ .withChild(leafNode(keyName, keyValue));
+ }
+
+ public static MapEntryNode mapEntry(final QName nodeName,final QName keyName,final Object keyValue) {
+ return mapEntryBuilder(nodeName, keyName, keyValue).build();
+ }
+
+ public static DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder() {
+ return ImmutableMapEntryNodeBuilder.create();
+ }
+
+ public static NormalizedNode<?, ?> containerNode(final QName name) {
+ return ImmutableContainerNodeBuilder.create().withNodeIdentifier(new NodeIdentifier(name)).build();
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Iterator;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+import com.google.common.base.Optional;
+
+public final class NormalizedNodeUtils {
+ private NormalizedNodeUtils() {
+ throw new UnsupportedOperationException("Utilities class should not be instantiated");
+ }
+
+ public static Optional<NormalizedNode<?, ?>> findNode(final InstanceIdentifier rootPath, final NormalizedNode<?, ?> rootNode, final InstanceIdentifier childPath) {
+ if(rootPath.contains(childPath)) {
+ int common = rootPath.getPath().size();
+ InstanceIdentifier relativePath = new InstanceIdentifier(childPath.getPath().subList(common, childPath.getPath().size()));
+ return findNode(rootNode, relativePath);
+ }
+ return Optional.absent();
+ }
+
+ public static Optional<NormalizedNode<?, ?>> findNode(final NormalizedNode<?, ?> tree, final InstanceIdentifier path) {
+ checkNotNull(tree, "Tree must not be null");
+ checkNotNull(path, "Path must not be null");
+
+ Optional<NormalizedNode<?, ?>> currentNode = Optional.<NormalizedNode<?, ?>> of(tree);
+ Iterator<PathArgument> pathIterator = path.getPath().iterator();
+ while (currentNode.isPresent() && pathIterator.hasNext()) {
+ currentNode = getDirectChild(currentNode.get(), pathIterator.next());
+ }
+ return currentNode;
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public static Optional<NormalizedNode<?, ?>> getDirectChild(final NormalizedNode<?, ?> node, final PathArgument pathArg) {
+ if (node instanceof LeafNode<?> || node instanceof LeafSetEntryNode<?>) {
+ return Optional.absent();
+ } else if (node instanceof DataContainerNode<?>) {
+ return (Optional) ((DataContainerNode<?>) node).getChild(pathArg);
+ } else if (node instanceof MapNode && pathArg instanceof NodeIdentifierWithPredicates) {
+ return (Optional) ((MapNode) node).getChild((NodeIdentifierWithPredicates) pathArg);
+ } else if (node instanceof LeafSetNode<?>) {
+ return (Optional) ((LeafSetNode<?>) node).getChild((NodeWithValue) pathArg);
+ }
+ return Optional.absent();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.builder.api;
+
+import java.util.Map;
+
+import org.opendaylight.yangtools.yang.common.QName;
+
+public interface AttributesBuilder<B> {
+ /**
+ * Attach a map of attributes. The map is expected to remain unchanged,
+ * otherwise undefined behavior may occur.
+ *
+ * @param attributes Attribute map
+ * @return Builder instance, such that fluent use is possible
+ */
+ B withAttributes(Map<QName, String> attributes);
+}
import java.util.List;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-public interface CollectionNodeBuilder<V, R extends NormalizedNode<InstanceIdentifier.NodeIdentifier, ?>>
- extends NormalizedNodeBuilder<InstanceIdentifier.NodeIdentifier, List<V>, R> {
+public interface CollectionNodeBuilder<V extends NormalizedNode<?, ?>, R extends NormalizedNode<InstanceIdentifier.NodeIdentifier, ?>>
+ extends NormalizedNodeContainerBuilder<NodeIdentifier,PathArgument, V, R> {
- //TODO might be list to keep ordering and map internal
@Override
CollectionNodeBuilder<V, R> withValue(List<V> value);
CollectionNodeBuilder<V, R> withNodeIdentifier(InstanceIdentifier.NodeIdentifier nodeIdentifier);
CollectionNodeBuilder<V, R> withChild(V child);
+ CollectionNodeBuilder<V, R> withoutChild(InstanceIdentifier.PathArgument key);
}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.builder.api;
+
+import java.util.List;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
+
+public interface DataContainerNodeAttrBuilder<I extends InstanceIdentifier.PathArgument, R extends DataContainerNode<I>>
+ extends DataContainerNodeBuilder<I, R>,
+ AttributesBuilder<DataContainerNodeAttrBuilder<I, R>> {
+
+ @Override
+ DataContainerNodeAttrBuilder<I, R> withValue(List<DataContainerChild<? extends InstanceIdentifier.PathArgument, ?>> value);
+
+ @Override
+ DataContainerNodeAttrBuilder<I, R> withNodeIdentifier(I nodeIdentifier);
+
+ DataContainerNodeAttrBuilder<I, R> withChild(DataContainerChild<?, ?> child);
+}
package org.opendaylight.yangtools.yang.data.impl.schema.builder.api;
import java.util.List;
-import java.util.Map;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
public interface DataContainerNodeBuilder<I extends InstanceIdentifier.PathArgument, R extends DataContainerNode<I>>
- extends NormalizedNodeBuilder<I, List<DataContainerChild<? extends InstanceIdentifier.PathArgument, ?>>, R> {
+ extends NormalizedNodeContainerBuilder<I, PathArgument, DataContainerChild<? extends PathArgument, ?>, R> {
@Override
DataContainerNodeBuilder<I, R> withValue(List<DataContainerChild<? extends InstanceIdentifier.PathArgument, ?>> value);
DataContainerNodeBuilder<I, R> withNodeIdentifier(I nodeIdentifier);
DataContainerNodeBuilder<I, R> withChild(DataContainerChild<?, ?> child);
-}
+ DataContainerNodeBuilder<I, R> withoutChild(PathArgument key);
+}
\ No newline at end of file
package org.opendaylight.yangtools.yang.data.impl.schema.builder.api;
import java.util.List;
+import java.util.Map;
+import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
public interface ListNodeBuilder<T, V>
- extends CollectionNodeBuilder<V, LeafSetNode<T>> {
+ extends CollectionNodeBuilder<LeafSetEntryNode<T>, LeafSetNode<T>> {
@Override
ListNodeBuilder<T, V> withNodeIdentifier(InstanceIdentifier.NodeIdentifier nodeIdentifier);
@Override
- ListNodeBuilder<T, V> withValue(List<V> value);
+ ListNodeBuilder<T, V> withValue(List<LeafSetEntryNode<T>> value);
@Override
- ListNodeBuilder<T, V> withChild(V child);
+ ListNodeBuilder<T, V> withChild(LeafSetEntryNode<T> child);
+
+ @Override
+ ListNodeBuilder<T, V> withoutChild(InstanceIdentifier.PathArgument key);
ListNodeBuilder<T, V> withChildValue(T child);
+
+ ListNodeBuilder<T, LeafSetEntryNode<T>> withChildValue(T value, Map<QName, String> attributes);
}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.builder.api;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public interface NormalizedNodeAttrBuilder<I extends InstanceIdentifier.PathArgument, V, R extends NormalizedNode<I, ?>>
+ extends AttributesBuilder<NormalizedNodeAttrBuilder<I, V, R>>,
+ NormalizedNodeBuilder<I, V, R> {
+
+ @Override
+ NormalizedNodeAttrBuilder<I, V, R> withValue(V value);
+
+ @Override
+ NormalizedNodeAttrBuilder<I, V, R> withNodeIdentifier(I nodeIdentifier);
+
+}
--- /dev/null
+package org.opendaylight.yangtools.yang.data.impl.schema.builder.api;
+
+import java.util.List;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public interface NormalizedNodeContainerBuilder<K extends PathArgument,CK extends PathArgument,CV extends NormalizedNode<? extends CK, ?>,P extends NormalizedNode<K, ?>>
+extends NormalizedNodeBuilder<K,List<CV>,P>{
+
+ @Override
+ NormalizedNodeContainerBuilder<K,CK,CV,P> withNodeIdentifier(K nodeIdentifier);
+
+ @Override
+ NormalizedNodeContainerBuilder<K,CK,CV,P> withValue(List<CV> value);
+
+ NormalizedNodeContainerBuilder<K,CK,CV,P> addChild(CV child);
+ NormalizedNodeContainerBuilder<K,CK,CV,P> removeChild(CK key);
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.builder.impl;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.nodes.AbstractImmutableDataContainerAttrNode;
+
+abstract class AbstractImmutableDataContainerNodeAttrBuilder<I extends InstanceIdentifier.PathArgument, R extends DataContainerNode<I>>
+ extends AbstractImmutableDataContainerNodeBuilder<I, R>
+ implements DataContainerNodeAttrBuilder<I, R> {
+
+ private Map<QName, String> attributes;
+
+ protected AbstractImmutableDataContainerNodeAttrBuilder() {
+ this.attributes = Collections.emptyMap();
+ }
+
+ protected AbstractImmutableDataContainerNodeAttrBuilder(final AbstractImmutableDataContainerAttrNode<I> node) {
+ super(node);
+ this.attributes = node.getAttributes();
+ }
+
+ protected final Map<QName, String> getAttributes() {
+ return attributes;
+ }
+
+ @Override
+ public DataContainerNodeAttrBuilder<I, R> withAttributes(final Map<QName, String> attributes){
+ this.attributes = attributes;
+ return this;
+ }
+
+ @Override
+ public DataContainerNodeAttrBuilder<I, R> withValue(final List<DataContainerChild<? extends InstanceIdentifier.PathArgument, ?>> value) {
+ return (DataContainerNodeAttrBuilder<I, R>) super.withValue(value);
+ }
+
+ @Override
+ public DataContainerNodeAttrBuilder<I, R> withChild(final DataContainerChild<?, ?> child) {
+ return (DataContainerNodeAttrBuilder<I, R>) super.withChild(child);
+ }
+
+ @Override
+ public DataContainerNodeAttrBuilder<I, R> withNodeIdentifier(final I nodeIdentifier) {
+ return (DataContainerNodeAttrBuilder<I, R>) super.withNodeIdentifier(nodeIdentifier);
+ }
+}
*/
package org.opendaylight.yangtools.yang.data.impl.schema.builder.impl;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
-
-import com.google.common.collect.Maps;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.nodes.AbstractImmutableDataContainerNode;
abstract class AbstractImmutableDataContainerNodeBuilder<I extends InstanceIdentifier.PathArgument, R extends DataContainerNode<I>>
implements DataContainerNodeBuilder<I, R> {
- protected Map<InstanceIdentifier.PathArgument, DataContainerChild<? extends InstanceIdentifier.PathArgument, ?>> value;
- protected I nodeIdentifier;
+ private Map<InstanceIdentifier.PathArgument, DataContainerChild<? extends InstanceIdentifier.PathArgument, ?>> value;
+ private I nodeIdentifier;
+
+ /*
+ * Tracks whether the builder is dirty, e.g. whether the value map has been used
+ * to construct a child. If it has, we detect this condition before any further
+ * modification and create a new value map with same contents. This way we do not
+ * force a map copy if the builder is not reused.
+ */
+ private boolean dirty;
protected AbstractImmutableDataContainerNodeBuilder() {
- this.value = Maps.newLinkedHashMap();
+ this.value = new HashMap<>();
+ this.dirty = false;
+ }
+
+ protected AbstractImmutableDataContainerNodeBuilder(final AbstractImmutableDataContainerNode<I> node) {
+ this.value = node.getChildren();
+ this.dirty = true;
+ }
+
+ protected final I getNodeIdentifier() {
+ return nodeIdentifier;
+ }
+
+ protected final DataContainerChild<? extends PathArgument, ?> getChild(final PathArgument child) {
+ return value.get(child);
+ }
+
+ protected final Map<PathArgument, DataContainerChild<? extends PathArgument, ?>> buildValue() {
+ dirty = true;
+ return value;
+ }
+
+ private void checkDirty() {
+ if (dirty) {
+ value = new HashMap<>(value);
+ dirty = false;
+ }
}
@Override
- public DataContainerNodeBuilder<I, R> withValue(List<DataContainerChild<? extends InstanceIdentifier.PathArgument, ?>> value) {
+ public DataContainerNodeBuilder<I, R> withValue(final List<DataContainerChild<? extends InstanceIdentifier.PathArgument, ?>> value) {
// TODO Replace or putAll ?
- for (DataContainerChild<? extends InstanceIdentifier.PathArgument, ?> dataContainerChild : value) {
+ for (final DataContainerChild<? extends InstanceIdentifier.PathArgument, ?> dataContainerChild : value) {
withChild(dataContainerChild);
}
return this;
}
@Override
- public DataContainerNodeBuilder<I, R> withChild(DataContainerChild<?, ?> child) {
+ public DataContainerNodeBuilder<I, R> withChild(final DataContainerChild<?, ?> child) {
+ checkDirty();
this.value.put(child.getIdentifier(), child);
return this;
}
+ @Override
+ public DataContainerNodeBuilder<I, R> withoutChild(final PathArgument key) {
+ checkDirty();
+ this.value.remove(key);
+ return this;
+ }
@Override
- public DataContainerNodeBuilder<I, R> withNodeIdentifier(I nodeIdentifier) {
+ public DataContainerNodeBuilder<I, R> withNodeIdentifier(final I nodeIdentifier) {
this.nodeIdentifier = nodeIdentifier;
return this;
}
+
+ @Override
+ public DataContainerNodeBuilder<I, R> addChild(
+ final DataContainerChild<? extends PathArgument, ?> child) {
+ return withChild(child);
+ }
+
+ @Override
+ public NormalizedNodeContainerBuilder<I, PathArgument, DataContainerChild<? extends PathArgument, ?>, R> removeChild(final PathArgument key) {
+ return withoutChild(key);
+ }
}
*/
package org.opendaylight.yangtools.yang.data.impl.schema.builder.impl;
+import java.util.Collections;
+import java.util.Map;
+
+import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder;
abstract class AbstractImmutableNormalizedNodeBuilder<I extends InstanceIdentifier.PathArgument, V, R extends NormalizedNode<I, ?>>
- implements NormalizedNodeBuilder<I,V,R> {
+ implements NormalizedNodeAttrBuilder<I,V,R> {
+
+ private Map<QName, String> attributes = Collections.emptyMap();
+ private I nodeIdentifier;
+ private V value;
+
+ protected final I getNodeIdentifier() {
+ return nodeIdentifier;
+ }
- protected V value;
- protected I nodeIdentifier;
+ protected final V getValue() {
+ return value;
+ }
+
+ protected final Map<QName, String> getAttributes() {
+ return attributes;
+ }
@Override
- public NormalizedNodeBuilder<I,V,R> withValue(V value) {
+ public NormalizedNodeAttrBuilder<I,V,R> withValue(final V value) {
this.value = value;
return this;
}
-
@Override
- public NormalizedNodeBuilder<I,V,R> withNodeIdentifier(I nodeIdentifier) {
+ public NormalizedNodeAttrBuilder<I,V,R> withNodeIdentifier(final I nodeIdentifier) {
this.nodeIdentifier = nodeIdentifier;
return this;
}
+ @Override
+ public NormalizedNodeAttrBuilder<I,V,R> withAttributes(final Map<QName, String> attributes){
+ this.attributes = attributes;
+ return this;
+ }
}
import java.util.Map;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
@Override
public DataContainerNodeBuilder<InstanceIdentifier.AugmentationIdentifier, AugmentationNode> withChild(
- DataContainerChild<?, ?> child) {
+ final DataContainerChild<?, ?> child) {
// Check nested augments
Preconditions.checkArgument(child instanceof AugmentationNode == false,
"Unable to add: %s, as a child for: %s, Nested augmentations are not permitted", child.getNodeType(),
- nodeIdentifier == null ? this : nodeIdentifier);
+ getNodeIdentifier() == null ? this : getNodeIdentifier());
return super.withChild(child);
}
+ @Override
+ public DataContainerNodeBuilder<AugmentationIdentifier, AugmentationNode> withoutChild(final PathArgument key) {
+ return super.withoutChild(key);
+ }
+
@Override
public AugmentationNode build() {
- return new ImmutableAugmentationNode(nodeIdentifier, value);
+ return new ImmutableAugmentationNode(getNodeIdentifier(), buildValue());
}
- static final class ImmutableAugmentationNode
+ private static final class ImmutableAugmentationNode
extends AbstractImmutableDataContainerNode<InstanceIdentifier.AugmentationIdentifier>
implements AugmentationNode {
- ImmutableAugmentationNode(InstanceIdentifier.AugmentationIdentifier nodeIdentifier, Map<InstanceIdentifier.PathArgument, DataContainerChild<? extends InstanceIdentifier.PathArgument, ?>> children) {
+ ImmutableAugmentationNode(final InstanceIdentifier.AugmentationIdentifier nodeIdentifier, final Map<InstanceIdentifier.PathArgument, DataContainerChild<? extends InstanceIdentifier.PathArgument, ?>> children) {
super(children, nodeIdentifier);
}
}
+
}
import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-import com.google.common.base.Preconditions;
import com.google.common.collect.Sets;
public class ImmutableAugmentationNodeSchemaAwareBuilder extends ImmutableAugmentationNodeBuilder {
private final DataNodeContainerValidator validator;
protected ImmutableAugmentationNodeSchemaAwareBuilder(AugmentationSchema schema) {
- super();
this.validator = new DataNodeContainerValidator(schema);
// TODO no QName for augmentation
super.withNodeIdentifier(new InstanceIdentifier.AugmentationIdentifier(null, getChildQNames(schema)));
return new ImmutableChoiceNodeBuilder();
}
+ @Override
public ChoiceNode build() {
- return new ImmutableChoiceNode(nodeIdentifier, value);
+ return new ImmutableChoiceNode(getNodeIdentifier(), buildValue());
}
- static final class ImmutableChoiceNode
+ private static final class ImmutableChoiceNode
extends AbstractImmutableDataContainerNode<InstanceIdentifier.NodeIdentifier>
implements ChoiceNode {
- ImmutableChoiceNode(InstanceIdentifier.NodeIdentifier nodeIdentifier,
- Map<InstanceIdentifier.PathArgument, DataContainerChild<? extends InstanceIdentifier.PathArgument, ?>> children) {
+ ImmutableChoiceNode(final InstanceIdentifier.NodeIdentifier nodeIdentifier,
+ final Map<InstanceIdentifier.PathArgument, DataContainerChild<? extends InstanceIdentifier.PathArgument, ?>> children) {
super(children, nodeIdentifier);
}
-
}
}
import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.valid.DataNodeContainerValidator;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.SchemaUtils;
import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import com.google.common.base.Preconditions;
+import com.google.common.base.Supplier;
public class ImmutableChoiceNodeSchemaAwareBuilder extends ImmutableChoiceNodeBuilder {
private DataNodeContainerValidator validator;
protected ImmutableChoiceNodeSchemaAwareBuilder(org.opendaylight.yangtools.yang.model.api.ChoiceNode schema) {
- super();
- this.schema = schema;
+ this.schema = Preconditions.checkNotNull(schema);
super.withNodeIdentifier(new InstanceIdentifier.NodeIdentifier(schema.getQName()));
}
}
@Override
- public DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifier, ChoiceNode> withChild(DataContainerChild<?, ?> child) {
+ public DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifier, ChoiceNode> withChild(final DataContainerChild<?, ?> child) {
if(detectedCase == null) {
- detectedCase = detectCase(child);
+ detectedCase = SchemaUtils.detectCase(schema, child).or(new Supplier<ChoiceCaseNode>() {
+ @Override
+ public ChoiceCaseNode get() {
+ throw new IllegalArgumentException(String.format("Unknown child node: %s, for choice: %s", child.getNodeType(),
+ schema.getQName()));
+ }
+ });
validator = new DataNodeContainerValidator(detectedCase);
}
return super.build();
}
- private ChoiceCaseNode detectCase(DataContainerChild<?, ?> child) {
- for (ChoiceCaseNode choiceCaseNode : schema.getCases()) {
- for (DataSchemaNode childFromCase : choiceCaseNode.getChildNodes()) {
- if (childFromCase.getQName().equals(child.getNodeType())) {
- return choiceCaseNode;
- }
- }
- }
-
- throw new IllegalArgumentException(String.format("Unknown child node: %s, for choice: %s", child.getNodeType(),
- schema.getQName()));
- }
-
public static DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifier, ChoiceNode> create(org.opendaylight.yangtools.yang.model.api.ChoiceNode schema) {
return new ImmutableChoiceNodeSchemaAwareBuilder(schema);
}
import java.util.Map;
+import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.nodes.AbstractImmutableDataContainerNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.nodes.AbstractImmutableDataContainerAttrNode;
-public class ImmutableContainerNodeBuilder extends AbstractImmutableDataContainerNodeBuilder<InstanceIdentifier.NodeIdentifier, ContainerNode> {
+public class ImmutableContainerNodeBuilder extends
+ AbstractImmutableDataContainerNodeAttrBuilder<InstanceIdentifier.NodeIdentifier, ContainerNode> {
- public static DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifier, ContainerNode> create() {
+ protected ImmutableContainerNodeBuilder() {
+ super();
+ }
+
+ protected ImmutableContainerNodeBuilder(final ImmutableContainerNode node) {
+ super(node);
+ }
+
+ public static DataContainerNodeAttrBuilder<InstanceIdentifier.NodeIdentifier, ContainerNode> create() {
return new ImmutableContainerNodeBuilder();
}
+ public static DataContainerNodeAttrBuilder<InstanceIdentifier.NodeIdentifier, ContainerNode> create(final ContainerNode node) {
+ if (!(node instanceof ImmutableContainerNode)) {
+ throw new UnsupportedOperationException(String.format("Cannot initialize from class %s", node.getClass()));
+ }
+ return new ImmutableContainerNodeBuilder((ImmutableContainerNode) node);
+ }
+
@Override
public ContainerNode build() {
- return new ImmutableContainerNode(nodeIdentifier, value);
+ return new ImmutableContainerNode(getNodeIdentifier(), buildValue(), getAttributes());
}
- final class ImmutableContainerNode
- extends AbstractImmutableDataContainerNode<InstanceIdentifier.NodeIdentifier>
- implements ContainerNode {
+ protected static final class ImmutableContainerNode extends
+ AbstractImmutableDataContainerAttrNode<InstanceIdentifier.NodeIdentifier> implements ContainerNode {
ImmutableContainerNode(
- InstanceIdentifier.NodeIdentifier nodeIdentifier,
- Map<InstanceIdentifier.PathArgument, DataContainerChild<? extends InstanceIdentifier.PathArgument, ?>> children) {
- super(children, nodeIdentifier);
+ final InstanceIdentifier.NodeIdentifier nodeIdentifier,
+ final Map<InstanceIdentifier.PathArgument, DataContainerChild<? extends InstanceIdentifier.PathArgument, ?>> children,
+ final Map<QName, String> attributes) {
+ super(children, nodeIdentifier, attributes);
}
-
}
}
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.valid.DataNodeContainerValidator;
import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
public final class ImmutableContainerNodeSchemaAwareBuilder extends ImmutableContainerNodeBuilder {
private final DataNodeContainerValidator validator;
+ // TODO remove schema aware builders, replace by validator called at build() ?
- // TODO remove schema aware builders, replace by validator called at build()
+ private ImmutableContainerNodeSchemaAwareBuilder(final ContainerSchemaNode schema) {
+ this.validator = new DataNodeContainerValidator(schema);
+ super.withNodeIdentifier(new InstanceIdentifier.NodeIdentifier(schema.getQName()));
+ }
- private ImmutableContainerNodeSchemaAwareBuilder(ContainerSchemaNode schema) {
- super();
+ private ImmutableContainerNodeSchemaAwareBuilder(final ContainerSchemaNode schema, final ImmutableContainerNode node) {
+ super(node);
this.validator = new DataNodeContainerValidator(schema);
super.withNodeIdentifier(new InstanceIdentifier.NodeIdentifier(schema.getQName()));
}
- public static DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifier, ContainerNode> create(ContainerSchemaNode schema) {
+ public static DataContainerNodeAttrBuilder<InstanceIdentifier.NodeIdentifier, ContainerNode> create(final ContainerSchemaNode schema) {
return new ImmutableContainerNodeSchemaAwareBuilder(schema);
}
+ public static DataContainerNodeAttrBuilder<InstanceIdentifier.NodeIdentifier, ContainerNode> create(final ContainerSchemaNode schema, final ContainerNode node) {
+ if (!(node instanceof ImmutableContainerNode)) {
+ throw new UnsupportedOperationException(String.format("Cannot initialize from class %s", node.getClass()));
+ }
+ return new ImmutableContainerNodeSchemaAwareBuilder(schema, (ImmutableContainerNode)node);
+ }
+
@Override
- public DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifier, ContainerNode> withNodeIdentifier(InstanceIdentifier.NodeIdentifier nodeIdentifier) {
+ public DataContainerNodeAttrBuilder<InstanceIdentifier.NodeIdentifier, ContainerNode> withNodeIdentifier(final InstanceIdentifier.NodeIdentifier nodeIdentifier) {
throw new UnsupportedOperationException("Node identifier created from schema");
}
@Override
- public DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifier, ContainerNode> withChild(DataContainerChild<?, ?> child) {
+ public DataContainerNodeAttrBuilder<InstanceIdentifier.NodeIdentifier, ContainerNode> withChild(final DataContainerChild<?, ?> child) {
validator.validateChild(child.getIdentifier());
return super.withChild(child);
}
*/
package org.opendaylight.yangtools.yang.data.impl.schema.builder.impl;
+import java.util.Map;
+
+import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.nodes.AbstractImmutableNormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.nodes.AbstractImmutableNormalizedAttrNode;
public class ImmutableLeafNodeBuilder<T> extends AbstractImmutableNormalizedNodeBuilder<InstanceIdentifier.NodeIdentifier, T, LeafNode<T>> {
- protected ImmutableLeafNodeBuilder() {
- }
-
- public static <T> NormalizedNodeBuilder<InstanceIdentifier.NodeIdentifier, T, LeafNode<T>> create() {
+ public static <T> NormalizedNodeAttrBuilder<InstanceIdentifier.NodeIdentifier, T, LeafNode<T>> create() {
return new ImmutableLeafNodeBuilder<>();
}
@Override
public LeafNode<T> build() {
- return new ImmutableLeafNode<>(nodeIdentifier, value);
+ return new ImmutableLeafNode<>(getNodeIdentifier(), getValue(), getAttributes());
}
- static final class ImmutableLeafNode<T> extends AbstractImmutableNormalizedNode<InstanceIdentifier.NodeIdentifier, T> implements LeafNode<T> {
-
- ImmutableLeafNode(InstanceIdentifier.NodeIdentifier nodeIdentifier, T value) {
- super(nodeIdentifier, value);
- }
+ private static final class ImmutableLeafNode<T> extends AbstractImmutableNormalizedAttrNode<InstanceIdentifier.NodeIdentifier, T> implements LeafNode<T> {
- @Override
- public String toString() {
- final StringBuffer sb = new StringBuffer("ImmutableLeafNode{");
- sb.append("nodeIdentifier=").append(nodeIdentifier);
- sb.append(", value=").append(value);
- sb.append('}');
- return sb.toString();
+ ImmutableLeafNode(final InstanceIdentifier.NodeIdentifier nodeIdentifier, final T value, final Map<QName, String> attributes) {
+ super(nodeIdentifier, value, attributes);
}
}
}
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder;
import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
public final class ImmutableLeafNodeSchemaAwareBuilder<T> extends ImmutableLeafNodeBuilder<T> {
- private final LeafSchemaNode schema;
-
private ImmutableLeafNodeSchemaAwareBuilder(LeafSchemaNode schema) {
- super();
- this.schema = schema;
super.withNodeIdentifier(new InstanceIdentifier.NodeIdentifier(schema.getQName()));
}
- public static <T> NormalizedNodeBuilder<InstanceIdentifier.NodeIdentifier, T, LeafNode<T>> create(LeafSchemaNode schema) {
+ public static <T> NormalizedNodeAttrBuilder<InstanceIdentifier.NodeIdentifier, T, LeafNode<T>> create(LeafSchemaNode schema) {
return new ImmutableLeafNodeSchemaAwareBuilder<>(schema);
}
@Override
- public NormalizedNodeBuilder<InstanceIdentifier.NodeIdentifier, T, LeafNode<T>> withValue(T value) {
+ public NormalizedNodeAttrBuilder<InstanceIdentifier.NodeIdentifier, T, LeafNode<T>> withValue(T value) {
// TODO check value type
return super.withValue(value);
}
@Override
- public NormalizedNodeBuilder<InstanceIdentifier.NodeIdentifier, T, LeafNode<T>> withNodeIdentifier(InstanceIdentifier.NodeIdentifier nodeIdentifier) {
+ public NormalizedNodeAttrBuilder<InstanceIdentifier.NodeIdentifier, T, LeafNode<T>> withNodeIdentifier(InstanceIdentifier.NodeIdentifier nodeIdentifier) {
throw new UnsupportedOperationException("Node identifier created from schema");
}
}
*/
package org.opendaylight.yangtools.yang.data.impl.schema.builder.impl;
+import java.util.Map;
+
+import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.nodes.AbstractImmutableNormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.nodes.AbstractImmutableNormalizedAttrNode;
import com.google.common.base.Preconditions;
public class ImmutableLeafSetEntryNodeBuilder<T> extends AbstractImmutableNormalizedNodeBuilder<InstanceIdentifier.NodeWithValue, T, LeafSetEntryNode<T>> {
- public static <T> NormalizedNodeBuilder<InstanceIdentifier.NodeWithValue, T, LeafSetEntryNode<T>> create() {
+ public static <T> ImmutableLeafSetEntryNodeBuilder<T> create() {
return new ImmutableLeafSetEntryNodeBuilder<>();
}
@Override
public LeafSetEntryNode<T> build() {
- return new ImmutableLeafSetEntryNode<>(nodeIdentifier, value);
+ return new ImmutableLeafSetEntryNode<>(getNodeIdentifier(), getValue(), getAttributes());
}
- static final class ImmutableLeafSetEntryNode<T> extends AbstractImmutableNormalizedNode<InstanceIdentifier.NodeWithValue, T> implements LeafSetEntryNode<T> {
+ private static final class ImmutableLeafSetEntryNode<T> extends AbstractImmutableNormalizedAttrNode<InstanceIdentifier.NodeWithValue, T> implements LeafSetEntryNode<T> {
- ImmutableLeafSetEntryNode(InstanceIdentifier.NodeWithValue nodeIdentifier, T value) {
- super(nodeIdentifier, value);
+ ImmutableLeafSetEntryNode(final InstanceIdentifier.NodeWithValue nodeIdentifier, final T value, final Map<QName, String> attributes) {
+ super(nodeIdentifier, value, attributes);
Preconditions.checkArgument(nodeIdentifier.getValue().equals(value),
"Node identifier contains different value: %s than value itself: %s", nodeIdentifier, value);
}
-
- @Override
- public String toString() {
- final StringBuffer sb = new StringBuffer("ImmutableLeafSetEntryNode{");
- sb.append("nodeIdentifier=").append(nodeIdentifier);
- sb.append(", value=").append(value);
- sb.append('}');
- return sb.toString();
- }
}
}
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder;
import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import com.google.common.base.Preconditions;
+
public final class ImmutableLeafSetEntryNodeSchemaAwareBuilder<T> extends ImmutableLeafSetEntryNodeBuilder<T> {
private final LeafListSchemaNode schema;
private ImmutableLeafSetEntryNodeSchemaAwareBuilder(LeafListSchemaNode schema) {
- super();
- this.schema = schema;
+ this.schema = Preconditions.checkNotNull(schema);
}
- public static <T> NormalizedNodeBuilder<InstanceIdentifier.NodeWithValue, T, LeafSetEntryNode<T>> create(LeafListSchemaNode schema) {
+ public static <T> NormalizedNodeAttrBuilder<InstanceIdentifier.NodeWithValue, T, LeafSetEntryNode<T>> create(LeafListSchemaNode schema) {
return new ImmutableLeafSetEntryNodeSchemaAwareBuilder<>(schema);
}
@Override
- public NormalizedNodeBuilder<InstanceIdentifier.NodeWithValue, T, LeafSetEntryNode<T>> withValue(T value) {
+ public NormalizedNodeAttrBuilder<InstanceIdentifier.NodeWithValue, T, LeafSetEntryNode<T>> withValue(T value) {
super.withNodeIdentifier(new InstanceIdentifier.NodeWithValue(schema.getQName(), value));
// TODO check value type
return super.withValue(value);
}
@Override
- public NormalizedNodeBuilder<InstanceIdentifier.NodeWithValue, T, LeafSetEntryNode<T>> withNodeIdentifier(InstanceIdentifier.NodeWithValue nodeIdentifier) {
+ public NormalizedNodeAttrBuilder<InstanceIdentifier.NodeWithValue, T, LeafSetEntryNode<T>> withNodeIdentifier(InstanceIdentifier.NodeWithValue nodeIdentifier) {
throw new UnsupportedOperationException("Node identifier created from schema");
}
*/
package org.opendaylight.yangtools.yang.data.impl.schema.builder.impl;
+import java.util.Collections;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
import org.opendaylight.yangtools.yang.data.impl.schema.nodes.AbstractImmutableNormalizedNode;
import com.google.common.base.Optional;
-import com.google.common.collect.Maps;
-import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import com.google.common.collect.Iterables;
-public class ImmutableLeafSetNodeBuilder<T>
- implements ListNodeBuilder<T, LeafSetEntryNode<T>> {
+public class ImmutableLeafSetNodeBuilder<T> implements ListNodeBuilder<T, LeafSetEntryNode<T>> {
- protected Map<InstanceIdentifier.NodeWithValue, LeafSetEntryNode<T>> value;
- protected InstanceIdentifier.NodeIdentifier nodeIdentifier;
+ private Map<InstanceIdentifier.NodeWithValue, LeafSetEntryNode<T>> value;
+ private InstanceIdentifier.NodeIdentifier nodeIdentifier;
+ private boolean dirty;
+
+ protected ImmutableLeafSetNodeBuilder() {
+ value = new LinkedHashMap<>();
+ dirty = false;
+ }
+
+ protected ImmutableLeafSetNodeBuilder(final ImmutableLeafSetNode<T> node) {
+ value = node.getChildren();
+ nodeIdentifier = node.getIdentifier();
+ dirty = true;
+ }
public static <T> ListNodeBuilder<T, LeafSetEntryNode<T>> create() {
return new ImmutableLeafSetNodeBuilder<>();
}
- public ListNodeBuilder<T, LeafSetEntryNode<T>> withChild(LeafSetEntryNode<T> child) {
- if(this.value == null) {
- this.value = Maps.newLinkedHashMap();
+ public static <T> ListNodeBuilder<T, LeafSetEntryNode<T>> create(final LeafSetNode<T> node) {
+ if (!(node instanceof ImmutableLeafSetNode<?>)) {
+ throw new UnsupportedOperationException(String.format("Cannot initialize from class %s", node.getClass()));
}
+ return new ImmutableLeafSetNodeBuilder<T>((ImmutableLeafSetNode<T>) node);
+ }
+
+ private void checkDirty() {
+ if (dirty) {
+ value = new LinkedHashMap<>(value);
+ dirty = false;
+ }
+ }
+
+ @Override
+ public ListNodeBuilder<T, LeafSetEntryNode<T>> withChild(final LeafSetEntryNode<T> child) {
+ checkDirty();
this.value.put(child.getIdentifier(), child);
return this;
}
+ @Override
+ public ListNodeBuilder<T, LeafSetEntryNode<T>> withoutChild(final PathArgument key) {
+ checkDirty();
+ this.value.remove(key);
+ return this;
+ }
+
@Override
public LeafSetNode<T> build() {
+ dirty = true;
return new ImmutableLeafSetNode<>(nodeIdentifier, value);
}
@Override
- public ListNodeBuilder<T, LeafSetEntryNode<T>> withNodeIdentifier(InstanceIdentifier.NodeIdentifier nodeIdentifier) {
+ public ListNodeBuilder<T, LeafSetEntryNode<T>> withNodeIdentifier(
+ final InstanceIdentifier.NodeIdentifier nodeIdentifier) {
this.nodeIdentifier = nodeIdentifier;
return this;
}
@Override
- public ListNodeBuilder<T, LeafSetEntryNode<T>> withValue(List<LeafSetEntryNode<T>> value) {
- for (LeafSetEntryNode<T> leafSetEntry : value) {
+ public ListNodeBuilder<T, LeafSetEntryNode<T>> withValue(final List<LeafSetEntryNode<T>> value) {
+ checkDirty();
+ for (final LeafSetEntryNode<T> leafSetEntry : value) {
withChild(leafSetEntry);
}
return this;
}
+
@Override
- public ListNodeBuilder<T, LeafSetEntryNode<T>> withChildValue(T value) {
- return withChild(new ImmutableLeafSetEntryNodeBuilder.ImmutableLeafSetEntryNode<>(new InstanceIdentifier.NodeWithValue(nodeIdentifier.getNodeType(), value), value));
+ public ListNodeBuilder<T, LeafSetEntryNode<T>> withChildValue(final T value, final Map<QName, String> attributes) {
+ final ImmutableLeafSetEntryNodeBuilder<T> b = ImmutableLeafSetEntryNodeBuilder.create();
+ b.withNodeIdentifier(new InstanceIdentifier.NodeWithValue(nodeIdentifier.getNodeType(), value));
+ b.withValue(value);
+ b.withAttributes(attributes);
+ return withChild(b.build());
}
- final class ImmutableLeafSetNode<T> extends AbstractImmutableNormalizedNode<InstanceIdentifier.NodeIdentifier, Iterable<LeafSetEntryNode<T>>> implements LeafSetNode<T> {
+ @Override
+ public ListNodeBuilder<T, LeafSetEntryNode<T>> withChildValue(final T value) {
+ return withChildValue(value, Collections.<QName,String>emptyMap());
+ }
- private final Map<InstanceIdentifier.NodeWithValue, LeafSetEntryNode<T>> mappedChildren;
+ protected final static class ImmutableLeafSetNode<T> extends
+ AbstractImmutableNormalizedNode<InstanceIdentifier.NodeIdentifier, Iterable<LeafSetEntryNode<T>>> implements
+ Immutable, LeafSetNode<T> {
- ImmutableLeafSetNode(InstanceIdentifier.NodeIdentifier nodeIdentifier, Map<InstanceIdentifier.NodeWithValue, LeafSetEntryNode<T>> children) {
- super(nodeIdentifier, children.values());
- this.mappedChildren = children;
+ private final Map<InstanceIdentifier.NodeWithValue, LeafSetEntryNode<T>> children;
+
+ ImmutableLeafSetNode(final InstanceIdentifier.NodeIdentifier nodeIdentifier,
+ final Map<InstanceIdentifier.NodeWithValue, LeafSetEntryNode<T>> children) {
+ super(nodeIdentifier, Iterables.unmodifiableIterable(children.values()));
+ this.children = children;
}
@Override
- public Optional<LeafSetEntryNode<T>> getChild(InstanceIdentifier.NodeWithValue child) {
- return Optional.fromNullable(mappedChildren.get(child));
+ public Optional<LeafSetEntryNode<T>> getChild(final InstanceIdentifier.NodeWithValue child) {
+ return Optional.fromNullable(children.get(child));
+ }
+
+ @Override
+ protected int valueHashCode() {
+ return children.hashCode();
+ }
+
+ private Map<InstanceIdentifier.NodeWithValue, LeafSetEntryNode<T>> getChildren() {
+ return Collections.unmodifiableMap(children);
}
@Override
- public String toString() {
- final StringBuffer sb = new StringBuffer("ImmutableLeafSetNode{");
- sb.append("nodeIdentifier=").append(nodeIdentifier);
- sb.append(", children=").append(value);
- sb.append('}');
- return sb.toString();
+ protected boolean valueEquals(final AbstractImmutableNormalizedNode<?, ?> other) {
+ return children.equals(((ImmutableLeafSetNode<?>) other).children);
}
}
+ @Override
+ public NormalizedNodeContainerBuilder<NodeIdentifier, PathArgument, LeafSetEntryNode<T>, LeafSetNode<T>> addChild(
+ final LeafSetEntryNode<T> child) {
+ return withChild(child);
+ }
+
+ @Override
+ public NormalizedNodeContainerBuilder<NodeIdentifier, PathArgument, LeafSetEntryNode<T>, LeafSetNode<T>> removeChild(
+ final PathArgument key) {
+ return withoutChild(key);
+ }
+
}
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
private final LeafListSchemaNode schema;
- private ImmutableLeafSetNodeSchemaAwareBuilder(LeafListSchemaNode schema) {
- super();
- this.schema = schema;
+ private ImmutableLeafSetNodeSchemaAwareBuilder(final LeafListSchemaNode schema) {
+ this.schema = Preconditions.checkNotNull(schema);
super.withNodeIdentifier(new InstanceIdentifier.NodeIdentifier(schema.getQName()));
}
- public static <T> ListNodeBuilder<T, LeafSetEntryNode<T>> create(LeafListSchemaNode schema) {
+ public ImmutableLeafSetNodeSchemaAwareBuilder(final LeafListSchemaNode schema, final ImmutableLeafSetNode<T> node) {
+ super(node);
+ this.schema = Preconditions.checkNotNull(schema);
+ // FIXME: Preconditions.checkArgument(schema.getQName().equals(node.getIdentifier()));
+ super.withNodeIdentifier(new InstanceIdentifier.NodeIdentifier(schema.getQName()));
+ }
+
+ public static <T> ListNodeBuilder<T, LeafSetEntryNode<T>> create(final LeafListSchemaNode schema) {
return new ImmutableLeafSetNodeSchemaAwareBuilder<>(schema);
}
+ public static <T> ListNodeBuilder<T, LeafSetEntryNode<T>> create(final LeafListSchemaNode schema, final LeafSetNode<T> node) {
+ if (!(node instanceof ImmutableLeafSetNode<?>)) {
+ throw new UnsupportedOperationException(String.format("Cannot initialize from class %s", node.getClass()));
+ }
+
+ return new ImmutableLeafSetNodeSchemaAwareBuilder<T>(schema, (ImmutableLeafSetNode<T>) node);
+ }
+
@Override
- public ListNodeBuilder<T, LeafSetEntryNode<T>> withChildValue(T value) {
+ public ListNodeBuilder<T, LeafSetEntryNode<T>> withChildValue(final T value) {
// TODO check value type
return super.withChildValue(value);
}
@Override
- public ListNodeBuilder<T, LeafSetEntryNode<T>> withChild(LeafSetEntryNode<T> child) {
+ public ListNodeBuilder<T, LeafSetEntryNode<T>> withChild(final LeafSetEntryNode<T> child) {
Preconditions.checkArgument(schema.getQName().equals(child.getNodeType()),
"Incompatible node type, should be: %s, is: %s", schema.getQName(), child.getNodeType());
return super.withChild(child);
}
@Override
- public ListNodeBuilder<T, LeafSetEntryNode<T>> withNodeIdentifier(InstanceIdentifier.NodeIdentifier nodeIdentifier) {
+ public ListNodeBuilder<T, LeafSetEntryNode<T>> withNodeIdentifier(final InstanceIdentifier.NodeIdentifier nodeIdentifier) {
throw new UnsupportedOperationException("Node identifier created from schema");
}
}
*/
package org.opendaylight.yangtools.yang.data.impl.schema.builder.impl;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.valid.DataNodeContainerValidator;
-import org.opendaylight.yangtools.yang.data.impl.schema.nodes.AbstractImmutableDataContainerNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.nodes.AbstractImmutableDataContainerAttrNode;
import com.google.common.base.Preconditions;
-import com.google.common.collect.Maps;
public class ImmutableMapEntryNodeBuilder
- extends AbstractImmutableDataContainerNodeBuilder<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> {
+ extends AbstractImmutableDataContainerNodeAttrBuilder<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> {
protected final Map<QName, InstanceIdentifier.PathArgument> childrenQNamesToPaths;
protected ImmutableMapEntryNodeBuilder() {
- this.childrenQNamesToPaths = Maps.newLinkedHashMap();
+ this.childrenQNamesToPaths = new LinkedHashMap<>();
}
- public static DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> create() {
+ protected ImmutableMapEntryNodeBuilder(final ImmutableMapEntryNode node) {
+ super(node);
+ this.childrenQNamesToPaths = new LinkedHashMap<>();
+ fillQnames(node.getValue(), childrenQNamesToPaths);
+ }
+
+ public static DataContainerNodeAttrBuilder<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> create() {
return new ImmutableMapEntryNodeBuilder();
}
+ public static DataContainerNodeAttrBuilder<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> create(final MapEntryNode node) {
+ if (!(node instanceof ImmutableMapEntryNode)) {
+ throw new UnsupportedOperationException(String.format("Cannot initialize from class %s", node.getClass()));
+ }
+
+ return new ImmutableMapEntryNodeBuilder((ImmutableMapEntryNode)node);
+ }
+
+ private static void fillQnames(final Iterable<DataContainerChild<? extends PathArgument, ?>> iterable, final Map<QName, PathArgument> out) {
+ for (final DataContainerChild<? extends InstanceIdentifier.PathArgument, ?> childId : iterable) {
+ final InstanceIdentifier.PathArgument identifier = childId.getIdentifier();
+
+ // Augmentation nodes cannot be keys, and do not have to be present in childrenQNamesToPaths map
+ if(identifier instanceof InstanceIdentifier.AugmentationIdentifier) {
+ continue;
+ }
+
+ out.put(childId.getNodeType(), identifier);
+ }
+ }
+
// FIXME, find better solution than 2 maps (map from QName to Child ?)
@Override
- public DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> withValue(List<DataContainerChild<? extends InstanceIdentifier.PathArgument, ?>> value) {
- for (DataContainerChild<? extends InstanceIdentifier.PathArgument, ?> childId : value) {
- this.childrenQNamesToPaths.put(childId.getNodeType(), childId.getIdentifier());
- }
+ public DataContainerNodeAttrBuilder<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> withValue(final List<DataContainerChild<? extends InstanceIdentifier.PathArgument, ?>> value) {
+ fillQnames(value, childrenQNamesToPaths);
return super.withValue(value);
}
@Override
- public DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> withChild(DataContainerChild<?, ?> child) {
- childrenQNamesToPaths.put(child.getNodeType(), child.getIdentifier());
+ public DataContainerNodeAttrBuilder<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> withChild(final DataContainerChild<?, ?> child) {
+ // Augmentation nodes cannot be keys, and do not have to be present in childrenQNamesToPaths map
+ if(child.getIdentifier() instanceof InstanceIdentifier.AugmentationIdentifier == false) {
+ childrenQNamesToPaths.put(child.getNodeType(), child.getIdentifier());
+ }
return super.withChild(child);
}
+ @Override
public MapEntryNode build() {
checkKeys();
- return new ImmutableMapEntryNode(nodeIdentifier, value);
+ return new ImmutableMapEntryNode(getNodeIdentifier(), buildValue(), getAttributes());
}
private void checkKeys() {
- for (QName keyQName : nodeIdentifier.getKeyValues().keySet()) {
+ for (final QName keyQName : getNodeIdentifier().getKeyValues().keySet()) {
- InstanceIdentifier.PathArgument childNodePath = childrenQNamesToPaths.get(keyQName);
- DataContainerChild<?, ?> childNode = value.get(childNodePath);
+ final InstanceIdentifier.PathArgument childNodePath = childrenQNamesToPaths.get(keyQName);
+ final DataContainerChild<?, ?> childNode = getChild(childNodePath);
Preconditions.checkNotNull(childNode, "Key child node: %s, not present", keyQName);
- Object actualValue = nodeIdentifier.getKeyValues().get(keyQName);
- Object expectedValue = childNode.getValue();
+ final Object actualValue = getNodeIdentifier().getKeyValues().get(keyQName);
+ final Object expectedValue = childNode.getValue();
Preconditions.checkArgument(expectedValue.equals(actualValue),
"Key child node with unexpected value, is: %s, should be: %s", actualValue, expectedValue);
}
}
- static final class ImmutableMapEntryNode extends AbstractImmutableDataContainerNode<InstanceIdentifier.NodeIdentifierWithPredicates> implements MapEntryNode {
+ private static final class ImmutableMapEntryNode extends AbstractImmutableDataContainerAttrNode<InstanceIdentifier.NodeIdentifierWithPredicates> implements MapEntryNode {
- ImmutableMapEntryNode(InstanceIdentifier.NodeIdentifierWithPredicates nodeIdentifier,
- Map<InstanceIdentifier.PathArgument, DataContainerChild<? extends InstanceIdentifier.PathArgument, ?>> children) {
- super(children, nodeIdentifier);
+ ImmutableMapEntryNode(final InstanceIdentifier.NodeIdentifierWithPredicates nodeIdentifier,
+ final Map<InstanceIdentifier.PathArgument, DataContainerChild<? extends InstanceIdentifier.PathArgument, ?>> children, final Map<QName, String> attributes) {
+ super(children, nodeIdentifier, attributes);
}
}
}
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.valid.DataNodeContainerValidator;
import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
private final ListSchemaNode schema;
private final DataNodeContainerValidator validator;
- protected ImmutableMapEntryNodeSchemaAwareBuilder(ListSchemaNode schema) {
- this.schema = schema;
+ protected ImmutableMapEntryNodeSchemaAwareBuilder(final ListSchemaNode schema) {
+ this.schema = Preconditions.checkNotNull(schema);
this.validator = new DataNodeContainerValidator(schema);
}
@Override
- public ImmutableMapEntryNodeBuilder withNodeIdentifier(InstanceIdentifier.NodeIdentifierWithPredicates nodeIdentifier) {
+ public ImmutableMapEntryNodeBuilder withNodeIdentifier(final InstanceIdentifier.NodeIdentifierWithPredicates nodeIdentifier) {
throw new UnsupportedOperationException("Node identifier created from schema");
}
@Override
- public DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> withChild(DataContainerChild<?, ?> child) {
+ public DataContainerNodeAttrBuilder<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> withChild(final DataContainerChild<?, ?> child) {
validator.validateChild(child.getIdentifier());
return super.withChild(child);
}
keys = childrenQNamesToPaths.keySet();
}
- Map<QName, Object> keysToValues = Maps.newHashMap();
- for (QName key : keys) {
+ final Map<QName, Object> keysToValues = Maps.newHashMap();
+ for (final QName key : keys) {
// TODO two maps ? find better solution
- DataContainerChild<?, ?> valueForKey = value.get(childrenQNamesToPaths.get(key));
+ final DataContainerChild<?, ?> valueForKey = getChild(childrenQNamesToPaths.get(key));
Preconditions.checkState(valueForKey != null, "Key value: %s cannot be empty for: %s", key, schema.getQName());
keysToValues.put(key, valueForKey.getValue());
}
+
return new InstanceIdentifier.NodeIdentifierWithPredicates(schema.getQName(), keysToValues);
}
- public static ImmutableMapEntryNodeSchemaAwareBuilder create(ListSchemaNode schema) {
+ public static DataContainerNodeAttrBuilder<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> create(final ListSchemaNode schema) {
return new ImmutableMapEntryNodeSchemaAwareBuilder(schema);
}
*/
package org.opendaylight.yangtools.yang.data.impl.schema.builder.impl;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import org.opendaylight.yangtools.concepts.Immutable;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
import org.opendaylight.yangtools.yang.data.impl.schema.nodes.AbstractImmutableNormalizedNode;
import com.google.common.base.Optional;
-import com.google.common.collect.Maps;
+import com.google.common.collect.Iterables;
public class ImmutableMapNodeBuilder
implements CollectionNodeBuilder<MapEntryNode, MapNode> {
- protected Map<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> value;
- protected InstanceIdentifier.NodeIdentifier nodeIdentifier;
+ private Map<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> value;
+ private InstanceIdentifier.NodeIdentifier nodeIdentifier;
+ private boolean dirty = false;
+
+ protected ImmutableMapNodeBuilder() {
+ this.value = new LinkedHashMap<>();
+ this.dirty = false;
+ }
+
+ protected ImmutableMapNodeBuilder(final ImmutableMapNode node) {
+ this.value = node.children;
+ this.dirty = true;
+ }
public static CollectionNodeBuilder<MapEntryNode, MapNode> create() {
return new ImmutableMapNodeBuilder();
}
- public CollectionNodeBuilder<MapEntryNode, MapNode> withChild(MapEntryNode child) {
- if(this.value == null) {
- this.value = Maps.newLinkedHashMap();
+ public static CollectionNodeBuilder<MapEntryNode, MapNode> create(final MapNode node) {
+ if (!(node instanceof ImmutableMapNode)) {
+ throw new UnsupportedOperationException(String.format("Cannot initialize from class %s", node.getClass()));
}
+ return new ImmutableMapNodeBuilder((ImmutableMapNode) node);
+ }
+
+ private void checkDirty() {
+ if (dirty) {
+ value = new LinkedHashMap<>(value);
+ dirty = false;
+ }
+ }
+
+ @Override
+ public CollectionNodeBuilder<MapEntryNode, MapNode> withChild(final MapEntryNode child) {
+ checkDirty();
this.value.put(child.getIdentifier(), child);
return this;
}
@Override
- public CollectionNodeBuilder<MapEntryNode, MapNode> withValue(List<MapEntryNode> value) {
+ public CollectionNodeBuilder<MapEntryNode, MapNode> withoutChild(final InstanceIdentifier.PathArgument key) {
+ checkDirty();
+ this.value.remove(key);
+ return this;
+ }
+
+ @Override
+ public CollectionNodeBuilder<MapEntryNode, MapNode> withValue(final List<MapEntryNode> value) {
// TODO replace or putAll ?
- for (MapEntryNode mapEntryNode : value) {
+ for (final MapEntryNode mapEntryNode : value) {
withChild(mapEntryNode);
}
return this;
}
- public CollectionNodeBuilder<MapEntryNode, MapNode> withNodeIdentifier(InstanceIdentifier.NodeIdentifier nodeIdentifier) {
+ @Override
+ public CollectionNodeBuilder<MapEntryNode, MapNode> withNodeIdentifier(final InstanceIdentifier.NodeIdentifier nodeIdentifier) {
this.nodeIdentifier = nodeIdentifier;
return this;
}
@Override
public MapNode build() {
+ dirty = true;
return new ImmutableMapNode(nodeIdentifier, value);
}
- static final class ImmutableMapNode extends AbstractImmutableNormalizedNode<InstanceIdentifier.NodeIdentifier, Iterable<MapEntryNode>> implements MapNode {
+ @Override
+ public CollectionNodeBuilder<MapEntryNode, MapNode> addChild(
+ final MapEntryNode child) {
+ return withChild(child);
+ }
+
+
+ @Override
+ public NormalizedNodeContainerBuilder<NodeIdentifier, PathArgument, MapEntryNode, MapNode> removeChild(
+ final PathArgument key) {
+ return withoutChild(key);
+ }
+
+ protected static final class ImmutableMapNode extends AbstractImmutableNormalizedNode<InstanceIdentifier.NodeIdentifier, Iterable<MapEntryNode>> implements Immutable,MapNode {
- private final Map<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> mappedChildren;
+ private final Map<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> children;
- ImmutableMapNode(InstanceIdentifier.NodeIdentifier nodeIdentifier,
- Map<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> children) {
- super(nodeIdentifier, children.values());
- this.mappedChildren = children;
+ ImmutableMapNode(final InstanceIdentifier.NodeIdentifier nodeIdentifier,
+ final Map<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> children) {
+ super(nodeIdentifier, Iterables.unmodifiableIterable(children.values()));
+ this.children = children;
+ }
+
+ @Override
+ public Optional<MapEntryNode> getChild(final InstanceIdentifier.NodeIdentifierWithPredicates child) {
+ return Optional.fromNullable(children.get(child));
}
@Override
- public Optional<MapEntryNode> getChild(InstanceIdentifier.NodeIdentifierWithPredicates child) {
- return Optional.fromNullable(mappedChildren.get(child));
+ protected int valueHashCode() {
+ return children.hashCode();
}
@Override
- public String toString() {
- final StringBuffer sb = new StringBuffer("ImmutableMapNode{");
- sb.append("nodeIdentifier=").append(nodeIdentifier);
- sb.append(", children=").append(mappedChildren);
- sb.append('}');
- return sb.toString();
+ protected boolean valueEquals(final AbstractImmutableNormalizedNode<?, ?> other) {
+ return children.equals(((ImmutableMapNode) other).children);
}
}
}
private final ListSchemaNode schema;
- protected ImmutableMapNodeSchemaAwareBuilder(ListSchemaNode schema) {
- super();
- this.schema = schema;
+ protected ImmutableMapNodeSchemaAwareBuilder(final ListSchemaNode schema) {
+ this.schema = Preconditions.checkNotNull(schema);
super.withNodeIdentifier(new InstanceIdentifier.NodeIdentifier(schema.getQName()));
}
- public static CollectionNodeBuilder<MapEntryNode, MapNode> create(ListSchemaNode schema) {
+ protected ImmutableMapNodeSchemaAwareBuilder(final ListSchemaNode schema, final ImmutableMapNode node) {
+ super(node);
+ this.schema = Preconditions.checkNotNull(schema);
+ super.withNodeIdentifier(new InstanceIdentifier.NodeIdentifier(schema.getQName()));
+ }
+
+ public static CollectionNodeBuilder<MapEntryNode, MapNode> create(final ListSchemaNode schema) {
return new ImmutableMapNodeSchemaAwareBuilder(schema);
}
+ public static CollectionNodeBuilder<MapEntryNode, MapNode> create(final ListSchemaNode schema, final MapNode node) {
+ if (!(node instanceof ImmutableMapNode)) {
+ throw new UnsupportedOperationException(String.format("Cannot initialize from class %s", node.getClass()));
+ }
+
+ return new ImmutableMapNodeSchemaAwareBuilder(schema, (ImmutableMapNode) node);
+ }
+
@Override
- public CollectionNodeBuilder<MapEntryNode, MapNode> withChild(MapEntryNode child) {
+ public CollectionNodeBuilder<MapEntryNode, MapNode> withChild(final MapEntryNode child) {
Preconditions.checkArgument(schema.getQName().equals(child.getNodeType()),
"Incompatible node type, should be: %s, is: %s", schema.getQName(), child.getNodeType());
return super.withChild(child);
}
@Override
- public CollectionNodeBuilder<MapEntryNode, MapNode> withNodeIdentifier(InstanceIdentifier.NodeIdentifier nodeIdentifier) {
+ public CollectionNodeBuilder<MapEntryNode, MapNode> withNodeIdentifier(final InstanceIdentifier.NodeIdentifier nodeIdentifier) {
throw new UnsupportedOperationException("Node identifier created from schema");
}
}
*/
package org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.valid;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
+import java.util.Collection;
+import java.util.Collections;
+
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableAugmentationNodeSchemaAwareBuilder;
import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-import java.util.Collection;
-import java.util.Collections;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
/**
* General validator for container like statements, e.g. container, list-entry, choice, augment
public class DataNodeContainerValidator {
private final DataNodeContainer schema;
- private Collection<AugmentationSchema> augmentations;
+ private final Collection<AugmentationSchema> augmentations;
public DataNodeContainerValidator(DataNodeContainer schema) {
- this.schema = schema;
+ this.schema = Preconditions.checkNotNull(schema);
augmentations = schema instanceof AugmentationTarget ? ((AugmentationTarget) schema)
.getAvailableAugmentations() : Collections.<AugmentationSchema> emptyList();
}
return true;
}
}
- // check regular child node
+ // check regular child node (also in child cases)
+ } else if(schema.getDataChildByName(child.getNodeType()) == null) {
+ for (DataSchemaNode dataSchemaNode : schema.getChildNodes()) {
+ if(dataSchemaNode instanceof ChoiceCaseNode) {
+ if(((ChoiceCaseNode) dataSchemaNode).getDataChildByName(child.getNodeType()) != null) {
+ return true;
+ }
+ }
+ }
} else {
- return schema.getDataChildByName(child.getNodeType()) != null;
+ return true;
}
return false;
// FIXME, need to compare Set of QNames(AugmentationIdentifier) with Set of DataSchemaNodes(AugmentationSchema)
// throw away set is created just to compare
// Or if augmentationSchemaNode had a QName, we would just compare a QName
- private boolean equalAugments(AugmentationSchema augmentationSchema, InstanceIdentifier.AugmentationIdentifier identifier) {
+ public static boolean equalAugments(AugmentationSchema augmentationSchema, InstanceIdentifier.AugmentationIdentifier identifier) {
return identifier.getPossibleChildNames().equals(ImmutableAugmentationNodeSchemaAwareBuilder.getChildQNames(augmentationSchema));
}
public void validateChild(InstanceIdentifier.PathArgument child) {
- Preconditions.checkArgument(isKnownChild(child), "Unknown child node: %s, does not belong to: %s", child.getNodeType(), schema);
+ Preconditions.checkArgument(isKnownChild(child), "Unknown child node: %s, does not belong to: %s", child, schema);
// FIXME make a cache for augmentation child sets in constructor
Optional<AugmentationSchema> augmentChild = isAugmentChild(child);
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.nodes;
+
+import java.util.Map;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.AttributesContainer;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+
+import com.google.common.base.Objects.ToStringHelper;
+
+public abstract class AbstractImmutableDataContainerAttrNode<K extends InstanceIdentifier.PathArgument>
+ extends AbstractImmutableDataContainerNode<K>
+ implements AttributesContainer {
+
+ private final Map<QName, String> attributes;
+
+ public AbstractImmutableDataContainerAttrNode(
+ final Map<InstanceIdentifier.PathArgument, DataContainerChild<? extends InstanceIdentifier.PathArgument, ?>> children,
+ final K nodeIdentifier, final Map<QName, String> attributes) {
+ super(children, nodeIdentifier);
+ this.attributes = attributes;
+ }
+
+ @Override
+ public final Map<QName, String> getAttributes() {
+ return attributes;
+ }
+
+ @Override
+ public final Object getAttributeValue(final QName value) {
+ return attributes.get(value);
+ }
+
+ @Override
+ protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
+ return super.addToStringAttributes(toStringHelper).add("attributes", attributes);
+ }
+
+// FIXME: are attributes part of hashCode/equals?
+// @Override
+// protected int valueHashCode() {
+// int result = super.valueHashCode();
+// for (final Entry<?, ?> a : attributes.entrySet()) {
+// result = 31 * result + a.hashCode();
+// }
+// return result;
+// }
+
+ // FIXME: are attributes part of hashCode/equals?
+// @Override
+// protected boolean valueEquals(final NormalizedNode<?, ?> other) {
+// if (!super.valueEquals(other)) {
+// return false;
+// }
+// final Set<Entry<QName, String>> tas = getAttributes().entrySet();
+// final Set<Entry<QName, String>> oas = container.getAttributes().entrySet();
+//
+// return tas.containsAll(oas) && oas.containsAll(tas);
+// return true;
+// }
+}
*/
package org.opendaylight.yangtools.yang.data.impl.schema.nodes;
+import java.util.Collections;
import java.util.Map;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
import com.google.common.base.Optional;
+import com.google.common.collect.Iterables;
-public abstract class AbstractImmutableDataContainerNode<K extends InstanceIdentifier.PathArgument>
- extends AbstractImmutableNormalizedNode<K, Iterable<DataContainerChild<? extends InstanceIdentifier.PathArgument, ?>>>
- implements DataContainerNode<K> {
+public abstract class AbstractImmutableDataContainerNode<K extends PathArgument> //
+ extends AbstractImmutableNormalizedNode<K, Iterable<DataContainerChild<? extends PathArgument, ?>>> //
+ implements Immutable, DataContainerNode<K> {
- protected Map<InstanceIdentifier.PathArgument, DataContainerChild<? extends InstanceIdentifier.PathArgument, ?>> children;
+ protected final Map<PathArgument, DataContainerChild<? extends PathArgument, ?>> children;
- public AbstractImmutableDataContainerNode(Map<InstanceIdentifier.PathArgument, DataContainerChild<? extends InstanceIdentifier.PathArgument, ?>> children, K nodeIdentifier) {
- super(nodeIdentifier, children.values());
+ public AbstractImmutableDataContainerNode(
+ final Map<PathArgument, DataContainerChild<? extends PathArgument, ?>> children, final K nodeIdentifier) {
+ super(nodeIdentifier, Iterables.unmodifiableIterable(children.values()));
this.children = children;
}
@Override
- public Optional<DataContainerChild<? extends InstanceIdentifier.PathArgument, ?>> getChild(InstanceIdentifier.PathArgument child) {
- return Optional.<DataContainerChild<? extends InstanceIdentifier.PathArgument, ?>>fromNullable(children.get(child));
+ public final Optional<DataContainerChild<? extends PathArgument, ?>> getChild(final PathArgument child) {
+ return Optional.<DataContainerChild<? extends PathArgument, ?>> fromNullable(children.get(child));
}
@Override
- public String toString() {
- final StringBuffer sb = new StringBuffer("ImmutableContainerNode{");
- sb.append("nodeIdentifier=").append(nodeIdentifier);
- sb.append(", children=").append(children);
- sb.append('}');
- return sb.toString();
+ protected int valueHashCode() {
+ return children.hashCode();
+ }
+
+ public final Map<PathArgument, DataContainerChild<? extends PathArgument, ?>> getChildren() {
+ // Make sure we do not leak a mutable view
+ return Collections.unmodifiableMap(children);
+ }
+
+ @Override
+ protected boolean valueEquals(final AbstractImmutableNormalizedNode<?, ?> other) {
+ if (!(other instanceof AbstractImmutableDataContainerNode<?>)) {
+ return false;
+ }
+
+ return children.equals(((AbstractImmutableDataContainerNode<?>)other).children);
}
}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.nodes;
+
+import java.util.Map;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.AttributesContainer;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+
+import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.collect.ImmutableMap;
+
+public abstract class AbstractImmutableNormalizedAttrNode<K extends InstanceIdentifier.PathArgument,V>
+ extends AbstractImmutableNormalizedNode<K, V>
+ implements AttributesContainer {
+
+ private final Map<QName, String> attributes;
+
+ protected AbstractImmutableNormalizedAttrNode(final K nodeIdentifier, final V value, final Map<QName, String> attributes) {
+ super(nodeIdentifier, value);
+ this.attributes = ImmutableMap.copyOf(attributes);
+ }
+
+ @Override
+ public final Map<QName, String> getAttributes() {
+ return attributes;
+ }
+
+ @Override
+ public final Object getAttributeValue(final QName value) {
+ return attributes.get(value);
+ }
+
+ @Override
+ protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
+ return super.addToStringAttributes(toStringHelper).add("attributes", attributes);
+ }
+
+ @Override
+ protected int valueHashCode() {
+ final int result = getValue().hashCode();
+// FIXME: are attributes part of hashCode/equals?
+// for (final Entry<?, ?> a : attributes.entrySet()) {
+// result = 31 * result + a.hashCode();
+// }
+ return result;
+ }
+
+ @Override
+ protected boolean valueEquals(final AbstractImmutableNormalizedNode<?, ?> other) {
+ if (!getValue().equals(other.getValue())) {
+ return false;
+ }
+
+// FIXME: are attributes part of hashCode/equals?
+// final Set<Entry<QName, String>> tas = getAttributes().entrySet();
+// final Set<Entry<QName, String>> oas = container.getAttributes().entrySet();
+//
+// return tas.containsAll(oas) && oas.containsAll(tas);
+ return true;
+ }
+}
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import com.google.common.base.Objects;
+import com.google.common.base.Objects.ToStringHelper;
import com.google.common.base.Preconditions;
public abstract class AbstractImmutableNormalizedNode<K extends InstanceIdentifier.PathArgument,V>
implements NormalizedNode<K, V>, Immutable {
- protected final K nodeIdentifier;
- protected V value;
+ private final K nodeIdentifier;
+ private final V value;
- protected AbstractImmutableNormalizedNode(K nodeIdentifier, V value) {
+ protected AbstractImmutableNormalizedNode(final K nodeIdentifier, final V value) {
this.nodeIdentifier = Preconditions.checkNotNull(nodeIdentifier, "nodeIdentifier");
this.value = Preconditions.checkNotNull(value, "value");
}
@Override
- public QName getNodeType() {
+ public final QName getNodeType() {
return getIdentifier().getNodeType();
}
@Override
- public K getIdentifier() {
+ public final K getIdentifier() {
return nodeIdentifier;
}
@Override
- public CompositeNode getParent() {
+ public final CompositeNode getParent() {
throw new UnsupportedOperationException("Deprecated");
}
@Override
- public QName getKey() {
+ public final QName getKey() {
return getNodeType();
}
@Override
- public V getValue() {
+ public final V getValue() {
return value;
}
@Override
- public V setValue(V value) {
+ public final V setValue(final V value) {
throw new UnsupportedOperationException("Immutable");
}
@Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof AbstractImmutableNormalizedNode)) return false;
+ public final String toString() {
+ return addToStringAttributes(Objects.toStringHelper(this)).toString();
+ }
- AbstractImmutableNormalizedNode that = (AbstractImmutableNormalizedNode) o;
+ protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
+ return toStringHelper.add("nodeIdentifier", nodeIdentifier).add("value", getValue());
+ }
- if (!nodeIdentifier.equals(that.nodeIdentifier)) return false;
- if (!value.equals(that.value)) return false;
+ protected abstract boolean valueEquals(AbstractImmutableNormalizedNode<?, ?> other);
+ protected abstract int valueHashCode();
- return true;
+ @Override
+ public final boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (this.getClass() != obj.getClass()) {
+ return false;
+ }
+
+ final AbstractImmutableNormalizedNode<?, ?> other = (AbstractImmutableNormalizedNode<?, ?>)obj;
+ if (!nodeIdentifier.equals(other.nodeIdentifier)) {
+ return false;
+ }
+
+ return valueEquals(other);
}
@Override
- public int hashCode() {
+ public final int hashCode() {
int result = nodeIdentifier.hashCode();
- result = 31 * result + value.hashCode();
+ result = 31 * result + valueHashCode();
return result;
}
}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform;
+
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+/**
+ *
+ * Generic serializer for normalized nodes. NormalizedNodes can be serialized
+ * e.g. to Dom APIs.
+ *
+ * @param <E>
+ * type of resulting/serialized element from NormalizedNode
+ * @param <N>
+ * type of NormalizedNode to be serialized
+ * @param <S>
+ * schema belonging to the type N of NormalizedNode
+ */
+public interface FromNormalizedNodeSerializer<E, N extends NormalizedNode<?, ?>, S> {
+
+ /**
+ *
+ * Serialize one node of type N as a list of E elements. If the serialization
+ * process creates only one E element as a result e.g. container node, the
+ * result element is expected to be wrapped in a list.
+ *
+ * @param schema
+ * @param node
+ * @return Serialized N node as a list of E elements
+ */
+ Iterable<E> serialize(S schema, N node);
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform;
+
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+/**
+ * Factory for different normalized node serializers.
+ *
+ * @param <E>
+ * type of resulting/serialized element from NormalizedNode
+ */
+public interface FromNormalizedNodeSerializerFactory<E> {
+ FromNormalizedNodeSerializer<E, AugmentationNode, AugmentationSchema> getAugmentationNodeSerializer();
+ FromNormalizedNodeSerializer<E, ChoiceNode, org.opendaylight.yangtools.yang.model.api.ChoiceNode> getChoiceNodeSerializer();
+ FromNormalizedNodeSerializer<E, ContainerNode, ContainerSchemaNode> getContainerNodeSerializer();
+ FromNormalizedNodeSerializer<E, LeafNode<?>, LeafSchemaNode> getLeafNodeSerializer();
+ FromNormalizedNodeSerializer<E, LeafSetEntryNode<?>, LeafListSchemaNode> getLeafSetEntryNodeSerializer();
+ FromNormalizedNodeSerializer<E, LeafSetNode<?>, LeafListSchemaNode> getLeafSetNodeSerializer();
+ FromNormalizedNodeSerializer<E, MapEntryNode, ListSchemaNode> getMapEntryNodeSerializer();
+ FromNormalizedNodeSerializer<E, MapNode, ListSchemaNode> getMapNodeSerializer();
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform;
+
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+/**
+ *
+ * Generic parser for normalized nodes. NormalizedNodes can be parsed
+ * e.g. from Dom APIs.
+ *
+ * @param <E>
+ * type of element to be parsed into NormalizedNode
+ * @param <N>
+ * type of NormalizedNode to be the result of parsing
+ * @param <S>
+ * schema belonging to the type N of NormalizedNode
+ */
+public interface ToNormalizedNodeParser<E, N extends NormalizedNode<?, ?>, S> {
+
+ /**
+ *
+ * Parse a list of E elements as a NormalizedNode of type N. If the parsing
+ * process expects only one E element as input e.g. container node, the
+ * input element will be wrapped in a list.
+ *
+ * @param xmlDom
+ * @param schema
+ * @return NormalizedNode as a result of parsing list of E elements with schema S
+ */
+ N parse(Iterable<E> xmlDom, S schema);
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform;
+
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+/**
+ * Factory for different normalized node parsers.
+ *
+ * @param <E>
+ * type of element to be parsed into NormalizedNode
+ */
+public interface ToNormalizedNodeParserFactory<E> {
+ ToNormalizedNodeParser<E, AugmentationNode, AugmentationSchema> getAugmentationNodeParser();
+ ToNormalizedNodeParser<E, ChoiceNode, org.opendaylight.yangtools.yang.model.api.ChoiceNode> getChoiceNodeParser();
+ ToNormalizedNodeParser<E, ContainerNode, ContainerSchemaNode> getContainerNodeParser();
+ ToNormalizedNodeParser<E, LeafNode<?>, LeafSchemaNode> getLeafNodeParser();
+ ToNormalizedNodeParser<E, LeafSetEntryNode<?>, LeafListSchemaNode> getLeafSetEntryNodeParser();
+ ToNormalizedNodeParser<E, LeafSetNode<?>, LeafListSchemaNode> getLeafSetNodeParser();
+ ToNormalizedNodeParser<E, MapEntryNode, ListSchemaNode> getMapEntryNodeParser();
+ ToNormalizedNodeParser<E, MapNode, ListSchemaNode> getMapNodeParser();
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.base;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import com.google.common.collect.Maps;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.*;
+
+/**
+ * Proxy for AugmentationSchema. Child node schemas are replaced with actual schemas from parent.
+ */
+public final class AugmentationSchemaProxy implements AugmentationSchema {
+ private final AugmentationSchema delegate;
+ private final Set<DataSchemaNode> realChildSchemas;
+ private final Map<QName, DataSchemaNode> mappedChildSchemas;
+
+ public AugmentationSchemaProxy(AugmentationSchema augmentSchema, Set<DataSchemaNode> realChildSchemas) {
+ this.delegate = augmentSchema;
+ this.realChildSchemas = realChildSchemas;
+
+ this.mappedChildSchemas = Maps.newHashMap();
+ for (DataSchemaNode realChildSchema : realChildSchemas) {
+ mappedChildSchemas.put(realChildSchema.getQName(), realChildSchema);
+ }
+ }
+
+ @Override
+ public RevisionAwareXPath getWhenCondition() {
+ return delegate.getWhenCondition();
+ }
+
+ @Override
+ public String getDescription() {
+ return delegate.getDescription();
+ }
+
+ @Override
+ public String getReference() {
+ return delegate.getReference();
+ }
+
+ @Override
+ public Status getStatus() {
+ return delegate.getStatus();
+ }
+
+ @Override
+ public SchemaPath getTargetPath() {
+ return delegate.getTargetPath();
+ }
+
+ @Override
+ public List<UnknownSchemaNode> getUnknownSchemaNodes() {
+ return delegate.getUnknownSchemaNodes();
+ }
+
+ @Override
+ public Set<TypeDefinition<?>> getTypeDefinitions() {
+ return delegate.getTypeDefinitions();
+ }
+
+ @Override
+ public Set<DataSchemaNode> getChildNodes() {
+ return realChildSchemas;
+ }
+
+ @Override
+ public Set<GroupingDefinition> getGroupings() {
+ return delegate.getGroupings();
+ }
+
+ @Override
+ public DataSchemaNode getDataChildByName(QName name) {
+ if(mappedChildSchemas.containsKey(name)) {
+ return mappedChildSchemas.get(name);
+ }
+
+ throw new IllegalArgumentException("Unknown child: " + name + " in: " + delegate);
+ }
+
+ @Override
+ public DataSchemaNode getDataChildByName(String name) {
+ // Unused
+ throw new UnsupportedOperationException("Unable to retrieve child node by name");
+ }
+
+ @Override
+ public Set<UsesNode> getUses() {
+ return delegate.getUses();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.base;
+
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils;
+import org.opendaylight.yangtools.yang.model.api.*;
+import java.util.*;
+
+public final class SchemaUtils {
+
+ private SchemaUtils() {
+ }
+
+ public static DataSchemaNode findSchemaForChild(DataNodeContainer schema, QName qname) {
+ Set<DataSchemaNode> childNodes = schema.getChildNodes();
+ return findSchemaForChild(schema, qname, childNodes);
+ }
+
+ public static DataSchemaNode findSchemaForChild(DataNodeContainer schema, QName qname, Set<DataSchemaNode> childNodes) {
+ Optional<DataSchemaNode> childSchema = XmlDocumentUtils.findFirstSchema(qname, childNodes);
+ Preconditions.checkState(childSchema.isPresent(),
+ "Unknown child(ren) node(s) detected, identified by: %s, in: %s", qname, schema);
+ return childSchema.get();
+ }
+
+ public static AugmentationSchema findSchemaForAugment(AugmentationTarget schema, Set<QName> qNames) {
+ Optional<AugmentationSchema> schemaForAugment = findAugment(schema, qNames);
+ Preconditions.checkState(schemaForAugment.isPresent(), "Unknown augmentation node detected, identified by: %s, in: %s",
+ qNames, schema);
+ return schemaForAugment.get();
+ }
+
+ public static AugmentationSchema findSchemaForAugment(ChoiceNode schema, Set<QName> qNames) {
+ Optional<AugmentationSchema> schemaForAugment = Optional.absent();
+
+ for (ChoiceCaseNode choiceCaseNode : schema.getCases()) {
+ schemaForAugment = findAugment(choiceCaseNode, qNames);
+ if(schemaForAugment.isPresent()) {
+ break;
+ }
+ }
+
+ Preconditions.checkState(schemaForAugment.isPresent(), "Unknown augmentation node detected, identified by: %s, in: %s",
+ qNames, schema);
+ return schemaForAugment.get();
+ }
+
+ private static Optional<AugmentationSchema> findAugment(AugmentationTarget schema, Set<QName> qNames) {
+ for (AugmentationSchema augment : schema.getAvailableAugmentations()) {
+
+ HashSet<QName> qNamesFromAugment = Sets.newHashSet(Collections2.transform(augment.getChildNodes(), new Function<DataSchemaNode, QName>() {
+ @Override
+ public QName apply(DataSchemaNode input) {
+ return input.getQName();
+ }
+ }));
+
+ if(qNamesFromAugment.equals(qNames)) {
+ return Optional.of(augment);
+ }
+ }
+
+ return Optional.absent();
+ }
+
+ public static DataSchemaNode findSchemaForChild(ChoiceNode schema, QName childPartialQName) {
+ for (ChoiceCaseNode choiceCaseNode : schema.getCases()) {
+ Optional<DataSchemaNode> childSchema = XmlDocumentUtils.findFirstSchema(childPartialQName,
+ choiceCaseNode.getChildNodes());
+ if (childSchema.isPresent()) {
+ return childSchema.get();
+ }
+ }
+
+
+ throw new IllegalStateException(String.format("Unknown child(ren) node(s) detected, identified by: %s, in: %s",
+ childPartialQName, schema));
+ }
+
+ /**
+ * Recursively find all child nodes that come from choices in augment.
+ *
+ * @return Map with all child nodes, to their most top augmentation
+ */
+ public static Map<QName,ChoiceNode> mapChildElementsFromChoicesInAugment(AugmentationSchema schema, Set<DataSchemaNode> realChildSchemas) {
+ Map<QName, ChoiceNode> mappedChoices = Maps.newLinkedHashMap();
+
+ for (DataSchemaNode realChildSchema : realChildSchemas) {
+ if(realChildSchema instanceof ChoiceNode)
+ mappedChoices.putAll(mapChildElementsFromChoices(schema, realChildSchemas));
+ }
+
+ return mappedChoices;
+ }
+
+ /**
+ * Recursively find all child nodes that come from choices.
+ *
+ * @return Map with all child nodes, to their most top augmentation
+ */
+ public static Map<QName, ChoiceNode> mapChildElementsFromChoices(DataNodeContainer schema) {
+ Set<DataSchemaNode> childNodes = schema.getChildNodes();
+
+ return mapChildElementsFromChoices(schema, childNodes);
+ }
+
+ private static Map<QName, ChoiceNode> mapChildElementsFromChoices(DataNodeContainer schema, Set<DataSchemaNode> childNodes) {
+ Map<QName, ChoiceNode> mappedChoices = Maps.newLinkedHashMap();
+
+ for (final DataSchemaNode childSchema : childNodes) {
+ if(childSchema instanceof ChoiceNode) {
+ for (ChoiceCaseNode choiceCaseNode : ((ChoiceNode) childSchema).getCases()) {
+
+ for (QName qName : getChildNodes(choiceCaseNode)) {
+ mappedChoices.put(qName, (ChoiceNode) childSchema);
+ }
+ }
+ }
+ }
+
+ // Remove augmented choices
+ // TODO ineffective, mapping augments one more time is not necessary, the map could be injected
+ if(schema instanceof AugmentationTarget) {
+ final Map<QName, AugmentationSchema> augments = mapChildElementsFromAugments((AugmentationTarget) schema);
+
+ return Maps.filterKeys(mappedChoices, new Predicate<QName>() {
+ @Override
+ public boolean apply(QName input) {
+ return augments.containsKey(input) == false;
+ }
+ });
+ }
+
+ return mappedChoices;
+ }
+
+ /**
+ * Recursively find all child nodes that come from augmentations.
+ *
+ * @return Map with all child nodes, to their most top augmentation
+ */
+ public static Map<QName, AugmentationSchema> mapChildElementsFromAugments(AugmentationTarget schema) {
+
+ Map<QName, AugmentationSchema> childNodesToAugmentation = Maps.newLinkedHashMap();
+
+ // Find QNames of augmented child nodes
+ Map<QName, AugmentationSchema> augments = Maps.newHashMap();
+ for (final AugmentationSchema augmentationSchema : schema.getAvailableAugmentations()) {
+ for (DataSchemaNode dataSchemaNode : augmentationSchema.getChildNodes()) {
+ augments.put(dataSchemaNode.getQName(), augmentationSchema);
+ }
+ }
+
+ // Augmented nodes have to be looked up directly in augmentationTarget
+ // because nodes from augment do not contain nodes from other augmentations
+ if (schema instanceof DataNodeContainer) {
+
+ for (DataSchemaNode child : ((DataNodeContainer) schema).getChildNodes()) {
+ // If is not augmented child, continue
+ if (augments.containsKey(child.getQName()) == false)
+ continue;
+
+ AugmentationSchema mostTopAugmentation = augments.get(child.getQName());
+
+ // recursively add all child nodes in case of augment, case and choice
+ if (child instanceof AugmentationSchema || child instanceof ChoiceCaseNode) {
+ for (QName qName : getChildNodes((DataNodeContainer) child)) {
+ childNodesToAugmentation.put(qName, mostTopAugmentation);
+ }
+ } else if (child instanceof ChoiceNode) {
+ for (ChoiceCaseNode choiceCaseNode : ((ChoiceNode) child).getCases()) {
+ for (QName qName : getChildNodes(choiceCaseNode)) {
+ childNodesToAugmentation.put(qName, mostTopAugmentation);
+ }
+ }
+ } else {
+ childNodesToAugmentation.put(child.getQName(), mostTopAugmentation);
+ }
+ }
+ }
+
+ // Choice Node has to map child nodes from all its cases
+ if (schema instanceof ChoiceNode) {
+ for (ChoiceCaseNode choiceCaseNode : ((ChoiceNode) schema).getCases()) {
+ if (augments.containsKey(choiceCaseNode.getQName()) == false) {
+ continue;
+ }
+
+ for (QName qName : getChildNodes(choiceCaseNode)) {
+ childNodesToAugmentation.put(qName, augments.get(choiceCaseNode.getQName()));
+ }
+ }
+ }
+
+ return childNodesToAugmentation;
+ }
+
+ /**
+ * Recursively list all child nodes.
+ *
+ * In case of choice, augment and cases, step in.
+ */
+ public static Set<QName> getChildNodes(DataNodeContainer nodeContainer) {
+ Set<QName> allChildNodes = Sets.newHashSet();
+
+ for (DataSchemaNode childSchema : nodeContainer.getChildNodes()) {
+ if(childSchema instanceof ChoiceNode) {
+ for (ChoiceCaseNode choiceCaseNode : ((ChoiceNode) childSchema).getCases()) {
+ allChildNodes.addAll(getChildNodes(choiceCaseNode));
+ }
+ } else if(childSchema instanceof AugmentationSchema || childSchema instanceof ChoiceCaseNode) {
+ allChildNodes.addAll(getChildNodes((DataNodeContainer) childSchema));
+ }
+ else {
+ allChildNodes.add(childSchema.getQName());
+ }
+ }
+
+ return allChildNodes;
+ }
+
+ /**
+ * Retrieves real schemas for augmented child node.
+ *
+ * Schema of the same child node from augment, and directly from target is not the same.
+ * Schema of child node from augment is incomplete, therefore its useless for xml <-> normalizedNode translation.
+ *
+ */
+ public static Set<DataSchemaNode> getRealSchemasForAugment(AugmentationTarget targetSchema, AugmentationSchema augmentSchema) {
+ if(targetSchema.getAvailableAugmentations().contains(augmentSchema) == false) {
+ return Collections.emptySet();
+ }
+
+ Set<DataSchemaNode> realChildNodes = Sets.newHashSet();
+
+ if(targetSchema instanceof DataNodeContainer) {
+ realChildNodes = getRealSchemasForAugment((DataNodeContainer)targetSchema, augmentSchema);
+ } else if(targetSchema instanceof ChoiceNode) {
+ for (DataSchemaNode dataSchemaNode : augmentSchema.getChildNodes()) {
+ for (ChoiceCaseNode choiceCaseNode : ((ChoiceNode) targetSchema).getCases()) {
+ if(getChildNodes(choiceCaseNode).contains(dataSchemaNode.getQName())) {
+ realChildNodes.add(choiceCaseNode.getDataChildByName(dataSchemaNode.getQName()));
+ }
+ }
+ }
+ }
+
+ return realChildNodes;
+ }
+
+ public static Set<DataSchemaNode> getRealSchemasForAugment(DataNodeContainer targetSchema,
+ AugmentationSchema augmentSchema) {
+ Set<DataSchemaNode> realChildNodes = Sets.newHashSet();
+ for (DataSchemaNode dataSchemaNode : augmentSchema.getChildNodes()) {
+ DataSchemaNode realChild = targetSchema.getDataChildByName(dataSchemaNode.getQName());
+ realChildNodes.add(realChild);
+ }
+ return realChildNodes;
+ }
+
+ public static Optional<ChoiceCaseNode> detectCase(ChoiceNode schema, DataContainerChild<?, ?> child) {
+ for (ChoiceCaseNode choiceCaseNode : schema.getCases()) {
+ if (child instanceof AugmentationNode
+ && belongsToCaseAugment(choiceCaseNode,
+ (InstanceIdentifier.AugmentationIdentifier) child.getIdentifier())) {
+ return Optional.of(choiceCaseNode);
+ } else if (choiceCaseNode.getDataChildByName(child.getNodeType()) != null) {
+ return Optional.of(choiceCaseNode);
+ }
+ }
+
+ return Optional.absent();
+ }
+
+ public static boolean belongsToCaseAugment(ChoiceCaseNode caseNode, InstanceIdentifier.AugmentationIdentifier childToProcess) {
+ for (AugmentationSchema augmentationSchema : caseNode.getAvailableAugmentations()) {
+
+ Set<QName> currentAugmentChildNodes = Sets.newHashSet();
+ for (DataSchemaNode dataSchemaNode : augmentationSchema.getChildNodes()) {
+ currentAugmentChildNodes.add(dataSchemaNode.getQName());
+ }
+
+ if(childToProcess.getPossibleChildNames().equals(currentAugmentChildNodes)){
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.SchemaUtils;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+/**
+ * Abstract(base) parser for AugmentationNode, parses elements of type E.
+ *
+ * @param <E> type of elements to be parsed
+ */
+public abstract class AugmentationNodeBaseParser<E> extends
+ BaseDispatcherParser<E,AugmentationNode, AugmentationSchema> {
+
+ @Override
+ protected final DataContainerNodeBuilder<InstanceIdentifier.AugmentationIdentifier, AugmentationNode> getBuilder(AugmentationSchema schema) {
+ return Builders.augmentationBuilder(schema);
+ }
+
+ @Override
+ protected final Set<DataSchemaNode> getRealSchemasForAugment(AugmentationSchema schema, AugmentationSchema augmentSchema) {
+ return SchemaUtils.getRealSchemasForAugment(schema, augmentSchema);
+ }
+
+
+ @Override
+ protected final DataSchemaNode getSchemaForChild(AugmentationSchema schema, QName childQName) {
+ return SchemaUtils.findSchemaForChild(schema, childQName);
+ }
+
+ @Override
+ protected final Map<QName, ChoiceNode> mapChildElementsFromChoices(AugmentationSchema schema) {
+ return SchemaUtils.mapChildElementsFromChoices(schema);
+ }
+
+ @Override
+ protected final Map<QName, AugmentationSchema> mapChildElementsFromAugments(AugmentationSchema schema) {
+ return Collections.emptyMap();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.AttributesBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.ToNormalizedNodeParser;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.AugmentationSchemaProxy;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.LinkedListMultimap;
+
+/**
+ * Abstract(base) Parser for DataContainerNodes e.g. ContainerNode, AugmentationNode.
+ */
+public abstract class BaseDispatcherParser<E, N extends DataContainerNode<?>, S>
+ implements ToNormalizedNodeParser<E, N, S> {
+
+ /**
+ *
+ * @param schema
+ * @return New(empty) instance of a builder to build node identified by schema.
+ */
+ protected abstract DataContainerNodeBuilder<?, N> getBuilder(S schema);
+
+ /**
+ *
+ * @param schema
+ * @param childQName QName of a child being parsed, QName does not continue revision date
+ * @return schema object for child identified by parent schema: schema and QName childQName
+ */
+ protected abstract DataSchemaNode getSchemaForChild(S schema, QName childQName);
+
+ /**
+ *
+ * @param xml
+ * @return map from QName to child elements. Multiple elements are allowed under QName.
+ */
+ protected abstract LinkedListMultimap<QName, E> mapChildElements(Iterable<E> xml);
+
+ /**
+ *
+ * @param schema
+ * @return map from QName to ChoiceNode schema of child nodes that are
+ * contained within a choice statement under current schema.
+ */
+ protected abstract Map<QName, ChoiceNode> mapChildElementsFromChoices(S schema);
+
+ /**
+ *
+ * @param schema
+ * @return map from QName to child elements that are added by augmentation
+ * that targets current schema.
+ */
+ protected abstract Map<QName, AugmentationSchema> mapChildElementsFromAugments(S schema);
+
+ /**
+ *
+ * @param schema
+ * @param augmentSchema
+ * @return Set of real schema objects that represent child nodes of an
+ * augmentation. Augmentation schema child nodes, if further
+ * augmented, do not contain further augmented, that are crucial for
+ * parsing. The real schema object can be retrieved from parent schema: schema.
+ */
+ protected abstract Set<DataSchemaNode> getRealSchemasForAugment(S schema, AugmentationSchema augmentSchema);
+
+ /**
+ *
+ * @return dispatcher object to dispatch parsing of child elements, might be
+ * the same instance if provided parsers are immutable.
+ */
+ protected abstract NodeParserDispatcher<E> getDispatcher();
+
+ @Override
+ public N parse(Iterable<E> elements, S schema) {
+
+ checkAtLeastOneNode(schema, elements);
+
+ DataContainerNodeBuilder<?, N> containerBuilder = getBuilder(schema);
+
+ // Map child nodes to QName
+ LinkedListMultimap<QName, E> mappedChildElements = mapChildElements(elements);
+
+ // Map child nodes from Augments
+ Map<QName, AugmentationSchema> mappedAugmentChildNodes = mapChildElementsFromAugments(schema);
+ LinkedListMultimap<AugmentationSchema, E> augmentsToElements = LinkedListMultimap.create();
+
+ // Map child nodes from choices
+ Map<QName, ChoiceNode> mappedChoiceChildNodes = mapChildElementsFromChoices(schema);
+ LinkedListMultimap<ChoiceNode, E> choicesToElements = LinkedListMultimap.create();
+
+ // process Child nodes
+ for (QName childPartialQName : mappedChildElements.keySet()) {
+ DataSchemaNode childSchema = getSchemaForChild(schema, childPartialQName);
+ List<E> childrenForQName = mappedChildElements.get(childPartialQName);
+
+ // Augment
+ if (isMarkedAs(mappedAugmentChildNodes, childSchema.getQName())) {
+ AugmentationSchema augmentationSchema = mappedAugmentChildNodes.get(childSchema.getQName());
+ augmentsToElements.putAll(augmentationSchema, childrenForQName);
+ // Choices
+ } else if (isMarkedAs(mappedChoiceChildNodes, childSchema.getQName())) {
+ ChoiceNode choiceSchema = mappedChoiceChildNodes.get(childSchema.getQName());
+ choicesToElements.putAll(choiceSchema, childrenForQName);
+ // Regular child nodes
+ } else {
+ DataContainerChild<? extends InstanceIdentifier.PathArgument, ?> builtChildNode = getDispatcher()
+ .dispatchChildElement(childSchema, childrenForQName);
+ containerBuilder.withChild(builtChildNode);
+ }
+ }
+
+ // TODO ordering is not preserved for choice and augment elements
+ for (ChoiceNode choiceSchema : choicesToElements.keySet()) {
+ containerBuilder.withChild(getDispatcher().dispatchChildElement(choiceSchema,
+ choicesToElements.get(choiceSchema)));
+ }
+
+ for (AugmentationSchema augmentSchema : augmentsToElements.keySet()) {
+ Set<DataSchemaNode> realChildSchemas = getRealSchemasForAugment(schema, augmentSchema);
+ AugmentationSchemaProxy augSchemaProxy = new AugmentationSchemaProxy(augmentSchema, realChildSchemas);
+ containerBuilder.withChild(getDispatcher().dispatchChildElement(augSchemaProxy, augmentsToElements.get(augmentSchema)));
+ }
+
+ if (containerBuilder instanceof AttributesBuilder) {
+ final int size = Iterables.size(elements);
+ Preconditions.checkArgument(size == 1, "Unexpected number of elements: %s, should be 1 for: %s",
+ size, schema);
+ ((AttributesBuilder<?>) containerBuilder).withAttributes(getAttributes(elements.iterator().next()));
+ }
+
+ return containerBuilder.build();
+ }
+
+ protected Map<QName, String> getAttributes(E e) {
+ return Collections.emptyMap();
+ }
+
+ private boolean isMarkedAs(Map<QName, ?> mappedAugmentChildNodes, QName qName) {
+ return mappedAugmentChildNodes.containsKey(qName);
+ }
+
+ protected void checkOnlyOneNode(S schema, Iterable<E> childNodes) {
+ final int size = Iterables.size(childNodes);
+ Preconditions.checkArgument(size == 1,
+ "Node detected multiple times, should be 1, identified by: %s, found: %s", schema, childNodes);
+ }
+
+ private void checkAtLeastOneNode(S schema, Iterable<E> childNodes) {
+ Preconditions.checkArgument(Iterables.isEmpty(childNodes) == false,
+ "Node detected 0 times, should be at least 1, identified by: %s, found: %s", schema, childNodes);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.SchemaUtils;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+/**
+ * Abstract(base) parser for ChoiceNodes, parses elements of type E.
+ *
+ * @param <E> type of elements to be parsed
+ */
+public abstract class ChoiceNodeBaseParser<E> extends
+ BaseDispatcherParser<E, ChoiceNode, org.opendaylight.yangtools.yang.model.api.ChoiceNode> {
+
+ @Override
+ protected final DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifier, ChoiceNode> getBuilder(
+ org.opendaylight.yangtools.yang.model.api.ChoiceNode schema) {
+ return Builders.choiceBuilder(schema);
+ }
+
+ @Override
+ protected final Set<DataSchemaNode> getRealSchemasForAugment(org.opendaylight.yangtools.yang.model.api.ChoiceNode schema,
+ AugmentationSchema augmentSchema) {
+ Set<DataSchemaNode> fromAllCases = Sets.newHashSet();
+
+ fromAllCases.addAll(SchemaUtils.getRealSchemasForAugment(schema, augmentSchema));
+
+ for (ChoiceCaseNode choiceCaseNode : schema.getCases()) {
+ fromAllCases.addAll(SchemaUtils.getRealSchemasForAugment((AugmentationTarget) choiceCaseNode, augmentSchema));
+ }
+
+ return fromAllCases;
+ }
+
+ @Override
+ protected final DataSchemaNode getSchemaForChild(org.opendaylight.yangtools.yang.model.api.ChoiceNode schema,
+ QName childQName) {
+ return SchemaUtils.findSchemaForChild(schema, childQName);
+ }
+
+ @Override
+ protected final Map<QName, org.opendaylight.yangtools.yang.model.api.ChoiceNode> mapChildElementsFromChoices(
+ org.opendaylight.yangtools.yang.model.api.ChoiceNode schema) {
+ Map<QName, org.opendaylight.yangtools.yang.model.api.ChoiceNode> mappedChoices = Maps.newLinkedHashMap();
+
+ for (ChoiceCaseNode choiceCaseNode : schema.getCases()) {
+ mappedChoices.putAll(SchemaUtils.mapChildElementsFromChoices(choiceCaseNode));
+ }
+
+ return mappedChoices;
+ }
+
+ @Override
+ protected final Map<QName, AugmentationSchema> mapChildElementsFromAugments(
+ org.opendaylight.yangtools.yang.model.api.ChoiceNode schema) {
+ Map<QName, AugmentationSchema> mappedAugments = Maps.newLinkedHashMap();
+
+ for (ChoiceCaseNode choiceCaseNode : schema.getCases()) {
+ mappedAugments.putAll(SchemaUtils.mapChildElementsFromAugments(choiceCaseNode));
+ }
+ return mappedAugments;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.SchemaUtils;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+/**
+ * Abstract(base) parser for ContainerNodes, parses elements of type E.
+ *
+ * @param <E> type of elements to be parsed
+ */
+public abstract class ContainerNodeBaseParser<E> extends
+ BaseDispatcherParser<E, ContainerNode, ContainerSchemaNode> {
+
+ @Override
+ protected final DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifier, ContainerNode> getBuilder(
+ ContainerSchemaNode schema) {
+ return Builders.containerBuilder(schema);
+ }
+
+ @Override
+ public final ContainerNode parse(Iterable<E> elements, ContainerSchemaNode schema) {
+ checkOnlyOneNode(schema, elements);
+ return super.parse(elements, schema);
+ }
+
+ @Override
+ protected final Set<DataSchemaNode> getRealSchemasForAugment(ContainerSchemaNode schema, AugmentationSchema augmentSchema) {
+ return SchemaUtils.getRealSchemasForAugment((AugmentationTarget) schema, augmentSchema);
+ }
+
+ @Override
+ protected final DataSchemaNode getSchemaForChild(ContainerSchemaNode schema, QName childQName) {
+ return SchemaUtils.findSchemaForChild(schema, childQName);
+ }
+
+ @Override
+ protected final Map<QName, ChoiceNode> mapChildElementsFromChoices(ContainerSchemaNode schema) {
+ return SchemaUtils.mapChildElementsFromChoices(schema);
+ }
+
+ @Override
+ protected final Map<QName, AugmentationSchema> mapChildElementsFromAugments(ContainerSchemaNode schema) {
+ return SchemaUtils.mapChildElementsFromAugments(schema);
+ }
+
+ @Override
+ protected abstract Map<QName, String> getAttributes(E e);
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser;
+
+import java.util.Map;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.ToNormalizedNodeParser;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Iterables;
+
+/**
+ * Abstract(base) parser for LeafNodes, parses elements of type E.
+ *
+ * @param <E> type of elements to be parsed
+ */
+public abstract class LeafNodeBaseParser<E> implements
+ ToNormalizedNodeParser<E, LeafNode<?>, LeafSchemaNode> {
+
+ @Override
+ public final LeafNode<?> parse(Iterable<E> elements, LeafSchemaNode schema) {
+ final int size = Iterables.size(elements);
+ Preconditions.checkArgument(size == 1, "Elements mapped to leaf node illegal count: %s", size);
+
+ final E e = elements.iterator().next();
+ Object value = parseLeaf(e, schema);
+
+ NormalizedNodeAttrBuilder<InstanceIdentifier.NodeIdentifier,Object,LeafNode<Object>> leafBuilder = Builders.leafBuilder(schema);
+
+ leafBuilder.withAttributes(getAttributes(e));
+
+ return leafBuilder.withValue(value).build();
+ }
+
+ /**
+ *
+ * Parse the inner value of a LeafNode from element of type E.
+ *
+ * @param element to be parsed
+ * @param schema schema for leaf
+ * @return parsed element as an Object
+ */
+ protected abstract Object parseLeaf(E element, LeafSchemaNode schema);
+
+ /**
+ *
+ * @param e
+ * @return attributes mapped to QNames
+ */
+ protected abstract Map<QName, String> getAttributes(E e);
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser;
+
+import java.util.Map;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.ToNormalizedNodeParser;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Iterables;
+
+/**
+ * Abstract(base) parser for LeafSetEntryNodes, parses elements of type E.
+ *
+ * @param <E> type of elements to be parsed
+ */
+public abstract class LeafSetEntryNodeBaseParser<E> implements
+ ToNormalizedNodeParser<E, LeafSetEntryNode<?>, LeafListSchemaNode> {
+
+ @Override
+ public final LeafSetEntryNode<Object> parse(Iterable<E> elements, LeafListSchemaNode schema) {
+ final int size = Iterables.size(elements);
+ Preconditions.checkArgument(size == 1, "Xml elements mapped to leaf node illegal count: %s", size);
+
+ final E e = elements.iterator().next();
+ Object value = parseLeafListEntry(e,schema);
+
+ NormalizedNodeAttrBuilder<InstanceIdentifier.NodeWithValue, Object, LeafSetEntryNode<Object>> leafEntryBuilder = Builders
+ .leafSetEntryBuilder(schema);
+ leafEntryBuilder.withAttributes(getAttributes(e));
+
+ return leafEntryBuilder.withValue(value).build();
+ }
+
+ /**
+ *
+ * Parse the inner value of a LeafSetEntryNode from element of type E.
+ *
+ * @param element to be parsed
+ * @param schema schema for leaf-list
+ * @return parsed element as an Object
+ */
+ protected abstract Object parseLeafListEntry(E element, LeafListSchemaNode schema);
+
+ /**
+ *
+ * @param e
+ * @return attributes mapped to QNames
+ */
+ protected abstract Map<QName, String> getAttributes(E e);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser;
+
+import java.util.Collections;
+
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.ToNormalizedNodeParser;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+
+/**
+ * Abstract(base) parser for LeafSetNodes, parses elements of type E.
+ *
+ * @param <E> type of elements to be parsed
+ */
+public abstract class LeafSetNodeBaseParser<E> implements
+ ToNormalizedNodeParser<E, LeafSetNode<?>, LeafListSchemaNode> {
+
+ @Override
+ public final LeafSetNode<?> parse(Iterable<E> childNodes, LeafListSchemaNode schema) {
+
+ ListNodeBuilder<Object, LeafSetEntryNode<Object>> leafListBuilder = Builders.leafSetBuilder(schema);
+ for (E childNode : childNodes) {
+ LeafSetEntryNode<?> builtChild = getLeafSetEntryNodeParser().parse(
+ Collections.singletonList(childNode), schema);
+
+ // TODO: can we get rid of this cast/SuppressWarnings somehow?
+ @SuppressWarnings("unchecked")
+ final LeafSetEntryNode<Object> child = (LeafSetEntryNode<Object>) builtChild;
+ leafListBuilder.withChild(child);
+ }
+
+ return leafListBuilder.build();
+ }
+
+ /**
+ *
+ * @return parser for inner LeafSetEntryNodes used to parse every entry of LeafSetNode, might be the same instance in case its immutable
+ */
+ protected abstract ToNormalizedNodeParser<E, LeafSetEntryNode<?>, LeafListSchemaNode> getLeafSetEntryNodeParser();
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.SchemaUtils;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+/**
+ * Abstract(base) parser for MapEntryNodes, parses elements of type E.
+ *
+ * @param <E> type of elements to be parsed
+ */
+public abstract class MapEntryNodeBaseParser<E> extends BaseDispatcherParser<E, MapEntryNode, ListSchemaNode> {
+
+ @Override
+ protected final DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> getBuilder(
+ ListSchemaNode schema) {
+ return Builders.mapEntryBuilder(schema);
+ }
+
+ @Override
+ public final MapEntryNode parse(Iterable<E> elements, ListSchemaNode schema) {
+ checkOnlyOneNode(schema, elements);
+ return super.parse(elements, schema);
+ }
+
+ @Override
+ protected final Set<DataSchemaNode> getRealSchemasForAugment(ListSchemaNode schema, AugmentationSchema augmentSchema) {
+ return SchemaUtils.getRealSchemasForAugment((AugmentationTarget) schema, augmentSchema);
+ }
+
+ @Override
+ protected final DataSchemaNode getSchemaForChild(ListSchemaNode schema, QName childQName) {
+ return SchemaUtils.findSchemaForChild(schema, childQName);
+ }
+
+ @Override
+ protected final Map<QName, ChoiceNode> mapChildElementsFromChoices(ListSchemaNode schema) {
+ return SchemaUtils.mapChildElementsFromChoices(schema);
+ }
+
+ @Override
+ protected final Map<QName, AugmentationSchema> mapChildElementsFromAugments(ListSchemaNode schema) {
+ return SchemaUtils.mapChildElementsFromAugments(schema);
+ }
+
+ @Override
+ protected abstract Map<QName, String> getAttributes(E e);
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser;
+
+import java.util.Collections;
+
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.ToNormalizedNodeParser;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+/**
+ * Abstract(base) parser for MapNodes, parses elements of type E.
+ *
+ * @param <E> type of elements to be parsed
+ */
+public abstract class MapNodeBaseParser<E> implements ToNormalizedNodeParser<E, MapNode, ListSchemaNode> {
+
+ @Override
+ public final MapNode parse(Iterable<E> childNodes, ListSchemaNode schema) {
+ CollectionNodeBuilder<MapEntryNode, MapNode> listBuilder = Builders.mapBuilder(schema);
+
+ for (E childNode : childNodes) {
+ MapEntryNode listChild = getMapEntryNodeParser().parse(Collections.singletonList(childNode), schema);
+ listBuilder.withChild(listChild);
+ }
+
+ return listBuilder.build();
+ }
+
+ /**
+ *
+ * @return parser for inner MapEntryNodes used to parse every entry of MapNode, might be the same instance in case its immutable
+ */
+ protected abstract ToNormalizedNodeParser<E, MapEntryNode, ListSchemaNode> getMapEntryNodeParser();
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser;
+
+import java.util.List;
+
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.ToNormalizedNodeParserFactory;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+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 com.google.common.base.Preconditions;
+
+/**
+ *
+ * Dispatches the parsing process of elements according to schema and returns the parsed Node.
+ *
+ * @param <E> type of elements parsed
+ */
+public interface NodeParserDispatcher<E> {
+
+ DataContainerChild<?, ?> dispatchChildElement(Object schema, List<E> childNodes);
+
+ /**
+ * Abstract implementation that implements the dispatch conditions. Only requires parsers to be provided.
+ * The same instance of parser can be provided in case it is immutable.
+ */
+ public static abstract class BaseNodeParserDispatcher<E> implements NodeParserDispatcher<E> {
+ private final ToNormalizedNodeParserFactory<E> factory;
+
+ protected BaseNodeParserDispatcher(final ToNormalizedNodeParserFactory<E> factory) {
+ this.factory = Preconditions.checkNotNull(factory);
+ }
+
+ @Override
+ public final DataContainerChild<?, ?> dispatchChildElement(Object schema, List<E> childNodes) {
+ Preconditions.checkArgument(childNodes.isEmpty() == false);
+
+ if (schema instanceof ContainerSchemaNode) {
+ return factory.getContainerNodeParser().parse(childNodes, (ContainerSchemaNode) schema);
+ } else if (schema instanceof LeafSchemaNode) {
+ return factory.getLeafNodeParser().parse(childNodes, (LeafSchemaNode) schema);
+ } else if (schema instanceof LeafListSchemaNode) {
+ return factory.getLeafSetNodeParser().parse(childNodes, (LeafListSchemaNode) schema);
+ } else if (schema instanceof ListSchemaNode) {
+ return factory.getMapNodeParser().parse(childNodes, (ListSchemaNode) schema);
+ } else if (schema instanceof ChoiceNode) {
+ return factory.getChoiceNodeParser().parse(childNodes, (ChoiceNode) schema);
+ } else if (schema instanceof AugmentationSchema) {
+ return factory.getAugmentationNodeParser().parse(childNodes, (AugmentationSchema) schema);
+ }
+
+ throw new IllegalArgumentException("Unable to parse node, unknown schema type: " + schema.getClass());
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer;
+
+import java.util.Set;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.SchemaUtils;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+/**
+ * Abstract(base) serializer for AugmentationNode, serializes elements of type E.
+ *
+ * @param <E> type of serialized elements
+ */
+public abstract class AugmentationNodeBaseSerializer<E> extends
+ BaseDispatcherSerializer<E, AugmentationNode, AugmentationSchema> {
+
+ @Override
+ protected Set<DataSchemaNode> getRealSchemasForAugment(AugmentationSchema schema, AugmentationSchema augmentationSchema) {
+ return SchemaUtils.getRealSchemasForAugment(schema, augmentationSchema);
+ }
+
+ @Override
+ protected DataSchemaNode getSchemaForChild(AugmentationSchema schema,
+ DataContainerChild<? extends InstanceIdentifier.PathArgument, ?> childNode) {
+ return SchemaUtils.findSchemaForChild(schema, childNode.getNodeType());
+ }
+
+ @Override
+ protected AugmentationSchema getAugmentedCase(AugmentationSchema schema, AugmentationNode augmentationNode) {
+ throw new UnsupportedOperationException("");
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer;
+
+import java.util.List;
+import java.util.Set;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.FromNormalizedNodeSerializer;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.AugmentationSchemaProxy;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+/**
+ * Abstract(base) Serializer for DataContainerNodes e.g. ContainerNode, AugmentationNode.
+ */
+public abstract class BaseDispatcherSerializer<E, N extends DataContainerNode<?>, S> implements
+ FromNormalizedNodeSerializer<E, N, S> {
+
+ /**
+ *
+ * @param schema
+ * @param augmentationSchema
+ * @return Set of real schema objects that represent child nodes of an
+ * augmentation. Augmentation schema child nodes, if further
+ * augmented, do not contain further augmented, that are crucial for
+ * parsing. The real schema object can be retrieved from parent schema: schema.
+ */
+ protected abstract Set<DataSchemaNode> getRealSchemasForAugment(S schema, AugmentationSchema augmentationSchema);
+
+ /**
+ *
+ * @param schema
+ * @param childNode
+ * @return Schema object associated with child node identified as: childNode.
+ * Schema should be retrieved from parent schema: schema.
+ */
+ protected abstract DataSchemaNode getSchemaForChild(S schema,
+ DataContainerChild<? extends InstanceIdentifier.PathArgument, ?> childNode);
+
+ /**
+ *
+ * @param schema
+ * @param augmentationNode
+ * @return Schema object associated with augmentation child node identified as: augmentationNode.
+ * Schema should be retrieved from parent schema: schema.
+ */
+ protected abstract AugmentationSchema getAugmentedCase(S schema, AugmentationNode augmentationNode);
+
+ /**
+ *
+ * @return Dispatcher object to dispatch serialization of child elements, might be
+ * the same instance if provided serializers are immutable.
+ */
+ protected abstract NodeSerializerDispatcher<E> getNodeDispatcher();
+
+ @Override
+ public Iterable<E> serialize(S schema, N node) {
+ List<Iterable<E>> choiceChildren = Lists.newArrayList();
+
+ for (DataContainerChild<? extends InstanceIdentifier.PathArgument, ?> choiceChild : node.getValue()) {
+
+ Object childSchema;
+
+ if (choiceChild instanceof AugmentationNode) {
+
+ AugmentationSchema augSchema = getAugmentedCase(schema, (AugmentationNode) choiceChild);
+ Set<DataSchemaNode> realChildSchemas = getRealSchemasForAugment(schema, augSchema);
+ childSchema = new AugmentationSchemaProxy(augSchema, realChildSchemas);
+
+ } else {
+ childSchema = getSchemaForChild(schema, choiceChild);
+ }
+
+ Iterable<E> childElements = getNodeDispatcher().dispatchChildElement(childSchema, choiceChild);
+ choiceChildren.add(Preconditions.checkNotNull(childElements));
+ }
+
+ return Iterables.concat(choiceChildren);
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer;
+
+import java.util.Set;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.SchemaUtils;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+import com.google.common.collect.Sets;
+
+/**
+ * Abstract(base) serializer for ChoiceNodes, serializes elements of type E.
+ *
+ * @param <E> type of serialized elements
+ */
+public abstract class ChoiceNodeBaseSerializer<E>
+ extends
+ BaseDispatcherSerializer<E, ChoiceNode, org.opendaylight.yangtools.yang.model.api.ChoiceNode> {
+
+ @Override
+ protected final DataSchemaNode getSchemaForChild(org.opendaylight.yangtools.yang.model.api.ChoiceNode schema,
+ DataContainerChild<? extends InstanceIdentifier.PathArgument, ?> childNode) {
+ return SchemaUtils.findSchemaForChild(schema, childNode.getNodeType());
+ }
+
+ @Override
+ protected final AugmentationSchema getAugmentedCase(org.opendaylight.yangtools.yang.model.api.ChoiceNode schema,
+ AugmentationNode augmentationNode) {
+ return SchemaUtils.findSchemaForAugment(schema, augmentationNode.getIdentifier().getPossibleChildNames());
+ }
+
+ @Override
+ protected final Set<DataSchemaNode> getRealSchemasForAugment(org.opendaylight.yangtools.yang.model.api.ChoiceNode schema, AugmentationSchema augmentationSchema) {
+ Set<DataSchemaNode> aggregatedSchemas = Sets.newHashSet();
+
+ aggregatedSchemas.addAll(SchemaUtils.getRealSchemasForAugment(schema, augmentationSchema));
+
+ for (ChoiceCaseNode choiceCaseNode : schema.getCases()) {
+ aggregatedSchemas.addAll(SchemaUtils.getRealSchemasForAugment((AugmentationTarget) choiceCaseNode, augmentationSchema));
+ }
+
+ return aggregatedSchemas;
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer;
+
+import java.util.Set;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.SchemaUtils;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+/**
+ * Abstract(base) serializer for ContainerNodes, serializes elements of type E.
+ *
+ * @param <E> type of serialized elements
+ */
+public abstract class ContainerNodeBaseSerializer<E> extends
+ BaseDispatcherSerializer<E, ContainerNode, ContainerSchemaNode> {
+
+ @Override
+ protected final DataSchemaNode getSchemaForChild(ContainerSchemaNode schema,
+ DataContainerChild<? extends InstanceIdentifier.PathArgument, ?> childNode) {
+ return SchemaUtils.findSchemaForChild(schema, childNode.getNodeType());
+ }
+
+ @Override
+ protected final AugmentationSchema getAugmentedCase(ContainerSchemaNode schema, AugmentationNode augmentationNode) {
+ return SchemaUtils.findSchemaForAugment(schema, augmentationNode.getIdentifier().getPossibleChildNames());
+ }
+
+ @Override
+ protected final Set<DataSchemaNode> getRealSchemasForAugment(ContainerSchemaNode schema, AugmentationSchema augmentationSchema) {
+ return SchemaUtils.getRealSchemasForAugment((AugmentationTarget) schema, augmentationSchema);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer;
+
+import java.util.Collections;
+
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.FromNormalizedNodeSerializer;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+
+/**
+ * Abstract(base) serializer for LeafNodes, serializes elements of type E.
+ *
+ * @param <E> type of serialized elements
+ */
+public abstract class LeafNodeBaseSerializer<E> implements
+ FromNormalizedNodeSerializer<E, LeafNode<?>, LeafSchemaNode> {
+
+ @Override
+ public final Iterable<E> serialize(LeafSchemaNode schema, LeafNode<?> node) {
+ return Collections.singletonList(serializeLeaf(schema, node));
+ }
+
+ /**
+ *
+ * Serialize the inner value of a LeafNode into element of type E.
+ *
+ * @param node to be serialized
+ * @param schema schema for leaf
+ * @return serialized inner value as an Element
+ */
+ protected abstract E serializeLeaf(LeafSchemaNode schema, LeafNode<?> node);
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer;
+
+import java.util.Collections;
+
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.FromNormalizedNodeSerializer;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+
+/**
+ * Abstract(base) serializer for LeafSetEntryNodes, serializes elements of type E.
+ *
+ * @param <E> type of serialized elements
+ */
+public abstract class LeafSetEntryNodeBaseSerializer<E> implements
+ FromNormalizedNodeSerializer<E, LeafSetEntryNode<?>, LeafListSchemaNode> {
+
+ @Override
+ public final Iterable<E> serialize(LeafListSchemaNode schema, LeafSetEntryNode<?> node) {
+ return Collections.singletonList(serializeLeaf(schema, node));
+ }
+
+ /**
+ *
+ * Serialize the inner value of a LeafSetEntryNode into element of type E.
+ *
+ * @param node to be serialized
+ * @param schema schema for leaf-list
+ * @return serialized inner value as an Element
+ */
+ protected abstract E serializeLeaf(LeafListSchemaNode schema, LeafSetEntryNode<?> node);
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer;
+
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.FromNormalizedNodeSerializer;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Iterables;
+
+/**
+ * Abstract(base) serializer for LeafSetNodes, serializes elements of type E.
+ *
+ * @param <E> type of serialized elements
+ */
+public abstract class LeafSetNodeBaseSerializer<E> implements
+ FromNormalizedNodeSerializer<E, LeafSetNode<?>, LeafListSchemaNode> {
+
+ @Override
+ public final Iterable<E> serialize(final LeafListSchemaNode schema, final LeafSetNode<?> node) {
+ return Iterables.concat(Iterables.transform(node.getValue(), new Function<LeafSetEntryNode<?>, Iterable<E>>() {
+ @Override
+ public Iterable<E> apply(final LeafSetEntryNode<?> input) {
+ final Iterable<E> serializedChild = getLeafSetEntryNodeSerializer().serialize(schema, input);
+ final int size = Iterables.size(serializedChild);
+ Preconditions.checkState(size == 1,
+ "Unexpected count of elements for leaf-list entry serialized from: %s, should be 1, was: %s",
+ input, size);
+ return serializedChild;
+ }
+ }));
+ }
+
+ /**
+ *
+ * @return serializer for inner LeafSetEntryNodes used to serialize every entry of LeafSetNode, might be the same instance in case its immutable
+ */
+ protected abstract FromNormalizedNodeSerializer<E, LeafSetEntryNode<?>, LeafListSchemaNode> getLeafSetEntryNodeSerializer();
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer;
+
+import java.util.Set;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.SchemaUtils;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+/**
+ * Abstract(base) serializer for MapEntryNodes, serializes elements of type E.
+ *
+ * @param <E> type of serialized elements
+ */
+public abstract class MapEntryNodeBaseSerializer<E> extends
+ BaseDispatcherSerializer<E, MapEntryNode, ListSchemaNode> {
+
+ @Override
+ protected final DataSchemaNode getSchemaForChild(ListSchemaNode schema,
+ DataContainerChild<? extends InstanceIdentifier.PathArgument, ?> childNode) {
+ return SchemaUtils.findSchemaForChild(schema, childNode.getNodeType());
+ }
+
+ @Override
+ protected final AugmentationSchema getAugmentedCase(ListSchemaNode schema, AugmentationNode augmentationNode) {
+ return SchemaUtils.findSchemaForAugment(schema, augmentationNode.getIdentifier().getPossibleChildNames());
+ }
+
+ @Override
+ protected final Set<DataSchemaNode> getRealSchemasForAugment(ListSchemaNode schema, AugmentationSchema augmentationSchema) {
+ return SchemaUtils.getRealSchemasForAugment((AugmentationTarget) schema, augmentationSchema);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer;
+
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.FromNormalizedNodeSerializer;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Iterables;
+
+/**
+ * Abstract(base) serializer for MapNodes, serializes elements of type E.
+ *
+ * @param <E> type of serialized elements
+ */
+public abstract class MapNodeBaseSerializer<E> implements FromNormalizedNodeSerializer<E, MapNode, ListSchemaNode> {
+
+ @Override
+ public final Iterable<E> serialize(final ListSchemaNode schema, final MapNode node) {
+ return Iterables.concat(Iterables.transform(node.getValue(), new Function<MapEntryNode, Iterable<E>>() {
+ @Override
+ public Iterable<E> apply(MapEntryNode input) {
+ final Iterable<E> serializedChild = getMapEntryNodeDomSerializer().serialize(schema, input);
+ final int size = Iterables.size(serializedChild);
+
+ Preconditions.checkState(size == 1,
+ "Unexpected count of entries for list serialized from: %s, should be 1, was: %s",
+ input, size);
+ return serializedChild;
+ }
+ }));
+ }
+
+ /**
+ *
+ * @return serializer for inner MapEntryNodes used to serialize every entry of MapNode, might be the same instance in case its immutable
+ */
+ protected abstract FromNormalizedNodeSerializer<E, MapEntryNode, ListSchemaNode> getMapEntryNodeDomSerializer();
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MixinNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.FromNormalizedNodeSerializerFactory;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+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 com.google.common.base.Preconditions;
+import com.google.common.collect.Iterables;
+
+/**
+ *
+ * Dispatches the serialization process of nodes according to schema and returns the serialized elements.
+ *
+ * @param <E> type of serialized elements
+ */
+public interface NodeSerializerDispatcher<E> {
+
+ Iterable<E> dispatchChildElement(Object childSchema,
+ DataContainerChild<? extends InstanceIdentifier.PathArgument, ?> dataContainerChild);
+
+ /**
+ * Abstract implementation that implements the dispatch conditions. Only requires serializers to be provided.
+ * The same instance of serializer can be provided in case it is immutable.
+ */
+ public static abstract class BaseNodeSerializerDispatcher<E> implements NodeSerializerDispatcher<E> {
+ private final FromNormalizedNodeSerializerFactory<E> factory;
+
+ protected BaseNodeSerializerDispatcher(final FromNormalizedNodeSerializerFactory<E> factory) {
+ this.factory = Preconditions.checkNotNull(factory);
+ }
+
+ @Override
+ public final Iterable<E> dispatchChildElement(Object childSchema,
+ DataContainerChild<? extends InstanceIdentifier.PathArgument, ?> dataContainerChild) {
+ if (dataContainerChild instanceof ContainerNode) {
+ return onContainerNode(childSchema, dataContainerChild);
+ } else if (dataContainerChild instanceof LeafNode<?>) {
+ return onLeafNode(childSchema, dataContainerChild);
+ } else if (dataContainerChild instanceof MixinNode) {
+ if (dataContainerChild instanceof LeafSetNode<?>) {
+ return onLeafListNode(childSchema, dataContainerChild);
+ } else if (dataContainerChild instanceof MapNode) {
+ return onListNode(childSchema, dataContainerChild);
+ } else if (dataContainerChild instanceof ChoiceNode) {
+ return onChoiceNode(childSchema, dataContainerChild);
+ } else if (dataContainerChild instanceof AugmentationNode) {
+ return onAugmentationSchema(childSchema, dataContainerChild);
+ }
+ }
+ throw new IllegalArgumentException("Unable to serialize " + childSchema);
+ }
+
+ private Iterable<E> onAugmentationSchema(Object childSchema,
+ DataContainerChild<? extends InstanceIdentifier.PathArgument, ?> dataContainerChild) {
+ checkSchemaCompatibility(childSchema, AugmentationSchema.class, dataContainerChild);
+ return factory.getAugmentationNodeSerializer().serialize((AugmentationSchema) childSchema,
+ (AugmentationNode) dataContainerChild);
+ }
+
+ private Iterable<E> onChoiceNode(Object childSchema,
+ DataContainerChild<? extends InstanceIdentifier.PathArgument, ?> dataContainerChild) {
+ checkSchemaCompatibility(childSchema, org.opendaylight.yangtools.yang.model.api.ChoiceNode.class,
+ dataContainerChild);
+ return factory.getChoiceNodeSerializer()
+ .serialize((org.opendaylight.yangtools.yang.model.api.ChoiceNode) childSchema,
+ (ChoiceNode) dataContainerChild);
+ }
+
+ private Iterable<E> onListNode(Object childSchema,
+ DataContainerChild<? extends InstanceIdentifier.PathArgument, ?> dataContainerChild) {
+ checkSchemaCompatibility(childSchema, ListSchemaNode.class, dataContainerChild);
+ return factory.getMapNodeSerializer().serialize((ListSchemaNode) childSchema, (MapNode) dataContainerChild);
+ }
+
+ private Iterable<E> onLeafListNode(Object childSchema,
+ DataContainerChild<? extends InstanceIdentifier.PathArgument, ?> dataContainerChild) {
+ checkSchemaCompatibility(childSchema, LeafListSchemaNode.class, dataContainerChild);
+ return factory.getLeafSetNodeSerializer().serialize((LeafListSchemaNode) childSchema,
+ (LeafSetNode<?>) dataContainerChild);
+ }
+
+ private Iterable<E> onLeafNode(Object childSchema,
+ DataContainerChild<? extends InstanceIdentifier.PathArgument, ?> dataContainerChild) {
+ checkSchemaCompatibility(childSchema, LeafSchemaNode.class, dataContainerChild);
+ Iterable<E> elements = factory.getLeafNodeSerializer().serialize((LeafSchemaNode) childSchema,
+ (LeafNode<?>) dataContainerChild);
+ checkOnlyOneSerializedElement(elements, dataContainerChild);
+ return elements;
+ }
+
+ private static void checkOnlyOneSerializedElement(Iterable<?> elements,
+ DataContainerChild<? extends InstanceIdentifier.PathArgument, ?> dataContainerChild) {
+ final int size = Iterables.size(elements);
+ Preconditions.checkArgument(size == 1,
+ "Unexpected count of elements for entry serialized from: %s, should be 1, was: %s",
+ dataContainerChild, size);
+ }
+
+ private Iterable<E> onContainerNode(Object childSchema,
+ DataContainerChild<? extends InstanceIdentifier.PathArgument, ?> dataContainerChild) {
+ checkSchemaCompatibility(childSchema, ContainerSchemaNode.class, dataContainerChild);
+
+ Iterable<E> elements = factory.getContainerNodeSerializer().serialize((ContainerSchemaNode) childSchema,
+ (ContainerNode) dataContainerChild);
+ checkOnlyOneSerializedElement(elements, dataContainerChild);
+ return elements;
+ }
+
+ private static void checkSchemaCompatibility(Object childSchema, Class<?> containerSchemaNodeClass,
+ DataContainerChild<? extends InstanceIdentifier.PathArgument, ?> dataContainerChild) {
+ Preconditions.checkArgument(containerSchemaNodeClass.isAssignableFrom(childSchema.getClass()),
+ "Incompatible schema: %s with node: %s, expected: %s", childSchema, dataContainerChild,
+ containerSchemaNodeClass);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.dom;
+
+import java.net.URI;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.XMLConstants;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec;
+import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlCodecProvider;
+import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import com.google.common.collect.LinkedListMultimap;
+import com.google.common.collect.Lists;
+
+public class DomUtils {
+
+ private DomUtils() {
+ }
+
+ private static final XmlCodecProvider DEFAULT_XML_VALUE_CODEC_PROVIDER = new XmlCodecProvider() {
+
+ @Override
+ public TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> codecFor(TypeDefinition<?> baseType) {
+ return TypeDefinitionAwareCodec.from(baseType);
+ }
+ };
+
+ public static XmlCodecProvider defaultValueCodecProvider() {
+ return DEFAULT_XML_VALUE_CODEC_PROVIDER;
+ }
+
+ public static Object parseXmlValue(Element xml, XmlCodecProvider codecProvider, TypeDefinition<?> type) {
+ TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> codec = codecProvider.codecFor(type);
+
+ String text = xml.getTextContent();
+ text = text.trim();
+
+ Object value;
+ if (codec != null) {
+ value = codec.deserialize(text);
+ } else {
+ value = text;
+ }
+
+ return value;
+ }
+
+ public static void serializeXmlValue(Element itemEl, TypeDefinition<? extends TypeDefinition<?>> type, XmlCodecProvider codecProvider, Object value) {
+ XmlDocumentUtils.writeValueByType(itemEl, type, codecProvider, value);
+ }
+
+ public static LinkedListMultimap<QName, Element> mapChildElementsForSingletonNode(Element node) {
+ List<Element> childNodesCollection = Lists.newArrayList();
+ NodeList childNodes = node.getChildNodes();
+ for (int i = 0; i < childNodes.getLength(); i++) {
+ if(childNodes.item(i) instanceof Element) {
+ childNodesCollection.add((Element) childNodes.item(i));
+ }
+ }
+
+ return mapChildElements(childNodesCollection);
+ }
+
+ public static LinkedListMultimap<QName, Element> mapChildElements(Iterable<Element> childNodesCollection) {
+ LinkedListMultimap<QName, Element> mappedChildElements = LinkedListMultimap.create();
+
+ for (Element element : childNodesCollection) {
+ QName childQName = XmlDocumentUtils.qNameFromElement(element);
+ mappedChildElements.put(childQName, element);
+ }
+
+ return mappedChildElements;
+ }
+
+
+ public static Map<QName, String> toAttributes(NamedNodeMap xmlAttributes) {
+ Map<QName, String> attributes = new HashMap<>();
+
+ for (int i = 0; i < xmlAttributes.getLength(); i++) {
+ Node node = xmlAttributes.item(i);
+ String namespace = node.getNamespaceURI();
+ if (namespace == null) {
+ namespace = "";
+ }
+
+ // Skip namespace definitions
+ if(namespace.equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) {
+ continue;
+ }
+
+ QName qName = new QName(URI.create(namespace), node.getLocalName());
+ attributes.put(qName, node.getNodeValue());
+ }
+ return attributes;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser.AugmentationNodeBaseParser;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser.NodeParserDispatcher;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.DomUtils;
+import org.w3c.dom.Element;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.LinkedListMultimap;
+
+final class AugmentationNodeDomParser extends AugmentationNodeBaseParser<Element> {
+
+ private final NodeParserDispatcher<Element> dispatcher;
+
+ AugmentationNodeDomParser(final NodeParserDispatcher<Element> dispatcher) {
+ this.dispatcher = Preconditions.checkNotNull(dispatcher);
+ }
+
+ @Override
+ protected LinkedListMultimap<QName, Element> mapChildElements(Iterable<Element> elements) {
+ return DomUtils.mapChildElements(elements);
+ }
+
+ @Override
+ protected NodeParserDispatcher<Element> getDispatcher() {
+ return dispatcher;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser.ChoiceNodeBaseParser;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser.NodeParserDispatcher;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.DomUtils;
+import org.w3c.dom.Element;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.LinkedListMultimap;
+
+final class ChoiceNodeDomParser extends ChoiceNodeBaseParser<Element> {
+
+ private final NodeParserDispatcher<Element> dispatcher;
+
+ ChoiceNodeDomParser(NodeParserDispatcher<Element> dispatcher) {
+ this.dispatcher = Preconditions.checkNotNull(dispatcher);
+ }
+
+ @Override
+ protected LinkedListMultimap<QName, Element> mapChildElements(Iterable<Element> xml) {
+ return DomUtils.mapChildElements(xml);
+ }
+
+ @Override
+ protected NodeParserDispatcher<Element> getDispatcher() {
+ return dispatcher;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser;
+
+import java.util.Map;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser.ContainerNodeBaseParser;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser.NodeParserDispatcher;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.DomUtils;
+import org.w3c.dom.Element;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.LinkedListMultimap;
+
+final class ContainerNodeDomParser extends ContainerNodeBaseParser<Element> {
+
+ private final NodeParserDispatcher<Element> dispatcher;
+
+ ContainerNodeDomParser(final NodeParserDispatcher<Element> dispatcher) {
+ this.dispatcher = Preconditions.checkNotNull(dispatcher);
+ }
+
+ @Override
+ protected Map<QName, String> getAttributes(Element element) {
+ return DomUtils.toAttributes(element.getAttributes());
+ }
+
+ @Override
+ protected NodeParserDispatcher<Element> getDispatcher() {
+ return dispatcher;
+ }
+
+ @Override
+ protected LinkedListMultimap<QName, Element> mapChildElements(Iterable<Element> elements) {
+ return DomUtils.mapChildElementsForSingletonNode(elements.iterator().next());
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser;
+
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlCodecProvider;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.ToNormalizedNodeParser;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.ToNormalizedNodeParserFactory;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser.NodeParserDispatcher;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+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.w3c.dom.Element;
+
+public final class DomToNormalizedNodeParserFactory implements ToNormalizedNodeParserFactory<Element> {
+ private final AugmentationNodeDomParser augmentationNodeParser;
+ private final ChoiceNodeDomParser choiceNodeParser;
+ private final ContainerNodeDomParser containerNodeParser;
+ private final LeafNodeDomParser leafNodeParser;
+ private final LeafSetEntryNodeDomParser leafSetEntryNodeParser;
+ private final LeafSetNodeDomParser leafSetNodeParser;
+ private final MapNodeDomParser mapNodeParser;
+ private final MapEntryNodeDomParser mapEntryNodeParser;
+
+ private DomToNormalizedNodeParserFactory(final XmlCodecProvider codecProvider) {
+ leafNodeParser = new LeafNodeDomParser(codecProvider);
+ leafSetEntryNodeParser = new LeafSetEntryNodeDomParser(codecProvider);
+ leafSetNodeParser = new LeafSetNodeDomParser(leafSetEntryNodeParser);
+
+ final NodeParserDispatcher<Element> dispatcher = new NodeParserDispatcher.BaseNodeParserDispatcher<Element>(this) {
+
+ };
+
+ containerNodeParser = new ContainerNodeDomParser(dispatcher);
+ mapEntryNodeParser = new MapEntryNodeDomParser(dispatcher);
+ mapNodeParser = new MapNodeDomParser(mapEntryNodeParser);
+ choiceNodeParser = new ChoiceNodeDomParser(dispatcher);
+ augmentationNodeParser = new AugmentationNodeDomParser(dispatcher);
+ }
+
+ public static DomToNormalizedNodeParserFactory getInstance(final XmlCodecProvider codecProvider) {
+ return new DomToNormalizedNodeParserFactory(codecProvider);
+ }
+
+ @Override
+ public ToNormalizedNodeParser<Element, AugmentationNode, AugmentationSchema> getAugmentationNodeParser() {
+ return augmentationNodeParser;
+ }
+
+ @Override
+ public ToNormalizedNodeParser<Element, ChoiceNode, org.opendaylight.yangtools.yang.model.api.ChoiceNode> getChoiceNodeParser() {
+ return choiceNodeParser;
+ }
+
+ @Override
+ public ToNormalizedNodeParser<Element, ContainerNode, ContainerSchemaNode> getContainerNodeParser() {
+ return containerNodeParser;
+ }
+
+ @Override
+ public ToNormalizedNodeParser<Element, LeafNode<?>, LeafSchemaNode> getLeafNodeParser() {
+ return leafNodeParser;
+ }
+
+ @Override
+ public ToNormalizedNodeParser<Element, LeafSetEntryNode<?>, LeafListSchemaNode> getLeafSetEntryNodeParser() {
+ return leafSetEntryNodeParser;
+ }
+
+ @Override
+ public ToNormalizedNodeParser<Element, LeafSetNode<?>, LeafListSchemaNode> getLeafSetNodeParser() {
+ return leafSetNodeParser;
+ }
+
+ @Override
+ public ToNormalizedNodeParser<Element, MapEntryNode, ListSchemaNode> getMapEntryNodeParser() {
+ return mapEntryNodeParser;
+ }
+
+ @Override
+ public ToNormalizedNodeParser<Element, MapNode, ListSchemaNode> getMapNodeParser() {
+ return mapNodeParser;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser;
+
+import java.util.Map;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlCodecProvider;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser.LeafNodeBaseParser;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.DomUtils;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.w3c.dom.Element;
+
+import com.google.common.base.Preconditions;
+
+final class LeafNodeDomParser extends LeafNodeBaseParser<Element> {
+
+ private final XmlCodecProvider codecProvider;
+
+ LeafNodeDomParser(XmlCodecProvider codecProvider) {
+ this.codecProvider = Preconditions.checkNotNull(codecProvider);
+ }
+
+ @Override
+ protected Object parseLeaf(Element xmlElement, LeafSchemaNode schema) {
+ return DomUtils.parseXmlValue(xmlElement, codecProvider, schema.getType());
+ }
+
+ @Override
+ protected Map<QName, String> getAttributes(Element element) {
+ return DomUtils.toAttributes(element.getAttributes());
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser;
+
+import java.util.Map;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlCodecProvider;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser.LeafSetEntryNodeBaseParser;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.DomUtils;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.w3c.dom.Element;
+
+import com.google.common.base.Preconditions;
+
+final class LeafSetEntryNodeDomParser extends LeafSetEntryNodeBaseParser<Element> {
+
+ private final XmlCodecProvider codecProvider;
+
+ LeafSetEntryNodeDomParser(XmlCodecProvider codecProvider) {
+ this.codecProvider = Preconditions.checkNotNull(codecProvider);
+ }
+
+ @Override
+ protected Object parseLeafListEntry(Element xmlElement, LeafListSchemaNode schema) {
+ return DomUtils.parseXmlValue(xmlElement, codecProvider, schema.getType());
+ }
+
+ @Override
+ protected Map<QName, String> getAttributes(Element element) {
+ return DomUtils.toAttributes(element.getAttributes());
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser;
+
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.ToNormalizedNodeParser;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser.LeafSetNodeBaseParser;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.w3c.dom.Element;
+
+final class LeafSetNodeDomParser extends LeafSetNodeBaseParser<Element> {
+
+ private final LeafSetEntryNodeDomParser leafSetEntryNodeBaseParser;
+
+ LeafSetNodeDomParser(LeafSetEntryNodeDomParser leafSetEntryNodeBaseParser) {
+ this.leafSetEntryNodeBaseParser = leafSetEntryNodeBaseParser;
+ }
+
+ @Override
+ protected ToNormalizedNodeParser<Element, LeafSetEntryNode<?>, LeafListSchemaNode> getLeafSetEntryNodeParser() {
+ return leafSetEntryNodeBaseParser;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser;
+
+import java.util.Map;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser.MapEntryNodeBaseParser;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser.NodeParserDispatcher;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.DomUtils;
+import org.w3c.dom.Element;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.LinkedListMultimap;
+
+final class MapEntryNodeDomParser extends MapEntryNodeBaseParser<Element> {
+
+ private final NodeParserDispatcher<Element> dispatcher;
+
+ MapEntryNodeDomParser(final NodeParserDispatcher<Element> dispatcher) {
+ this.dispatcher = Preconditions.checkNotNull(dispatcher);
+ }
+
+ @Override
+ protected LinkedListMultimap<QName, Element> mapChildElements(Iterable<Element> elements) {
+ return DomUtils.mapChildElementsForSingletonNode(elements.iterator().next());
+ }
+
+ @Override
+ protected NodeParserDispatcher<Element> getDispatcher() {
+ return dispatcher;
+ }
+
+ @Override
+ protected Map<QName, String> getAttributes(Element element) {
+ return DomUtils.toAttributes(element.getAttributes());
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser;
+
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.ToNormalizedNodeParser;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser.MapNodeBaseParser;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.w3c.dom.Element;
+
+final class MapNodeDomParser extends MapNodeBaseParser<Element> {
+
+ private final MapEntryNodeDomParser mapEntryParser;
+
+ MapNodeDomParser(MapEntryNodeDomParser mapEntryParser) {
+ this.mapEntryParser = mapEntryParser;
+ }
+
+ @Override
+ protected ToNormalizedNodeParser<Element, MapEntryNode, ListSchemaNode> getMapEntryNodeParser() {
+ return mapEntryParser;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.serializer;
+
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer.AugmentationNodeBaseSerializer;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer.NodeSerializerDispatcher;
+import org.w3c.dom.Element;
+
+import com.google.common.base.Preconditions;
+
+final class AugmentationNodeDomSerializer extends
+ AugmentationNodeBaseSerializer<Element> {
+
+ private final NodeSerializerDispatcher<Element> dispatcher;
+
+ AugmentationNodeDomSerializer(NodeSerializerDispatcher<Element> dispatcher) {
+ this.dispatcher = Preconditions.checkNotNull(dispatcher);
+ }
+
+ @Override
+ protected NodeSerializerDispatcher<Element> getNodeDispatcher() {
+ return dispatcher;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.serializer;
+
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer.ChoiceNodeBaseSerializer;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer.NodeSerializerDispatcher;
+import org.w3c.dom.Element;
+
+import com.google.common.base.Preconditions;
+
+final class ChoiceNodeDomSerializer extends ChoiceNodeBaseSerializer<Element> {
+ private final NodeSerializerDispatcher<Element> dispatcher;
+
+ ChoiceNodeDomSerializer(final NodeSerializerDispatcher<Element> dispatcher) {
+ this.dispatcher = Preconditions.checkNotNull(dispatcher);
+ }
+
+ @Override
+ protected NodeSerializerDispatcher<Element> getNodeDispatcher() {
+ return dispatcher;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.serializer;
+
+import java.util.Collections;
+
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer.ContainerNodeBaseSerializer;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer.NodeSerializerDispatcher;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import com.google.common.base.Preconditions;
+
+final class ContainerNodeDomSerializer extends
+ ContainerNodeBaseSerializer<Element> {
+
+ private final NodeSerializerDispatcher<Element> dispatcher;
+ private final Document doc;
+
+ ContainerNodeDomSerializer(final Document doc, final NodeSerializerDispatcher<Element> dispatcher) {
+ this.doc = Preconditions.checkNotNull(doc);
+ this.dispatcher = Preconditions.checkNotNull(dispatcher);
+ }
+
+ @Override
+ public Iterable<Element> serialize(ContainerSchemaNode schema, ContainerNode containerNode) {
+ Element itemEl = XmlDocumentUtils.createElementFor(doc, containerNode);
+
+ for (Element element : super.serialize(schema, containerNode)) {
+ itemEl.appendChild(element);
+ }
+ return Collections.singletonList(itemEl);
+ }
+
+ @Override
+ protected NodeSerializerDispatcher<Element> getNodeDispatcher() {
+ return dispatcher;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.serializer;
+
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlCodecProvider;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.FromNormalizedNodeSerializer;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.FromNormalizedNodeSerializerFactory;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer.NodeSerializerDispatcher;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+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.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public final class DomFromNormalizedNodeSerializerFactory implements FromNormalizedNodeSerializerFactory<Element> {
+ private final ContainerNodeDomSerializer containerSerializer;
+ private final ChoiceNodeDomSerializer choiceSerializer;
+ private final AugmentationNodeDomSerializer augmentSerializer;
+ private final LeafNodeDomSerializer leafNodeSerializer;
+ private final LeafSetNodeDomSerializer leafSetSerializer;
+ private final MapNodeDomSerializer mapNodeSerializer;
+ private final LeafSetEntryNodeDomSerializer leafSetEntryNodeSerializer;
+ private final MapEntryNodeDomSerializer mapEntryNodeSerializer;
+
+ private DomFromNormalizedNodeSerializerFactory(final Document doc, final XmlCodecProvider codecProvider) {
+ final NodeSerializerDispatcher.BaseNodeSerializerDispatcher<Element> dispatcher = new NodeSerializerDispatcher.BaseNodeSerializerDispatcher<Element>(this) {
+
+ };
+
+ containerSerializer = new ContainerNodeDomSerializer(doc, dispatcher);
+ choiceSerializer = new ChoiceNodeDomSerializer(dispatcher);
+ augmentSerializer = new AugmentationNodeDomSerializer(dispatcher);
+ leafNodeSerializer = new LeafNodeDomSerializer(doc, codecProvider);
+
+ leafSetEntryNodeSerializer = new LeafSetEntryNodeDomSerializer(doc, codecProvider);
+ leafSetSerializer = new LeafSetNodeDomSerializer(leafSetEntryNodeSerializer);
+
+ mapEntryNodeSerializer = new MapEntryNodeDomSerializer(doc, dispatcher);
+ mapNodeSerializer = new MapNodeDomSerializer(mapEntryNodeSerializer);
+ }
+
+ public static DomFromNormalizedNodeSerializerFactory getInstance(final Document doc, final XmlCodecProvider codecProvider) {
+ return new DomFromNormalizedNodeSerializerFactory(doc, codecProvider);
+ }
+
+ @Override
+ public FromNormalizedNodeSerializer<Element, AugmentationNode, AugmentationSchema> getAugmentationNodeSerializer() {
+ return augmentSerializer;
+ }
+
+ @Override
+ public FromNormalizedNodeSerializer<Element, ChoiceNode, org.opendaylight.yangtools.yang.model.api.ChoiceNode> getChoiceNodeSerializer() {
+ return choiceSerializer;
+ }
+
+ @Override
+ public FromNormalizedNodeSerializer<Element, ContainerNode, ContainerSchemaNode> getContainerNodeSerializer() {
+ return containerSerializer;
+ }
+
+ @Override
+ public FromNormalizedNodeSerializer<Element, LeafNode<?>, LeafSchemaNode> getLeafNodeSerializer() {
+ return leafNodeSerializer;
+ }
+
+ @Override
+ public FromNormalizedNodeSerializer<Element, LeafSetEntryNode<?>, LeafListSchemaNode> getLeafSetEntryNodeSerializer() {
+ return leafSetEntryNodeSerializer;
+ }
+
+ @Override
+ public FromNormalizedNodeSerializer<Element, LeafSetNode<?>, LeafListSchemaNode> getLeafSetNodeSerializer() {
+ return leafSetSerializer;
+ }
+
+ @Override
+ public FromNormalizedNodeSerializer<Element, MapEntryNode, ListSchemaNode> getMapEntryNodeSerializer() {
+ return mapEntryNodeSerializer;
+ }
+
+ @Override
+ public FromNormalizedNodeSerializer<Element, MapNode, ListSchemaNode> getMapNodeSerializer() {
+ return mapNodeSerializer;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.serializer;
+
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlCodecProvider;
+import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer.LeafNodeBaseSerializer;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.DomUtils;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import com.google.common.base.Preconditions;
+
+final class LeafNodeDomSerializer extends LeafNodeBaseSerializer<Element> {
+ private final XmlCodecProvider codecProvider;
+ private final Document doc;
+
+ LeafNodeDomSerializer(Document doc, XmlCodecProvider codecProvider) {
+ this.doc = Preconditions.checkNotNull(doc);
+ this.codecProvider = Preconditions.checkNotNull(codecProvider);
+ }
+
+ @Override
+ protected Element serializeLeaf(LeafSchemaNode schema, LeafNode<?> node) {
+ Element itemEl = XmlDocumentUtils.createElementFor(doc, node);
+ DomUtils.serializeXmlValue(itemEl, schema.getType(), codecProvider, node.getValue());
+
+ return itemEl;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.serializer;
+
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlCodecProvider;
+import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer.LeafSetEntryNodeBaseSerializer;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.DomUtils;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import com.google.common.base.Preconditions;
+
+final class LeafSetEntryNodeDomSerializer extends
+ LeafSetEntryNodeBaseSerializer<Element> {
+
+ private final Document doc;
+ private final XmlCodecProvider codecProvider;
+
+ LeafSetEntryNodeDomSerializer(Document doc, XmlCodecProvider codecProvider) {
+ this.doc = Preconditions.checkNotNull(doc);
+ this.codecProvider = Preconditions.checkNotNull(codecProvider);
+ }
+
+ @Override
+ protected Element serializeLeaf(LeafListSchemaNode schema, LeafSetEntryNode<?> node) {
+ Element itemEl = XmlDocumentUtils.createElementFor(doc, node);
+
+ DomUtils.serializeXmlValue(itemEl, schema.getType(), codecProvider, node.getValue());
+
+ return itemEl;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.serializer;
+
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.FromNormalizedNodeSerializer;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer.LeafSetNodeBaseSerializer;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.w3c.dom.Element;
+
+final class LeafSetNodeDomSerializer extends LeafSetNodeBaseSerializer<Element> {
+ private final FromNormalizedNodeSerializer<Element, LeafSetEntryNode<?>, LeafListSchemaNode> leafSetEntryNodeSerializer;
+
+ LeafSetNodeDomSerializer(LeafSetEntryNodeDomSerializer leafSetEntryNodeSerializer) {
+ this.leafSetEntryNodeSerializer = leafSetEntryNodeSerializer;
+ }
+
+ @Override
+ protected FromNormalizedNodeSerializer<Element, LeafSetEntryNode<?>, LeafListSchemaNode> getLeafSetEntryNodeSerializer() {
+ return leafSetEntryNodeSerializer;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.serializer;
+
+import java.util.Collections;
+
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer.MapEntryNodeBaseSerializer;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer.NodeSerializerDispatcher;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import com.google.common.base.Preconditions;
+
+final class MapEntryNodeDomSerializer extends MapEntryNodeBaseSerializer<Element> {
+ private final NodeSerializerDispatcher<Element> dispatcher;
+ private final Document doc;
+
+ MapEntryNodeDomSerializer(final Document doc, final NodeSerializerDispatcher<Element> dispatcher) {
+ this.doc = Preconditions.checkNotNull(doc);
+ this.dispatcher = Preconditions.checkNotNull(dispatcher);
+ }
+
+ @Override
+ public Iterable<Element> serialize(ListSchemaNode schema, MapEntryNode node) {
+ Element itemEl = XmlDocumentUtils.createElementFor(doc, node);
+
+ for (Element element : super.serialize(schema, node)) {
+ itemEl.appendChild(element);
+ }
+
+ return Collections.singletonList(itemEl);
+ }
+
+ @Override
+ protected NodeSerializerDispatcher<Element> getNodeDispatcher() {
+ return dispatcher;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.serializer;
+
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.FromNormalizedNodeSerializer;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer.MapNodeBaseSerializer;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.w3c.dom.Element;
+
+final class MapNodeDomSerializer extends MapNodeBaseSerializer<Element> {
+
+ private final FromNormalizedNodeSerializer<Element, MapEntryNode, ListSchemaNode> mapEntrySerializer;
+
+ MapNodeDomSerializer(MapEntryNodeDomSerializer mapEntrySerializer) {
+ this.mapEntrySerializer = mapEntrySerializer;
+ }
+
+ @Override
+ protected FromNormalizedNodeSerializer<Element, MapEntryNode, ListSchemaNode> getMapEntryNodeDomSerializer() {
+ return mapEntrySerializer;
+ }
+}
*/
package org.opendaylight.yangtools.yang.data.impl.schema;
-import com.google.common.base.Function;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Collections2;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
import org.junit.Before;
import org.junit.Test;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.*;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableChoiceNodeSchemaAwareBuilder;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeSchemaAwareBuilder;
-import org.opendaylight.yangtools.yang.model.api.*;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
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.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.xml.sax.SAXException;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.*;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.StringWriter;
-import java.net.URI;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
public class NormalizedDataBuilderTest {
private ContainerSchemaNode containerNode;
private SchemaContext schema;
- SchemaContext parseTestSchema() {
+ SchemaContext parseTestSchema(String... yangPath) {
YangParserImpl yangParserImpl = new YangParserImpl();
- Set<Module> modules = yangParserImpl.parseYangModelsFromStreams(getTestYangs());
+ Set<Module> modules = yangParserImpl.parseYangModelsFromStreams(getTestYangs(yangPath));
return yangParserImpl.resolveSchemaContext(modules);
}
- List<InputStream> getTestYangs() {
+ List<InputStream> getTestYangs(String... yangPaths) {
- return Lists.newArrayList(Collections2.transform(Lists.newArrayList("test.yang"),
+ return Lists.newArrayList(Collections2.transform(Lists.newArrayList(yangPaths),
new Function<String, InputStream>() {
@Override
public InputStream apply(String input) {
@Before
public void setUp() throws Exception {
- schema = parseTestSchema();
+ schema = parseTestSchema("test.yang");
containerNode = (ContainerSchemaNode) getSchemaNode(schema, "test", "container");
}
@Test
public void testSchemaUnaware() throws Exception {
// Container
- DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifier, ContainerNode> builder = Builders.containerBuilder().withNodeIdentifier(
- getNodeIdentifier("container"));
+ DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifier, ContainerNode> builder = Builders
+ .containerBuilder().withNodeIdentifier(getNodeIdentifier("container"));
// leaf
- LeafNode<String> leafChild = Builders.<String>leafBuilder()
- .withNodeIdentifier(getNodeIdentifier("leaf")).withValue("String").build();
+ LeafNode<String> leafChild = Builders.<String> leafBuilder().withNodeIdentifier(getNodeIdentifier("leaf"))
+ .withValue("String").build();
builder.withChild(leafChild);
// leafList
- LeafSetNode<Integer> leafList = Builders.<Integer>leafSetBuilder()
+ LeafSetNode<Integer> leafList = Builders
+ .<Integer> leafSetBuilder()
.withNodeIdentifier(getNodeIdentifier("leaf"))
.withChildValue(1)
- .withChild(Builders.<Integer>leafSetEntryBuilder().withNodeIdentifier(getNodeWithValueIdentifier("leaf", 3)).withValue(3).build())
+ .withChild(
+ Builders.<Integer> leafSetEntryBuilder()
+ .withNodeIdentifier(getNodeWithValueIdentifier("leaf", 3)).withValue(3).build())
.build();
builder.withChild(leafList);
// list
- MapEntryNode listChild1 = Builders.mapEntryBuilder()
- .withChild(
- Builders.<Integer>leafBuilder()
- .withNodeIdentifier(getNodeIdentifier("uint32InList")).withValue(1).build())
+ MapEntryNode listChild1 = Builders
+ .mapEntryBuilder()
.withChild(
- Builders.containerBuilder().withNodeIdentifier(
- getNodeIdentifier("containerInList"))
- .build())
+ Builders.<Integer> leafBuilder().withNodeIdentifier(getNodeIdentifier("uint32InList"))
+ .withValue(1).build())
+ .withChild(Builders.containerBuilder().withNodeIdentifier(getNodeIdentifier("containerInList")).build())
.withNodeIdentifier(
new InstanceIdentifier.NodeIdentifierWithPredicates(getNodeIdentifier("list").getNodeType(),
Collections.singletonMap(getNodeIdentifier("uint32InList").getNodeType(), (Object) 1)))
.build();
- MapNode list = Builders.mapBuilder().withChild(listChild1).withNodeIdentifier(getNodeIdentifier("list")).build();
+ MapNode list = Builders.mapBuilder().withChild(listChild1).withNodeIdentifier(getNodeIdentifier("list"))
+ .build();
builder.withChild(list);
- AugmentationNode augmentation = Builders.augmentationBuilder()
- .withNodeIdentifier(new InstanceIdentifier.AugmentationIdentifier(null, Sets.newHashSet(getQName("augmentUint32"))))
+ AugmentationNode augmentation = Builders
+ .augmentationBuilder()
+ .withNodeIdentifier(
+ new InstanceIdentifier.AugmentationIdentifier(null, Sets.newHashSet(getQName("augmentUint32"))))
.withChild(
- Builders.<Integer>leafBuilder().withNodeIdentifier(getNodeIdentifier("augmentUint32")).withValue(11).build())
- .build();
+ Builders.<Integer> leafBuilder().withNodeIdentifier(getNodeIdentifier("augmentUint32"))
+ .withValue(11).build()).build();
builder.withChild(augmentation);
- // This works without schema (adding child from augment as a direct child)
- builder.withChild(Builders.<Integer>leafBuilder().withNodeIdentifier(getNodeIdentifier("augmentUint32")).withValue(11).build());
-
- System.out.println(builder.build());
+ // This works without schema (adding child from augment as a direct
+ // child)
+ builder.withChild(Builders.<Integer> leafBuilder().withNodeIdentifier(getNodeIdentifier("augmentUint32"))
+ .withValue(11).build());
}
@Test
public void testSchemaAware() throws Exception {
- DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifier, ContainerNode> builder = Builders.containerBuilder(containerNode);
+ DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifier, ContainerNode> builder = Builders
+ .containerBuilder(containerNode);
LeafSchemaNode schemaNode = (LeafSchemaNode) getSchemaNode(schema, "test", "uint32");
- LeafNode<String> leafChild = Builders.<String>leafBuilder(schemaNode)
- .withValue("String").build();
+ LeafNode<String> leafChild = Builders.<String> leafBuilder(schemaNode).withValue("String").build();
builder.withChild(leafChild);
LeafListSchemaNode leafListSchemaNode = (LeafListSchemaNode) getSchemaNode(schema, "test", "leafList");
- LeafSetNode<Integer> leafList = Builders.<Integer>leafSetBuilder(leafListSchemaNode)
- .withChildValue(1)
- .withChild(Builders.<Integer>leafSetEntryBuilder(leafListSchemaNode).withValue(3).build())
- .build();
+ LeafSetNode<Integer> leafList = Builders.<Integer> leafSetBuilder(leafListSchemaNode).withChildValue(1)
+ .withChild(Builders.<Integer> leafSetEntryBuilder(leafListSchemaNode).withValue(3).build()).build();
builder.withChild(leafList);
ListSchemaNode listSchema = (ListSchemaNode) getSchemaNode(schema, "test", "list");
LeafSchemaNode uint32InListSchemaNode = (LeafSchemaNode) getSchemaNode(schema, "test", "uint32InList");
- ContainerSchemaNode containerInListSchemaNode = (ContainerSchemaNode) getSchemaNode(schema, "test", "containerInList");
+ ContainerSchemaNode containerInListSchemaNode = (ContainerSchemaNode) getSchemaNode(schema, "test",
+ "containerInList");
MapEntryNode listChild1 = Builders.mapEntryBuilder(listSchema)
- .withChild(
- Builders.<Integer>leafBuilder(uint32InListSchemaNode).withValue(1).build())
- .withChild(
- Builders.containerBuilder(containerInListSchemaNode).build())
- .build();
+ .withChild(Builders.<Integer> leafBuilder(uint32InListSchemaNode).withValue(1).build())
+ .withChild(Builders.containerBuilder(containerInListSchemaNode).build()).build();
MapNode list = ImmutableMapNodeSchemaAwareBuilder.create(listSchema).withChild(listChild1).build();
builder.withChild(list);
LeafSchemaNode augmentUint32SchemaNode = (LeafSchemaNode) getSchemaNode(schema, "test", "augmentUint32");
- AugmentationSchema augmentationSchema = getAugmentationSchemaForChild(containerNode, augmentUint32SchemaNode.getQName());
+ AugmentationSchema augmentationSchema = getAugmentationSchemaForChild(containerNode,
+ augmentUint32SchemaNode.getQName());
- AugmentationNode augmentation = Builders.augmentationBuilder(augmentationSchema).withChild(
- Builders.<Integer>leafBuilder(augmentUint32SchemaNode).withValue(11).build())
- .build();
+ AugmentationNode augmentation = Builders.augmentationBuilder(augmentationSchema)
+ .withChild(Builders.<Integer>leafBuilder(augmentUint32SchemaNode).withValue(11).build()).build();
builder.withChild(augmentation);
// This should fail with schema, since the leaf comes from augmentation
-// builder.withChild(ImmutableLeafNodeSchemaAwareBuilder.<Integer>get(augmentUint32SchemaNode).withValue(11).build());
+ // builder.withChild(ImmutableLeafNodeSchemaAwareBuilder.<Integer>get(augmentUint32SchemaNode).withValue(11).build());
LeafSchemaNode augumentString1SchemaNode = (LeafSchemaNode) getSchemaNode(schema, "test", "augmentString1");
LeafSchemaNode augumentString2SchemaNode = (LeafSchemaNode) getSchemaNode(schema, "test", "augmentString2");
ChoiceNode choice1SchemaNode = (ChoiceNode) getSchemaNode(schema, "test", "choice");
- org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode choice = ImmutableChoiceNodeSchemaAwareBuilder.create(choice1SchemaNode)
- .withChild(Builders.<String>leafBuilder(augumentString1SchemaNode).withValue("case1")
- .build())
- // This should fail, since child node belongs to different case
-// .withChild(Builders.<String>leafBuilder(augumentString2SchemaNode).withValue("case2")
-// .build())
+ org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode choice = ImmutableChoiceNodeSchemaAwareBuilder
+ .create(choice1SchemaNode)
+ .withChild(Builders.<String> leafBuilder(augumentString1SchemaNode).withValue("case1").build())
+ // This should fail, since child node belongs to different case
+ // .withChild(Builders.<String>leafBuilder(augumentString2SchemaNode).withValue("case2")
+ // .build())
.build();
-; builder.withChild(choice);
+ ;
+ builder.withChild(choice);
// This should fail, child from case
-// builder.withChild(Builders.<String>leafBuilder(augumentString1SchemaNode).withValue("case1")
-// .build());
-
- System.out.println(builder.build());
+ // builder.withChild(Builders.<String>leafBuilder(augumentString1SchemaNode).withValue("case1")
+ // .build());
}
private AugmentationSchema getAugmentationSchemaForChild(ContainerSchemaNode containerNode, QName qName) {
for (AugmentationSchema augmentationSchema : containerNode.getAvailableAugmentations()) {
- if(augmentationSchema.getDataChildByName(qName) != null) {
+ if (augmentationSchema.getDataChildByName(qName) != null) {
return augmentationSchema;
}
}
return new QName(URI.create(namespace), localName);
}
- private InstanceIdentifier.NodeWithValue getNodeWithValueIdentifier(QName q, Object value) {
- return new InstanceIdentifier.NodeWithValue(q, value);
- }
-
private InstanceIdentifier.NodeIdentifier getNodeIdentifier(String localName) {
return new InstanceIdentifier.NodeIdentifier(getQName(localName));
}
- private InstanceIdentifier.NodeIdentifier getNodeIdentifier(QName q) {
- return new InstanceIdentifier.NodeIdentifier(q);
- }
-
- private Document loadDocument(String xmlPath) throws Exception {
- InputStream resourceAsStream = getClass().getResourceAsStream(xmlPath);
-
- Document currentConfigElement = readXmlToDocument(resourceAsStream);
- Preconditions.checkNotNull(currentConfigElement);
- return currentConfigElement;
- }
-
- private static final DocumentBuilderFactory BUILDERFACTORY;
-
- static {
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- factory.setNamespaceAware(true);
- factory.setCoalescing(true);
- factory.setIgnoringElementContentWhitespace(true);
- factory.setIgnoringComments(true);
- BUILDERFACTORY = factory;
- }
-
- private Document readXmlToDocument(InputStream xmlContent) throws IOException, SAXException {
- DocumentBuilder dBuilder;
- try {
- dBuilder = BUILDERFACTORY.newDocumentBuilder();
- } catch (ParserConfigurationException e) {
- throw new RuntimeException("Failed to parse XML document", e);
- }
- Document doc = dBuilder.parse(xmlContent);
-
- doc.getDocumentElement().normalize();
- return doc;
- }
-
- public static String toString(Element xml) {
- try {
- Transformer transformer = TransformerFactory.newInstance().newTransformer();
- transformer.setOutputProperty(OutputKeys.INDENT, "yes");
-
- StreamResult result = new StreamResult(new StringWriter());
- DOMSource source = new DOMSource(xml);
- transformer.transform(source, result);
-
- return result.getWriter().toString();
- } catch (IllegalArgumentException | TransformerFactoryConfigurationError | TransformerException e) {
- throw new RuntimeException("Unable to serialize xml element " + xml, e);
- }
- }
-
- DataSchemaNode getSchemaNode(SchemaContext context, String moduleName, String childNodeName) {
+ public static DataSchemaNode getSchemaNode(SchemaContext context, String moduleName, String childNodeName) {
for (Module module : context.getModules()) {
if (module.getName().equals(moduleName)) {
DataSchemaNode found = findChildNode(module.getChildNodes(), childNodeName);
- Preconditions.checkState(found!=null, "Unable to find %s", childNodeName);
+ Preconditions.checkState(found != null, "Unable to find %s", childNodeName);
return found;
}
}
throw new IllegalStateException("Unable to find child node " + childNodeName);
}
- DataSchemaNode findChildNode(Set<DataSchemaNode> children, String name) {
+ static DataSchemaNode findChildNode(Set<DataSchemaNode> children, String name) {
List<DataNodeContainer> containers = Lists.newArrayList();
for (DataSchemaNode dataSchemaNode : children) {
if (dataSchemaNode.getQName().getLocalName().equals(name))
return dataSchemaNode;
- if(dataSchemaNode instanceof DataNodeContainer) {
+ if (dataSchemaNode instanceof DataNodeContainer) {
containers.add((DataNodeContainer) dataSchemaNode);
- } else if(dataSchemaNode instanceof ChoiceNode) {
+ } else if (dataSchemaNode instanceof ChoiceNode) {
containers.addAll(((ChoiceNode) dataSchemaNode).getCases());
}
}
for (DataNodeContainer container : containers) {
DataSchemaNode retVal = findChildNode(container.getChildNodes(), name);
- if(retVal != null) {
+ if (retVal != null) {
return retVal;
}
}
--- /dev/null
+package org.opendaylight.yangtools.yang.data.impl.schema.test;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntry;
+import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntryBuilder;
+import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapNodeBuilder;
+
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeUtils;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
+
+import com.google.common.base.Optional;
+
+/**
+ *
+ * Schema structure of document is
+ *
+ * <pre>
+ * container root {Â
+ * list list-a {
+ * key leaf-a;
+ * leaf leaf-a;
+ * choice choice-a {
+ * case one {
+ * leaf one;
+ * }
+ * case two-three {
+ * leaf two;
+ * leaf three;
+ * }
+ * }
+ * list list-b {
+ * key leaf-b;
+ * leaf leaf-b;
+ * }
+ * }
+ * }
+ * </pre>
+ *
+ */
+public class NormalizedNodeUtilsTest {
+
+ private static final QName ROOT_QNAME = QName.create("urn:opendalight:controller:sal:dom:store:test", "2014-03-13",
+ "root");
+ private static final QName LIST_A_QNAME = QName.create(ROOT_QNAME, "list-a");
+ private static final QName LIST_B_QNAME = QName.create(ROOT_QNAME, "list-b");
+ private static final QName CHOICE_A_QNAME = QName.create(ROOT_QNAME, "choice-a");
+ private static final QName LEAF_A_QNAME = QName.create(ROOT_QNAME, "leaf-a");
+ private static final QName LEAF_B_QNAME = QName.create(ROOT_QNAME, "leaf-b");
+ private static final String FOO = "foo";
+ private static final String BAR = "bar";
+ private static final String ONE = "one";
+ private static final String TWO = "two";
+
+ private static final InstanceIdentifier LIST_A_FOO_PATH = InstanceIdentifier.builder()
+ //.node(ROOT_QNAME)
+ .node(LIST_A_QNAME)
+ .nodeWithKey(LIST_A_QNAME, LEAF_A_QNAME, FOO)
+ .build();
+ private static final InstanceIdentifier LIST_B_TWO_PATH = InstanceIdentifier.builder()
+ //.node(ROOT_QNAME)
+ .node(LIST_A_QNAME)
+ .nodeWithKey(LIST_A_QNAME, LEAF_A_QNAME, BAR)
+ .node(LIST_B_QNAME)
+ .nodeWithKey(LIST_B_QNAME,LEAF_B_QNAME,TWO)
+ .build();
+
+ /**
+ * Returns a test document
+ *
+ * <pre>
+ * root
+ * list-a
+ * leaf-a "foo"
+ * list-a
+ * leaf-a "bar"
+ * list-b
+ * leaf-b "one"
+ * list-b
+ * leaf-b "two"
+ *
+ * </pre>
+ *
+ * @return
+ */
+ public NormalizedNode<?, ?> createDocumentOne() {
+ return ImmutableContainerNodeBuilder
+ .create()
+ .withNodeIdentifier(new NodeIdentifier(ROOT_QNAME))
+ .withChild(
+ mapNodeBuilder(LIST_A_QNAME)
+ .withChild(mapEntry(LIST_A_QNAME, LEAF_A_QNAME, FOO))
+ .withChild(
+ mapEntryBuilder(LIST_A_QNAME, LEAF_A_QNAME, BAR).withChild(
+ mapNodeBuilder(LIST_B_QNAME)
+ .withChild(mapEntry(LIST_B_QNAME, LEAF_B_QNAME, ONE))
+ .withChild(mapEntry(LIST_B_QNAME, LEAF_B_QNAME, TWO)).build())
+ .build()).build()).build();
+
+ }
+
+ @Test
+ public void findNodeTest() {
+ NormalizedNode<?, ?> tree = createDocumentOne();
+ assertNotNull(tree);
+
+ Optional<NormalizedNode<?, ?>> listFooResult = NormalizedNodeUtils.findNode(tree, LIST_A_FOO_PATH);
+ assertTrue(listFooResult.isPresent());
+
+ Optional<NormalizedNode<?, ?>> listTwoResult = NormalizedNodeUtils.findNode(tree, LIST_B_TWO_PATH);
+ assertTrue(listTwoResult.isPresent());
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.serializer;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.net.URI;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.TransformerFactoryConfigurationError;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.custommonkey.xmlunit.Diff;
+import org.custommonkey.xmlunit.XMLAssert;
+import org.custommonkey.xmlunit.XMLUnit;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedDataBuilderTest;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.DomUtils;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+@RunWith(Parameterized.class)
+public class NormalizedNodeXmlTranslationTest {
+ private static final Logger logger = LoggerFactory.getLogger(NormalizedNodeXmlTranslationTest.class);
+
+ @Parameterized.Parameters()
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][]{
+ {"augment_choice_hell.yang", "augment_choice_hell_ok.xml", augmentChoiceHell()},
+ {"augment_choice_hell.yang", "augment_choice_hell_ok2.xml", null},
+ {"test.yang", "simple.xml", null},
+ {"test.yang", "simple2.xml", null},
+ // TODO check attributes
+ {"test.yang", "simple_xml_with_attributes.xml", withAttributes()}
+ });
+ }
+
+
+ public static final String NAMESPACE = "urn:opendaylight:params:xml:ns:yang:controller:test";
+ private static Date revision;
+ static {
+ try {
+ revision = new SimpleDateFormat("yyyy-MM-dd").parse("2014-03-13");
+ } catch (ParseException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static ContainerNode withAttributes() {
+ DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifier, ContainerNode> b = Builders.containerBuilder();
+ b.withNodeIdentifier(getNodeIdentifier("container"));
+
+ CollectionNodeBuilder<MapEntryNode, MapNode> listBuilder = Builders.mapBuilder().withNodeIdentifier(
+ getNodeIdentifier("list"));
+
+ Map<QName, Object> predicates = Maps.newHashMap();
+ predicates.put(getNodeIdentifier("uint32InList").getNodeType(), 3L);
+
+ DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> list1Builder = Builders
+ .mapEntryBuilder().withNodeIdentifier(
+ new InstanceIdentifier.NodeIdentifierWithPredicates(getNodeIdentifier("list").getNodeType(),
+ predicates));
+ NormalizedNodeBuilder<InstanceIdentifier.NodeIdentifier,Object,LeafNode<Object>> uint32InListBuilder
+ = Builders.leafBuilder().withNodeIdentifier(getNodeIdentifier("uint32InList"));
+
+ list1Builder.withChild(uint32InListBuilder.withValue(3L).build());
+
+ listBuilder.withChild(list1Builder.build());
+ b.withChild(listBuilder.build());
+
+ NormalizedNodeBuilder<InstanceIdentifier.NodeIdentifier, Object, LeafNode<Object>> booleanBuilder
+ = Builders.leafBuilder().withNodeIdentifier(getNodeIdentifier("boolean"));
+ booleanBuilder.withValue(false);
+ b.withChild(booleanBuilder.build());
+
+ ListNodeBuilder<Object, LeafSetEntryNode<Object>> leafListBuilder
+ = Builders.leafSetBuilder().withNodeIdentifier(getNodeIdentifier("leafList"));
+
+ NormalizedNodeBuilder<InstanceIdentifier.NodeWithValue, Object, LeafSetEntryNode<Object>> leafList1Builder
+ = Builders.leafSetEntryBuilder().withNodeIdentifier(new InstanceIdentifier.NodeWithValue(getNodeIdentifier("leafList").getNodeType(), "a"));
+
+ leafList1Builder.withValue("a");
+
+ leafListBuilder.withChild(leafList1Builder.build());
+ b.withChild(leafListBuilder.build());
+
+ return b.build();
+ }
+
+ private static ContainerNode augmentChoiceHell() {
+
+ DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifier, ContainerNode> b = Builders.containerBuilder();
+ b.withNodeIdentifier(getNodeIdentifier("container"));
+
+ b.withChild(
+ Builders.choiceBuilder().withNodeIdentifier(getNodeIdentifier("ch2"))
+ .withChild(Builders.leafBuilder().withNodeIdentifier(getNodeIdentifier("c2Leaf")).withValue("2").build())
+ .withChild(
+ Builders.choiceBuilder().withNodeIdentifier(getNodeIdentifier("c2DeepChoice"))
+ .withChild(Builders.leafBuilder().withNodeIdentifier(getNodeIdentifier("c2DeepChoiceCase1Leaf2")).withValue("2").build())
+ .build()
+ )
+ .build()
+ );
+
+ b.withChild(
+ Builders.choiceBuilder().withNodeIdentifier(getNodeIdentifier("ch3")).withChild(
+ Builders.leafBuilder().withNodeIdentifier(getNodeIdentifier("c3Leaf")).withValue("3").build())
+ .build());
+
+ b.withChild(
+ Builders.augmentationBuilder().withNodeIdentifier(getAugmentIdentifier("augLeaf")).withChild(
+ Builders.leafBuilder().withNodeIdentifier(getNodeIdentifier("augLeaf")).withValue("augment").build())
+ .build());
+
+ b.withChild(
+ Builders.augmentationBuilder().withNodeIdentifier(getAugmentIdentifier("ch")).withChild(
+ Builders.choiceBuilder().withNodeIdentifier(getNodeIdentifier("ch"))
+ .withChild(
+ Builders.leafBuilder().withNodeIdentifier(getNodeIdentifier("c1Leaf")).withValue("1").build())
+ .withChild(
+ Builders.augmentationBuilder().withNodeIdentifier(getAugmentIdentifier("c1Leaf_AnotherAugment", "deepChoice"))
+ .withChild(
+ Builders.leafBuilder().withNodeIdentifier(getNodeIdentifier("c1Leaf_AnotherAugment")).withValue("1").build())
+ .withChild(
+ Builders.choiceBuilder().withNodeIdentifier(getNodeIdentifier("deepChoice"))
+ .withChild(
+ Builders.leafBuilder().withNodeIdentifier(getNodeIdentifier("deepLeafc1")).withValue("1").build()
+ ).build()
+ ).build()
+ ).build()
+ ).build());
+
+ return b.build();
+ }
+
+ private static InstanceIdentifier.NodeIdentifier getNodeIdentifier(String localName) {
+ return new InstanceIdentifier.NodeIdentifier(new QName(URI.create(NAMESPACE), revision, localName));
+ }
+
+ public static InstanceIdentifier.AugmentationIdentifier getAugmentIdentifier(String... childNames) {
+ Set<QName> qn = Sets.newHashSet();
+
+ for (String childName : childNames) {
+ qn.add(getNodeIdentifier(childName).getNodeType());
+ }
+
+ return new InstanceIdentifier.AugmentationIdentifier(null, qn);
+ }
+
+ public NormalizedNodeXmlTranslationTest(String yangPath, String xmlPath, ContainerNode expectedNode) {
+ SchemaContext schema = parseTestSchema(yangPath);
+ this.xmlPath = xmlPath;
+ this.containerNode = (ContainerSchemaNode) NormalizedDataBuilderTest.getSchemaNode(schema, "test", "container");
+ this.expectedNode = expectedNode;
+ }
+
+ private final ContainerNode expectedNode;
+ private final ContainerSchemaNode containerNode;
+ private final String xmlPath;
+
+
+ SchemaContext parseTestSchema(String... yangPath) {
+ YangParserImpl yangParserImpl = new YangParserImpl();
+ Set<Module> modules = yangParserImpl.parseYangModelsFromStreams(getTestYangs(yangPath));
+ return yangParserImpl.resolveSchemaContext(modules);
+ }
+
+ List<InputStream> getTestYangs(String... yangPaths) {
+
+ return Lists.newArrayList(Collections2.transform(Lists.newArrayList(yangPaths),
+ new Function<String, InputStream>() {
+ @Override
+ public InputStream apply(String input) {
+ InputStream resourceAsStream = NormalizedDataBuilderTest.class.getResourceAsStream(input);
+ Preconditions.checkNotNull(resourceAsStream, "File %s was null", resourceAsStream);
+ return resourceAsStream;
+ }
+ }));
+ }
+
+ @Test
+ public void testTranslation() throws Exception {
+ Document doc = loadDocument(xmlPath);
+
+ ContainerNode built =
+ DomToNormalizedNodeParserFactory.getInstance(DomUtils.defaultValueCodecProvider()).getContainerNodeParser().parse(
+ Collections.singletonList(doc.getDocumentElement()), containerNode);
+
+ if (expectedNode != null)
+ junit.framework.Assert.assertEquals(expectedNode, built);
+
+ logger.info("{}", built);
+
+ Iterable<Element> els = DomFromNormalizedNodeSerializerFactory.getInstance(XmlDocumentUtils.getDocument(), DomUtils.defaultValueCodecProvider())
+ .getContainerNodeSerializer().serialize(containerNode, built);
+
+ Element el = els.iterator().next();
+
+ XMLUnit.setIgnoreWhitespace(true);
+ XMLUnit.setIgnoreComments(true);
+
+ System.err.println(toString(doc.getDocumentElement()));
+ System.err.println(toString(el));
+
+ boolean diff = new Diff(XMLUnit.buildControlDocument(toString(doc.getDocumentElement())), XMLUnit.buildTestDocument(toString(el))).similar();
+ }
+
+ private Document loadDocument(String xmlPath) throws Exception {
+ InputStream resourceAsStream = NormalizedDataBuilderTest.class.getResourceAsStream(xmlPath);
+
+ Document currentConfigElement = readXmlToDocument(resourceAsStream);
+ Preconditions.checkNotNull(currentConfigElement);
+ return currentConfigElement;
+ }
+
+ private static final DocumentBuilderFactory BUILDERFACTORY;
+
+ static {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ factory.setCoalescing(true);
+ factory.setIgnoringElementContentWhitespace(true);
+ factory.setIgnoringComments(true);
+ BUILDERFACTORY = factory;
+ }
+
+ private Document readXmlToDocument(InputStream xmlContent) throws IOException, SAXException {
+ DocumentBuilder dBuilder;
+ try {
+ dBuilder = BUILDERFACTORY.newDocumentBuilder();
+ } catch (ParserConfigurationException e) {
+ throw new RuntimeException("Failed to parse XML document", e);
+ }
+ Document doc = dBuilder.parse(xmlContent);
+
+ doc.getDocumentElement().normalize();
+ return doc;
+ }
+
+ public static String toString(Element xml) {
+ try {
+ Transformer transformer = TransformerFactory.newInstance().newTransformer();
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+
+ StreamResult result = new StreamResult(new StringWriter());
+ DOMSource source = new DOMSource(xml);
+ transformer.transform(source, result);
+
+ return result.getWriter().toString();
+ } catch (IllegalArgumentException | TransformerFactoryConfigurationError | TransformerException e) {
+ throw new RuntimeException("Unable to serialize xml element " + xml, e);
+ }
+ }
+}
--- /dev/null
+// vi: set smarttab et sw=4 tabstop=4:
+module test {
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:test";
+ prefix "test";
+
+ organization "Cisco Systems, Inc.";
+
+ revision "2014-3-13" {
+ description
+ "Initial revision";
+ }
+
+
+ container container {
+ choice ch2{}
+ choice ch3{
+ case c3 {
+ leaf c3Leaf {
+ type string;
+ }
+ }
+ }
+ }
+
+ augment "/container/" {
+ leaf augLeaf {
+ type string;
+ }
+ }
+
+ augment "/container/" {
+ choice ch{}
+ }
+
+ augment "/container/ch/" {
+ case c1 {
+ leaf c1Leaf {
+ type string;
+ }
+ }
+
+ leaf c12 {
+ type string;
+ }
+ }
+ augment "/container/ch/c1/" {
+ leaf c1Leaf_AnotherAugment {
+ type string;
+ }
+
+ choice deepChoice{}
+ }
+
+ augment "/container/ch3/" {
+ case c32 {
+ leaf c32Leaf {
+ type string;
+ }
+ }
+
+ leaf c34LeafS {
+ type string;
+ }
+ }
+
+
+ augment "/container/ch/c1/deepChoice/" {
+ case deepCase1 {
+ leaf deepLeafc1 {
+ type string;
+ }
+ }
+ case deepCase2 {
+ leaf deepLeafc2 {
+ type string;
+ }
+ }
+ }
+
+ augment "/container/ch2/" {
+ case c2 {
+ leaf c2Leaf {
+ type string;
+ }
+
+ choice c2DeepChoice {
+ case c2DeepChoiceCase1 {
+ leaf c2DeepChoiceCase1Leaf1 {
+ type string;
+ }
+ }
+ case c2DeepChoiceCase2 {
+ leaf c2DeepChoiceCase1Leaf2 {
+ type string;
+ }
+ }
+ }
+ }
+ }
+
+ augment "/container/ch2/" {
+ leaf c22Leaf {
+ type string;
+ }
+ }
+
+
+}
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+
+ <c2Leaf>2</c2Leaf>
+ <c2DeepChoiceCase1Leaf2>2</c2DeepChoiceCase1Leaf2>
+ <!--<c2DeepChoiceCase1Leaf1>2</c2DeepChoiceCase1Leaf1>-->
+
+ <c3Leaf>3</c3Leaf>
+
+ <augLeaf>augment</augLeaf>
+
+ <c1Leaf>1</c1Leaf>
+ <c1Leaf_AnotherAugment>1</c1Leaf_AnotherAugment>
+ <deepLeafc1>1</deepLeafc1>
+ <!--<deepLeafc2>1</deepLeafc2>-->
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+
+ <c22Leaf>2</c22Leaf>
+
+ <c34LeafS>3</c34LeafS>
+
+ <augLeaf>augment</augLeaf>
+
+ <c1Leaf>1</c1Leaf>
+ <c1Leaf_AnotherAugment>1</c1Leaf_AnotherAugment>
+ <deepLeafc2>1</deepLeafc2>
+</container>
\ No newline at end of file
<list>
<uint32InList>1</uint32InList>
- <containerInList>
+ <containerInList name="inContainer">
<uint32>32</uint32>
<uint16>16</uint16>
</containerInList>
+ <stringAugmentedToList>augmentInList</stringAugmentedToList>
+ <stringAugmentedToListInCase1>augmentInListCase1</stringAugmentedToListInCase1>
</list>
<list>
<uint32InList>2</uint32InList>
<uint32>32</uint32>
<uint16>16</uint16>
</containerInList>
+ <!--<stringAugmentedToListInCase1>augmentInListCase1</stringAugmentedToListInCase1>-->
+ <stringAugmentedToListInCase2>augmentInListCase2</stringAugmentedToListInCase2>
</list>
<list>
<uint32InList>3</uint32InList>
</list>
- <augmentUint32>999</augmentUint32>
-
<augmentString1>choice1Case1</augmentString1>
+ <!--<augmentString2>choice1Case1</augmentString2>-->
<augmentInt1>41</augmentInt1>
+ <!--<stringInAugmentedCaseInAugmentedChoice>deep</stringInAugmentedCaseInAugmentedChoice>-->
+ <stringInAugmentedCaseInAugmentedChoiceFromAugment>deep</stringInAugmentedCaseInAugmentedChoiceFromAugment>
<augmentContainer>
<augmentStringInaugmentContainer>choice2Case1</augmentStringInaugmentContainer>
</augmentContainer>
+ <augmentUint32>999</augmentUint32>
+
+
</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+ <augmentString1>choice1Case1</augmentString1>
+ <!--<augmentString2>choice1Case1</augmentString2>-->
+ <augmentInt1>41</augmentInt1>
+ <!--<stringInAugmentedCaseInAugmentedChoice>deep</stringInAugmentedCaseInAugmentedChoice>-->
+ <stringInAugmentedCaseInAugmentedChoice2>deep</stringInAugmentedCaseInAugmentedChoice2>
+
+ <augmentedList>
+ <augmentStringInaugmentList>aug1</augmentStringInaugmentList>
+ </augmentedList>
+
+ <augmentedList>
+ <augmentStringInaugmentList>aug2</augmentStringInaugmentList>
+ <augmentedContainerInAugmentedListInAugmentedCase>
+ <leafInAugmentedContainerInAugmentedListInAugmentedCase>
+ 66
+ </leafInAugmentedContainerInAugmentedListInAugmentedCase>
+ </augmentedContainerInAugmentedListInAugmentedCase>
+
+ <augmentedListInAugmentedListInAugmentedCase>
+ <leafInAugmentedListInAugmentedListInAugmentedCase>
+ 661
+ </leafInAugmentedListInAugmentedListInAugmentedCase>
+ <leafInAugmentedListInAugmentedListInAugmentedCase>
+ 662
+ </leafInAugmentedListInAugmentedListInAugmentedCase>
+ </augmentedListInAugmentedListInAugmentedCase>
+
+ <augmentedListInAugmentedListInAugmentedCase>
+ <leafInAugmentedListInAugmentedListInAugmentedCase>
+ 6621
+ </leafInAugmentedListInAugmentedListInAugmentedCase>
+ </augmentedListInAugmentedListInAugmentedCase>
+ </augmentedList>
+
+ <augmentedList>
+ <augmentStringInaugmentList>aug3</augmentStringInaugmentList>
+ <augmentedContainerInAugmentedListInAugmentedCase/>
+
+ <augmentedListInAugmentedListInAugmentedCase/>
+ </augmentedList>
+
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test" name="test" xmlns:foo="http://www.foo.com/" foo:baz="baz">
+
+ <list list="on list entry">
+ <uint32InList name="test" foo:baz="baz">3</uint32InList>
+ </list>
+
+ <boolean xmlns:leaf="test:namespace:in:leaf" leaf:a="b">false</boolean>
+
+ <leafList foo:b="b">a</leafList>
+
+</container>
\ No newline at end of file
organization "Cisco Systems, Inc.";
- revision "2013-2-21" {
+ revision "2014-3-13" {
description
"Initial revision";
}
type string;
}
- uses listGroup;
+ uses listGroup {
+ augment "list/" {
+ leaf stringAugmentedToList{
+ type string;
+ }
+
+ choice choiceInList {
+ case caseInList1 {
+ leaf stringAugmentedToListInCase1 {
+ type string;
+ }
+ }
+ case caseInList2 {
+ leaf stringAugmentedToListInCase2 {
+ type string;
+ }
+ }
+ }
+ }
+ }
+
+ list directList {
+ leaf stringInDirectList {
+ type string;
+ }
+ }
+
uses innerContainerGrouping;
choice choice{}
}
}
+ augment "/container/directList/" {
+ leaf augmentedString {
+ type uint32;
+ }
+ }
+
augment "/container/choice/" {
case test-identity-augment {
when "/container/identityRef = 'test-identity'";
}
}
+ augment "/container/choice/test-identity-augment/" {
+
+ choice augmentedChoiceInCase {
+
+ case augmentedCaseInAugmentedChoice {
+ leaf stringInAugmentedCaseInAugmentedChoice {
+ type string;
+ }
+ }
+
+ case augmentedCaseInAugmentedChoice2 {
+ leaf stringInAugmentedCaseInAugmentedChoice2 {
+ type string;
+ }
+ }
+ }
+ }
+
+ augment "/container/choice/test-identity-augment/augmentedChoiceInCase/" {
+ case augmentedCaseInAugmentedChoiceFromAugment {
+ leaf stringInAugmentedCaseInAugmentedChoiceFromAugment {
+ type string;
+ }
+ }
+ }
+
augment "/container/choice2/" {
case test-identity-augment {
when "/container/identityRef = 'test-identity'";
}
+ augment "/container/choice2/test-identity-augment2/augmentedList/" {
+
+ container augmentedContainerInAugmentedListInAugmentedCase {
+ leaf-list leafInAugmentedContainerInAugmentedListInAugmentedCase {
+ type uint32;
+ }
+ }
+
+ list augmentedListInAugmentedListInAugmentedCase {
+ leaf-list leafInAugmentedListInAugmentedListInAugmentedCase {
+ type uint32;
+ }
+ }
+ }
+
identity test-identity {}
identity test-identity2 {
base test-identity;
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!-- Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ and is available at http://www.eclipse.org/legal/epl-v10.html -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang</artifactId>
+ <version>0.6.2-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>yang-data-json</artifactId>
+ <name>${project.artifactId}</name>
+ <description>${project.artifactId}</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>yang-data-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>yang-data-impl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>yang-model-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>yang-parser-impl</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+</project>
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.json.schema.cnsn.parser;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser.AugmentationNodeBaseParser;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser.NodeParserDispatcher;
+import org.opendaylight.yangtools.yang.data.json.schema.json.CnSnToNormalizedNodesUtils;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.LinkedListMultimap;
+
+public final class AugmentationNodeCnSnParser extends AugmentationNodeBaseParser<Node<?>> {
+
+ private final NodeParserDispatcher<Node<?>> dispatcher;
+
+ public AugmentationNodeCnSnParser(final NodeParserDispatcher<Node<?>> dispatcher) {
+ this.dispatcher = Preconditions.checkNotNull(dispatcher);
+ }
+
+ @Override
+ protected LinkedListMultimap<QName, Node<?>> mapChildElements(Iterable<Node<?>> elements) {
+ return CnSnToNormalizedNodesUtils.mapChildElements(elements);
+ }
+
+ @Override
+ protected NodeParserDispatcher<Node<?>> getDispatcher() {
+ return dispatcher;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.json.schema.cnsn.parser;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser.ChoiceNodeBaseParser;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser.NodeParserDispatcher;
+import org.opendaylight.yangtools.yang.data.json.schema.json.CnSnToNormalizedNodesUtils;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.LinkedListMultimap;
+
+public final class ChoiceNodeCnSnParser extends ChoiceNodeBaseParser<Node<?>> {
+
+ private final NodeParserDispatcher<Node<?>> dispatcher;
+
+ public ChoiceNodeCnSnParser(final NodeParserDispatcher<Node<?>> dispatcher) {
+ this.dispatcher = Preconditions.checkNotNull(dispatcher);
+ }
+
+ @Override
+ protected LinkedListMultimap<QName, Node<?>> mapChildElements(Iterable<Node<?>> elements) {
+ return CnSnToNormalizedNodesUtils.mapChildElements(elements);
+ }
+
+ @Override
+ protected NodeParserDispatcher<Node<?>> getDispatcher() {
+ return dispatcher;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.json.schema.cnsn.parser;
+
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.ToNormalizedNodeParser;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.ToNormalizedNodeParserFactory;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser.NodeParserDispatcher;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+public class CnSnToNormalizedNodeParserFactory implements ToNormalizedNodeParserFactory<Node<?>> {
+
+ private final ContainerNodeCnSnParser containerNodeCnSnParser;
+ private final LeafNodeCnSnParser leafNodeCnSnParser;
+ private final LeafSetEntryNodeCnSnParser leafSetEntryNodeCnSnParser;
+ private final LeafSetNodeCnSnParser leafSetNodeCnSnParser;
+ private final MapNodeCnSnParser mapNodeCnSnParser;
+ private final MapEntryNodeCnSnParser mapEntryNodeCnSnParser;
+ private final ChoiceNodeCnSnParser choiceNodeCnSnParser;
+ private final AugmentationNodeCnSnParser augmentationNodeCnSnParser;
+
+ private CnSnToNormalizedNodeParserFactory() {
+ leafNodeCnSnParser = new LeafNodeCnSnParser();
+ leafSetEntryNodeCnSnParser = new LeafSetEntryNodeCnSnParser();
+ leafSetNodeCnSnParser = new LeafSetNodeCnSnParser(leafSetEntryNodeCnSnParser);
+
+ final NodeParserDispatcher<Node<?>> dispatcher = new NodeParserDispatcher.BaseNodeParserDispatcher<Node<?>>(
+ this) {
+
+ };
+
+ containerNodeCnSnParser = new ContainerNodeCnSnParser(dispatcher);
+ mapEntryNodeCnSnParser = new MapEntryNodeCnSnParser(dispatcher);
+ mapNodeCnSnParser = new MapNodeCnSnParser(mapEntryNodeCnSnParser);
+ choiceNodeCnSnParser = new ChoiceNodeCnSnParser(dispatcher);
+ augmentationNodeCnSnParser = new AugmentationNodeCnSnParser(dispatcher);
+ }
+
+ public static CnSnToNormalizedNodeParserFactory getInstance() {
+ return new CnSnToNormalizedNodeParserFactory();
+ }
+
+ @Override
+ public ToNormalizedNodeParser<Node<?>, ContainerNode, ContainerSchemaNode> getContainerNodeParser() {
+ return containerNodeCnSnParser;
+ }
+
+ @Override
+ public ToNormalizedNodeParser<Node<?>, LeafNode<?>, LeafSchemaNode> getLeafNodeParser() {
+ return leafNodeCnSnParser;
+ }
+
+ @Override
+ public ToNormalizedNodeParser<Node<?>, LeafSetNode<?>, LeafListSchemaNode> getLeafSetNodeParser() {
+ return leafSetNodeCnSnParser;
+ }
+
+ @Override
+ public ToNormalizedNodeParser<Node<?>, MapNode, ListSchemaNode> getMapNodeParser() {
+ return mapNodeCnSnParser;
+ }
+
+ @Override
+ public ToNormalizedNodeParser<Node<?>, org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode, ChoiceNode> getChoiceNodeParser() {
+ return choiceNodeCnSnParser;
+ }
+
+ @Override
+ public ToNormalizedNodeParser<Node<?>, AugmentationNode, AugmentationSchema> getAugmentationNodeParser() {
+ return augmentationNodeCnSnParser;
+ }
+
+ @Override
+ public ToNormalizedNodeParser<Node<?>, LeafSetEntryNode<?>, LeafListSchemaNode> getLeafSetEntryNodeParser() {
+ return leafSetEntryNodeCnSnParser;
+ }
+
+ @Override
+ public ToNormalizedNodeParser<Node<?>, MapEntryNode, ListSchemaNode> getMapEntryNodeParser() {
+ return mapEntryNodeCnSnParser;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.json.schema.cnsn.parser;
+
+import java.util.Collections;
+import java.util.Map;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser.ContainerNodeBaseParser;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser.NodeParserDispatcher;
+import org.opendaylight.yangtools.yang.data.json.schema.json.CnSnToNormalizedNodesUtils;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.LinkedListMultimap;
+
+public final class ContainerNodeCnSnParser extends ContainerNodeBaseParser<Node<?>> {
+
+ private final NodeParserDispatcher<Node<?>> dispatcher;
+
+ public ContainerNodeCnSnParser(final NodeParserDispatcher<Node<?>> dispatcher) {
+ this.dispatcher = Preconditions.checkNotNull(dispatcher);
+ }
+
+ @Override
+ protected NodeParserDispatcher<Node<?>> getDispatcher() {
+ return dispatcher;
+ }
+
+ @Override
+ protected LinkedListMultimap<QName, Node<?>> mapChildElements(Iterable<Node<?>> elements) {
+ return CnSnToNormalizedNodesUtils.mapChildElementsForSingletonNode(elements.iterator().next());
+ }
+
+ @Override
+ protected Map<QName, String> getAttributes(Node<?> e) {
+ return Collections.emptyMap();
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.json.schema.cnsn.parser;
+
+import java.util.Collections;
+import java.util.Map;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser.LeafNodeBaseParser;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+
+public class LeafNodeCnSnParser extends LeafNodeBaseParser<Node<?>> {
+
+ public LeafNodeCnSnParser() {
+ super();
+ }
+
+ @Override
+ protected Object parseLeaf(Node<?> elements, LeafSchemaNode schema) {
+ return elements.getValue();
+ }
+
+ @Override
+ protected Map<QName, String> getAttributes(Node<?> e) {
+ return Collections.emptyMap();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.json.schema.cnsn.parser;
+
+import java.util.Collections;
+import java.util.Map;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser.LeafSetEntryNodeBaseParser;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+
+public class LeafSetEntryNodeCnSnParser extends LeafSetEntryNodeBaseParser<Node<?>> {
+
+ public LeafSetEntryNodeCnSnParser() {
+ super();
+ }
+
+ @Override
+ protected Object parseLeafListEntry(Node<?> elements, LeafListSchemaNode schema) {
+ return elements.getValue();
+ }
+
+ @Override
+ protected Map<QName, String> getAttributes(Node<?> e) {
+ return Collections.emptyMap();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.json.schema.cnsn.parser;
+
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.ToNormalizedNodeParser;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser.LeafSetNodeBaseParser;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+
+public class LeafSetNodeCnSnParser extends LeafSetNodeBaseParser<Node<?>> {
+
+ private final LeafSetEntryNodeCnSnParser leafSetEntryNodeCnSnParser;
+
+ public LeafSetNodeCnSnParser(LeafSetEntryNodeCnSnParser leafSetEntryNodeCnSnParser) {
+ this.leafSetEntryNodeCnSnParser = leafSetEntryNodeCnSnParser;
+ }
+
+ @Override
+ protected ToNormalizedNodeParser<Node<?>, LeafSetEntryNode<?>, LeafListSchemaNode> getLeafSetEntryNodeParser() {
+ return leafSetEntryNodeCnSnParser;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.json.schema.cnsn.parser;
+
+import java.util.Collections;
+import java.util.Map;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser.MapEntryNodeBaseParser;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser.NodeParserDispatcher;
+import org.opendaylight.yangtools.yang.data.json.schema.json.CnSnToNormalizedNodesUtils;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.LinkedListMultimap;
+
+public final class MapEntryNodeCnSnParser extends MapEntryNodeBaseParser<Node<?>> {
+
+ private final NodeParserDispatcher<Node<?>> dispatcher;
+
+ public MapEntryNodeCnSnParser(final NodeParserDispatcher<Node<?>> dispatcher) {
+ this.dispatcher = Preconditions.checkNotNull(dispatcher);
+ }
+
+
+ @Override
+ protected LinkedListMultimap<QName, Node<?>> mapChildElements(Iterable<Node<?>> elements) {
+ return CnSnToNormalizedNodesUtils.mapChildElementsForSingletonNode(elements.iterator().next());
+ }
+
+ @Override
+ protected NodeParserDispatcher<Node<?>> getDispatcher() {
+ return dispatcher;
+ }
+
+ @Override
+ protected Map<QName, String> getAttributes(Node<?> e) {
+ return Collections.emptyMap();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.json.schema.cnsn.parser;
+
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.ToNormalizedNodeParser;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser.MapNodeBaseParser;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+public final class MapNodeCnSnParser extends MapNodeBaseParser<Node<?>> {
+
+ private final MapEntryNodeCnSnParser mapEntryNodeCnSnParser;
+
+ public MapNodeCnSnParser(MapEntryNodeCnSnParser mapEntryNodeCnSnParser) {
+ this.mapEntryNodeCnSnParser = mapEntryNodeCnSnParser;
+ }
+
+ @Override
+ protected ToNormalizedNodeParser<Node<?>, MapEntryNode, ListSchemaNode> getMapEntryNodeParser() {
+ return mapEntryNodeCnSnParser;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.json.schema.cnsn.serializer;
+
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer.AugmentationNodeBaseSerializer;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer.NodeSerializerDispatcher;
+
+import com.google.common.base.Preconditions;
+
+public class AugmentationNodeCnSnSerializer extends AugmentationNodeBaseSerializer<Node<?>> {
+
+ private NodeSerializerDispatcher<Node<?>> dispatcher;
+
+ AugmentationNodeCnSnSerializer(final NodeSerializerDispatcher<Node<?>> dispatcher) {
+ this.dispatcher = Preconditions.checkNotNull(dispatcher);
+ }
+
+ @Override
+ protected NodeSerializerDispatcher<Node<?>> getNodeDispatcher() {
+ return dispatcher;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.json.schema.cnsn.serializer;
+
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer.ChoiceNodeBaseSerializer;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer.NodeSerializerDispatcher;
+
+import com.google.common.base.Preconditions;
+
+public class ChoiceNodeCnSnSerializer
+ extends
+ ChoiceNodeBaseSerializer<Node<?>> {
+
+ private final NodeSerializerDispatcher<Node<?>> dispatcher;
+
+ ChoiceNodeCnSnSerializer(final NodeSerializerDispatcher<Node<?>> dispatcher) {
+ this.dispatcher = Preconditions.checkNotNull(dispatcher);
+ }
+
+ @Override
+ protected NodeSerializerDispatcher<Node<?>> getNodeDispatcher() {
+ return dispatcher;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.json.schema.cnsn.serializer;
+
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.FromNormalizedNodeSerializer;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.FromNormalizedNodeSerializerFactory;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer.NodeSerializerDispatcher;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+public final class CnSnFromNormalizedNodeSerializerFactory implements FromNormalizedNodeSerializerFactory<Node<?>> {
+ private final ContainerNodeCnSnSerializer containerSerializer;
+ private final ChoiceNodeCnSnSerializer choiceSerializer;
+ private final AugmentationNodeCnSnSerializer augmentSerializer;
+ private final LeafNodeCnSnSerializer leafNodeSerializer;
+ private final LeafSetNodeCnSnSerializer leafSetSerializer;
+ private final MapNodeCnSnSerializer mapNodeSerializer;
+ private final LeafSetEntryNodeCnSnSerializer leafSetEntryNodeSerializer;
+ private final MapEntryNodeCnSnSerializer mapEntryNodeSerializer;
+
+ private CnSnFromNormalizedNodeSerializerFactory() {
+ final NodeSerializerDispatcher.BaseNodeSerializerDispatcher<Node<?>> dispatcher = new NodeSerializerDispatcher.BaseNodeSerializerDispatcher<Node<?>>(
+ this) {
+
+ };
+
+ containerSerializer = new ContainerNodeCnSnSerializer(dispatcher);
+ choiceSerializer = new ChoiceNodeCnSnSerializer(dispatcher);
+ augmentSerializer = new AugmentationNodeCnSnSerializer(dispatcher);
+ leafNodeSerializer = new LeafNodeCnSnSerializer();
+
+ leafSetEntryNodeSerializer = new LeafSetEntryNodeCnSnSerializer();
+ leafSetSerializer = new LeafSetNodeCnSnSerializer(leafSetEntryNodeSerializer);
+
+ mapEntryNodeSerializer = new MapEntryNodeCnSnSerializer(dispatcher);
+ mapNodeSerializer = new MapNodeCnSnSerializer(mapEntryNodeSerializer);
+ }
+
+
+ public static CnSnFromNormalizedNodeSerializerFactory getInstance() {
+ return new CnSnFromNormalizedNodeSerializerFactory();
+}
+
+ @Override
+ public FromNormalizedNodeSerializer<Node<?>, ContainerNode, ContainerSchemaNode> getContainerNodeSerializer() {
+ return containerSerializer;
+ }
+
+ @Override
+ public FromNormalizedNodeSerializer<Node<?>, LeafNode<?>, LeafSchemaNode> getLeafNodeSerializer() {
+ return leafNodeSerializer;
+ }
+
+ @Override
+ public FromNormalizedNodeSerializer<Node<?>, LeafSetNode<?>, LeafListSchemaNode> getLeafSetNodeSerializer() {
+ return leafSetSerializer;
+ }
+
+ @Override
+ public FromNormalizedNodeSerializer<Node<?>, MapNode, ListSchemaNode> getMapNodeSerializer() {
+ return mapNodeSerializer;
+ }
+
+ @Override
+ public FromNormalizedNodeSerializer<Node<?>, ChoiceNode, org.opendaylight.yangtools.yang.model.api.ChoiceNode> getChoiceNodeSerializer() {
+ return choiceSerializer;
+ }
+
+ @Override
+ public FromNormalizedNodeSerializer<Node<?>, AugmentationNode, AugmentationSchema> getAugmentationNodeSerializer() {
+ return augmentSerializer;
+ }
+
+
+ @Override
+ public FromNormalizedNodeSerializer<Node<?>, LeafSetEntryNode<?>, LeafListSchemaNode> getLeafSetEntryNodeSerializer() {
+ return leafSetEntryNodeSerializer;
+ }
+
+
+ @Override
+ public FromNormalizedNodeSerializer<Node<?>, MapEntryNode, ListSchemaNode> getMapEntryNodeSerializer() {
+ return mapEntryNodeSerializer;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.json.schema.cnsn.serializer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode;
+import org.opendaylight.yangtools.yang.data.api.MutableNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.impl.NodeFactory;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer.ContainerNodeBaseSerializer;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer.NodeSerializerDispatcher;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+
+import com.google.common.base.Preconditions;
+
+public class ContainerNodeCnSnSerializer extends ContainerNodeBaseSerializer<Node<?>> {
+
+ private NodeSerializerDispatcher<Node<?>> dispatcher;
+
+ ContainerNodeCnSnSerializer(final NodeSerializerDispatcher<Node<?>> dispatcher) {
+ this.dispatcher = Preconditions.checkNotNull(dispatcher);;
+ }
+
+ @Override
+ public List<Node<?>> serialize(ContainerSchemaNode schema, ContainerNode containerNode) {
+
+ MutableCompositeNode mutCompNode = NodeFactory.createMutableCompositeNode(containerNode.getNodeType(), null,
+ null, null, null);
+
+ for (Node<?> element : super.serialize(schema, containerNode)) {
+ if (element instanceof MutableNode<?>) {
+ ((MutableNode<?>) element).setParent(mutCompNode);
+ }
+ mutCompNode.getValue().add(element);
+ }
+
+ List<Node<?>> lst = new ArrayList<>();
+ lst.add(mutCompNode);
+ return lst;
+ }
+
+ @Override
+ protected NodeSerializerDispatcher<Node<?>> getNodeDispatcher() {
+ return dispatcher;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.json.schema.cnsn.serializer;
+
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.impl.NodeFactory;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer.LeafNodeBaseSerializer;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+
+public class LeafNodeCnSnSerializer extends LeafNodeBaseSerializer<Node<?>> {
+
+ @Override
+ protected Node<?> serializeLeaf(LeafSchemaNode schema, LeafNode<?> node) {
+ return NodeFactory.createMutableSimpleNode(node.getNodeType(), null, node.getValue(), null, null);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.json.schema.cnsn.serializer;
+
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.impl.NodeFactory;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer.LeafSetEntryNodeBaseSerializer;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+
+public class LeafSetEntryNodeCnSnSerializer extends
+ LeafSetEntryNodeBaseSerializer<Node<?>> {
+
+ @Override
+ protected Node<?> serializeLeaf(LeafListSchemaNode schema, LeafSetEntryNode<?> node) {
+ return NodeFactory.createMutableSimpleNode(
+ node.getNodeType(), null, node.getValue(), null, null);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.json.schema.cnsn.serializer;
+
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.FromNormalizedNodeSerializer;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer.LeafSetNodeBaseSerializer;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+
+public class LeafSetNodeCnSnSerializer extends
+ LeafSetNodeBaseSerializer<Node<?>> {
+
+ private FromNormalizedNodeSerializer<Node<?>, LeafSetEntryNode<?>, LeafListSchemaNode> leafSetEntryNodeSerializer;
+
+ public LeafSetNodeCnSnSerializer(final LeafSetEntryNodeCnSnSerializer leafSetEntryNodeSerializer) {
+ this.leafSetEntryNodeSerializer = leafSetEntryNodeSerializer;
+ }
+
+ @Override
+ protected FromNormalizedNodeSerializer<Node<?>, LeafSetEntryNode<?>, LeafListSchemaNode> getLeafSetEntryNodeSerializer() {
+ return leafSetEntryNodeSerializer;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.json.schema.cnsn.serializer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode;
+import org.opendaylight.yangtools.yang.data.api.MutableNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.impl.NodeFactory;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer.MapEntryNodeBaseSerializer;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer.NodeSerializerDispatcher;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+import com.google.common.base.Preconditions;
+
+public class MapEntryNodeCnSnSerializer extends MapEntryNodeBaseSerializer<Node<?>> {
+
+ private NodeSerializerDispatcher<Node<?>> dispatcher;
+
+ MapEntryNodeCnSnSerializer(final NodeSerializerDispatcher<Node<?>> dispatcher) {
+ this.dispatcher = Preconditions.checkNotNull(dispatcher);
+ }
+
+ public List<Node<?>> serialize(ListSchemaNode schema, MapEntryNode node) {
+
+ MutableCompositeNode mutCompNode = NodeFactory.createMutableCompositeNode(node.getNodeType(), null, null, null,
+ null);
+
+ for (Node<?> element : super.serialize(schema, node)) {
+ if (element instanceof MutableNode<?>) {
+ ((MutableNode<?>) element).setParent(mutCompNode);
+ }
+ mutCompNode.getValue().add(element);
+ }
+
+ List<Node<?>> lst = new ArrayList<>();
+ lst.add(mutCompNode);
+ return lst;
+ }
+
+ @Override
+ protected NodeSerializerDispatcher<Node<?>> getNodeDispatcher() {
+ return dispatcher;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.json.schema.cnsn.serializer;
+
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.FromNormalizedNodeSerializer;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer.MapNodeBaseSerializer;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+public class MapNodeCnSnSerializer extends MapNodeBaseSerializer<Node<?>> {
+
+ private final FromNormalizedNodeSerializer<Node<?>, MapEntryNode, ListSchemaNode> mapEntrySerializer;
+
+ public MapNodeCnSnSerializer(final MapEntryNodeCnSnSerializer mapEntrySerializer) {
+ this.mapEntrySerializer = mapEntrySerializer;
+ }
+
+ @Override
+ protected FromNormalizedNodeSerializer<Node<?>, MapEntryNode, ListSchemaNode> getMapEntryNodeDomSerializer() {
+ return mapEntrySerializer;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.json.schema.json;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+
+import com.google.common.collect.LinkedListMultimap;
+
+public class CnSnToNormalizedNodesUtils {
+
+ public static LinkedListMultimap<QName, Node<?>> mapChildElementsForSingletonNode(Node<?> node) {
+ return mapChildElements( ((CompositeNode)node).getValue());
+ }
+
+ public static LinkedListMultimap<QName, Node<?>> mapChildElements(Iterable<Node<?>> childNodesCollection) {
+ LinkedListMultimap<QName, Node<?>> mappedChildElements = LinkedListMultimap.create();
+
+ for (Node<?> node : childNodesCollection) {
+ mappedChildElements.put(node.getNodeType(), node);
+ }
+
+ return mappedChildElements;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.json.schema;
+
+import static org.junit.Assert.assertNotNull;
+import static org.opendaylight.yangtools.yang.data.impl.NodeFactory.createMutableCompositeNode;
+import static org.opendaylight.yangtools.yang.data.impl.NodeFactory.createMutableSimpleNode;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.parser.api.YangModelParser;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TestUtils {
+
+ private static final Logger LOG = LoggerFactory.getLogger(TestUtils.class);
+
+ private static final String NAMESPACE_BASE = "simple:container:yang";
+ private static final String NAMESPACE_AUGMENT = "augment:container:yang";
+ private static Date revision_base;
+ private static Date revision_augment;
+
+ static {
+ try {
+ revision_base = new SimpleDateFormat("yyyy-MM-dd").parse("2013-11-12");
+ revision_augment = new SimpleDateFormat("yyyy-MM-dd").parse("2014-03-19");
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static Set<Module> loadModules(URI resourceURI) throws FileNotFoundException {
+ final YangModelParser parser = new YangParserImpl();
+ final File testDir = new File(resourceURI);
+ final String[] fileList = testDir.list();
+ final List<File> testFiles = new ArrayList<>();
+ if (fileList == null) {
+ throw new FileNotFoundException(resourceURI.toString());
+ }
+ for (String fileName : fileList) {
+ testFiles.add(new File(testDir, fileName));
+ }
+ return parser.parseYangModels(testFiles);
+ }
+
+ public static Set<Module> loadModulesFrom(String yangPath) throws URISyntaxException {
+ try {
+ return loadModules(TestUtils.class.getResource(yangPath).toURI());
+ } catch (FileNotFoundException e) {
+ LOG.error("Yang files at path: " + yangPath + " weren't loaded.");
+ }
+
+ return null;
+ }
+
+ public static DataSchemaNode resolveDataSchemaNode(String searchedDataSchemaName, Module module) {
+ assertNotNull("Module can't be null", module);
+
+ if (searchedDataSchemaName != null) {
+ for (DataSchemaNode dsn : module.getChildNodes()) {
+ if (dsn.getQName().getLocalName().equals(searchedDataSchemaName)) {
+ return dsn;
+ }
+ }
+ } else if (module.getChildNodes().size() == 1) {
+ return module.getChildNodes().iterator().next();
+ }
+ return null;
+ }
+
+ public static Module resolveModule(String searchedModuleName, Set<Module> modules) {
+ assertNotNull("Modules can't be null.", modules);
+ if (searchedModuleName != null) {
+ for (Module m : modules) {
+ if (m.getName().equals(searchedModuleName)) {
+ return m;
+ }
+ }
+ } else if (modules.size() == 1) {
+ return modules.iterator().next();
+ }
+ return null;
+ }
+
+ /**
+ * Prepare composite node structure according to
+ * /cnsn-to-normalized-node/simple-conainer.json
+ */
+ public static CompositeNode prepareCompositeNodeStruct() {
+ MutableCompositeNode cont = createMutableCompositeNode(new QName(URI.create(NAMESPACE_BASE), revision_base,
+ "cont"), null, null, null, null);
+
+ // cont1
+ List<Node<?>> contChilds = new ArrayList<>();
+ contChilds.add(createMutableCompositeNode(new QName(URI.create(NAMESPACE_BASE), revision_base, "cont1"), cont,
+ Collections.<Node<?>> emptyList(), null, null));
+
+ // cont2
+ MutableCompositeNode cont2 = createMutableCompositeNode(new QName(URI.create(NAMESPACE_BASE), revision_base,
+ "cont2"), cont, null, null, null);
+ List<Node<?>> cont2Childs = new ArrayList<>();
+ cont2Childs.add(createMutableSimpleNode(new QName(URI.create(NAMESPACE_BASE), revision_base, "lf21"), cont2,
+ "value in cont2/lf21", null, null));
+ cont2.setValue(cont2Childs);
+ contChilds.add(cont2);
+
+ // lst1
+ contChilds.add(createMutableCompositeNode(new QName(URI.create(NAMESPACE_BASE), revision_base, "lst1"), cont,
+ Collections.<Node<?>> emptyList(), null, null));
+
+ // lst2
+ MutableCompositeNode lst2_1 = createMutableCompositeNode(new QName(URI.create(NAMESPACE_BASE), revision_base,
+ "lst2"), cont, null, null, null);
+ List<Node<?>> lst2_1Childs = new ArrayList<>();
+ lst2_1Childs.add(createMutableSimpleNode(new QName(URI.create(NAMESPACE_BASE), revision_base, "lf21"), lst2_1,
+ "some value21", null, null));
+ lst2_1.setValue(lst2_1Childs);
+ contChilds.add(lst2_1);
+
+ MutableCompositeNode lst2_2 = createMutableCompositeNode(new QName(URI.create(NAMESPACE_BASE), revision_base,
+ "lst2"), cont, null, null, null);
+ List<Node<?>> lst2_2Childs = new ArrayList<>();
+ lst2_2Childs.add(createMutableSimpleNode(new QName(URI.create(NAMESPACE_BASE), revision_base, "lf22"), lst2_2,
+ "some value22", null, null));
+ lst2_2.setValue(lst2_2Childs);
+ contChilds.add(lst2_2);
+
+ // lflst1
+ contChilds.add(createMutableSimpleNode(new QName(URI.create(NAMESPACE_BASE), revision_base, "lflst1"), cont,
+ "lflst1_1", null, null));
+ contChilds.add(createMutableSimpleNode(new QName(URI.create(NAMESPACE_BASE), revision_base, "lflst1"), cont,
+ "lflst1_2", null, null));
+
+ // lf1
+ contChilds.add(createMutableSimpleNode(new QName(URI.create(NAMESPACE_BASE), revision_base, "lf1"), cont,
+ "lf1", null, null));
+
+ // lf11
+ contChilds.add(createMutableSimpleNode(new QName(URI.create(NAMESPACE_BASE), revision_base, "lf11"), cont,
+ "value from case (cs1)", null, null));
+
+ // cont3
+ MutableCompositeNode cont3 = createMutableCompositeNode(new QName(URI.create(NAMESPACE_AUGMENT),
+ revision_augment, "cont3"), cont, null, null, null);
+ List<Node<?>> cont3Childs = new ArrayList<>();
+ cont3Childs.add(createMutableSimpleNode(new QName(URI.create(NAMESPACE_AUGMENT), revision_augment, "lf31"),
+ cont3, "value in leaf in augment", null, null));
+ cont3.setValue(cont3Childs);
+ contChilds.add(cont3);
+
+ cont.setValue(contChilds);
+ return cont;
+ }
+
+ /**
+ * Prepare composite node structure according to
+ * /cnsn-to-normalized-node/simple-conainer.json
+ */
+ public static ContainerNode prepareNormalizedNodeStruct() throws URISyntaxException {
+ DataContainerNodeBuilder<NodeIdentifier, ContainerNode> containerBuilder = Builders.containerBuilder();
+ containerBuilder.withNodeIdentifier(getNodeIdentifier("cont"));
+ containerBuilder.withChild(Builders.containerBuilder().withNodeIdentifier(getNodeIdentifier("cont1")).build());
+ containerBuilder.withChild(Builders
+ .containerBuilder()
+ .withNodeIdentifier(getNodeIdentifier("cont2"))
+ .withChild(
+ Builders.leafBuilder().withNodeIdentifier(getNodeIdentifier("lf21"))
+ .withValue("value in cont2/lf21").build()).build());
+
+ CollectionNodeBuilder<MapEntryNode, MapNode> lst1 = Builders.mapBuilder().withNodeIdentifier(
+ getNodeIdentifier("lst1"));
+ lst1.withChild(Builders.mapEntryBuilder()
+ .withNodeIdentifier(getNodeIdentifierPredicate("lst1", new HashMap<String, Object>()))
+ .withValue(Collections.<DataContainerChild<? extends PathArgument, ?>> emptyList()).build());
+ containerBuilder.withChild(lst1.build());
+
+ CollectionNodeBuilder<MapEntryNode, MapNode> lst2 = Builders.mapBuilder().withNodeIdentifier(
+ getNodeIdentifier("lst2"));
+
+ Map<String, Object> lst2_1 = new HashMap<>();
+ lst2_1.put("lf21", "some value21");
+
+ List<DataContainerChild<? extends PathArgument, ?>> lst2_1_values = new ArrayList<>();
+ lst2_1_values.add(Builders.leafBuilder().withNodeIdentifier(getNodeIdentifier("lf21"))
+ .withValue("some value21").build());
+ lst2.withChild(Builders.mapEntryBuilder().withNodeIdentifier(getNodeIdentifierPredicate("lst2", lst2_1))
+ .withValue(lst2_1_values).build());
+
+ Map<String, Object> lst2_2 = new HashMap<>();
+ lst2_2.put("lf22", "some value22");
+ List<DataContainerChild<? extends PathArgument, ?>> lst2_2_values = new ArrayList<>();
+ lst2_2_values.add(Builders.leafBuilder().withNodeIdentifier(getNodeIdentifier("lf22"))
+ .withValue("some value22").build());
+ lst2.withChild(Builders.mapEntryBuilder().withNodeIdentifier(getNodeIdentifierPredicate("lst2", lst2_2))
+ .withValue(lst2_2_values).build());
+ containerBuilder.withChild(lst2.build());
+
+ ListNodeBuilder<Object, LeafSetEntryNode<Object>> lflst1 = Builders.leafSetBuilder().withNodeIdentifier(
+ getNodeIdentifier("lflst1"));
+ lflst1.withChild(Builders.leafSetEntryBuilder().withNodeIdentifier(getNodeIdentifier("lflst1", "lflst1_1"))
+ .withValue("lflst1_1").build());
+ lflst1.withChild(Builders.leafSetEntryBuilder().withNodeIdentifier(getNodeIdentifier("lflst1", "lflst1_2"))
+ .withValue("lflst1_2").build());
+ containerBuilder.withChild(lflst1.build());
+
+ containerBuilder.withChild(Builders.leafBuilder().withNodeIdentifier(getNodeIdentifier("lf1")).withValue("lf1")
+ .build());
+
+ containerBuilder.withChild(Builders
+ .choiceBuilder()
+ .withNodeIdentifier(getNodeIdentifier("chc"))
+ .withChild(
+ Builders.leafBuilder().withNodeIdentifier(getNodeIdentifier("lf11"))
+ .withValue("value from case (cs1)").build()).build());
+
+ Set<QName> children = new HashSet<>();
+ children.add(new QName(new URI(NAMESPACE_AUGMENT), revision_augment, "cont3"));
+
+ containerBuilder.withChild(Builders
+ .augmentationBuilder()
+ .withNodeIdentifier(getAugmentationIdentifier(null, null, null, children))
+ .withChild(
+ Builders.containerBuilder()
+ .withNodeIdentifier(getNodeIdentifier("cont3", NAMESPACE_AUGMENT, revision_augment))
+ .withChild(
+ Builders.leafBuilder()
+ .withNodeIdentifier(
+ getNodeIdentifier("lf31", NAMESPACE_AUGMENT, revision_augment))
+ .withValue("value in leaf in augment").build()).build()).build());
+
+ ContainerNode build = containerBuilder.build();
+ return build;
+ }
+
+ private static InstanceIdentifier.NodeIdentifier getNodeIdentifier(String localName) {
+ return new InstanceIdentifier.NodeIdentifier(new QName(URI.create(NAMESPACE_BASE), revision_base, localName));
+ }
+
+ private static InstanceIdentifier.NodeIdentifier getNodeIdentifier(String localName, String namespace, Date revision) {
+ return new InstanceIdentifier.NodeIdentifier(new QName(URI.create(namespace), revision, localName));
+ }
+
+ private static InstanceIdentifier.NodeWithValue getNodeIdentifier(String localName, Object value) {
+ return new InstanceIdentifier.NodeWithValue(new QName(URI.create(NAMESPACE_BASE), revision_base, localName),
+ value);
+ }
+
+ private static InstanceIdentifier.NodeIdentifierWithPredicates getNodeIdentifierPredicate(String localName,
+ Map<String, Object> keys) {
+ Map<QName, Object> predicate = new HashMap<>();
+ for (String key : keys.keySet()) {
+ predicate.put(new QName(URI.create(NAMESPACE_BASE), revision_base, key), keys.get(key));
+ }
+
+ return new InstanceIdentifier.NodeIdentifierWithPredicates(
+
+ new QName(URI.create(NAMESPACE_BASE), revision_base, localName), predicate);
+ }
+
+ private static InstanceIdentifier.AugmentationIdentifier getAugmentationIdentifier(String localName,
+ String namespace, Date revision, Set<QName> children) {
+ return new InstanceIdentifier.AugmentationIdentifier(null, children);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.json.schema.cnsn.parser;
+
+import static org.junit.Assert.assertEquals;
+
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.json.schema.TestUtils;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+
+public class ParseCnSnStructToNormalizedStructTest {
+
+ private static DataSchemaNode resolvedDataSchemaNode;
+
+ @BeforeClass
+ public static void loadData() throws URISyntaxException {
+ Set<Module> modules = TestUtils.loadModulesFrom("/cnsn-to-normalized-node/yang");
+ Module resolvedModule = TestUtils.resolveModule("simple-container-yang", modules);
+ resolvedDataSchemaNode = TestUtils.resolveDataSchemaNode("cont", resolvedModule);
+ }
+
+ @Test
+ public void testCnSnToNormalizedNode() throws URISyntaxException {
+
+ CompositeNode compNode = TestUtils.prepareCompositeNodeStruct();
+
+ List<Node<?>> lst = new ArrayList<Node<?>>();
+ lst.add(compNode);
+ ContainerNode parsed = CnSnToNormalizedNodeParserFactory.getInstance().getContainerNodeParser()
+ .parse(lst, (ContainerSchemaNode) resolvedDataSchemaNode);
+
+ ContainerNode prepareExpectedStruct = TestUtils.prepareNormalizedNodeStruct();
+ assertEquals(prepareExpectedStruct, parsed);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.json.schema.cnsn.serializer;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.net.URISyntaxException;
+import java.util.Set;
+
+import com.google.common.collect.Sets;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.json.schema.TestUtils;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+
+public class SerializeNormalizedStructToCnSnStructTest {
+
+ private static DataSchemaNode resolvedDataSchemaNode;
+
+ @BeforeClass
+ public static void loadData() throws URISyntaxException {
+ Set<Module> modules = TestUtils.loadModulesFrom("/cnsn-to-normalized-node/yang");
+ Module resolvedModule = TestUtils.resolveModule("simple-container-yang", modules);
+ resolvedDataSchemaNode = TestUtils.resolveDataSchemaNode("cont", resolvedModule);
+ }
+
+ @Test
+ public void testCnSnToNormalizedNode() throws URISyntaxException {
+ ContainerNode containerNode = TestUtils.prepareNormalizedNodeStruct();
+
+ Iterable<Node<?>> serialized = CnSnFromNormalizedNodeSerializerFactory.getInstance()
+ .getContainerNodeSerializer().serialize((ContainerSchemaNode) resolvedDataSchemaNode, containerNode);
+
+ assertNotNull(serialized);
+ assertNotNull(serialized.iterator());
+ assertNotNull(serialized.iterator().hasNext());
+
+ CompositeNode compNode = TestUtils.prepareCompositeNodeStruct();
+
+ assertEquals(serialized.iterator().next().getNodeType(), compNode.getNodeType());
+
+ Set<Node<?>> value = Sets.newHashSet(((CompositeNode)serialized.iterator().next()).getValue());
+ assertEquals(value, Sets.newHashSet(compNode.getValue()));
+ }
+}
--- /dev/null
+{
+ "simple-container-yang:cont":{
+ "cont1":{
+ },
+ "cont2":{
+ "lf21":"value in cont2/lf21"
+ },
+ "augment-container-yang:cont3":{
+ "lf31":"value in leaf in augment"
+ },
+ "lst1": [
+ {
+ }
+ ],
+ "lst2": [
+ {
+ "lf21":"some value21"
+ },
+ {
+ "lf22":"some value22"
+ }
+ ],
+ "lflst1":[
+ "lflst1_1",
+ "lflst1_2"
+ ],
+ "lf1":"lf1",
+
+ "lf11":"value from case (cs1)"
+ }
+}
\ No newline at end of file
--- /dev/null
+module augment-container-yang {
+ namespace "augment:container:yang";
+
+ prefix "auconyang";
+ import simple-container-yang { prefix "simple"; revision-date 2013-11-12; }
+
+ revision 2014-03-19 {
+ }
+
+ augment "/simple:cont" {
+ container cont3 {
+ leaf lf31 {
+ type string;
+ }
+ }
+ }
+
+}
--- /dev/null
+module simple-container-yang {
+ namespace "simple:container:yang";
+
+ prefix "smpdtp";
+ revision 2013-11-12 {
+ }
+
+ container cont {
+ container cont1 {
+ }
+ container cont2 {
+ leaf lf21 {
+ type string;
+ }
+ }
+ list lst1 {
+ }
+ list lst2 {
+ leaf lf21 {
+ type string;
+ }
+ leaf lf22 {
+ type string;
+ }
+ }
+ leaf-list lflst1 {
+ type string;
+ }
+ leaf lf1 {
+ type string;
+ }
+
+ choice chc {
+ case cs1 {
+ leaf lf11 {
+ type string;
+ }
+ }
+ case cs2 {
+ leaf lf21 {
+ type string;
+ }
+ }
+ }
+
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ and is available at http://www.eclipse.org/legal/epl-v10.html
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang</artifactId>
+ <version>0.6.2-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>yang-data-operations</artifactId>
+ <name>${project.artifactId}</name>
+ <description>${project.artifactId}</description>
+
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Export-Package>
+ org.opendaylight.yangtools.yang.data.operations
+ </Export-Package>
+ <Import-Package>
+ *
+ </Import-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>yang-data-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>yang-model-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>yang-data-impl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>yang-parser-impl</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+</project>
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.operations;
+
+import java.util.List;
+import java.util.Set;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+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 com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+abstract class AbstractContainerNodeModification<S, N extends DataContainerNode<?>> implements Modification<S, N> {
+
+ @Override
+ public final Optional<N> modify(S schema, Optional<N> actual, Optional<N> modification,
+ OperationStack operationStack) throws DataModificationException {
+
+ operationStack.enteringNode(modification);
+
+ Optional<N> result;
+ QName nodeQName = getQName(schema);
+
+ switch (operationStack.getCurrentOperation()) {
+ case DELETE: {
+ DataModificationException.DataMissingException.check(nodeQName, actual);
+ }
+ case REMOVE: {
+ result = Optional.absent();
+ break;
+ }
+ case CREATE: {
+ DataModificationException.DataExistsException.check(nodeQName, actual, null);
+ }
+ case REPLACE: {
+ result = modification;
+ break;
+ }
+ case NONE: {
+ DataModificationException.DataMissingException.check(nodeQName, actual);
+ }
+ case MERGE: {
+ // Recursively modify all child nodes
+ result = modifyContainer(schema, actual, modification, operationStack);
+ break;
+ }
+ default:
+ throw new UnsupportedOperationException(String.format("Unable to perform operation: %s on: %s, unknown",
+ operationStack.getCurrentOperation(), schema));
+ }
+
+ operationStack.exitingNode(modification);
+ return result;
+ }
+
+ protected abstract QName getQName(S schema);
+
+ private Optional<N> modifyContainer(S schema, Optional<N> actual, Optional<N> modification,
+ OperationStack operationStack) throws DataModificationException {
+
+ if (actual.isPresent() == false) {
+ return modification;
+ }
+
+ if (modification.isPresent() == false) {
+ return actual;
+ }
+
+ Set<InstanceIdentifier.PathArgument> toProcess = getChildrenToProcess(schema, actual, modification);
+
+ List<? extends DataContainerChild<?, ?>> merged = modifyContainerChildNodes(schema, operationStack,
+ actual.get(), modification.get(), toProcess);
+ return build(schema, merged);
+ }
+
+ private List<? extends DataContainerChild<?, ?>> modifyContainerChildNodes(S schema, OperationStack operationStack,
+ N actual, N modification, Set<InstanceIdentifier.PathArgument> toProcess) throws DataModificationException {
+ List<DataContainerChild<?, ?>> result = Lists.newArrayList();
+
+ for (InstanceIdentifier.PathArgument childToProcessId : toProcess) {
+ Object schemaOfChildToProcess = findSchema(schema, childToProcessId);
+
+ Optional<? extends DataContainerChild<?, ?>> modifiedValues = modifyContainerNode(operationStack, actual,
+ modification, childToProcessId, schemaOfChildToProcess);
+
+ if (modifiedValues.isPresent()) {
+ result.add(modifiedValues.get());
+ }
+ }
+
+ return result;
+ }
+
+ private Optional<? extends DataContainerChild<?, ?>> modifyContainerNode(OperationStack operationStack, N actual,
+ N modification, InstanceIdentifier.PathArgument childToProcess, Object schemaChild)
+ throws DataModificationException {
+
+ Optional<DataContainerChild<?, ?>> storedChildren = actual.getChild(childToProcess);
+ Optional<DataContainerChild<?, ?>> modifiedChildren = modification.getChild(childToProcess);
+
+ return NodeDispatcher.dispatchChildModification(schemaChild, storedChildren, modifiedChildren, operationStack);
+ }
+
+ private Object findSchema(S schema, InstanceIdentifier.PathArgument childToProcessId) {
+ if (childToProcessId instanceof InstanceIdentifier.AugmentationIdentifier) {
+ return findSchemaForAugment(schema, (InstanceIdentifier.AugmentationIdentifier) childToProcessId);
+ } else {
+ return findSchemaForChild(schema, childToProcessId.getNodeType());
+ }
+ }
+
+ protected abstract Object findSchemaForChild(S schema, QName nodeType);
+
+ protected abstract Object findSchemaForAugment(S schema, InstanceIdentifier.AugmentationIdentifier childToProcessId);
+
+ private Optional<N> build(S schema, List<? extends DataContainerChild<?, ?>> result) {
+ DataContainerNodeBuilder<?, N> b = getBuilder(schema);
+
+ // TODO skip empty container nodes ? e.g. if container looses all its child nodes
+// if(result.isEmpty()) {
+// return Optional.absent();
+// }
+
+ for (DataContainerChild<?, ?> dataContainerChild : result) {
+ b.withChild(dataContainerChild);
+ }
+ return Optional.of(b.build());
+ }
+
+ protected abstract DataContainerNodeBuilder<?, N> getBuilder(S schema);
+
+ protected Set<InstanceIdentifier.PathArgument> getChildrenToProcess(S schema, Optional<N> actual,
+ Optional<N> modification) throws DataModificationException {
+ Set<InstanceIdentifier.PathArgument> qNames = Sets.newLinkedHashSet();
+
+ qNames.addAll(getChildQNames(actual));
+ qNames.addAll(getChildQNames(modification));
+ return qNames;
+ }
+
+ private Set<? extends InstanceIdentifier.PathArgument> getChildQNames(Optional<N> actual) {
+ Set<InstanceIdentifier.PathArgument> qNames = Sets.newLinkedHashSet();
+
+ for (DataContainerChild<? extends InstanceIdentifier.PathArgument, ?> child : actual.get().getValue()) {
+ qNames.add(child.getIdentifier());
+ }
+
+ return qNames;
+ }
+
+ private static final class NodeDispatcher {
+
+ private static final LeafNodeModification LEAF_NODE_MODIFICATION = new LeafNodeModification();
+ private static final LeafSetNodeModification LEAF_SET_NODE_MODIFICATION = new LeafSetNodeModification();
+ private static final AugmentationNodeModification AUGMENTATION_NODE_MODIFICATION = new AugmentationNodeModification();
+ private static final MapNodeModification MAP_NODE_MODIFICATION = new MapNodeModification();
+ private static final ContainerNodeModification CONTAINER_NODE_MODIFICATION = new ContainerNodeModification();
+ private static final ChoiceNodeModification CHOICE_NODE_MODIFICATION = new ChoiceNodeModification();
+
+ static Optional<? extends DataContainerChild<?, ?>> dispatchChildModification(Object schemaChild,
+ Optional<DataContainerChild<?, ?>> actual, Optional<DataContainerChild<?, ?>> modification,
+ OperationStack operations) throws DataModificationException {
+
+ if (schemaChild instanceof LeafSchemaNode) {
+ return onLeafNode((LeafSchemaNode) schemaChild, actual, modification, operations);
+ } else if (schemaChild instanceof ContainerSchemaNode) {
+ return onContainerNode((ContainerSchemaNode) schemaChild, actual, modification, operations);
+ } else if (schemaChild instanceof LeafListSchemaNode) {
+ return onLeafSetNode((LeafListSchemaNode) schemaChild, actual, modification, operations);
+ } else if (schemaChild instanceof AugmentationSchema) {
+ return onAugmentationNode((AugmentationSchema) schemaChild, actual, modification, operations);
+ } else if (schemaChild instanceof ListSchemaNode) {
+ return onMapNode((ListSchemaNode) schemaChild, actual, modification, operations);
+ } else if (schemaChild instanceof org.opendaylight.yangtools.yang.model.api.ChoiceNode) {
+ return onChoiceNode((org.opendaylight.yangtools.yang.model.api.ChoiceNode) schemaChild, actual,
+ modification, operations);
+ }
+
+ throw new IllegalArgumentException("Unknown schema node type " + schemaChild);
+ }
+
+ private static Optional<? extends DataContainerChild<?, ?>> onChoiceNode(
+ org.opendaylight.yangtools.yang.model.api.ChoiceNode schemaChild,
+ Optional<? extends DataContainerChild<?, ?>> actual,
+ Optional<? extends DataContainerChild<?, ?>> modification, OperationStack operations)
+ throws DataModificationException {
+ checkType(actual, ChoiceNode.class);
+ checkType(modification, ChoiceNode.class);
+ return CHOICE_NODE_MODIFICATION.modify(schemaChild, (Optional<ChoiceNode>) actual,
+ (Optional<ChoiceNode>) modification, operations);
+ }
+
+ private static Optional<? extends DataContainerChild<?, ?>> onMapNode(ListSchemaNode schemaChild,
+ Optional<? extends DataContainerChild<?, ?>> actual,
+ Optional<? extends DataContainerChild<?, ?>> modification, OperationStack operations)
+ throws DataModificationException {
+ checkType(actual, MapNode.class);
+ checkType(modification, MapNode.class);
+ return MAP_NODE_MODIFICATION.modify(schemaChild, (Optional<MapNode>) actual,
+ (Optional<MapNode>) modification, operations);
+ }
+
+ private static Optional<? extends DataContainerChild<?, ?>> onAugmentationNode(AugmentationSchema schemaChild,
+ Optional<? extends DataContainerChild<?, ?>> actual,
+ Optional<? extends DataContainerChild<?, ?>> modification, OperationStack operations)
+ throws DataModificationException {
+ checkType(actual, AugmentationNode.class);
+ checkType(modification, AugmentationNode.class);
+ return AUGMENTATION_NODE_MODIFICATION.modify(schemaChild, (Optional<AugmentationNode>) actual,
+ (Optional<AugmentationNode>) modification, operations);
+ }
+
+ private static Optional<? extends DataContainerChild<?, ?>> onLeafSetNode(LeafListSchemaNode schemaChild,
+ Optional<? extends DataContainerChild<?, ?>> actual,
+ Optional<? extends DataContainerChild<?, ?>> modification, OperationStack operations)
+ throws DataModificationException {
+ checkType(actual, LeafSetNode.class);
+ checkType(modification, LeafSetNode.class);
+ return LEAF_SET_NODE_MODIFICATION.modify(schemaChild, (Optional<LeafSetNode<?>>) actual,
+ (Optional<LeafSetNode<?>>) modification, operations);
+ }
+
+ private static Optional<? extends DataContainerChild<?, ?>> onContainerNode(ContainerSchemaNode schemaChild,
+ Optional<? extends DataContainerChild<?, ?>> actual,
+ Optional<? extends DataContainerChild<?, ?>> modification, OperationStack operations)
+ throws DataModificationException {
+ checkType(actual, ContainerNode.class);
+ checkType(modification, ContainerNode.class);
+ return CONTAINER_NODE_MODIFICATION.modify(schemaChild, (Optional<ContainerNode>) actual,
+ (Optional<ContainerNode>) modification, operations);
+ }
+
+ private static Optional<? extends DataContainerChild<?, ?>> onLeafNode(LeafSchemaNode schemaChild,
+ Optional<? extends DataContainerChild<?, ?>> actual,
+ Optional<? extends DataContainerChild<?, ?>> modification, OperationStack operations)
+ throws DataModificationException {
+ checkType(actual, LeafNode.class);
+ checkType(modification, LeafNode.class);
+ return LEAF_NODE_MODIFICATION.modify(schemaChild, (Optional<LeafNode<?>>) actual,
+ (Optional<LeafNode<?>>) modification, operations);
+ }
+
+ private static void checkType(Optional<? extends DataContainerChild<?, ?>> actual, Class<?> leafNodeClass) {
+ if (actual.isPresent()) {
+ Preconditions.checkArgument(leafNodeClass.isAssignableFrom(actual.get().getClass()),
+ "Unexpected node type, should be: %s, but was: %s, for: %s", leafNodeClass, actual.getClass(),
+ actual);
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.operations;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.SchemaUtils;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+
+final class AugmentationNodeModification extends AbstractContainerNodeModification<AugmentationSchema, AugmentationNode> {
+
+ @Override
+ protected QName getQName(AugmentationSchema schema) {
+ // FIXME null qname for AUGMENT
+ return null;
+ }
+
+ @Override
+ protected Object findSchemaForChild(AugmentationSchema schema, QName nodeType) {
+ return SchemaUtils.findSchemaForChild(schema, nodeType);
+ }
+
+ @Override
+ protected Object findSchemaForAugment(AugmentationSchema schema, InstanceIdentifier.AugmentationIdentifier childToProcessId) {
+ throw new UnsupportedOperationException("Augmentation cannot be augmented directly, " + schema);
+ }
+
+ @Override
+ protected DataContainerNodeBuilder<?, AugmentationNode> getBuilder(AugmentationSchema schema) {
+ return Builders.augmentationBuilder(schema);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.operations;
+
+import java.util.Set;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.SchemaUtils;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
+
+final class ChoiceNodeModification extends
+ AbstractContainerNodeModification<ChoiceNode, org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode> {
+
+ @Override
+ protected QName getQName(ChoiceNode schema) {
+ return schema.getQName();
+ }
+
+ @Override
+ protected Object findSchemaForChild(ChoiceNode schema, QName nodeType) {
+ return SchemaUtils.findSchemaForChild(schema, nodeType);
+ }
+
+ @Override
+ protected Set<InstanceIdentifier.PathArgument> getChildrenToProcess(ChoiceNode schema,
+ Optional<org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode> actual,
+ Optional<org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode> modification)
+ throws DataModificationException {
+ Set<InstanceIdentifier.PathArgument> childrenToProcess = super.getChildrenToProcess(schema, actual,
+ modification);
+
+ if (modification.isPresent() == false) {
+ return childrenToProcess;
+ }
+
+ // Detect case node from modification
+ ChoiceCaseNode detectedCase = null;
+ for (DataContainerChild<? extends InstanceIdentifier.PathArgument, ?> child : modification.get().getValue()) {
+ Optional<ChoiceCaseNode> detectedCaseForChild = SchemaUtils.detectCase(schema, child);
+
+ if(detectedCaseForChild.isPresent() == false) {
+ DataModificationException.IllegalChoiceValuesException.throwUnknownChild(schema.getQName(),
+ child.getNodeType());
+ }
+
+ if (detectedCase != null && detectedCase.equals(detectedCaseForChild.get()) == false) {
+ DataModificationException.IllegalChoiceValuesException.throwMultipleCasesReferenced(schema.getQName(),
+ modification.get(), detectedCase.getQName(), detectedCaseForChild.get().getQName());
+ }
+ detectedCase = detectedCaseForChild.get();
+ }
+
+ if (detectedCase == null)
+ return childrenToProcess;
+
+ // Filter out child nodes that do not belong to detected case =
+ // Nodes from other cases present in actual
+ Set<InstanceIdentifier.PathArgument> childrenToProcessFiltered = Sets.newLinkedHashSet();
+ for (InstanceIdentifier.PathArgument childToProcess : childrenToProcess) {
+ // child from other cases, skip
+ if (childToProcess instanceof AugmentationNode
+ && SchemaUtils.belongsToCaseAugment(detectedCase,
+ (InstanceIdentifier.AugmentationIdentifier) childToProcess) == false) {
+ continue;
+ } else if (belongsToCase(detectedCase, childToProcess) == false) {
+ continue;
+ }
+
+ childrenToProcessFiltered.add(childToProcess);
+ }
+
+ return childrenToProcessFiltered;
+ }
+
+ private boolean belongsToCase(ChoiceCaseNode detectedCase, InstanceIdentifier.PathArgument childToProcess) {
+ return detectedCase.getDataChildByName(childToProcess.getNodeType()) != null;
+ }
+
+ @Override
+ protected Object findSchemaForAugment(ChoiceNode schema, InstanceIdentifier.AugmentationIdentifier childToProcessId) {
+ return SchemaUtils.findSchemaForAugment(schema, childToProcessId.getPossibleChildNames());
+ }
+
+ @Override
+ protected DataContainerNodeBuilder<?, org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode> getBuilder(
+ ChoiceNode schema) {
+ return Builders.choiceBuilder(schema);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.operations;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.SchemaUtils;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+
+final class ContainerNodeModification extends AbstractContainerNodeModification<ContainerSchemaNode, ContainerNode> {
+
+ // FIXME normalized nodes as a result from merge contain attributes e.g. operation="merge" from modification
+
+ @Override
+ protected QName getQName(ContainerSchemaNode schema) {
+ return schema.getQName();
+ }
+
+ @Override
+ protected Object findSchemaForChild(ContainerSchemaNode schema, QName nodeType) {
+ return SchemaUtils.findSchemaForChild(schema, nodeType);
+ }
+
+ @Override
+ protected Object findSchemaForAugment(ContainerSchemaNode schema,
+ InstanceIdentifier.AugmentationIdentifier childToProcessId) {
+ return SchemaUtils.findSchemaForAugment(schema, childToProcessId.getPossibleChildNames());
+ }
+
+ @Override
+ protected DataContainerNodeBuilder<?, ContainerNode> getBuilder(ContainerSchemaNode schema) {
+ return Builders.containerBuilder(schema);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.operations;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+import com.google.common.base.Optional;
+
+public class DataModificationException extends Exception {
+ // TODO replace QName as identifier for node with schema or NodeIdentifier,
+ // Augmentation does not have a QName
+
+ private static final long serialVersionUID = 1L;
+ private final QName node;
+
+ public DataModificationException(String message, QName node) {
+ super(message);
+ this.node = node;
+ }
+
+ public QName getNodeQName() {
+ return node;
+ }
+
+ public static final class DataMissingException extends DataModificationException {
+ private static final long serialVersionUID = 1L;
+
+ public DataMissingException(QName nodeType) {
+ super(String.format("Data missing for node: %s", nodeType), nodeType);
+ }
+
+ public DataMissingException(QName nodeType, Node<?> modificationNode) {
+ super(String.format("Data missing for node: %s, %s", nodeType, modificationNode), nodeType);
+ }
+
+ static void check(QName nodeQName, Optional<? extends NormalizedNode<?, ?>> actualNode) throws DataMissingException {
+ if (actualNode.isPresent() == false) {
+ throw new DataMissingException(nodeQName);
+ }
+ }
+
+ static void check(QName nodeQName, Optional<LeafSetNode<?>> actualNodes, LeafSetEntryNode<?> modificationNode)
+ throws DataMissingException {
+ if (actualNodes.isPresent()==false || actualNodes.get().getChild(modificationNode.getIdentifier()).isPresent() == false) {
+ throw new DataMissingException(nodeQName, modificationNode);
+ }
+ }
+
+ static void check(QName nodeQName, Optional<MapNode> actualNodes, MapEntryNode modificationNode)
+ throws DataModificationException {
+ if (actualNodes.isPresent()==false || actualNodes.get().getChild(modificationNode.getIdentifier()).isPresent() == false) {
+ throw new DataMissingException(nodeQName, modificationNode);
+ }
+ }
+ }
+
+ public static final class DataExistsException extends DataModificationException {
+ private static final long serialVersionUID = 1L;
+
+ public DataExistsException(QName nodeType, NormalizedNode<?, ?> actualNode, NormalizedNode<?, ?> modificationNode) {
+ super(String
+ .format("Data already exists for node: %s, current value: %s. modification value: %s", nodeType, actualNode, modificationNode),
+ nodeType);
+ }
+
+ static void check(QName nodeQName, Optional<? extends NormalizedNode<?, ?>> actualNode, NormalizedNode<?, ?> modificationNode) throws DataExistsException {
+ if (actualNode.isPresent()) {
+ throw new DataExistsException(nodeQName, actualNode.get(), modificationNode);
+ }
+ }
+
+ static void check(QName nodeQName, Optional<LeafSetNode<?>> actualNodes, LeafSetEntryNode<?> modificationNode)
+ throws DataExistsException {
+ if (actualNodes.isPresent() && actualNodes.get().getChild(modificationNode.getIdentifier()).isPresent()) {
+ throw new DataExistsException(nodeQName, actualNodes.get(), modificationNode);
+ }
+ }
+
+ public static void check(QName qName, Optional<MapNode> actualNodes, MapEntryNode listModification)
+ throws DataModificationException {
+ if (actualNodes.isPresent() && actualNodes.get().getChild(listModification.getIdentifier()).isPresent()) {
+ throw new DataExistsException(qName, actualNodes.get(), listModification);
+ }
+ }
+ }
+
+ public static final class IllegalChoiceValuesException extends DataModificationException {
+ private static final long serialVersionUID = 1L;
+
+ public IllegalChoiceValuesException(String message, QName node) {
+ super(message, node);
+ }
+
+ public static void throwMultipleCasesReferenced(QName choiceQName, ChoiceNode modification,
+ QName case1QName, QName case2QName) throws IllegalChoiceValuesException {
+ throw new IllegalChoiceValuesException(String.format(
+ "Child nodes from multiple cases present in modification: %s, choice: %s, case1: %s, case2: %s",
+ modification, choiceQName, case1QName, case2QName), choiceQName);
+ }
+
+ public static void throwUnknownChild(QName choiceQName, QName nodeQName) throws IllegalChoiceValuesException {
+ throw new IllegalChoiceValuesException(String.format(
+ "Unknown child node detected, choice: %s, child node: %s",
+ choiceQName, nodeQName), choiceQName);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.operations;
+
+import org.opendaylight.yangtools.yang.data.api.ModifyAction;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+import com.google.common.base.Optional;
+
+/**
+ * Edit config operations utilities.
+ */
+public final class DataOperations {
+
+ private DataOperations() {}
+
+ public static Optional<ContainerNode> modify(ContainerSchemaNode schema, ContainerNode stored,
+ ContainerNode modified) throws DataModificationException {
+ return modify(schema, stored, modified, ModifyAction.MERGE);
+ }
+
+ public static Optional<MapNode> modify(ListSchemaNode schema, MapNode stored, MapNode modified)
+ throws DataModificationException {
+ return modify(schema, stored, modified, ModifyAction.MERGE);
+ }
+
+ public static Optional<ContainerNode> modify(ContainerSchemaNode schema, ContainerNode stored,
+ ContainerNode modified, ModifyAction defaultOperation) throws DataModificationException {
+
+ OperationStack operations = new OperationStack(defaultOperation);
+
+ return new ContainerNodeModification().modify(schema, Optional.fromNullable(stored),
+ Optional.fromNullable(modified), operations);
+ }
+
+ public static Optional<MapNode> modify(ListSchemaNode schema, MapNode stored, MapNode modified,
+ ModifyAction defaultOperation) throws DataModificationException {
+
+ OperationStack operations = new OperationStack(defaultOperation);
+
+ return new MapNodeModification().modify(schema, Optional.fromNullable(stored), Optional.fromNullable(modified),
+ operations);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.operations;
+
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+
+import com.google.common.base.Optional;
+
+final class LeafNodeModification implements Modification<LeafSchemaNode, LeafNode<?>> {
+
+ @Override
+ public Optional<LeafNode<?>> modify(LeafSchemaNode schema, Optional<LeafNode<?>> actualNode,
+ Optional<LeafNode<?>> modificationNode, OperationStack operationStack) throws DataModificationException {
+
+ operationStack.enteringNode(modificationNode);
+
+ Optional<LeafNode<?>> result;
+
+ // Returns either actual node, modification node or empty in case of removal
+ switch (operationStack.getCurrentOperation()) {
+ case MERGE: {
+ result = modificationNode.isPresent() ? modificationNode : actualNode;
+ break;
+ }
+ case CREATE: {
+ DataModificationException.DataExistsException.check(schema.getQName(), actualNode, null);
+ }
+ case REPLACE: {
+ result = modificationNode;
+ break;
+ }
+ case DELETE: {
+ DataModificationException.DataMissingException.check(schema.getQName(), actualNode);
+ }
+ case REMOVE: {
+ result = Optional.absent();
+ break;
+ }
+ case NONE: {
+ result = actualNode;
+ break;
+ }
+ default:
+ throw new UnsupportedOperationException(String.format("Unable to perform operation: %s on: %s, unknown", operationStack.getCurrentOperation(), schema));
+
+ }
+
+ operationStack.exitingNode(modificationNode);
+
+ return result;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.operations;
+
+import java.util.List;
+
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+final class LeafSetNodeModification implements Modification<LeafListSchemaNode, LeafSetNode<?>> {
+
+ @Override
+ public Optional<LeafSetNode<?>> modify(LeafListSchemaNode schema, Optional<LeafSetNode<?>> actual,
+ Optional<LeafSetNode<?>> modification, OperationStack operationStack) throws DataModificationException {
+
+ List<LeafSetEntryNode<?>> resultNodes = Lists.newArrayList();
+ if(actual.isPresent()) {
+ Iterables.addAll(resultNodes, actual.get().getValue());
+ }
+
+ // TODO implement ordering for modification nodes
+
+ for (LeafSetEntryNode<?> leafListModification : modification.get().getValue()) {
+ operationStack.enteringNode(leafListModification);
+
+ switch (operationStack.getCurrentOperation()) {
+ case MERGE:
+ case CREATE: {
+ DataModificationException.DataExistsException.check(schema.getQName(), actual, leafListModification);
+ }
+ case REPLACE: {
+ if (contains(actual, leafListModification) == false) {
+ resultNodes.add(leafListModification);
+ }
+ break;
+ }
+ case DELETE: {
+ DataModificationException.DataMissingException.check(schema.getQName(), actual, leafListModification);
+ }
+ case REMOVE: {
+ if (resultNodes.contains(leafListModification)) {
+ resultNodes.remove(leafListModification);
+ }
+ break;
+ }
+ case NONE: {
+ break;
+ }
+ default:
+ throw new UnsupportedOperationException(String.format("Unable to perform operation: %s on: %s, unknown", operationStack.getCurrentOperation(), schema));
+ }
+
+ operationStack.exitingNode(leafListModification);
+ }
+ return build(schema, resultNodes);
+ }
+
+ private Optional<LeafSetNode<?>> build(LeafListSchemaNode schemaNode, List<LeafSetEntryNode<?>> resultNodes) {
+ if(resultNodes.isEmpty())
+ return Optional.absent();
+
+ ListNodeBuilder<Object, LeafSetEntryNode<Object>> b = Builders.leafSetBuilder(schemaNode);
+ for (LeafSetEntryNode<?> resultNode : resultNodes) {
+ // FIXME: can we do something about this SuppressWarnings?
+ @SuppressWarnings("unchecked")
+ final LeafSetEntryNode<Object> child = (LeafSetEntryNode<Object>) resultNode;
+ b.withChild(child);
+ }
+
+ return Optional.<LeafSetNode<?>>of(b.build());
+ }
+
+ private static boolean contains(Optional<LeafSetNode<?>> actual, LeafSetEntryNode<?> leafListModification) {
+ boolean contains = actual.isPresent();
+ contains &= actual.get().getChild(leafListModification.getIdentifier()).isPresent();
+
+ return contains;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.operations;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.SchemaUtils;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+final class MapEntryNodeModification extends AbstractContainerNodeModification<ListSchemaNode, MapEntryNode> {
+
+ @Override
+ protected QName getQName(ListSchemaNode schema) {
+ return schema.getQName();
+ }
+
+ @Override
+ protected Object findSchemaForChild(ListSchemaNode schema, QName nodeType) {
+ return SchemaUtils.findSchemaForChild(schema, nodeType);
+ }
+
+ @Override
+ protected Object findSchemaForAugment(ListSchemaNode schema, InstanceIdentifier.AugmentationIdentifier childToProcessId) {
+ return SchemaUtils.findSchemaForAugment(schema, childToProcessId.getPossibleChildNames());
+ }
+
+ @Override
+ protected DataContainerNodeBuilder<?, MapEntryNode> getBuilder(ListSchemaNode schema) {
+ return Builders.mapEntryBuilder(schema);
+ }
+}
--- /dev/null
+/*
+* Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License v1.0 which accompanies this distribution,
+* and is available at http://www.eclipse.org/legal/epl-v10.html
+*/
+package org.opendaylight.yangtools.yang.data.operations;
+
+import java.util.Map;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Maps;
+
+public class MapNodeModification implements Modification<ListSchemaNode, MapNode> {
+
+ public static final MapEntryNodeModification MAP_ENTRY_NODE_MODIFICATION = new MapEntryNodeModification();
+
+ @Override
+ public Optional<MapNode> modify(ListSchemaNode schema, Optional<MapNode> actual,
+ Optional<MapNode> modification, OperationStack operationStack) throws DataModificationException {
+
+ // Merge or None operation on parent, leaving actual if modification not present
+ if (modification.isPresent() == false)
+ return actual;
+
+ Map<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> resultNodes = Maps.newLinkedHashMap();
+ if(actual.isPresent())
+ resultNodes.putAll(mapEntries(actual.get()));
+
+ // TODO implement ordering for modification nodes
+
+ for (MapEntryNode mapEntryModification : modification.get().getValue()) {
+
+ operationStack.enteringNode(mapEntryModification);
+
+ InstanceIdentifier.NodeIdentifierWithPredicates entryKey = mapEntryModification.getIdentifier();
+
+ switch (operationStack.getCurrentOperation()) {
+ case NONE:
+ DataModificationException.DataMissingException.check(schema.getQName(), actual, mapEntryModification);
+ case MERGE: {
+ MapEntryNode mergedListNode;
+ if (resultNodes.containsKey(entryKey)) {
+ MapEntryNode actualEntry = resultNodes.get(entryKey);
+ mergedListNode = MAP_ENTRY_NODE_MODIFICATION.modify(schema, Optional.of(actualEntry), Optional.of(mapEntryModification), operationStack).get();
+ } else {
+ mergedListNode = mapEntryModification;
+ }
+
+ resultNodes.put(mergedListNode.getIdentifier(), mergedListNode);
+ break;
+ }
+ case CREATE: {
+ DataModificationException.DataExistsException.check(schema.getQName(), actual, mapEntryModification);
+ }
+ case REPLACE: {
+ resultNodes.put(entryKey, mapEntryModification);
+ break;
+ }
+ case DELETE: {
+ DataModificationException.DataMissingException.check(schema.getQName(), actual, mapEntryModification);
+ }
+ case REMOVE: {
+ if (resultNodes.containsKey(entryKey)) {
+ resultNodes.remove(entryKey);
+ }
+ break;
+ }
+ default:
+ throw new UnsupportedOperationException(String.format("Unable to perform operation: %s on: %s, unknown", operationStack.getCurrentOperation(), schema));
+ }
+
+ operationStack.exitingNode(mapEntryModification);
+ }
+ return build(schema, resultNodes);
+ }
+
+ private Optional<MapNode> build(ListSchemaNode schema, Map<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> resultNodes) {
+ if(resultNodes.isEmpty())
+ return Optional.absent();
+
+ CollectionNodeBuilder<MapEntryNode, MapNode> b = Builders.mapBuilder(schema);
+
+ for (MapEntryNode child : resultNodes.values()) {
+ b.withChild(child);
+ }
+
+ return Optional.of(b.build());
+ }
+
+ private Map<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> mapEntries(MapNode mapNode) {
+ Map<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> mapped = Maps.newLinkedHashMap();
+
+ for (MapEntryNode mapEntryNode : mapNode.getValue()) {
+ mapped.put(mapEntryNode.getIdentifier(), mapEntryNode);
+ }
+
+ return mapped;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.operations;
+
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+import com.google.common.base.Optional;
+
+/**
+ * Strategy interface for data modification.
+ *
+ * @param <S> SchemaNode type
+ * @param <N> LeafNode type
+ *
+ */
+interface Modification<S, N extends NormalizedNode<?, ?>> {
+
+ Optional<N> modify(S schemaNode, Optional<N> actual, Optional<N> modification, OperationStack operations) throws DataModificationException;
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.operations;
+
+import java.net.URI;
+import java.util.Deque;
+import java.util.LinkedList;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.AttributesContainer;
+import org.opendaylight.yangtools.yang.data.api.ModifyAction;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+
+/**
+ * Tracks netconf operations on nested nodes.
+ */
+final class OperationStack {
+
+ private static final Logger logger = LoggerFactory.getLogger(OperationStack.class);
+ private static final QName OPERATION_NAME = new QName(URI.create("urn:ietf:params:xml:ns:netconf:base:1.0"), "operation");
+
+ private final Deque<ModifyAction> operations = new LinkedList<>();
+
+ public OperationStack(ModifyAction operation) {
+ operations.add(operation);
+ }
+
+ public void enteringNode(Optional<? extends NormalizedNode<?, ?>> modificationNode) {
+ if (modificationNode.isPresent() == false) {
+ return;
+ }
+
+ NormalizedNode<?, ?> modification = modificationNode.get();
+
+ enteringNode(modification);
+ }
+
+ public void enteringNode(NormalizedNode<?, ?> modificationNode) {
+ ModifyAction operation = getOperation(modificationNode);
+ if (operation == null) {
+ return;
+ }
+
+ addOperation(operation);
+ }
+
+ private ModifyAction getOperation(NormalizedNode<?, ?> modificationNode) {
+ if (modificationNode instanceof AttributesContainer == false)
+ return null;
+
+ String operationString = ((AttributesContainer) modificationNode).getAttributes().get(OPERATION_NAME);
+
+ return operationString == null ? null : ModifyAction.fromXmlValue(operationString);
+ }
+
+ private void addOperation(ModifyAction operation) {
+ // Add check for permitted operation
+ operations.add(operation);
+ logger.trace("Operation added {}, {}", operation, this);
+ }
+
+ public ModifyAction getCurrentOperation() {
+ return operations.getLast();
+ }
+
+ public void exitingNode(Optional<? extends NormalizedNode<?, ?>> modificationNode) {
+ if (modificationNode.isPresent() == false) {
+ return;
+ }
+
+ NormalizedNode<?, ?> modification = modificationNode.get();
+
+ exitingNode(modification);
+ }
+
+ public void exitingNode(NormalizedNode<?, ?> modification) {
+ ModifyAction operation = getOperation(modification);
+ if (operation == null) {
+ return;
+ }
+
+ Preconditions.checkState(operations.size() > 1);
+ Preconditions.checkState(operations.peekLast().equals(operation), "Operations mismatch %s, %s",
+ operations.peekLast(), operation);
+
+ ModifyAction removed = operations.removeLast();
+ logger.trace("Operation removed {}, {}", removed, this);
+ }
+
+ @Override
+ public String toString() {
+ return operations.toString();
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.operations;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class YangDataOperationsNegativeTest extends YangDataOperationsTest{
+
+ private static final String XML_NEG_FOLDER_NAME = "/xmls-negative";
+ private final Class<? extends DataModificationException> expected;
+
+ @Parameterized.Parameters()
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][] {
+
+ // Container
+ { "/containerTest_noneContainerActualMissing", DataModificationException.DataMissingException.class },
+ { "/containerTest_createContainerActualPresent", DataModificationException.DataExistsException.class },
+ { "/containerTest_deleteContainerActualMissing", DataModificationException.DataMissingException.class },
+ // List
+ { "/listTest_createListActualPresent", DataModificationException.DataExistsException.class },
+ { "/listTest_deleteListActualMissing", DataModificationException.DataMissingException.class },
+ { "/listTest_noneListActualMissing", DataModificationException.DataMissingException.class },
+ // Leaf
+ { "/leafTest_createLeafActualPresent", DataModificationException.DataExistsException.class },
+ { "/leafTest_deleteLeafActualMissing", DataModificationException.DataMissingException.class },
+ // Leaf list
+ { "/leafListTest_createLeafActualPresent", DataModificationException.DataExistsException.class },
+ { "/leafListTest_deleteLeafActualMissing", DataModificationException.DataMissingException.class },
+ });
+ }
+
+ public YangDataOperationsNegativeTest(String testDir, Class<? extends DataModificationException> e) throws Exception {
+ super(testDir);
+ this.expected = e;
+ }
+
+ @Override
+ protected String getXmlFolderName() {
+ return XML_NEG_FOLDER_NAME;
+ }
+
+ @Test
+ public void testModification() throws Exception {
+ try {
+ DataOperations.modify(containerNode,
+ currentConfig.orNull(), modification.orNull(), modifyAction);
+ fail("Negative test for " + testDirName + " should have failed");
+ } catch (Exception e) {
+ assertEquals(e.getClass(), expected);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.operations;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import javax.activation.UnsupportedDataTypeException;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.TransformerFactoryConfigurationError;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.opendaylight.yangtools.yang.data.api.ModifyAction;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.DomUtils;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.serializer.DomFromNormalizedNodeSerializerFactory;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Lists;
+import com.google.common.io.Files;
+
+@RunWith(Parameterized.class)
+public class YangDataOperationsTest {
+
+ public static final String CURRENT_XML_NAME = "/current.xml";
+ public static final String MODIFICATION_XML_NAME = "/merge.xml";
+ private static final String XML_FOLDER_NAME = "/xmls";
+ public static final String RESULT_XML_NAME = "/result.xml";
+ private static final Object OPERATION_XML_NAME = "/defaultOperation.txt";
+
+ protected final ContainerSchemaNode containerNode;
+ protected final String testDirName;
+ protected final Optional<ContainerNode> currentConfig;
+ protected final Optional<ContainerNode> modification;
+ protected final ModifyAction modifyAction;
+
+ @Parameterized.Parameters()
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][] {
+ // Container
+ { "/containerTest_createContainer" },
+ { "/containerTest_deleteContainer" },
+ { "/containerTest_innerContainerContainer" },
+ { "/containerTest_innerLeavesBaseOperationsContainer" },
+ { "/containerTest_noneContainer" },
+ { "/containerTest_removeContainer"},
+ { "/containerTest_replaceContainer"},
+ { "/containerTest_choiceActualModificationSameCase"},
+ { "/containerTest_choiceActualModificationDifferentCases"},
+ { "/containerTest_choiceActualOneCaseModificationOtherCase"},
+// LeafList
+ { "/leafListTest" },
+ // List
+ { "/listTest" },
+ // Additional
+ {"/none_NoChange"},
+ {"/listTest_alterInnerValue"}
+ });
+ }
+
+ public YangDataOperationsTest(String testDir) throws Exception {
+ SchemaContext schema = parseTestSchema();
+ containerNode = (ContainerSchemaNode) getSchemaNode(schema, "test", "container");
+ this.testDirName = testDir;
+
+ currentConfig = loadXmlToCompositeNode(getXmlFolderName() + testDirName + CURRENT_XML_NAME);
+ modification = loadXmlToCompositeNode(getXmlFolderName() + testDirName + MODIFICATION_XML_NAME);
+ Preconditions.checkState(modification.isPresent(), "Modification xml has to be present under "
+ + getXmlFolderName() + testDirName + MODIFICATION_XML_NAME);
+
+ modifyAction = loadModifyAction(getXmlFolderName() + testDirName + OPERATION_XML_NAME);
+ }
+
+ protected String getXmlFolderName() {
+ return XML_FOLDER_NAME;
+ }
+
+ // TODO unite testing resources e.g. schemas with yang-data-impl
+ // TODO create extract common testing infrastructure from this and yang-data-impl e.g. xml dom handling
+
+ @Test
+ public void testModification() throws Exception {
+
+ Optional<ContainerNode> result = DataOperations.modify(containerNode,
+ currentConfig.orNull(), modification.orNull(), modifyAction);
+
+ String expectedResultXmlPath = getXmlFolderName() + testDirName + RESULT_XML_NAME;
+ Optional<ContainerNode> expectedResult = loadXmlToCompositeNode(expectedResultXmlPath);
+
+ if (result.isPresent()) {
+ verifyModificationResult(result, expectedResult);
+ } else {
+ junit.framework.Assert.assertNull("Result of modification is empty node, result xml should not be present "
+ + expectedResultXmlPath, getClass().getResourceAsStream(expectedResultXmlPath));
+ }
+
+ }
+
+ private ModifyAction loadModifyAction(String path) throws Exception {
+ URL resource = getClass().getResource(path);
+ if (resource == null) {
+ return ModifyAction.MERGE;
+ }
+
+ return ModifyAction.fromXmlValue(Files.toString(new File(resource.toURI()), Charsets.UTF_8).trim());
+ }
+
+ private void verifyModificationResult(Optional<ContainerNode> result, Optional<ContainerNode> expectedResult)
+ throws UnsupportedDataTypeException {
+ Assert.assertEquals(
+ String.format(
+ "Test result %n %s %n Expected %n %s %n",
+ toString(toDom(result.get())),
+ toString(toDom(expectedResult.get()))), expectedResult.get(), result.get());
+ }
+
+ private Element toDom(ContainerNode container) {
+ Iterable<Element> a =
+ DomFromNormalizedNodeSerializerFactory.getInstance(newDocument(), DomUtils.defaultValueCodecProvider())
+ .getContainerNodeSerializer().serialize(containerNode, container);
+ return a.iterator().next();
+ }
+
+ private Document newDocument() {
+ try {
+ return BUILDERFACTORY.newDocumentBuilder().newDocument();
+ } catch (ParserConfigurationException e) {
+ throw new RuntimeException("Failed to parse XML document", e);
+ }
+ }
+
+ private Optional<ContainerNode> loadXmlToCompositeNode(String xmlPath) throws IOException, SAXException {
+ InputStream resourceAsStream = getClass().getResourceAsStream(xmlPath);
+ if (resourceAsStream == null) {
+ return Optional.absent();
+ }
+
+ Document currentConfigElement = readXmlToDocument(resourceAsStream);
+ Preconditions.checkNotNull(currentConfigElement);
+
+ return Optional.of(DomToNormalizedNodeParserFactory.getInstance(DomUtils.defaultValueCodecProvider()).getContainerNodeParser().parse(
+ Collections.singletonList(currentConfigElement.getDocumentElement()), containerNode));
+ }
+
+ SchemaContext parseTestSchema() {
+ YangParserImpl yangParserImpl = new YangParserImpl();
+ Set<Module> modules = yangParserImpl.parseYangModelsFromStreams(getTestYangs());
+ return yangParserImpl.resolveSchemaContext(modules);
+ }
+
+ List<InputStream> getTestYangs() {
+
+ return Lists.newArrayList(Collections2.transform(Lists.newArrayList("/schemas/test.yang"),
+ new Function<String, InputStream>() {
+ @Override
+ public InputStream apply(String input) {
+ InputStream resourceAsStream = getClass().getResourceAsStream(input);
+ Preconditions.checkNotNull(resourceAsStream, "File %s was null", resourceAsStream);
+ return resourceAsStream;
+ }
+ }));
+ }
+
+ DataSchemaNode getSchemaNode(SchemaContext context, String moduleName, String childNodeName) {
+ for (Module module : context.getModules()) {
+ if (module.getName().equals(moduleName)) {
+ for (DataSchemaNode dataSchemaNode : module.getChildNodes()) {
+ if (dataSchemaNode.getQName().getLocalName().equals(childNodeName))
+ return dataSchemaNode;
+ }
+ }
+ }
+
+ throw new IllegalStateException("Unable to find child node " + childNodeName);
+ }
+
+ private static final DocumentBuilderFactory BUILDERFACTORY;
+
+ static {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ factory.setCoalescing(true);
+ factory.setIgnoringElementContentWhitespace(true);
+ factory.setIgnoringComments(true);
+ BUILDERFACTORY = factory;
+ }
+
+ private Document readXmlToDocument(InputStream xmlContent) throws IOException, SAXException {
+ DocumentBuilder dBuilder;
+ try {
+ dBuilder = BUILDERFACTORY.newDocumentBuilder();
+ } catch (ParserConfigurationException e) {
+ throw new RuntimeException("Failed to parse XML document", e);
+ }
+ Document doc = dBuilder.parse(xmlContent);
+
+ doc.getDocumentElement().normalize();
+ return doc;
+ }
+
+ public static String toString(Element xml) {
+ try {
+ Transformer transformer = TransformerFactory.newInstance().newTransformer();
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+
+ StreamResult result = new StreamResult(new StringWriter());
+ DOMSource source = new DOMSource(xml);
+ transformer.transform(source, result);
+
+ return result.getWriter().toString();
+ } catch (IllegalArgumentException | TransformerFactoryConfigurationError | TransformerException e) {
+ throw new RuntimeException("Unable to serialize xml element " + xml, e);
+ }
+ }
+
+}
--- /dev/null
+// vi: set smarttab et sw=4 tabstop=4:
+module test {
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:test";
+ prefix "test";
+
+ organization "Cisco Systems, Inc.";
+
+ revision "2013-2-21" {
+ description
+ "Initial revision";
+ }
+
+ grouping listGroup {
+ list list {
+ key "uint32";
+
+ leaf uint32 {
+ type uint32;
+ }
+
+ container containerInList{
+ leaf uint32 {
+ type uint32;
+ }
+ leaf uint16 {
+ type uint16;
+ }
+ }
+ }
+ }
+
+ grouping innerContainerGrouping {
+ container innerContainer {
+ leaf uint16 {
+ type uint16;
+ }
+
+ container innerInnerContainer {
+
+ leaf uint16 {
+ type uint16;
+ }
+
+ leaf uint32 {
+ type uint32;
+ }
+ }
+ }
+ }
+
+ container container {
+ leaf uint32 {
+ type uint32;
+ }
+
+ leaf decimal64 {
+ type decimal64 {
+ fraction-digits 2;
+ }
+ }
+
+ leaf boolean {
+ type boolean;
+ }
+
+ leaf binary {
+ type binary;
+ }
+
+ leaf string {
+ type string;
+ }
+
+ uses listGroup;
+ uses innerContainerGrouping;
+
+ choice choice{}
+ choice choice2{}
+
+ leaf-list leafList {
+ type string;
+ }
+
+ leaf identityRef {
+ type identityref {
+ base test-identity;
+ }
+ }
+
+ /* TODO test modification with empty type
+ leaf empty {
+ type empty;
+ }
+ */
+ }
+
+ augment "/container/" {
+ leaf augumentUint32 {
+ type uint32;
+ }
+ }
+
+ augment "/container/choice/" {
+ case test-identity-augument {
+ when "/container/identityRef = 'test-identity'";
+ leaf augumentString1 {
+ type string;
+ }
+
+ leaf augumentInt1 {
+ type uint32;
+ }
+ }
+ case test-identity-augument2 {
+ when "/container/identityRef = 'test-identity2'";
+ leaf augumentString2 {
+ type string;
+ }
+
+ leaf augumentInt2 {
+ type uint32;
+ }
+ }
+ }
+
+ augment "/container/choice2/" {
+ case test-identity-augument {
+ when "/container/identityRef = 'test-identity'";
+ container augumentContainer {
+ leaf augumentStringInAugumentContainer {
+ type string;
+ }
+ }
+ }
+ case test-identity-augument2 {
+ when "/container/identityRef = 'test-identity2'";
+ list augumentedList {
+ leaf augumentStringInAugumentList {
+ type string;
+ }
+ }
+ }
+ }
+
+
+ identity test-identity {}
+ identity test-identity2 {
+ base test-identity;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+ xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <identityRef>test-identity2</identityRef>
+
+ <augumentedList>
+ <augumentStringInAugumentList>str1</augumentStringInAugumentList>
+ </augumentedList>
+
+ <augumentContainer>
+ </augumentContainer>
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+ xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
+ nc:operation="create">
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+ xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
+ nc:operation="delete">
+</container>
\ No newline at end of file
--- /dev/null
+none
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+ xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+
+ <!--container is not present and default value is NONE-->
+ <uint32 nc:operation="replace">88</uint32>
+
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+ <leafList>currentLeafList1</leafList>
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+ xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
+ nc:operation="merge">
+ <leafList nc:operation="create">currentLeafList1</leafList>
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+ xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
+ nc:operation="merge">
+ <leafList nc:operation="delete">currentLeafList1</leafList>
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+ <uint32>44</uint32>
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+ xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
+ nc:operation="merge">
+
+ <uint32 nc:operation="create">88</uint32>
+
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+ xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
+ nc:operation="merge">
+
+ <uint32 nc:operation="delete">88</uint32>
+
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+ <list>
+ <uint32>1</uint32>
+ </list>
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+ xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+
+ <list nc:operation="create">
+ <uint32>1</uint32>
+ </list>
+
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+ <list>
+ <uint32>1</uint32>
+ </list>
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+ xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+
+ <list nc:operation="delete">
+ <uint32>2</uint32>
+ </list>
+
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+ <list>
+ <uint32>1</uint32>
+ </list>
+</container>
\ No newline at end of file
--- /dev/null
+none
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+ xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+
+ <list>
+ <uint32>2</uint32>
+ <containerInList nc:operation="create">
+ <uint32>88</uint32>
+ </containerInList>
+ </list>
+
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+ <identityRef>test-identity2</identityRef>
+ <augumentString2>augumentString2</augumentString2>
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+ xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <augumentedList nc:operation="create">
+ <augumentStringInAugumentList>str1</augumentStringInAugumentList>
+ </augumentedList>
+
+ <augumentedList nc:operation="replace">
+ <augumentStringInAugumentList>str2</augumentStringInAugumentList>
+ </augumentedList>
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+ <identityRef>test-identity2</identityRef>
+
+ <augumentedList>
+ <augumentStringInAugumentList>str1</augumentStringInAugumentList>
+ </augumentedList>
+
+ <augumentedList>
+ <augumentStringInAugumentList>str2</augumentStringInAugumentList>
+ </augumentedList>
+
+ <augumentString2>augumentString2</augumentString2>
+
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+ <identityRef>test-identity</identityRef>
+ <augumentString1>augumentString1</augumentString1>
+ <augumentContainer>
+ <augumentStringInAugumentContainer>
+ case1
+ </augumentStringInAugumentContainer>
+ </augumentContainer>
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+ xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <augumentString1>augumentString1</augumentString1>
+
+ <augumentContainer>
+ <augumentStringInAugumentContainer nc:operation="delete">
+ </augumentStringInAugumentContainer>
+ </augumentContainer>
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+ <identityRef>test-identity</identityRef>
+
+ <augumentString1>augumentString1</augumentString1>
+
+ <augumentContainer>
+ </augumentContainer>
+
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+ <identityRef>test-identity</identityRef>
+ <augumentContainer>
+ <augumentStringInAugumentContainer>
+ case1
+ </augumentStringInAugumentContainer>
+ </augumentContainer>
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+ xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <identityRef>test-identity2</identityRef>
+ <augumentedList nc:operation="create">
+ <augumentStringInAugumentList>str1</augumentStringInAugumentList>
+ </augumentedList>
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+ <identityRef>test-identity2</identityRef>
+ <augumentedList>
+ <augumentStringInAugumentList>str1</augumentStringInAugumentList>
+ </augumentedList>
+</container>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+ xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
+ nc:operation="create">
+
+ <!--Inner operations under create are ignored-->
+ <uint32 nc:operation="replace">88</uint32>
+
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+ <uint32>88</uint32>
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+ <uint32>1</uint32>
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+ xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" nc:operation="delete">
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+ <innerContainer>
+ <uint16>11</uint16>
+ <innerInnerContainer>
+ <uint32>11</uint32>
+ <uint16>11</uint16>
+ </innerInnerContainer>
+ </innerContainer>
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+ xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+
+ <innerContainer nc:operation="merge">
+ <!--TODO integer element has to contain value in order to be parsed even if its being removed-->
+ <uint16 nc:operation="remove">-1</uint16>
+ <innerInnerContainer nc:operation="replace">
+ <uint16>22</uint16>
+ </innerInnerContainer>
+ </innerContainer>
+
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+ <innerContainer>
+ <innerInnerContainer>
+ <uint16>22</uint16>
+ </innerInnerContainer>
+ </innerContainer>
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+ <uint32>1</uint32>
+ <augumentUint32>1</augumentUint32>
+ <string>currentString</string>
+ <decimal64>45.1</decimal64>
+ <binary>abcd</binary>
+
+ <identityRef>test-identity</identityRef>
+ <augumentString1>augumentString1</augumentString1>
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+ xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <uint32 nc:operation="replace">88</uint32>
+ <augumentUint32>88</augumentUint32>
+ <decimal64 nc:operation="merge">88.1</decimal64>
+ <string nc:operation="delete"></string>
+ <binary nc:operation="remove"></binary>
+ <boolean nc:operation="create">false</boolean>
+
+ <identityRef>test-identity2</identityRef>
+ <augumentString2 nc:operation="create">augumentString2</augumentString2>
+
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+ <uint32>88</uint32>
+ <augumentUint32>88</augumentUint32>
+ <decimal64>88.1</decimal64>
+ <identityRef>test-identity2</identityRef>
+ <boolean>false</boolean>
+ <augumentString2>augumentString2</augumentString2>
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+ <uint32>1</uint32>
+ <string>currentString</string>
+ <decimal64>45.1</decimal64>
+</container>
\ No newline at end of file
--- /dev/null
+none
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+ xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+
+ <uint32 nc:operation="replace">88</uint32>
+ <decimal64 nc:operation="merge">88.1</decimal64>
+ <string>newString</string>
+ <binary >aaa</binary>
+
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+ <uint32>88</uint32>
+ <string>currentString</string>
+ <decimal64>88.1</decimal64>
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+ <uint32>1</uint32>
+</container>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+ xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
+ nc:operation="remove"
+ >
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+ <uint32>1</uint32>
+ <string>currentString</string>
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+ xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
+ nc:operation="replace">
+ <!--Inner strategies under replace are ignored-->
+ <uint32 nc:operation="remove">88</uint32>
+ <string nc:operation="delete">string</string>
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+ <uint32>88</uint32>
+ <string>string</string>
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+
+ <leafList>currentLeafList1</leafList>
+ <leafList>currentLeafList2</leafList>
+
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+ xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+
+ <leafList nc:operation="delete">currentLeafList1</leafList>
+ <leafList nc:operation="remove">random</leafList>
+ <leafList nc:operation="create">currentLeafList3</leafList>
+ <leafList nc:operation="replace">currentLeafList4</leafList>
+ <leafList nc:operation="merge">currentLeafList5</leafList>
+
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+
+ <leafList>currentLeafList2</leafList>
+ <leafList>currentLeafList3</leafList>
+ <leafList>currentLeafList4</leafList>
+ <leafList>currentLeafList5</leafList>
+
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+
+ <list>
+ <uint32>1</uint32>
+ <containerInList>
+ <uint32>32</uint32>
+ </containerInList>
+ </list>
+ <list>
+ <uint32>2</uint32>
+ <containerInList>
+ <uint32>32</uint32>
+ </containerInList>
+ </list>
+ <list>
+ <uint32>6</uint32>
+ <containerInList>
+ <uint32>32</uint32>
+ </containerInList>
+ </list>
+ <list>
+ <uint32>3</uint32>
+ </list>
+ <list>
+ <uint32>4</uint32>
+ </list>
+ <list>
+ <uint32>5</uint32>
+ </list>
+
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+ xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+
+ <list nc:operation="merge">
+ <uint32>1</uint32>
+ <containerInList>
+ <uint32>88</uint32>
+ </containerInList>
+ </list>
+ <list nc:operation="merge">
+ <uint32>2</uint32>
+ <containerInList nc:operation="replace">
+ </containerInList>
+ </list>
+ <list nc:operation="delete">
+ <uint32>3</uint32>
+ </list>
+ <list nc:operation="remove">
+ <uint32>4</uint32>
+ </list>
+ <list>
+ <uint32>5</uint32>
+ <containerInList nc:operation="create">
+ <uint32>88</uint32>
+ </containerInList>
+ </list>
+ <list>
+ <uint32>6</uint32>
+ <containerInList>
+ <uint32 nc:operation="delete">-1</uint32>
+ </containerInList>
+ </list>
+
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+ <list>
+ <uint32>1</uint32>
+ <containerInList>
+ <uint32>88</uint32>
+ </containerInList>
+ </list>
+ <list>
+ <uint32>2</uint32>
+ <containerInList>
+ </containerInList>
+ </list>
+ <list>
+ <uint32>6</uint32>
+ <containerInList>
+ </containerInList>
+ </list>
+ <list>
+ <uint32>5</uint32>
+ <containerInList>
+ <uint32>88</uint32>
+ </containerInList>
+ </list>
+
+</container>
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+ <list>
+ <uint32>1</uint32>
+ <containerInList>
+ <uint32>32</uint32>
+ <uint16>32</uint16>
+ </containerInList>
+ </list>
+</container>
\ No newline at end of file
--- /dev/null
+none
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+ xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+
+ <list>
+ <uint32>1</uint32>
+ <containerInList>
+ <uint16 nc:operation="delete">88</uint16>
+ </containerInList>
+ </list>
+
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+ <list>
+ <uint32>1</uint32>
+ <containerInList>
+ <uint32>32</uint32>
+ </containerInList>
+ </list>
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+ <uint32>1</uint32>
+ <string>currentString</string>
+ <decimal64>45.1</decimal64>
+</container>
\ No newline at end of file
--- /dev/null
+none
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+ xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+
+ <uint32>88</uint32>
+ <decimal64>88.1</decimal64>
+ <string>newString</string>
+ <binary >aaa</binary>
+
+</container>
\ No newline at end of file
--- /dev/null
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+ <uint32>1</uint32>
+ <string>currentString</string>
+ <decimal64>45.1</decimal64>
+</container>
\ No newline at end of file
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-binding</artifactId>
</dependency>
- <dependency>
- <groupId>org.eclipse.xtend</groupId>
- <artifactId>org.eclipse.xtend.lib</artifactId>
- </dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<build>
<plugins>
- <plugin>
- <groupId>org.eclipse.xtend</groupId>
- <artifactId>xtend-maven-plugin</artifactId>
- </plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
</plugin>
</plugins>
</build>
+
</project>
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.model.util;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.*;
+
+import com.google.common.base.Preconditions;
+
+import java.util.Set;
+
+/**
+ * The Schema Context Util contains support methods for searching through Schema
+ * Context modules for specified schema nodes via Schema Path or Revision Aware
+ * XPath. The Schema Context Util is designed as mixin, so it is not
+ * instantiable.
+ *
+ */
+public class SchemaContextUtil {
+
+ private SchemaContextUtil() {
+ }
+
+ /**
+ * Method attempts to find DataSchemaNode in Schema Context via specified
+ * Schema Path. The returned DataSchemaNode from method will be the node at
+ * the end of the SchemaPath. If the DataSchemaNode is not present in the
+ * Schema Context the method will return <code>null</code>. <br>
+ * In case that Schema Context or Schema Path are not specified correctly
+ * (i.e. contains <code>null</code> values) the method will return
+ * IllegalArgumentException.
+ *
+ * @throws IllegalArgumentException
+ *
+ * @param context
+ * Schema Context
+ * @param schemaPath
+ * Schema Path to search for
+ * @return SchemaNode from the end of the Schema Path or <code>null</code>
+ * if the Node is not present.
+ */
+ public static SchemaNode findDataSchemaNode(SchemaContext context, SchemaPath schemaPath) {
+ Preconditions.checkArgument(context != null, "Schema Context reference cannot be NULL");
+ Preconditions.checkArgument(schemaPath != null, "Schema Path reference cannot be NULL");
+ List<QName> prefixedPath = (schemaPath.getPath());
+ if (prefixedPath != null) {
+ return findNodeInSchemaContext(context, prefixedPath);
+ }
+ return null;
+ }
+
+ /**
+ * Method attempts to find DataSchemaNode inside of provided Schema Context
+ * and Yang Module accordingly to Non-conditional Revision Aware XPath. The
+ * specified Module MUST be present in Schema Context otherwise the
+ * operation would fail and return <code>null</code>. <br>
+ * The Revision Aware XPath MUST be specified WITHOUT the conditional
+ * statement (i.e. without [cond]) in path, because in this state the Schema
+ * Context is completely unaware of data state and will be not able to
+ * properly resolve XPath. If the XPath contains condition the method will
+ * return IllegalArgumentException. <br>
+ * In case that Schema Context or Module or Revision Aware XPath contains
+ * <code>null</code> references the method will throw
+ * IllegalArgumentException <br>
+ * If the Revision Aware XPath is correct and desired Data Schema Node is
+ * present in Yang module or in depending module in Schema Context the
+ * method will return specified Data Schema Node, otherwise the operation
+ * will fail and method will return <code>null</code>.
+ *
+ * @throws IllegalArgumentException
+ *
+ * @param context
+ * Schema Context
+ * @param module
+ * Yang Module
+ * @param nonCondXPath
+ * Non Conditional Revision Aware XPath
+ * @return Returns Data Schema Node for specified Schema Context for given
+ * Non-conditional Revision Aware XPath, or <code>null</code> if the
+ * DataSchemaNode is not present in Schema Context.
+ */
+ public static SchemaNode findDataSchemaNode(SchemaContext context, Module module, RevisionAwareXPath nonCondXPath) {
+ Preconditions.checkArgument(context != null, "Schema Context reference cannot be NULL");
+ Preconditions.checkArgument(module != null, "Module reference cannot be NULL");
+ Preconditions.checkArgument(nonCondXPath != null, "Non Conditional Revision Aware XPath cannot be NULL");
+
+ String strXPath = nonCondXPath.toString();
+ if (strXPath != null) {
+ if (strXPath.contains("[")) {
+ throw new IllegalArgumentException("Revision Aware XPath cannot contains condition");
+ }
+ if (nonCondXPath.isAbsolute()) {
+ List<QName> qnamedPath = xpathToQNamePath(context, module, strXPath);
+ if (qnamedPath != null) {
+ return findNodeInSchemaContext(context, qnamedPath);
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Method attempts to find DataSchemaNode inside of provided Schema Context
+ * and Yang Module accordingly to Non-conditional relative Revision Aware
+ * XPath. The specified Module MUST be present in Schema Context otherwise
+ * the operation would fail and return <code>null</code>. <br>
+ * The relative Revision Aware XPath MUST be specified WITHOUT the
+ * conditional statement (i.e. without [cond]) in path, because in this
+ * state the Schema Context is completely unaware of data state and will be
+ * not able to properly resolve XPath. If the XPath contains condition the
+ * method will return IllegalArgumentException. <br>
+ * The Actual Schema Node MUST be specified correctly because from this
+ * Schema Node will search starts. If the Actual Schema Node is not correct
+ * the operation will simply fail, because it will be unable to find desired
+ * DataSchemaNode. <br>
+ * In case that Schema Context or Module or Actual Schema Node or relative
+ * Revision Aware XPath contains <code>null</code> references the method
+ * will throw IllegalArgumentException <br>
+ * If the Revision Aware XPath doesn't have flag
+ * <code>isAbsolute == false</code> the method will throw
+ * IllegalArgumentException. <br>
+ * If the relative Revision Aware XPath is correct and desired Data Schema
+ * Node is present in Yang module or in depending module in Schema Context
+ * the method will return specified Data Schema Node, otherwise the
+ * operation will fail and method will return <code>null</code>.
+ *
+ * @throws IllegalArgumentException
+ *
+ * @param context
+ * Schema Context
+ * @param module
+ * Yang Module
+ * @param actualSchemaNode
+ * Actual Schema Node
+ * @param relativeXPath
+ * Relative Non Conditional Revision Aware XPath
+ * @return DataSchemaNode if is present in specified Schema Context for
+ * given relative Revision Aware XPath, otherwise will return
+ * <code>null</code>.
+ */
+ public static SchemaNode findDataSchemaNodeForRelativeXPath(SchemaContext context, Module module,
+ SchemaNode actualSchemaNode, RevisionAwareXPath relativeXPath) {
+ Preconditions.checkArgument(context != null, "Schema Context reference cannot be NULL");
+ Preconditions.checkArgument(module != null, "Module reference cannot be NULL");
+ Preconditions.checkArgument(actualSchemaNode != null, "Actual Schema Node reference cannot be NULL");
+ Preconditions.checkArgument(relativeXPath != null, "Non Conditional Revision Aware XPath cannot be NULL");
+ Preconditions.checkState(!relativeXPath.isAbsolute(),
+ "Revision Aware XPath MUST be relative i.e. MUST contains ../, "
+ + "for non relative Revision Aware XPath use findDataSchemaNode method");
+
+ SchemaPath actualNodePath = actualSchemaNode.getPath();
+ if (actualNodePath != null) {
+ List<QName> qnamePath = resolveRelativeXPath(context, module, relativeXPath, actualSchemaNode);
+
+ if (qnamePath != null) {
+ return findNodeInSchemaContext(context, qnamePath);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns parent Yang Module for specified Schema Context in which Schema
+ * Node is declared. If the Schema Node is not present in Schema Context the
+ * operation will return <code>null</code>. <br>
+ * If Schema Context or Schema Node contains <code>null</code> references
+ * the method will throw IllegalArgumentException
+ *
+ * @throws IllegalArgumentException
+ *
+ * @param context
+ * Schema Context
+ * @param schemaNode
+ * Schema Node
+ * @return Yang Module for specified Schema Context and Schema Node, if
+ * Schema Node is NOT present, the method will returns
+ * <code>null</code>
+ */
+ public static Module findParentModule(SchemaContext context, SchemaNode schemaNode) {
+ Preconditions.checkArgument(context != null, "Schema Context reference cannot be NULL!");
+ Preconditions.checkArgument(schemaNode != null, "Schema Node cannot be NULL!");
+ Preconditions.checkState(schemaNode.getPath() != null, "Schema Path for Schema Node is not "
+ + "set properly (Schema Path is NULL)");
+
+ List<QName> qnamedPath = schemaNode.getPath().getPath();
+ if (qnamedPath == null || qnamedPath.isEmpty()) {
+ throw new IllegalStateException("Schema Path contains invalid state of path parts."
+ + "The Schema Path MUST contain at least ONE QName which defines namespace and Local name"
+ + "of path.");
+ }
+ QName qname = qnamedPath.get(qnamedPath.size() - 1);
+ return context.findModuleByNamespaceAndRevision(qname.getNamespace(), qname.getRevision());
+ }
+
+ public static SchemaNode findNodeInSchemaContext(SchemaContext context, List<QName> path) {
+ QName current = path.get(0);
+ Module module = context.findModuleByNamespaceAndRevision(current.getNamespace(), current.getRevision());
+ if (module == null)
+ return null;
+ return findNodeInModule(module, path);
+ }
+
+ public static GroupingDefinition findGrouping(SchemaContext context, Module module, List<QName> path) {
+ QName first = path.get(0);
+ Module m = context.findModuleByNamespace(first.getNamespace()).iterator().next();
+ DataNodeContainer currentParent = m;
+ for (QName qname : path) {
+ boolean found = false;
+ DataNodeContainer node = (DataNodeContainer) currentParent.getDataChildByName(qname.getLocalName());
+ if (node == null) {
+ Set<GroupingDefinition> groupings = currentParent.getGroupings();
+ for (GroupingDefinition gr : groupings) {
+ if (gr.getQName().getLocalName().equals(qname.getLocalName())) {
+ currentParent = gr;
+ found = true;
+ }
+ }
+ } else {
+ found = true;
+ currentParent = node;
+ }
+ if (!found) {
+ throw new IllegalArgumentException("Failed to find referenced grouping: " + path + "("
+ + qname.getLocalName() + ")");
+ }
+ }
+
+ return (GroupingDefinition) currentParent;
+ }
+
+ private static SchemaNode findNodeInModule(Module module, List<QName> path) {
+ QName current = path.get(0);
+ SchemaNode node = module.getDataChildByName(current);
+ if (node != null)
+ return findNode((DataSchemaNode) node, nextLevel(path));
+ node = getRpcByName(module, current);
+ if (node != null)
+ return findNodeInRpc((RpcDefinition) node, nextLevel(path));
+ node = getNotificationByName(module, current);
+ if (node != null)
+ return findNodeInNotification((NotificationDefinition) node, nextLevel(path));
+ node = getGroupingByName(module, current);
+ if (node != null)
+ return findNodeInGrouping((GroupingDefinition) node, nextLevel(path));
+ return node;
+ }
+
+ private static SchemaNode findNodeInGrouping(GroupingDefinition grouping, List<QName> path) {
+ if (path.isEmpty())
+ return grouping;
+ QName current = path.get(0);
+ DataSchemaNode node = grouping.getDataChildByName(current);
+ if (node != null)
+ return findNode(node, nextLevel(path));
+ return null;
+ }
+
+ private static SchemaNode findNodeInRpc(RpcDefinition rpc, List<QName> path) {
+ if (path.isEmpty())
+ return rpc;
+ QName current = path.get(0);
+ switch (current.getLocalName()) {
+ case "input":
+ return findNode(rpc.getInput(), nextLevel(path));
+ case "output":
+ return findNode(rpc.getOutput(), nextLevel(path));
+ }
+ return null;
+ }
+
+ private static SchemaNode findNodeInNotification(NotificationDefinition rpc, List<QName> path) {
+ if (path.isEmpty())
+ return rpc;
+ QName current = path.get(0);
+ DataSchemaNode node = rpc.getDataChildByName(current);
+ if (node != null)
+ return findNode(node, nextLevel(path));
+ return null;
+ }
+
+ private static SchemaNode findNode(ChoiceNode parent, List<QName> path) {
+ if (path.isEmpty())
+ return parent;
+ QName current = path.get(0);
+ ChoiceCaseNode node = parent.getCaseNodeByName(current);
+ if (node != null)
+ return findNodeInCase(node, nextLevel(path));
+ return null;
+ }
+
+ private static SchemaNode findNode(ContainerSchemaNode parent, List<QName> path) {
+ if (path.isEmpty())
+ return parent;
+ QName current = path.get(0);
+ DataSchemaNode node = parent.getDataChildByName(current);
+ if (node != null)
+ return findNode(node, nextLevel(path));
+ return null;
+ }
+
+ private static SchemaNode findNode(ListSchemaNode parent, List<QName> path) {
+ if (path.isEmpty())
+ return parent;
+ QName current = path.get(0);
+ DataSchemaNode node = parent.getDataChildByName(current);
+ if (node != null)
+ return findNode(node, nextLevel(path));
+ return null;
+ }
+
+ private static SchemaNode findNode(DataSchemaNode parent, List<QName> path) {
+ SchemaNode result = null;
+ if (path.isEmpty()) {
+ result = parent;
+ } else {
+ if (parent instanceof ContainerSchemaNode) {
+ result = findNode((ContainerSchemaNode) parent, path);
+ } else if (parent instanceof ListSchemaNode) {
+ result = findNode((ListSchemaNode) parent, path);
+ } else if (parent instanceof ChoiceNode) {
+ result = findNode((ChoiceNode) parent, path);
+ } else {
+ throw new IllegalArgumentException("Path nesting violation");
+ }
+ }
+ return result;
+ }
+
+ public static SchemaNode findNodeInCase(ChoiceCaseNode parent, List<QName> path) {
+ if (path.isEmpty())
+ return parent;
+ QName current = path.get(0);
+ DataSchemaNode node = parent.getDataChildByName(current);
+ if (node != null)
+ return findNode(node, nextLevel(path));
+ return null;
+ }
+
+ public static RpcDefinition getRpcByName(Module module, QName name) {
+ for (RpcDefinition rpc : module.getRpcs()) {
+ if (rpc.getQName().equals(name)) {
+ return rpc;
+ }
+ }
+ return null;
+ }
+
+ private static List<QName> nextLevel(List<QName> path) {
+ return path.subList(1, path.size());
+ }
+
+ public static NotificationDefinition getNotificationByName(Module module, QName name) {
+ for (NotificationDefinition notification : module.getNotifications()) {
+ if (notification.getQName().equals(name)) {
+ return notification;
+ }
+ }
+ return null;
+ }
+
+ public static GroupingDefinition getGroupingByName(Module module, QName name) {
+ for (GroupingDefinition grouping : module.getGroupings()) {
+ if (grouping.getQName().equals(name)) {
+ return grouping;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Utility method which search for original node defined in grouping.
+ *
+ * @param node
+ * @return
+ */
+ public static DataSchemaNode findOriginal(DataSchemaNode node, SchemaContext ctx) {
+ DataSchemaNode result = findCorrectTargetFromGrouping(node, ctx);
+ if (result == null) {
+ result = findCorrectTargetFromAugment(node, ctx);
+ if (result != null) {
+ if (result.isAddedByUses()) {
+ result = findOriginal(result, ctx);
+ }
+ }
+ }
+ return result;
+ }
+
+ private static DataSchemaNode findCorrectTargetFromGrouping(DataSchemaNode node, SchemaContext ctx) {
+ if (node.getPath().getPath().size() == 1) {
+ // uses is under module statement
+ Module m = findParentModule(ctx, node);
+ DataSchemaNode result = null;
+ for (UsesNode u : m.getUses()) {
+ SchemaNode targetGrouping = findNodeInSchemaContext(ctx, u.getGroupingPath().getPath());
+ if (!(targetGrouping instanceof GroupingDefinition)) {
+ throw new IllegalArgumentException("Failed to generate code for augment in " + u);
+ }
+ GroupingDefinition gr = (GroupingDefinition) targetGrouping;
+ result = gr.getDataChildByName(node.getQName().getLocalName());
+ }
+ if (result == null) {
+ throw new IllegalArgumentException("Failed to generate code for augment");
+ }
+ return result;
+ } else {
+ DataSchemaNode result = null;
+ QName currentName = node.getQName();
+ List<QName> tmpPath = new ArrayList<>();
+ Object parent = null;
+
+ SchemaPath sp = node.getPath();
+ List<QName> names = sp.getPath();
+ List<QName> newNames = new ArrayList<>(names);
+ newNames.remove(newNames.size() - 1);
+ SchemaPath newSp = new SchemaPath(newNames, sp.isAbsolute());
+ parent = findDataSchemaNode(ctx, newSp);
+
+ do {
+ tmpPath.add(currentName);
+ if (parent instanceof DataNodeContainer) {
+ DataNodeContainer dataNodeParent = (DataNodeContainer) parent;
+ for (UsesNode u : dataNodeParent.getUses()) {
+ if (result == null) {
+ result = getResultFromUses(u, currentName.getLocalName(), ctx);
+ }
+ }
+ }
+ if (result == null) {
+ currentName = ((SchemaNode) parent).getQName();
+ if (parent instanceof SchemaNode) {
+ SchemaPath nodeSp = ((SchemaNode) parent).getPath();
+ List<QName> nodeNames = nodeSp.getPath();
+ List<QName> nodeNewNames = new ArrayList<>(nodeNames);
+ nodeNewNames.remove(nodeNewNames.size() - 1);
+ if (nodeNewNames.isEmpty()) {
+ parent = getParentModule((SchemaNode) parent, ctx);
+ } else {
+ SchemaPath nodeNewSp = new SchemaPath(nodeNewNames, nodeSp.isAbsolute());
+ parent = findDataSchemaNode(ctx, nodeNewSp);
+ }
+ } else {
+ throw new IllegalArgumentException("Failed to generate code for augment");
+ }
+ }
+ } while (result == null && !(parent instanceof Module));
+
+ if (result != null) {
+ result = getTargetNode(tmpPath, result, ctx);
+ }
+ return result;
+ }
+ }
+
+ private static DataSchemaNode findCorrectTargetFromAugment(DataSchemaNode node, SchemaContext ctx) {
+ if (!node.isAugmenting()) {
+ return null;
+ }
+
+ QName currentName = node.getQName();
+ Object currentNode = node;
+ Object parent = node;
+ List<QName> tmpPath = new ArrayList<QName>();
+ List<SchemaNode> tmpTree = new ArrayList<SchemaNode>();
+
+ AugmentationSchema augment = null;
+ do {
+ SchemaPath sp = ((SchemaNode) parent).getPath();
+ List<QName> names = sp.getPath();
+ List<QName> newNames = new ArrayList<>(names);
+ newNames.remove(newNames.size() - 1);
+ SchemaPath newSp = new SchemaPath(newNames, sp.isAbsolute());
+ parent = findDataSchemaNode(ctx, newSp);
+ if (parent instanceof AugmentationTarget) {
+ tmpPath.add(currentName);
+ tmpTree.add((SchemaNode) currentNode);
+ augment = findNodeInAugment(((AugmentationTarget) parent).getAvailableAugmentations(), currentName);
+ if (augment == null) {
+ currentName = ((DataSchemaNode) parent).getQName();
+ currentNode = parent;
+ }
+ }
+ } while (((DataSchemaNode) parent).isAugmenting() && augment == null);
+
+ if (augment == null) {
+ return null;
+ } else {
+ Collections.reverse(tmpPath);
+ Collections.reverse(tmpTree);
+ Object actualParent = augment;
+ DataSchemaNode result = null;
+ for (QName name : tmpPath) {
+ if (actualParent instanceof DataNodeContainer) {
+ result = ((DataNodeContainer) actualParent).getDataChildByName(name.getLocalName());
+ actualParent = ((DataNodeContainer) actualParent).getDataChildByName(name.getLocalName());
+ } else {
+ if (actualParent instanceof ChoiceNode) {
+ result = ((ChoiceNode) actualParent).getCaseNodeByName(name.getLocalName());
+ actualParent = ((ChoiceNode) actualParent).getCaseNodeByName(name.getLocalName());
+ }
+ }
+ }
+
+ if (result.isAddedByUses()) {
+ result = findCorrectTargetFromAugmentGrouping(result, augment, tmpTree, ctx);
+ }
+
+ return result;
+ }
+ }
+
+ private static DataSchemaNode getResultFromUses(UsesNode u, String currentName, SchemaContext ctx) {
+ SchemaNode targetGrouping = findNodeInSchemaContext(ctx, u.getGroupingPath().getPath());
+ if (!(targetGrouping instanceof GroupingDefinition)) {
+ throw new IllegalArgumentException("Failed to generate code for augment in " + u);
+ }
+ GroupingDefinition gr = (GroupingDefinition) targetGrouping;
+ return gr.getDataChildByName(currentName);
+ }
+
+ private static Module getParentModule(SchemaNode node, SchemaContext ctx) {
+ QName qname = node.getPath().getPath().get(0);
+ URI namespace = qname.getNamespace();
+ Date revision = qname.getRevision();
+ return ctx.findModuleByNamespaceAndRevision(namespace, revision);
+ }
+
+ private static DataSchemaNode getTargetNode(List<QName> tmpPath, DataSchemaNode node, SchemaContext ctx) {
+ DataSchemaNode result = node;
+ if (tmpPath.size() == 1) {
+ if (result != null && result.isAddedByUses()) {
+ result = findOriginal(result, ctx);
+ }
+ return result;
+ } else {
+ DataSchemaNode newParent = result;
+ Collections.reverse(tmpPath);
+
+ tmpPath.remove(0);
+ for (QName name : tmpPath) {
+ // searching by local name is must, because node has different
+ // namespace in its original location
+ if (newParent == null) {
+ break;
+ }
+ if (newParent instanceof DataNodeContainer) {
+ newParent = ((DataNodeContainer) newParent).getDataChildByName(name.getLocalName());
+ } else {
+ newParent = ((ChoiceNode) newParent).getCaseNodeByName(name.getLocalName());
+ }
+ }
+ if (newParent != null && newParent.isAddedByUses()) {
+ newParent = findOriginal(newParent, ctx);
+ }
+ return newParent;
+ }
+ }
+
+ private static AugmentationSchema findNodeInAugment(Collection<AugmentationSchema> augments, QName name) {
+ for (AugmentationSchema augment : augments) {
+ DataSchemaNode node = augment.getDataChildByName(name);
+ if (node != null) {
+ return augment;
+ }
+ }
+ return null;
+ }
+
+ private static DataSchemaNode findCorrectTargetFromAugmentGrouping(DataSchemaNode node,
+ AugmentationSchema parentNode, List<SchemaNode> dataTree, SchemaContext ctx) {
+
+ DataSchemaNode result = null;
+ QName currentName = node.getQName();
+ List<QName> tmpPath = new ArrayList<>();
+ tmpPath.add(currentName);
+ int i = 1;
+ Object parent = null;
+
+ do {
+ if (dataTree.size() < 2 || dataTree.size() == i) {
+ parent = parentNode;
+ } else {
+ parent = dataTree.get(dataTree.size() - (i + 1));
+ tmpPath.add(((SchemaNode) parent).getQName());
+ }
+
+ if (parent instanceof DataNodeContainer) {
+ DataNodeContainer dataNodeParent = (DataNodeContainer) parent;
+ for (UsesNode u : dataNodeParent.getUses()) {
+ if (result == null) {
+ result = getResultFromUses(u, currentName.getLocalName(), ctx);
+ }
+ }
+ }
+
+ if (result == null) {
+ i = i + 1;
+ currentName = ((SchemaNode) parent).getQName();
+ }
+ } while (result == null);
+
+ if (result != null) {
+ result = getTargetNode(tmpPath, result, ctx);
+ }
+ return result;
+ }
+
+ /**
+ * Transforms string representation of XPath to Queue of QNames. The XPath
+ * is split by "/" and for each part of XPath is assigned correct module in
+ * Schema Path. <br>
+ * If Schema Context, Parent Module or XPath string contains
+ * <code>null</code> values, the method will throws IllegalArgumentException
+ *
+ * @throws IllegalArgumentException
+ *
+ * @param context
+ * Schema Context
+ * @param parentModule
+ * Parent Module
+ * @param xpath
+ * XPath String
+ * @return return a list of QName
+ */
+ private static List<QName> xpathToQNamePath(SchemaContext context, Module parentModule, String xpath) {
+ Preconditions.checkArgument(context != null, "Schema Context reference cannot be NULL");
+ Preconditions.checkArgument(parentModule != null, "Parent Module reference cannot be NULL");
+ Preconditions.checkArgument(xpath != null, "XPath string reference cannot be NULL");
+
+ List<QName> path = new LinkedList<QName>();
+ String[] prefixedPath = xpath.split("/");
+ for (String pathComponent : prefixedPath) {
+ if (!pathComponent.isEmpty()) {
+ path.add(stringPathPartToQName(context, parentModule, pathComponent));
+ }
+ }
+ return path;
+ }
+
+ /**
+ * Transforms part of Prefixed Path as java String to QName. <br>
+ * If the string contains module prefix separated by ":" (i.e.
+ * mod:container) this module is provided from from Parent Module list of
+ * imports. If the Prefixed module is present in Schema Context the QName
+ * can be constructed. <br>
+ * If the Prefixed Path Part does not contains prefix the Parent's Module
+ * namespace is taken for construction of QName. <br>
+ * If Schema Context, Parent Module or Prefixed Path Part refers to
+ * <code>null</code> the method will throw IllegalArgumentException
+ *
+ * @throws IllegalArgumentException
+ *
+ * @param context
+ * Schema Context
+ * @param parentModule
+ * Parent Module
+ * @param prefixedPathPart
+ * Prefixed Path Part string
+ * @return QName from prefixed Path Part String.
+ */
+ private static QName stringPathPartToQName(SchemaContext context, Module parentModule, String prefixedPathPart) {
+ Preconditions.checkArgument(context != null, "Schema Context reference cannot be NULL");
+ Preconditions.checkArgument(parentModule != null, "Parent Module reference cannot be NULL");
+ Preconditions.checkArgument(prefixedPathPart != null, "Prefixed Path Part cannot be NULL!");
+
+ if (prefixedPathPart.contains(":")) {
+ String[] prefixedName = prefixedPathPart.split(":");
+ Module module = resolveModuleForPrefix(context, parentModule, prefixedName[0]);
+ if (module == null) {
+ throw new IllegalArgumentException("Failed to resolve xpath: no module found for prefix "
+ + prefixedName[0] + " in module " + parentModule.getName());
+ } else {
+ return new QName(module.getNamespace(), module.getRevision(), prefixedName[1]);
+ }
+ } else {
+ return new QName(parentModule.getNamespace(), parentModule.getRevision(), prefixedPathPart);
+ }
+ }
+
+ /**
+ * Method will attempt to resolve and provide Module reference for specified
+ * module prefix. Each Yang module could contains multiple imports which
+ * MUST be associated with corresponding module prefix. The method simply
+ * looks into module imports and returns the module that is bounded with
+ * specified prefix. If the prefix is not present in module or the prefixed
+ * module is not present in specified Schema Context, the method will return
+ * <code>null</code>. <br>
+ * If String prefix is the same as prefix of the specified Module the
+ * reference to this module is returned. <br>
+ * If Schema Context, Module or Prefix are referring to <code>null</code>
+ * the method will return IllegalArgumentException
+ *
+ * @throws IllegalArgumentException
+ *
+ * @param context
+ * Schema Context
+ * @param module
+ * Yang Module
+ * @param prefix
+ * Module Prefix
+ * @return Module for given prefix in specified Schema Context if is
+ * present, otherwise returns <code>null</code>
+ */
+ private static Module resolveModuleForPrefix(SchemaContext context, Module module, String prefix) {
+ Preconditions.checkArgument(context != null, "Schema Context reference cannot be NULL");
+ Preconditions.checkArgument(module != null, "Module reference cannot be NULL");
+ Preconditions.checkArgument(prefix != null, "Prefix string cannot be NULL");
+
+ if (prefix.equals(module.getPrefix())) {
+ return module;
+ }
+
+ Set<ModuleImport> imports = module.getImports();
+ for (ModuleImport mi : imports) {
+ if (prefix.equals(mi.getPrefix())) {
+ return context.findModuleByName(mi.getModuleName(), mi.getRevision());
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @throws IllegalArgumentException
+ *
+ * @param context
+ * Schema Context
+ * @param module
+ * Yang Module
+ * @param relativeXPath
+ * Non conditional Revision Aware Relative XPath
+ * @param leafrefSchemaPath
+ * Schema Path for Leafref
+ * @return list of QName
+ */
+ private static List<QName> resolveRelativeXPath(SchemaContext context, Module module,
+ RevisionAwareXPath relativeXPath, SchemaNode leafrefParentNode) {
+ Preconditions.checkArgument(context != null, "Schema Context reference cannot be NULL");
+ Preconditions.checkArgument(module != null, "Module reference cannot be NULL");
+ Preconditions.checkArgument(relativeXPath != null, "Non Conditional Revision Aware XPath cannot be NULL");
+ Preconditions.checkState(!relativeXPath.isAbsolute(),
+ "Revision Aware XPath MUST be relative i.e. MUST contains ../, "
+ + "for non relative Revision Aware XPath use findDataSchemaNode method");
+ Preconditions.checkState(leafrefParentNode.getPath() != null,
+ "Schema Path reference for Leafref cannot be NULL");
+
+ List<QName> absolutePath = new LinkedList<QName>();
+ String strXPath = relativeXPath.toString();
+ String[] xpaths = strXPath.split("/");
+
+ int colCount = 0;
+ while (xpaths[colCount].contains("..")) {
+ colCount = colCount + 1;
+ }
+ List<QName> path = leafrefParentNode.getPath().getPath();
+ if (path != null) {
+ int lenght = path.size() - colCount;
+ absolutePath.addAll(path.subList(0, lenght));
+ List<String> xpathsList = Arrays.asList(xpaths);
+ List<String> sublistedXPath = xpathsList.subList(colCount, xpaths.length);
+ List<QName> sublist = new ArrayList<>();
+ for (String pathPart : sublistedXPath) {
+ sublist.add(stringPathPartToQName(context, module, pathPart));
+ }
+ absolutePath.addAll(sublist);
+ }
+
+ return absolutePath;
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.yangtools.yang.model.util;
-
-import java.net.URI;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Queue;
-
-import org.opendaylight.yangtools.yang.common.QName;
-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.ListSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.Module;
-import org.opendaylight.yangtools.yang.model.api.ModuleImport;
-import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.model.api.SchemaNode;
-import org.opendaylight.yangtools.yang.model.api.SchemaPath;
-import org.opendaylight.yangtools.yang.model.api.RpcDefinition
-import org.opendaylight.yangtools.yang.model.api.NotificationDefinition
-import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode
-import java.util.Date
-import org.opendaylight.yangtools.yang.model.api.GroupingDefinition
-import java.util.Set
-
-/**
- * The Schema Context Util contains support methods for searching through Schema Context modules for specified schema
- * nodes via Schema Path or Revision Aware XPath. The Schema Context Util is designed as mixin,
- * so it is not instantiable.
- *
- * @author Lukas Sedlak <lsedlak@cisco.com>
- */
-public class SchemaContextUtil {
-
- private new() {
- }
-
- /**
- * Method attempts to find DataSchemaNode in Schema Context via specified Schema Path. The returned
- * DataSchemaNode from method will be the node at the end of the SchemaPath. If the DataSchemaNode is not present
- * in the Schema Context the method will return <code>null</code>.
- * <br>
- * In case that Schema Context or Schema Path are not specified correctly (i.e. contains <code>null</code>
- * values) the method will return IllegalArgumentException.
- *
- * @throws IllegalArgumentException
- *
- * @param context
- * Schema Context
- * @param schemaPath
- * Schema Path to search for
- * @return DataSchemaNode from the end of the Schema Path or
- * <code>null</code> if the Node is not present.
- */
- public static def SchemaNode findDataSchemaNode( SchemaContext context, SchemaPath schemaPath) {
- if (context === null) {
- throw new IllegalArgumentException("Schema Context reference cannot be NULL!");
- }
- if (schemaPath === null) {
- throw new IllegalArgumentException("Schema Path reference cannot be NULL");
- }
- val prefixedPath = (schemaPath.getPath());
- if (prefixedPath != null) {
- return findNodeInSchemaContext(context,prefixedPath);
- }
- return null;
- }
-
- /**
- * Method attempts to find DataSchemaNode inside of provided Schema Context and Yang Module accordingly to
- * Non-conditional Revision Aware XPath. The specified Module MUST be present in Schema Context otherwise the
- * operation would fail and return <code>null</code>.
- * <br>
- * The Revision Aware XPath MUST be specified WITHOUT the conditional statement (i.e. without [cond]) in path,
- * because in this state the Schema Context is completely unaware of data state and will be not able to properly
- * resolve XPath. If the XPath contains condition the method will return IllegalArgumentException.
- * <br>
- * In case that Schema Context or Module or Revision Aware XPath contains <code>null</code> references the method
- * will throw IllegalArgumentException
- * <br>
- * If the Revision Aware XPath is correct and desired Data Schema Node is present in Yang module or in depending
- * module in Schema Context the method will return specified Data Schema Node, otherwise the operation will fail
- * and method will return <code>null</code>.
- *
- * @throws IllegalArgumentException
- *
- * @param context Schema Context
- * @param module Yang Module
- * @param nonCondXPath Non Conditional Revision Aware XPath
- * @return Returns Data Schema Node for specified Schema Context for given Non-conditional Revision Aware XPath,
- * or <code>null</code> if the DataSchemaNode is not present in Schema Context.
- */
- public static def SchemaNode findDataSchemaNode( SchemaContext context, Module module,
- RevisionAwareXPath nonCondXPath) {
- if (context === null) {
- throw new IllegalArgumentException("Schema Context reference cannot be NULL!");
- }
- if (module === null) {
- throw new IllegalArgumentException("Module reference cannot be NULL!");
- }
- if (nonCondXPath === null) {
- throw new IllegalArgumentException("Non Conditional Revision Aware XPath cannot be NULL!");
- }
-
- val strXPath = nonCondXPath.toString();
- if (strXPath != null) {
- if (strXPath.contains("[")) {
- throw new IllegalArgumentException("Revision Aware XPath cannot contains condition!");
- }
- if (nonCondXPath.isAbsolute()) {
- val qnamedPath = xpathToQNamePath(context, module, strXPath);
- if (qnamedPath != null) {
- return findNodeInSchemaContext(context,qnamedPath);
- }
- }
- }
- return null;
- }
-
- /**
- * Method attempts to find DataSchemaNode inside of provided Schema Context and Yang Module accordingly to
- * Non-conditional relative Revision Aware XPath. The specified Module MUST be present in Schema Context otherwise
- * the operation would fail and return <code>null</code>.
- * <br>
- * The relative Revision Aware XPath MUST be specified WITHOUT the conditional statement (i.e. without [cond]) in
- * path, because in this state the Schema Context is completely unaware of data state and will be not able to
- * properly resolve XPath. If the XPath contains condition the method will return IllegalArgumentException.
- * <br>
- * The Actual Schema Node MUST be specified correctly because from this Schema Node will search starts. If the
- * Actual Schema Node is not correct the operation will simply fail, because it will be unable to find desired
- * DataSchemaNode.
- * <br>
- * In case that Schema Context or Module or Actual Schema Node or relative Revision Aware XPath contains
- * <code>null</code> references the method will throw IllegalArgumentException
- * <br>
- * If the Revision Aware XPath doesn't have flag <code>isAbsolute == false</code> the method will
- * throw IllegalArgumentException.
- * <br>
- * If the relative Revision Aware XPath is correct and desired Data Schema Node is present in Yang module or in
- * depending module in Schema Context the method will return specified Data Schema Node,
- * otherwise the operation will fail
- * and method will return <code>null</code>.
- *
- * @throws IllegalArgumentException
- *
- * @param context Schema Context
- * @param module Yang Module
- * @param actualSchemaNode Actual Schema Node
- * @param relativeXPath Relative Non Conditional Revision Aware XPath
- * @return DataSchemaNode if is present in specified Schema Context for given relative Revision Aware XPath,
- * otherwise will return <code>null</code>.
- */
- public static def SchemaNode findDataSchemaNodeForRelativeXPath( SchemaContext context, Module module,
- SchemaNode actualSchemaNode, RevisionAwareXPath relativeXPath) {
- if (context === null) {
- throw new IllegalArgumentException("Schema Context reference cannot be NULL!");
- }
- if (module === null) {
- throw new IllegalArgumentException("Module reference cannot be NULL!");
- }
- if (actualSchemaNode === null) {
- throw new IllegalArgumentException("Actual Schema Node reference cannot be NULL!");
- }
- if (relativeXPath === null) {
- throw new IllegalArgumentException("Non Conditional Revision Aware XPath cannot be NULL!");
- }
- if (relativeXPath.isAbsolute()) {
- throw new IllegalArgumentException("Revision Aware XPath MUST be relative i.e. MUST contains ../, "
- + "for non relative Revision Aware XPath use findDataSchemaNode method!");
- }
-
- val actualNodePath = actualSchemaNode.getPath();
- if (actualNodePath != null) {
- val qnamePath = resolveRelativeXPath(context, module, relativeXPath, actualSchemaNode);
-
- if (qnamePath != null) {
- return findNodeInSchemaContext(context,qnamePath);
- }
- }
- return null;
- }
-
- /**
- * Returns parent Yang Module for specified Schema Context in which Schema Node is declared. If the Schema Node
- * is not present in Schema Context the operation will return <code>null</code>.
- * <br>
- * If Schema Context or Schema Node contains <code>null</code> references the method will throw IllegalArgumentException
- *
- * @throws IllegalArgumentException
- *
- * @param context Schema Context
- * @param schemaNode Schema Node
- * @return Yang Module for specified Schema Context and Schema Node, if Schema Node is NOT present,
- * the method will returns <code>null</code>
- */
- public static def Module findParentModule( SchemaContext context, SchemaNode schemaNode) {
- if (context === null) {
- throw new IllegalArgumentException("Schema Context reference cannot be NULL!");
- }
- if (schemaNode === null) {
- throw new IllegalArgumentException("Schema Node cannot be NULL!");
- }
-
- val schemaPath = schemaNode.getPath();
- if (schemaPath === null) {
- throw new IllegalStateException("Schema Path for Schema Node is not "
- + "set properly (Schema Path is NULL)");
- }
- val qnamedPath = schemaPath.path;
- if (qnamedPath === null || qnamedPath.empty) {
- throw new IllegalStateException("Schema Path contains invalid state of path parts."
- + "The Schema Path MUST contain at least ONE QName which defines namespace and Local name"
- + "of path.");
- }
- val qname = qnamedPath.get(qnamedPath.size() - 1);
- return context.findModuleByNamespaceAndRevision(qname.namespace,qname.revision);
- }
-
- /**
- * Method will attempt to find DataSchemaNode from specified Module and Queue of QNames through the Schema
- * Context. The QNamed path could be defined across multiple modules in Schema Context so the method is called
- * recursively. If the QNamed path contains QNames that are not part of any Module or Schema Context Path the
- * operation will fail and returns <code>null</code>
- * <br>
- * If Schema Context, Module or Queue of QNames refers to <code>null</code> values,
- * the method will throws IllegalArgumentException
- *
- * @throws IllegalArgumentException
- *
- * @param context Schema Context
- * @param module Yang Module
- * @param qnamedPath Queue of QNames
- * @return DataSchemaNode if is present in Module(s) for specified Schema Context and given QNamed Path,
- * otherwise will return <code>null</code>.
- */
- private static def SchemaNode findSchemaNodeForGivenPath( SchemaContext context, Module module,
- Queue<QName> qnamedPath) {
- if (context === null) {
- throw new IllegalArgumentException("Schema Context reference cannot be NULL!");
- }
- if (module === null) {
- throw new IllegalArgumentException("Module reference cannot be NULL!");
- }
- if (module.getNamespace() === null) {
- throw new IllegalArgumentException("Namespace for Module cannot contains NULL reference!");
- }
- if (qnamedPath === null || qnamedPath.isEmpty()) {
- throw new IllegalStateException("Schema Path contains invalid state of path parts."
- + "The Schema Path MUST contain at least ONE QName which defines namespace and Local name"
- + "of path.");
- }
-
- var DataNodeContainer nextNode = module;
- val moduleNamespace = module.getNamespace();
-
- var QName childNodeQName;
- var SchemaNode schemaNode = null;
- while ((nextNode != null) && !qnamedPath.isEmpty()) {
- childNodeQName = qnamedPath.peek();
- if (childNodeQName != null) {
- schemaNode = nextNode.getDataChildByName(childNodeQName.getLocalName());
- if(schemaNode === null && nextNode instanceof Module) {
- schemaNode = (nextNode as Module).getNotificationByName(childNodeQName);
- }
- if(schemaNode === null && nextNode instanceof Module) {
-
- }
- val URI childNamespace = childNodeQName.getNamespace();
- val Date childRevision = childNodeQName.getRevision();
-
- if (schemaNode != null) {
- if (schemaNode instanceof ContainerSchemaNode) {
- nextNode = schemaNode as ContainerSchemaNode;
- } else if (schemaNode instanceof ListSchemaNode) {
- nextNode = schemaNode as ListSchemaNode;
- } else if (schemaNode instanceof ChoiceNode) {
- val choice = schemaNode as ChoiceNode;
- qnamedPath.poll();
- if (!qnamedPath.isEmpty()) {
- childNodeQName = qnamedPath.peek();
- nextNode = choice.getCaseNodeByName(childNodeQName);
- schemaNode = nextNode as DataSchemaNode;
- }
- } else {
- nextNode = null;
- }
- } else if (!childNamespace.equals(moduleNamespace)) {
- val Module nextModule = context.findModuleByNamespaceAndRevision(childNamespace,childRevision);
- schemaNode = findSchemaNodeForGivenPath(context, nextModule, qnamedPath);
- return schemaNode;
- }
- qnamedPath.poll();
- }
- }
- return schemaNode;
- }
-
-
- public static def SchemaNode findNodeInSchemaContext(SchemaContext context, List<QName> path) {
- val current = path.get(0);
- val module = context.findModuleByNamespaceAndRevision(current.namespace,current.revision);
- if(module === null) return null;
- return findNodeInModule(module,path);
- }
-
- public static def GroupingDefinition findGrouping(SchemaContext context, Module module, List<QName> path) {
- var first = path.get(0);
- var Module m = context.findModuleByNamespace(first.namespace).iterator().next();
- var DataNodeContainer currentParent = m;
- for (qname : path) {
- var boolean found = false;
- var DataNodeContainer node = currentParent.getDataChildByName(qname.localName) as DataNodeContainer;
- if (node == null) {
- var Set<GroupingDefinition> groupings = currentParent.getGroupings();
- for (gr : groupings) {
- if(gr.getQName().localName.equals(qname.localName)) {
- currentParent = gr;
- found = true;
- }
- }
- } else {
- found = true;
- currentParent = node;
- }
- if (!found) {
- throw new IllegalArgumentException("Failed to find referenced grouping: " + path + "(" + qname.localName + ")");
- }
- }
-
- return currentParent as GroupingDefinition;
- }
-
- private static def SchemaNode findNodeInModule(Module module, List<QName> path) {
- val current = path.get(0)
- var SchemaNode node = module.getDataChildByName(current);
- if (node != null) return findNode(node as DataSchemaNode,path.nextLevel);
- node = module.getRpcByName(current);
- if (node != null) return findNodeInRpc(node as RpcDefinition,path.nextLevel)
- node = module.getNotificationByName(current);
- if (node != null) return findNodeInNotification(node as NotificationDefinition,path.nextLevel)
- node = module.getGroupingByName(current);
- if (node != null) return findNodeInGrouping(node as GroupingDefinition, path.nextLevel);
- return node
- }
-
- private static def SchemaNode findNodeInGrouping(GroupingDefinition grouping, List<QName> path) {
- if (path.empty) return grouping;
- val current = path.get(0)
- val node = grouping.getDataChildByName(current);
- if (node != null) return findNode(node, path.nextLevel);
- return null;
- }
-
- private static def SchemaNode findNodeInRpc(RpcDefinition rpc,List<QName> path) {
- if(path.empty) return rpc;
- val current = path.get(0);
- switch (current.localName) {
- case "input": return findNode(rpc.input,path.nextLevel)
- case "output": return findNode(rpc.output,path.nextLevel)
- }
- return null
- }
-
- private static def SchemaNode findNodeInNotification(NotificationDefinition rpc,List<QName> path) {
- if(path.empty) return rpc;
- val current = path.get(0)
- val node = rpc.getDataChildByName(current)
- if(node != null) return findNode(node,path.nextLevel)
- return null
- }
-
- private static dispatch def SchemaNode findNode(ChoiceNode parent,List<QName> path) {
- if(path.empty) return parent;
- val current = path.get(0)
- val node = parent.getCaseNodeByName(current)
- if (node != null) return findNodeInCase(node,path.nextLevel)
- return null
- }
-
- private static dispatch def SchemaNode findNode(ContainerSchemaNode parent,List<QName> path) {
- if(path.empty) return parent;
- val current = path.get(0)
- val node = parent.getDataChildByName(current)
- if (node != null) return findNode(node,path.nextLevel)
- return null
- }
-
- private static dispatch def SchemaNode findNode(ListSchemaNode parent,List<QName> path) {
- if(path.empty) return parent;
- val current = path.get(0)
- val node = parent.getDataChildByName(current)
- if (node != null) return findNode(node,path.nextLevel)
- return null
- }
-
- private static dispatch def SchemaNode findNode(DataSchemaNode parent,List<QName> path){
- if(path.empty) {
- return parent
- } else {
- throw new IllegalArgumentException("Path nesting violation");
- }
- }
-
- public static def SchemaNode findNodeInCase(ChoiceCaseNode parent,List<QName> path) {
- if(path.empty) return parent;
- val current = path.get(0)
- val node = parent.getDataChildByName(current)
- if (node != null) return findNode(node,path.nextLevel)
- return null
- }
-
-
- public static def RpcDefinition getRpcByName(Module module, QName name) {
- for (rpc : module.rpcs) {
- if (rpc.QName.equals(name)) {
- return rpc;
- }
- }
- return null;
- }
-
-
- private static def nextLevel(List<QName> path){
- return path.subList(1,path.size)
- }
-
- public static def NotificationDefinition getNotificationByName(Module module, QName name) {
- for(notification : module.notifications) {
- if(notification.QName.equals(name)) {
- return notification;
- }
- }
- return null;
- }
-
- public static def GroupingDefinition getGroupingByName(Module module, QName name) {
- for (grouping : module.groupings) {
- if (grouping.QName.equals(name)) {
- return grouping;
- }
- }
- return null;
- }
-
- /**
- * Transforms string representation of XPath to Queue of QNames. The XPath is split by "/" and for each part of
- * XPath is assigned correct module in Schema Path.
- * <br>
- * If Schema Context, Parent Module or XPath string contains <code>null</code> values,
- * the method will throws IllegalArgumentException
- *
- * @throws IllegalArgumentException
- *
- * @param context Schema Context
- * @param parentModule Parent Module
- * @param xpath XPath String
- * @return return a list of QName
- */
- private static def xpathToQNamePath( SchemaContext context, Module parentModule,
- String xpath) {
- if (context === null) {
- throw new IllegalArgumentException("Schema Context reference cannot be NULL!");
- }
- if (parentModule === null) {
- throw new IllegalArgumentException("Parent Module reference cannot be NULL!");
- }
- if (xpath === null) {
- throw new IllegalArgumentException("XPath string reference cannot be NULL!");
- }
-
- val path = new LinkedList<QName>();
- val String[] prefixedPath = xpath.split("/");
- for (pathComponent : prefixedPath) {
- if (!pathComponent.isEmpty()) {
- path.add(stringPathPartToQName(context, parentModule, pathComponent));
- }
- }
- return path;
- }
-
- /**
- * Transforms part of Prefixed Path as java String to QName.
- * <br>
- * If the string contains module prefix separated by ":" (i.e. mod:container) this module is provided from from
- * Parent Module list of imports. If the Prefixed module is present in Schema Context the QName can be
- * constructed.
- * <br>
- * If the Prefixed Path Part does not contains prefix the Parent's Module namespace is taken for construction of
- * QName.
- * <br>
- * If Schema Context, Parent Module or Prefixed Path Part refers to <code>null</code> the method will throw
- * IllegalArgumentException
- *
- * @throws IllegalArgumentException
- *
- * @param context Schema Context
- * @param parentModule Parent Module
- * @param prefixedPathPart Prefixed Path Part string
- * @return QName from prefixed Path Part String.
- */
- private static def QName stringPathPartToQName( SchemaContext context, Module parentModule,
- String prefixedPathPart) {
- if (context === null) {
- throw new IllegalArgumentException("Schema Context reference cannot be NULL!");
- }
- if (parentModule === null) {
- throw new IllegalArgumentException("Parent Module reference cannot be NULL!");
- }
- if (prefixedPathPart === null) {
- throw new IllegalArgumentException("Prefixed Path Part cannot be NULL!");
- }
-
- if (prefixedPathPart.contains(":")) {
- val String[] prefixedName = prefixedPathPart.split(":");
- val module = resolveModuleForPrefix(context, parentModule, prefixedName.get(0));
- if (module == null) {
- throw new IllegalArgumentException(
- "Failed to resolve xpath: no module found for prefix " + prefixedName.get(0) + " in module " +
- parentModule.name)
- } else {
- return new QName(module.getNamespace(), module.getRevision(), prefixedName.get(1));
- }
- } else {
- return new QName(parentModule.getNamespace(), parentModule.getRevision(), prefixedPathPart);
- }
- }
-
- /**
- * Method will attempt to resolve and provide Module reference for specified module prefix. Each Yang module
- * could contains multiple imports which MUST be associated with corresponding module prefix. The method simply
- * looks into module imports and returns the module that is bounded with specified prefix. If the prefix is not
- * present in module or the prefixed module is not present in specified Schema Context,
- * the method will return <code>null</code>.
- * <br>
- * If String prefix is the same as prefix of the specified Module the reference to this module is returned.
- * <br>
- * If Schema Context, Module or Prefix are referring to <code>null</code> the method will return
- * IllegalArgumentException
- *
- * @throws IllegalArgumentException
- *
- * @param context Schema Context
- * @param module Yang Module
- * @param prefix Module Prefix
- * @return Module for given prefix in specified Schema Context if is present, otherwise returns <code>null</code>
- */
- private static def Module resolveModuleForPrefix( SchemaContext context, Module module, String prefix) {
- if (context === null) {
- throw new IllegalArgumentException("Schema Context reference cannot be NULL!");
- }
- if (module === null) {
- throw new IllegalArgumentException("Module reference cannot be NULL!");
- }
- if (prefix === null) {
- throw new IllegalArgumentException("Prefix string cannot be NULL!");
- }
-
- if (prefix.equals(module.getPrefix())) {
- return module;
- }
-
- val imports = module.getImports();
- for ( ModuleImport mi : imports) {
- if (prefix.equals(mi.getPrefix())) {
- return context.findModuleByName(mi.getModuleName(), mi.getRevision());
- }
- }
- return null;
- }
-
- /**
- * @throws IllegalArgumentException
- *
- * @param context Schema Context
- * @param module Yang Module
- * @param relativeXPath Non conditional Revision Aware Relative XPath
- * @param leafrefSchemaPath Schema Path for Leafref
- * @return list of QName
- */
- private static def resolveRelativeXPath( SchemaContext context, Module module,
- RevisionAwareXPath relativeXPath, SchemaNode leafrefParentNode) {
-
- if (context === null) {
- throw new IllegalArgumentException("Schema Context reference cannot be NULL!");
- }
- if (module === null) {
- throw new IllegalArgumentException("Module reference cannot be NULL!");
- }
- if (relativeXPath === null) {
- throw new IllegalArgumentException("Non Conditional Revision Aware XPath cannot be NULL!");
- }
- if (relativeXPath.isAbsolute()) {
- throw new IllegalArgumentException("Revision Aware XPath MUST be relative i.e. MUST contains ../, "
- + "for non relative Revision Aware XPath use findDataSchemaNode method!");
- }
- if (leafrefParentNode.getPath() === null) {
- throw new IllegalArgumentException("Schema Path reference for Leafref cannot be NULL!");
- }
- val absolutePath = new LinkedList<QName>();
- val String strXPath = relativeXPath.toString();
- if (strXPath != null) {
- val String[] xpaths = strXPath.split("/");
- if (xpaths != null) {
- var int colCount = 0;
- while (xpaths.get(colCount).contains("..")) {
- colCount = colCount+ 1;
- }
- val path = leafrefParentNode.getPath().getPath();
- if (path != null) {
- val int lenght = path.size() - colCount;
- absolutePath.addAll(path.subList(0,lenght));
- val List<QName> sublist = xpaths.subList(colCount,xpaths.length).map[stringPathPartToQName(context, module,it)]
- absolutePath.addAll(sublist)
- }
- }
- }
- return absolutePath;
- }
-}
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
- <dependency>
- <groupId>org.eclipse.xtend</groupId>
- <artifactId>org.eclipse.xtend.lib</artifactId>
- </dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<listener>true</listener>
</configuration>
</plugin>
- <plugin>
- <groupId>org.eclipse.xtend</groupId>
- <artifactId>xtend-maven-plugin</artifactId>
- </plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
newPath.add(new QName(ns, rev, localPrefix, qn.getLocalName()));
}
}
- augment.setTargetNodeSchemaPath(new SchemaPath(newPath, augment.getTargetPath().isAbsolute()));
+ augment.setTargetNodeSchemaPath(new SchemaPath(newPath, true));
for (DataSchemaNodeBuilder childNode : augment.getChildNodeBuilders()) {
correctPathForAugmentNodes(childNode, augment.getTargetNodeSchemaPath());
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.parser.util;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.ModuleImport;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
+import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationTargetBuilder;
+import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
+import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
+import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
+import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
+import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
+import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceBuilder;
+import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceCaseBuilder;
+import org.opendaylight.yangtools.yang.parser.builder.impl.IdentitySchemaNodeBuilder;
+import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
+import org.opendaylight.yangtools.yang.parser.builder.impl.NotificationBuilder;
+import org.opendaylight.yangtools.yang.parser.builder.impl.RpcDefinitionBuilder;
+import org.opendaylight.yangtools.yang.parser.builder.api.GroupingMember;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+import java.util.HashSet;
+import java.net.URI;
+
+import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
+import org.opendaylight.yangtools.yang.parser.builder.impl.AnyXmlBuilder;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.parser.builder.impl.ContainerSchemaNodeBuilder;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.parser.builder.impl.ListSchemaNodeBuilder;
+import org.opendaylight.yangtools.yang.parser.builder.impl.LeafListSchemaNodeBuilder;
+import org.opendaylight.yangtools.yang.parser.builder.impl.LeafSchemaNodeBuilder;
+import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
+import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
+import org.opendaylight.yangtools.yang.parser.builder.impl.GroupingBuilderImpl;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.parser.builder.impl.TypeDefinitionBuilderImpl;
+import org.opendaylight.yangtools.yang.model.util.ExtendedType;
+import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
+import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
+import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+
+import com.google.common.base.Preconditions;
+
+public final class ParserUtils {
+
+ private ParserUtils() {
+ }
+
+ /**
+ * Create new SchemaPath from given path and qname.
+ *
+ * @param schemaPath
+ * base path
+ * @param qname
+ * one or more qnames added to base path
+ * @return new SchemaPath from given path and qname
+ */
+ public static SchemaPath createSchemaPath(SchemaPath schemaPath, QName... qname) {
+ List<QName> path = new ArrayList<>(schemaPath.getPath());
+ path.addAll(Arrays.asList(qname));
+ return new SchemaPath(path, schemaPath.isAbsolute());
+ }
+
+ /**
+ * Get module import referenced by given prefix.
+ *
+ * @param builder
+ * module to search
+ * @param prefix
+ * prefix associated with import
+ * @return ModuleImport based on given prefix
+ */
+ public static ModuleImport getModuleImport(ModuleBuilder builder, String prefix) {
+ for (ModuleImport mi : builder.getModuleImports()) {
+ if (mi.getPrefix().equals(prefix)) {
+ return mi;
+
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Find dependent module based on given prefix
+ *
+ * @param modules
+ * all available modules
+ * @param module
+ * current module
+ * @param prefix
+ * target module prefix
+ * @param line
+ * current line in yang model
+ * @return module builder if found, null otherwise
+ */
+ public static ModuleBuilder findModuleFromBuilders(Map<String, TreeMap<Date, ModuleBuilder>> modules,
+ ModuleBuilder module, String prefix, int line) {
+ ModuleBuilder dependentModule = null;
+ Date dependentModuleRevision = null;
+
+ if (prefix == null) {
+ dependentModule = module;
+ } else if (prefix.equals(module.getPrefix())) {
+ dependentModule = module;
+ } else {
+ ModuleImport dependentModuleImport = getModuleImport(module, prefix);
+ if (dependentModuleImport == null) {
+ throw new YangParseException(module.getName(), line, "No import found with prefix '" + prefix + "'.");
+ }
+ String dependentModuleName = dependentModuleImport.getModuleName();
+ dependentModuleRevision = dependentModuleImport.getRevision();
+
+ TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules.get(dependentModuleName);
+ if (moduleBuildersByRevision == null) {
+ return null;
+ }
+ if (dependentModuleRevision == null) {
+ dependentModule = moduleBuildersByRevision.lastEntry().getValue();
+ } else {
+ dependentModule = moduleBuildersByRevision.get(dependentModuleRevision);
+ }
+ }
+ return dependentModule;
+ }
+
+ /**
+ * Find module from context based on prefix.
+ *
+ * @param context
+ * schema context
+ * @param currentModule
+ * current module
+ * @param prefix
+ * current prefix used to reference dependent module
+ * @param line
+ * current line in yang model
+ * @return module based on given prefix if found in context, null otherwise
+ */
+ public static Module findModuleFromContext(SchemaContext context, ModuleBuilder currentModule, String prefix,
+ int line) {
+ if (context == null) {
+ throw new YangParseException(currentModule.getName(), line, "Cannot find module with prefix '" + prefix
+ + "'.");
+ }
+ TreeMap<Date, Module> modulesByRevision = new TreeMap<>();
+
+ ModuleImport dependentModuleImport = ParserUtils.getModuleImport(currentModule, prefix);
+ if (dependentModuleImport == null) {
+ throw new YangParseException(currentModule.getName(), line, "No import found with prefix '" + prefix + "'.");
+ }
+ String dependentModuleName = dependentModuleImport.getModuleName();
+ Date dependentModuleRevision = dependentModuleImport.getRevision();
+
+ for (Module contextModule : context.getModules()) {
+ if (contextModule.getName().equals(dependentModuleName)) {
+ Date revision = contextModule.getRevision();
+ if (revision == null) {
+ revision = new Date(0L);
+ }
+ modulesByRevision.put(revision, contextModule);
+ }
+ }
+
+ Module result = null;
+ if (dependentModuleRevision == null) {
+ result = modulesByRevision.get(modulesByRevision.firstKey());
+ } else {
+ result = modulesByRevision.get(dependentModuleRevision);
+ }
+ return result;
+ }
+
+ /**
+ * Parse XPath string.
+ *
+ * @param xpathString
+ * XPath as String
+ * @return SchemaPath from given String
+ */
+ public static SchemaPath parseXPathString(String xpathString) {
+ boolean absolute = xpathString.startsWith("/");
+ String[] splittedPath = xpathString.split("/");
+ List<QName> path = new ArrayList<QName>();
+ QName name;
+ for (String pathElement : splittedPath) {
+ if (pathElement.length() > 0) {
+ String[] splittedElement = pathElement.split(":");
+ if (splittedElement.length == 1) {
+ name = new QName(null, null, null, splittedElement[0]);
+ } else {
+ name = new QName(null, null, splittedElement[0], splittedElement[1]);
+ }
+ path.add(name);
+ }
+ }
+ return new SchemaPath(path, absolute);
+ }
+
+ /**
+ * Add all augment's child nodes to given target.
+ *
+ * @param augment
+ * builder of augment statement
+ * @param target
+ * augmentation target node
+ */
+ public static void fillAugmentTarget(AugmentationSchemaBuilder augment, Builder target) {
+ if (target instanceof DataNodeContainerBuilder) {
+ fillAugmentTarget(augment, (DataNodeContainerBuilder) target);
+ } else if (target instanceof ChoiceBuilder) {
+ fillAugmentTarget(augment, (ChoiceBuilder) target);
+ } else {
+ throw new YangParseException(
+ augment.getModuleName(),
+ augment.getLine(),
+ "Error in augment parsing: The target node MUST be either a container, list, choice, case, input, output, or notification node.");
+ }
+ }
+
+ /**
+ * Add all augment's child nodes to given target.
+ *
+ * @param augment
+ * builder of augment statement
+ * @param target
+ * augmentation target node
+ */
+ private static void fillAugmentTarget(AugmentationSchemaBuilder augment, DataNodeContainerBuilder target) {
+ for (DataSchemaNodeBuilder child : augment.getChildNodeBuilders()) {
+ DataSchemaNodeBuilder childCopy = CopyUtils.copy(child, target, false);
+ if (augment.getParent() instanceof UsesNodeBuilder) {
+ setNodeAddedByUses(childCopy);
+ }
+ setNodeAugmenting(childCopy);
+ try {
+ target.addChildNode(childCopy);
+ } catch (YangParseException e) {
+
+ // more descriptive message
+ throw new YangParseException(augment.getModuleName(), augment.getLine(),
+ "Failed to perform augmentation: " + e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * Add all augment's child nodes to given target.
+ *
+ * @param augment
+ * builder of augment statement
+ * @param target
+ * augmentation target choice node
+ */
+ private static void fillAugmentTarget(AugmentationSchemaBuilder augment, ChoiceBuilder target) {
+ for (DataSchemaNodeBuilder builder : augment.getChildNodeBuilders()) {
+ DataSchemaNodeBuilder childCopy = CopyUtils.copy(builder, target, false);
+ if (augment.getParent() instanceof UsesNodeBuilder) {
+ setNodeAddedByUses(childCopy);
+ }
+ setNodeAugmenting(childCopy);
+ target.addCase(childCopy);
+ }
+ for (UsesNodeBuilder usesNode : augment.getUsesNodeBuilders()) {
+ if (usesNode != null) {
+ throw new YangParseException(augment.getModuleName(), augment.getLine(),
+ "Error in augment parsing: cannot augment choice with nodes from grouping");
+ }
+ }
+ }
+
+ /**
+ * Set augmenting flag to true for node and all its child nodes.
+ *
+ * @param node
+ */
+ private static void setNodeAugmenting(DataSchemaNodeBuilder node) {
+ node.setAugmenting(true);
+ if (node instanceof DataNodeContainerBuilder) {
+ DataNodeContainerBuilder dataNodeChild = (DataNodeContainerBuilder) node;
+ for (DataSchemaNodeBuilder inner : dataNodeChild.getChildNodeBuilders()) {
+ setNodeAugmenting(inner);
+ }
+ } else if (node instanceof ChoiceBuilder) {
+ ChoiceBuilder choiceChild = (ChoiceBuilder) node;
+ for (ChoiceCaseBuilder inner : choiceChild.getCases()) {
+ setNodeAugmenting(inner);
+ }
+ }
+ }
+
+ /**
+ * Set addedByUses flag to true for node and all its child nodes.
+ *
+ * @param node
+ */
+ public static void setNodeAddedByUses(GroupingMember node) {
+ node.setAddedByUses(true);
+ if (node instanceof DataNodeContainerBuilder) {
+ DataNodeContainerBuilder dataNodeChild = (DataNodeContainerBuilder) node;
+ for (DataSchemaNodeBuilder inner : dataNodeChild.getChildNodeBuilders()) {
+ setNodeAddedByUses(inner);
+ }
+ } else if (node instanceof ChoiceBuilder) {
+ ChoiceBuilder choiceChild = (ChoiceBuilder) node;
+ for (ChoiceCaseBuilder inner : choiceChild.getCases()) {
+ setNodeAddedByUses(inner);
+ }
+ }
+ }
+
+ /**
+ * Set config flag to new value.
+ *
+ * @param node
+ * node to update
+ * @param config
+ * new config value
+ */
+ public static void setNodeConfig(DataSchemaNodeBuilder node, Boolean config) {
+ if (node instanceof ContainerSchemaNodeBuilder || node instanceof LeafSchemaNodeBuilder
+ || node instanceof LeafListSchemaNodeBuilder || node instanceof ListSchemaNodeBuilder
+ || node instanceof ChoiceBuilder || node instanceof AnyXmlBuilder) {
+ node.setConfiguration(config);
+ }
+ if (node instanceof DataNodeContainerBuilder) {
+ DataNodeContainerBuilder dataNodeChild = (DataNodeContainerBuilder) node;
+ for (DataSchemaNodeBuilder inner : dataNodeChild.getChildNodeBuilders()) {
+ setNodeConfig(inner, config);
+ }
+ } else if (node instanceof ChoiceBuilder) {
+ ChoiceBuilder choiceChild = (ChoiceBuilder) node;
+ for (ChoiceCaseBuilder inner : choiceChild.getCases()) {
+ setNodeConfig(inner, config);
+ }
+ }
+ }
+
+ public static DataSchemaNodeBuilder findSchemaNode(List<QName> path, SchemaNodeBuilder parentNode) {
+ DataSchemaNodeBuilder node = null;
+ SchemaNodeBuilder parent = parentNode;
+ int i = 0;
+ while (i < path.size()) {
+ String name = path.get(i).getLocalName();
+ if (parent instanceof DataNodeContainerBuilder) {
+ node = ((DataNodeContainerBuilder) parent).getDataChildByName(name);
+ } else if (parent instanceof ChoiceBuilder) {
+ node = ((ChoiceBuilder) parent).getCaseNodeByName(name);
+ } else if (parent instanceof RpcDefinitionBuilder) {
+ if ("input".equals(name)) {
+ node = ((RpcDefinitionBuilder) parent).getInput();
+ } else if ("output".equals(name)) {
+ node = ((RpcDefinitionBuilder) parent).getOutput();
+ } else {
+ return null;
+ }
+ } else {
+ return null;
+ }
+
+ if (i < path.size() - 1) {
+ parent = node;
+ }
+ i = i + 1;
+ }
+
+ return node;
+ }
+
+ public static SchemaNodeBuilder findSchemaNodeInModule(List<QName> pathToNode, ModuleBuilder module) {
+ List<QName> path = new ArrayList<>(pathToNode);
+ QName first = path.remove(0);
+
+ SchemaNodeBuilder node = module.getDataChildByName(first.getLocalName());
+ if (node == null) {
+ Set<NotificationBuilder> notifications = module.getAddedNotifications();
+ for (NotificationBuilder notification : notifications) {
+ if (notification.getQName().getLocalName().equals(first.getLocalName())) {
+ node = notification;
+ }
+ }
+ }
+ if (node == null) {
+ Set<RpcDefinitionBuilder> rpcs = module.getAddedRpcs();
+ for (RpcDefinitionBuilder rpc : rpcs) {
+ if (rpc.getQName().getLocalName().equals(first.getLocalName())) {
+ node = rpc;
+ }
+ }
+ }
+ if (node == null) {
+ return null;
+ }
+
+ if (!path.isEmpty()) {
+ node = findSchemaNode(path, node);
+ }
+
+ return node;
+ }
+
+ /**
+ * Find augment target node and perform augmentation.
+ *
+ * @param augment
+ * @param firstNodeParent
+ * parent of first node in path
+ * @param path
+ * path to augment target
+ * @return true if augmentation process succeed, false otherwise
+ */
+ public static boolean processAugmentation(AugmentationSchemaBuilder augment, ModuleBuilder firstNodeParent) {
+ List<QName> path = augment.getTargetPath().getPath();
+ Builder targetNode = findSchemaNodeInModule(path, firstNodeParent);
+ if (targetNode == null) {
+ return false;
+ }
+
+ fillAugmentTarget(augment, targetNode);
+ ((AugmentationTargetBuilder) targetNode).addAugmentation(augment);
+ augment.setResolved(true);
+ return true;
+ }
+
+ public static IdentitySchemaNodeBuilder findBaseIdentity(Map<String, TreeMap<Date, ModuleBuilder>> modules,
+ ModuleBuilder module, String baseString, int line) {
+ IdentitySchemaNodeBuilder result = null;
+ if (baseString.contains(":")) {
+ String[] splittedBase = baseString.split(":");
+ if (splittedBase.length > 2) {
+ throw new YangParseException(module.getName(), line, "Failed to parse identityref base: " + baseString);
+ }
+ String prefix = splittedBase[0];
+ String name = splittedBase[1];
+ ModuleBuilder dependentModule = findModuleFromBuilders(modules, module, prefix, line);
+ if (dependentModule != null) {
+ result = findIdentity(dependentModule.getAddedIdentities(), name);
+ }
+ } else {
+ result = findIdentity(module.getAddedIdentities(), baseString);
+ }
+ return result;
+ }
+
+ public static IdentitySchemaNode findBaseIdentityFromContext(Map<String, TreeMap<Date, ModuleBuilder>> modules,
+ ModuleBuilder module, String baseString, int line, SchemaContext context) {
+ IdentitySchemaNode result = null;
+
+ String[] splittedBase = baseString.split(":");
+ if (splittedBase.length > 2) {
+ throw new YangParseException(module.getName(), line, "Failed to parse identityref base: " + baseString);
+ }
+ String prefix = splittedBase[0];
+ String name = splittedBase[1];
+ Module dependentModule = findModuleFromContext(context, module, prefix, line);
+ result = findIdentityNode(dependentModule.getIdentities(), name);
+
+ if (result == null) {
+ throw new YangParseException(module.getName(), line, "Failed to find base identity");
+ }
+ return result;
+ }
+
+ private static IdentitySchemaNodeBuilder findIdentity(Set<IdentitySchemaNodeBuilder> identities, String name) {
+ for (IdentitySchemaNodeBuilder identity : identities) {
+ if (identity.getQName().getLocalName().equals(name)) {
+ return identity;
+ }
+ }
+ return null;
+ }
+
+ private static IdentitySchemaNode findIdentityNode(Set<IdentitySchemaNode> identities, String name) {
+ for (IdentitySchemaNode identity : identities) {
+ if (identity.getQName().getLocalName().equals(name)) {
+ return identity;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Get module in which this node is defined.
+ *
+ * @param node
+ * @return builder of module where this node is defined
+ */
+ public static ModuleBuilder getParentModule(Builder node) {
+ if (node instanceof ModuleBuilder) {
+ return (ModuleBuilder) node;
+ }
+ Builder parent = node.getParent();
+ while (!(parent instanceof ModuleBuilder)) {
+ parent = parent.getParent();
+ }
+ Preconditions.checkState(parent instanceof ModuleBuilder);
+ ModuleBuilder parentModule = (ModuleBuilder) parent;
+ if (parentModule.isSubmodule()) {
+ parentModule = parentModule.getParent();
+ }
+ return parentModule;
+ }
+
+ public static Set<DataSchemaNodeBuilder> wrapChildNodes(String moduleName, int line, Set<DataSchemaNode> nodes,
+ SchemaPath parentPath, URI ns, Date rev, String pref) {
+ Set<DataSchemaNodeBuilder> result = new HashSet<>();
+
+ for (DataSchemaNode node : nodes) {
+ QName qname = new QName(ns, rev, pref, node.getQName().getLocalName());
+ DataSchemaNodeBuilder wrapped = wrapChildNode(moduleName, line, node, parentPath, qname);
+ result.add(wrapped);
+ }
+ return result;
+ }
+
+ public static DataSchemaNodeBuilder wrapChildNode(String moduleName, int line, DataSchemaNode node,
+ SchemaPath parentPath, QName qname) {
+ List<QName> path = new ArrayList<>(parentPath.getPath());
+ path.add(qname);
+ SchemaPath schemaPath = new SchemaPath(path, parentPath.isAbsolute());
+
+ if (node instanceof AnyXmlSchemaNode) {
+ return new AnyXmlBuilder(moduleName, line, qname, schemaPath, ((AnyXmlSchemaNode) node));
+ } else if (node instanceof ChoiceNode) {
+ return new ChoiceBuilder(moduleName, line, qname, schemaPath, ((ChoiceNode) node));
+ } else if (node instanceof ContainerSchemaNode) {
+ return new ContainerSchemaNodeBuilder(moduleName, line, qname, schemaPath, ((ContainerSchemaNode) node));
+ } else if (node instanceof LeafSchemaNode) {
+ return new LeafSchemaNodeBuilder(moduleName, line, qname, schemaPath, ((LeafSchemaNode) node));
+ } else if (node instanceof LeafListSchemaNode) {
+ return new LeafListSchemaNodeBuilder(moduleName, line, qname, schemaPath, ((LeafListSchemaNode) node));
+ } else if (node instanceof ListSchemaNode) {
+ return new ListSchemaNodeBuilder(moduleName, line, qname, schemaPath, ((ListSchemaNode) node));
+ } else if (node instanceof ChoiceCaseNode) {
+ return new ChoiceCaseBuilder(moduleName, line, qname, schemaPath, ((ChoiceCaseNode) node));
+ } else {
+ throw new YangParseException(moduleName, line, "Failed to copy node: Unknown type of DataSchemaNode: "
+ + node);
+ }
+ }
+
+ public static Set<GroupingBuilder> wrapGroupings(String moduleName, int line, Set<GroupingDefinition> nodes,
+ SchemaPath parentPath, URI ns, Date rev, String pref) {
+ Set<GroupingBuilder> result = new HashSet<>();
+ for (GroupingDefinition node : nodes) {
+ QName qname = new QName(ns, rev, pref, node.getQName().getLocalName());
+ List<QName> path = new ArrayList<>(parentPath.getPath());
+ path.add(qname);
+ SchemaPath schemaPath = new SchemaPath(path, parentPath.isAbsolute());
+ result.add(new GroupingBuilderImpl(moduleName, line, qname, schemaPath, node));
+ }
+ return result;
+ }
+
+ public static Set<TypeDefinitionBuilder> wrapTypedefs(String moduleName, int line, DataNodeContainer dataNode,
+ SchemaPath parentPath, URI ns, Date rev, String pref) {
+ Set<TypeDefinition<?>> nodes = dataNode.getTypeDefinitions();
+ Set<TypeDefinitionBuilder> result = new HashSet<>();
+ for (TypeDefinition<?> node : nodes) {
+ QName qname = new QName(ns, rev, pref, node.getQName().getLocalName());
+ List<QName> path = new ArrayList<>(parentPath.getPath());
+ path.add(qname);
+ SchemaPath schemaPath = new SchemaPath(path, parentPath.isAbsolute());
+ result.add(new TypeDefinitionBuilderImpl(moduleName, line, qname, schemaPath, ((ExtendedType) node)));
+ }
+ return result;
+ }
+
+ public static List<UnknownSchemaNodeBuilder> wrapUnknownNodes(String moduleName, int line,
+ List<UnknownSchemaNode> nodes, SchemaPath parentPath, URI ns, Date rev, String pref) {
+ List<UnknownSchemaNodeBuilder> result = new ArrayList<>();
+ for (UnknownSchemaNode node : nodes) {
+ QName qname = new QName(ns, rev, pref, node.getQName().getLocalName());
+ List<QName> path = new ArrayList<>(parentPath.getPath());
+ path.add(qname);
+ SchemaPath schemaPath = new SchemaPath(path, parentPath.isAbsolute());
+ result.add(new UnknownSchemaNodeBuilder(moduleName, line, qname, schemaPath, node));
+ }
+ return result;
+ }
+
+}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.yangtools.yang.parser.util;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
-import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
-import org.opendaylight.yangtools.yang.model.api.Module;
-import org.opendaylight.yangtools.yang.model.api.ModuleImport;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.model.api.SchemaPath;
-import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
-import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationTargetBuilder;
-import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
-import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
-import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
-import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
-import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
-import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceBuilder;
-import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceCaseBuilder;
-import org.opendaylight.yangtools.yang.parser.builder.impl.IdentitySchemaNodeBuilder;
-import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
-import org.opendaylight.yangtools.yang.parser.builder.impl.RpcDefinitionBuilder
-import org.opendaylight.yangtools.yang.parser.builder.api.GroupingMember
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
-import java.util.HashSet
-import java.net.URI
-import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode
-import org.opendaylight.yangtools.yang.parser.builder.impl.AnyXmlBuilder
-import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
-import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
-import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode
-import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
-import org.opendaylight.yangtools.yang.parser.builder.impl.ContainerSchemaNodeBuilder
-import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode
-import org.opendaylight.yangtools.yang.parser.builder.impl.ListSchemaNodeBuilder
-import org.opendaylight.yangtools.yang.parser.builder.impl.LeafListSchemaNodeBuilder
-import org.opendaylight.yangtools.yang.parser.builder.impl.LeafSchemaNodeBuilder
-import org.opendaylight.yangtools.yang.model.api.GroupingDefinition
-import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder
-import org.opendaylight.yangtools.yang.parser.builder.impl.GroupingBuilderImpl
-import org.opendaylight.yangtools.yang.model.api.TypeDefinition
-import org.opendaylight.yangtools.yang.parser.builder.impl.TypeDefinitionBuilderImpl
-import org.opendaylight.yangtools.yang.model.util.ExtendedType
-import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder
-import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilder
-import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode
-import org.opendaylight.yangtools.yang.model.api.DataNodeContainer
-import com.google.common.base.Preconditions
-
-public final class ParserUtils {
-
- private new() {
- }
-
- /**
- * Create new SchemaPath from given path and qname.
- *
- * @param schemaPath
- * @param qname
- * @return new SchemaPath from given path and qname
- */
- public static def SchemaPath createSchemaPath(SchemaPath schemaPath, QName... qname) {
- val path = new ArrayList<QName>(schemaPath.getPath());
- path.addAll(Arrays.asList(qname));
- return new SchemaPath(path, schemaPath.isAbsolute());
- }
-
- /**
- * Get module import referenced by given prefix.
- *
- * @param builder
- * module to search
- * @param prefix
- * prefix associated with import
- * @return ModuleImport based on given prefix
- */
- public static def ModuleImport getModuleImport(ModuleBuilder builder, String prefix) {
- for (ModuleImport mi : builder.getModuleImports()) {
- if (mi.getPrefix().equals(prefix)) {
- return mi;
-
- }
- }
- return null;
- }
-
- /**
- * Find dependent module based on given prefix
- *
- * @param modules
- * all available modules
- * @param module
- * current module
- * @param prefix
- * target module prefix
- * @param line
- * current line in yang model
- * @return module builder if found, null otherwise
- */
- public static def ModuleBuilder findModuleFromBuilders(Map<String, TreeMap<Date, ModuleBuilder>> modules,
- ModuleBuilder module, String prefix, int line) {
- var ModuleBuilder dependentModule = null;
- var Date dependentModuleRevision = null;
-
- if(prefix == null) {
- dependentModule = module;
- } else if (prefix.equals(module.getPrefix())) {
- dependentModule = module;
- } else {
- val ModuleImport dependentModuleImport = getModuleImport(module, prefix);
- if (dependentModuleImport === null) {
- throw new YangParseException(module.getName(), line, "No import found with prefix '" + prefix + "'.");
- }
- val String dependentModuleName = dependentModuleImport.getModuleName();
- dependentModuleRevision = dependentModuleImport.getRevision();
-
- val TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules.get(dependentModuleName);
- if (moduleBuildersByRevision === null) {
- return null;
- }
- if (dependentModuleRevision === null) {
- dependentModule = moduleBuildersByRevision.lastEntry().getValue();
- } else {
- dependentModule = moduleBuildersByRevision.get(dependentModuleRevision);
- }
- }
- return dependentModule;
- }
-
- /**
- * Find module from context based on prefix.
- *
- * @param context
- * schema context
- * @param currentModule
- * current module
- * @param prefix
- * current prefix used to reference dependent module
- * @param line
- * current line in yang model
- * @return module based on given prefix if found in context, null otherwise
- */
- public static def Module findModuleFromContext(SchemaContext context, ModuleBuilder currentModule,
- String prefix, int line) {
- if (context === null) {
- throw new YangParseException(currentModule.getName(), line,
- "Cannot find module with prefix '" + prefix + "'.");
- }
- val modulesByRevision = new TreeMap<Date, Module>();
-
- val dependentModuleImport = ParserUtils.getModuleImport(currentModule, prefix);
- if (dependentModuleImport === null) {
- throw new YangParseException(currentModule.getName(), line, "No import found with prefix '" + prefix + "'.");
- }
- val dependentModuleName = dependentModuleImport.getModuleName();
- val dependentModuleRevision = dependentModuleImport.getRevision();
-
- for (Module contextModule : context.getModules()) {
- if (contextModule.getName().equals(dependentModuleName)) {
- var revision = contextModule.getRevision();
- if (revision === null) {
- revision = new Date(0L);
- }
- modulesByRevision.put(revision, contextModule);
- }
- }
-
- var Module result = null;
- if (dependentModuleRevision === null) {
- result = modulesByRevision.get(modulesByRevision.firstKey());
- } else {
- result = modulesByRevision.get(dependentModuleRevision);
- }
- return result;
- }
-
- /**
- * Parse XPath string.
- *
- * @param xpathString
- * as String
- * @return SchemaPath from given String
- */
- public static def SchemaPath parseXPathString(String xpathString) {
- val absolute = xpathString.startsWith("/");
- val String[] splittedPath = xpathString.split("/");
- val path = new ArrayList<QName>();
- var QName name;
- for (String pathElement : splittedPath) {
- if (pathElement.length() > 0) {
- val String[] splittedElement = pathElement.split(":");
- if (splittedElement.length == 1) {
- name = new QName(null, null, null, splittedElement.get(0));
- } else {
- name = new QName(null, null, splittedElement.get(0), splittedElement.get(1));
- }
- path.add(name);
- }
- }
- return new SchemaPath(path, absolute);
- }
-
- public static def dispatch fillAugmentTarget(AugmentationSchemaBuilder augment, Builder target) {
- }
-
- /**
- * Add all augment's child nodes to given target.
- *
- * @param augment
- * builder of augment statement
- * @param target
- * augmentation target node
- */
- public static def dispatch fillAugmentTarget(AugmentationSchemaBuilder augment, DataNodeContainerBuilder target) {
- for (DataSchemaNodeBuilder child : augment.getChildNodeBuilders()) {
- val childCopy = CopyUtils.copy(child, target, false);
- if (augment.parent instanceof UsesNodeBuilder) {
- setNodeAddedByUses(childCopy);
- }
- setNodeAugmenting(childCopy);
- try {
- target.addChildNode(childCopy);
- } catch (YangParseException e) {
-
- // more descriptive message
- throw new YangParseException(augment.getModuleName(), augment.getLine(),
- "Failed to perform augmentation: " + e.getMessage());
- }
- }
- }
-
- /**
- * Add all augment's child nodes to given target.
- *
- * @param augment
- * builder of augment statement
- * @param target
- * augmentation target choice node
- */
- public static def dispatch fillAugmentTarget(AugmentationSchemaBuilder augment, ChoiceBuilder target) {
- for (DataSchemaNodeBuilder builder : augment.getChildNodeBuilders()) {
- val childCopy = CopyUtils.copy(builder, target, false);
- if (augment.parent instanceof UsesNodeBuilder) {
- setNodeAddedByUses(childCopy);
- }
- setNodeAugmenting(childCopy)
- target.addCase(childCopy);
- }
- for (UsesNodeBuilder usesNode : augment.getUsesNodeBuilders()) {
- if (usesNode !== null) {
- throw new YangParseException(augment.getModuleName(), augment.getLine(),
- "Error in augment parsing: cannot augment choice with nodes from grouping");
- }
- }
- }
-
- /**
- * Set augmenting flag to true for node and all its child nodes.
- */
- private static def void setNodeAugmenting(DataSchemaNodeBuilder child) {
- child.setAugmenting(true);
- if (child instanceof DataNodeContainerBuilder) {
- val DataNodeContainerBuilder dataNodeChild = child as DataNodeContainerBuilder;
- for (inner : dataNodeChild.getChildNodeBuilders()) {
- setNodeAugmenting(inner);
- }
- } else if (child instanceof ChoiceBuilder) {
- val ChoiceBuilder choiceChild = child as ChoiceBuilder;
- for (inner : choiceChild.cases) {
- setNodeAugmenting(inner);
- }
- }
- }
-
- /**
- * Set addedByUses flag to true for node and all its child nodes.
- */
- public static def void setNodeAddedByUses(GroupingMember child) {
- child.setAddedByUses(true);
- if (child instanceof DataNodeContainerBuilder) {
- val DataNodeContainerBuilder dataNodeChild = child as DataNodeContainerBuilder;
- for (inner : dataNodeChild.getChildNodeBuilders()) {
- setNodeAddedByUses(inner);
- }
- } else if (child instanceof ChoiceBuilder) {
- val ChoiceBuilder choiceChild = child as ChoiceBuilder;
- for (inner : choiceChild.cases) {
- setNodeAddedByUses(inner);
- }
- }
- }
-
- public static def void setNodeConfig(DataSchemaNodeBuilder child, Boolean config) {
- if (child instanceof ContainerSchemaNodeBuilder || child instanceof LeafSchemaNodeBuilder ||
- child instanceof LeafListSchemaNodeBuilder || child instanceof ListSchemaNodeBuilder ||
- child instanceof ChoiceBuilder || child instanceof AnyXmlBuilder) {
- child.setConfiguration(config);
- }
- if (child instanceof DataNodeContainerBuilder) {
- val DataNodeContainerBuilder dataNodeChild = child as DataNodeContainerBuilder;
- for (inner : dataNodeChild.getChildNodeBuilders()) {
- setNodeConfig(inner, config);
- }
- } else if (child instanceof ChoiceBuilder) {
- val ChoiceBuilder choiceChild = child as ChoiceBuilder;
- for (inner : choiceChild.cases) {
- setNodeConfig(inner, config);
- }
- }
- }
-
- public static def DataSchemaNodeBuilder findSchemaNode(List<QName> path, SchemaNodeBuilder parentNode) {
- var DataSchemaNodeBuilder node
- var SchemaNodeBuilder parent = parentNode
- var int i = 0;
- while (i < path.size) {
- val String name = path.get(i).localName
- if (parent instanceof DataNodeContainerBuilder) {
- node = (parent as DataNodeContainerBuilder).getDataChildByName(name)
- } else if (parent instanceof ChoiceBuilder) {
- node = (parent as ChoiceBuilder).getCaseNodeByName(name)
- } else if (parent instanceof RpcDefinitionBuilder) {
- if ("input".equals(name)) {
- node = (parent as RpcDefinitionBuilder).input
- } else if ("output".equals(name)) {
- node = (parent as RpcDefinitionBuilder).output
- } else {
- return null
- }
- } else {
- return null
- }
-
- if (i < path.size - 1) {
- parent = node
- }
- i = i + 1
- }
-
- return node
- }
-
- public static def SchemaNodeBuilder findSchemaNodeInModule(List<QName> pathToNode, ModuleBuilder module) {
- val List<QName> path = new ArrayList(pathToNode)
- val QName first = path.remove(0)
-
- var SchemaNodeBuilder node = module.getDataChildByName(first.localName)
- if (node == null) {
- val notifications = module.getAddedNotifications
- for (notification : notifications) {
- if (notification.QName.localName.equals(first.localName)) {
- node = notification
- }
- }
- }
- if (node == null) {
- val rpcs = module.getAddedRpcs
- for (rpc : rpcs) {
- if (rpc.QName.localName.equals(first.localName)) {
- node = rpc
- }
- }
- }
- if (node == null) {
- return null;
- }
-
- if (!path.empty) {
- node = findSchemaNode(path, node)
- }
-
- return node
- }
-
- /**
- * Find augment target node and perform augmentation.
- *
- * @param augment
- * @param firstNodeParent
- * parent of first node in path
- * @param path
- * path to augment target
- * @return true if augmentation process succeed, false otherwise
- */
- public static def boolean processAugmentation(AugmentationSchemaBuilder augment, ModuleBuilder firstNodeParent) {
- val path = augment.targetPath.path
- var Builder targetNode = findSchemaNodeInModule(path, firstNodeParent)
- if(targetNode === null) return false;
-
- if (!(targetNode instanceof DataNodeContainerBuilder || targetNode instanceof ChoiceBuilder)) {
- throw new YangParseException(augment.getModuleName(), augment.getLine(),
- "Error in augment parsing: The target node MUST be either a container, list, choice, case, input, output, or notification node.");
- }
- fillAugmentTarget(augment, targetNode);
- (targetNode as AugmentationTargetBuilder).addAugmentation(augment);
- augment.setResolved(true);
- return true;
- }
-
- public static def IdentitySchemaNodeBuilder findBaseIdentity(Map<String, TreeMap<Date, ModuleBuilder>> modules,
- ModuleBuilder module, String baseString, int line) {
- var IdentitySchemaNodeBuilder result = null;
- if (baseString.contains(":")) {
- val String[] splittedBase = baseString.split(":");
- if (splittedBase.length > 2) {
- throw new YangParseException(module.getName(), line,
- "Failed to parse identityref base: " + baseString);
- }
- val prefix = splittedBase.get(0);
- val name = splittedBase.get(1);
- val dependentModule = findModuleFromBuilders(modules, module, prefix, line);
- if (dependentModule !== null) {
- result = findIdentity(dependentModule.getAddedIdentities, name);
- }
- } else {
- result = findIdentity(module.getAddedIdentities, baseString);
- }
- return result;
- }
-
- public static def IdentitySchemaNode findBaseIdentityFromContext(Map<String, TreeMap<Date, ModuleBuilder>> modules,
- ModuleBuilder module, String baseString, int line, SchemaContext context) {
- var IdentitySchemaNode result = null;
-
- val String[] splittedBase = baseString.split(":");
- if (splittedBase.length > 2) {
- throw new YangParseException(module.getName(), line, "Failed to parse identityref base: " + baseString);
- }
- val prefix = splittedBase.get(0);
- val name = splittedBase.get(1);
- val dependentModule = findModuleFromContext(context, module, prefix, line);
- result = findIdentityNode(dependentModule.identities, name);
-
- if (result == null) {
- throw new YangParseException(module.name, line, "Failed to find base identity");
- }
- return result;
- }
-
- private static def IdentitySchemaNodeBuilder findIdentity(Set<IdentitySchemaNodeBuilder> identities, String name) {
- for (identity : identities) {
- if (identity.QName.localName.equals(name)) {
- return identity;
- }
- }
- return null;
- }
-
- private static def IdentitySchemaNode findIdentityNode(Set<IdentitySchemaNode> identities, String name) {
- for (identity : identities) {
- if (identity.QName.localName.equals(name)) {
- return identity;
- }
- }
- return null;
- }
-
- /**
- * Get module in which this node is defined.
- *
- * @param node
- * @return builder of module where this node is defined
- */
- public static def ModuleBuilder getParentModule(Builder node) {
- if (node instanceof ModuleBuilder) {
- return node as ModuleBuilder;
- }
- var parent = node.getParent();
- while (!(parent instanceof ModuleBuilder)) {
- parent = parent.getParent();
- }
- Preconditions.checkState(parent instanceof ModuleBuilder)
- var parentModule = parent as ModuleBuilder
- if(parentModule.submodule) {
- parentModule = parentModule.parent;
- }
- return parentModule;
- }
-
- public static def Set<DataSchemaNodeBuilder> wrapChildNodes(String moduleName, int line, Set<DataSchemaNode> nodes,
- SchemaPath parentPath, URI ns, Date rev, String pref) {
- val Set<DataSchemaNodeBuilder> result = new HashSet()
-
- for (DataSchemaNode node : nodes) {
- val qname = new QName(ns, rev, pref, node.QName.localName)
- val DataSchemaNodeBuilder wrapped = wrapChildNode(moduleName, line, node, parentPath, qname)
- result.add(wrapped)
- }
- return result
- }
-
- public static def DataSchemaNodeBuilder wrapChildNode(String moduleName, int line, DataSchemaNode node,
- SchemaPath parentPath, QName qname) {
- val List<QName> path = new ArrayList(parentPath.getPath())
- path.add(qname)
- val SchemaPath schemaPath = new SchemaPath(path, parentPath.isAbsolute())
-
- if (node instanceof AnyXmlSchemaNode) {
- return new AnyXmlBuilder(moduleName, line, qname, schemaPath, (node as AnyXmlSchemaNode));
- } else if (node instanceof ChoiceNode) {
- return new ChoiceBuilder(moduleName, line, qname, schemaPath, (node as ChoiceNode));
- } else if (node instanceof ContainerSchemaNode) {
- return new ContainerSchemaNodeBuilder(moduleName, line, qname, schemaPath, (node as ContainerSchemaNode));
- } else if (node instanceof LeafSchemaNode) {
- return new LeafSchemaNodeBuilder(moduleName, line, qname, schemaPath, (node as LeafSchemaNode));
- } else if (node instanceof LeafListSchemaNode) {
- return new LeafListSchemaNodeBuilder(moduleName, line, qname, schemaPath, (node as LeafListSchemaNode));
- } else if (node instanceof ListSchemaNode) {
- return new ListSchemaNodeBuilder(moduleName, line, qname, schemaPath, (node as ListSchemaNode));
- } else if (node instanceof ChoiceCaseNode) {
- return new ChoiceCaseBuilder(moduleName, line, qname, schemaPath, (node as ChoiceCaseNode));
- } else {
- throw new YangParseException(moduleName, line,
- "Failed to copy node: Unknown type of DataSchemaNode: " + node)
- }
- }
-
- public static def Set<GroupingBuilder> wrapGroupings(String moduleName, int line, Set<GroupingDefinition> nodes,
- SchemaPath parentPath, URI ns, Date rev, String pref) {
- val Set<GroupingBuilder> result = new HashSet()
- for (GroupingDefinition node : nodes) {
- val qname = new QName(ns, rev, pref, node.QName.localName)
- val List<QName> path = new ArrayList(parentPath.getPath())
- path.add(qname)
- val SchemaPath schemaPath = new SchemaPath(path, parentPath.isAbsolute())
- result.add(new GroupingBuilderImpl(moduleName, line, qname, schemaPath, node))
- }
- return result
- }
-
- public static def Set<TypeDefinitionBuilder> wrapTypedefs(String moduleName, int line, DataNodeContainer dataNode,
- SchemaPath parentPath, URI ns, Date rev, String pref) {
- val Set<TypeDefinition<?>> nodes = dataNode.typeDefinitions
- val Set<TypeDefinitionBuilder> result = new HashSet()
- for (TypeDefinition<?> node : nodes) {
- val qname = new QName(ns, rev, pref, node.QName.localName)
- val List<QName> path = new ArrayList(parentPath.getPath())
- path.add(qname)
- val SchemaPath schemaPath = new SchemaPath(path, parentPath.isAbsolute())
- result.add(new TypeDefinitionBuilderImpl(moduleName, line, qname, schemaPath, (node as ExtendedType)))
- }
- return result
- }
-
- public static def List<UnknownSchemaNodeBuilder> wrapUnknownNodes(String moduleName, int line,
- List<UnknownSchemaNode> nodes, SchemaPath parentPath, URI ns, Date rev, String pref) {
- val List<UnknownSchemaNodeBuilder> result = new ArrayList()
- for (UnknownSchemaNode node : nodes) {
- val qname = new QName(ns, rev, pref, node.QName.localName)
- val List<QName> path = new ArrayList(parentPath.getPath())
- path.add(qname)
- val SchemaPath schemaPath = new SchemaPath(path, parentPath.isAbsolute())
- result.add(new UnknownSchemaNodeBuilder(moduleName, line, qname, schemaPath, node))
- }
- return result
- }
-
-}