From: Martin Sunal Date: Sat, 25 Jan 2014 14:03:11 +0000 (+0100) Subject: Instance identifier support X-Git-Tag: jenkins-controller-bulk-release-prepare-only-2-11~7^2 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=7667b0fe30e4dec2cda4316762467ba49200f1d7 Instance identifier support - codec for instance identifier (deserializer, serializer) was added - instance identifier from XML and JSON files to simple node - instance identifier from simple node to XML and JSON - corrected augments with the same names Change-Id: Iff49aedd209e61fb15e4a7bee61a2c9611c25355 Signed-off-by: Martin Sunal Signed-off-by: Jozef Gloncak --- diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonMapper.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonMapper.java index 627e2a9ce1..4c5fd9ff7c 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonMapper.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonMapper.java @@ -14,9 +14,11 @@ import org.opendaylight.controller.sal.core.api.mount.MountInstance; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO; import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO.IdentityValue; +import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO.Predicate; import org.opendaylight.controller.sal.restconf.impl.RestCodec; 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.Node; import org.opendaylight.yangtools.yang.data.api.SimpleNode; import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode; @@ -32,6 +34,7 @@ import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition; +import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition; import org.slf4j.Logger; @@ -47,12 +50,13 @@ class JsonMapper { private MountInstance mountPoint; private final Logger logger = LoggerFactory.getLogger(JsonMapper.class); - public void write(JsonWriter writer, CompositeNode data, DataNodeContainer schema, MountInstance mountPoint) throws IOException { + public void write(JsonWriter writer, CompositeNode data, DataNodeContainer schema, MountInstance mountPoint) + throws IOException { Preconditions.checkNotNull(writer); Preconditions.checkNotNull(data); Preconditions.checkNotNull(schema); this.mountPoint = mountPoint; - + writer.beginObject(); if (schema instanceof ContainerSchemaNode) { @@ -195,7 +199,8 @@ class JsonMapper { // TODO check InstanceIdentifierTypeDefinition if (baseType instanceof IdentityrefTypeDefinition) { if (node.getValue() instanceof QName) { - IdentityValuesDTO valueDTO = (IdentityValuesDTO) RestCodec.from(baseType, mountPoint).serialize(node.getValue()); + IdentityValuesDTO valueDTO = (IdentityValuesDTO) RestCodec.from(baseType, mountPoint).serialize( + node.getValue()); IdentityValue valueFromDTO = valueDTO.getValuesWithNamespaces().get(0); String moduleName; if (mountPoint != null) { @@ -207,19 +212,20 @@ class JsonMapper { } writer.value(moduleName + ":" + valueFromDTO.getValue()); } else { - Object value = node.getValue(); - logger.debug("Value of " + baseType.getQName().getNamespace() + ":" - + baseType.getQName().getLocalName() + " is not instance of " + QName.class + " but is " - + (value != null ? value.getClass() : "null")); - if (value == null) { - writer.value(""); - } else { - writer.value(String.valueOf(value)); - } + writeStringRepresentation(writer, node, baseType, QName.class); + } + } else if (baseType instanceof InstanceIdentifierTypeDefinition) { + if (node.getValue() instanceof InstanceIdentifier) { + IdentityValuesDTO valueDTO = (IdentityValuesDTO) RestCodec.from(baseType, mountPoint).serialize( + node.getValue()); + writeIdentityValuesDTOToJson(writer, valueDTO); + } else { + writeStringRepresentation(writer, node, baseType, InstanceIdentifier.class); } } else if (baseType instanceof DecimalTypeDefinition || baseType instanceof IntegerTypeDefinition || baseType instanceof UnsignedIntegerTypeDefinition) { - writer.value(new NumberForJsonWriter((String) RestCodec.from(baseType, mountPoint).serialize(node.getValue()))); + writer.value(new NumberForJsonWriter((String) RestCodec.from(baseType, mountPoint).serialize( + node.getValue()))); } else if (baseType instanceof BooleanTypeDefinition) { writer.value(Boolean.parseBoolean((String) RestCodec.from(baseType, mountPoint).serialize(node.getValue()))); } else if (baseType instanceof EmptyTypeDefinition) { @@ -233,6 +239,50 @@ class JsonMapper { } } + private void writeIdentityValuesDTOToJson(JsonWriter writer, IdentityValuesDTO valueDTO) throws IOException { + StringBuilder result = new StringBuilder(); + for (IdentityValue identityValue : valueDTO.getValuesWithNamespaces()) { + result.append("/"); + + writeModuleNameAndIdentifier(result, identityValue); + if (identityValue.getPredicates() != null) { + for (Predicate predicate : identityValue.getPredicates()) { + IdentityValue identityValuePredicate = predicate.getName(); + result.append("["); + writeModuleNameAndIdentifier(result, identityValuePredicate); + result.append("=\""); + result.append(predicate.getValue()); + result.append("\""); + result.append("]"); + } + } + } + + writer.value(result.toString()); + } + + private void writeModuleNameAndIdentifier(StringBuilder result, IdentityValue identityValue) { + String moduleName = ControllerContext.getInstance().findModuleNameByNamespace( + URI.create(identityValue.getNamespace())); + if (moduleName != null && !moduleName.isEmpty()) { + result.append(moduleName); + result.append(":"); + } + result.append(identityValue.getValue()); + } + + private void writeStringRepresentation(JsonWriter writer, SimpleNode node, TypeDefinition baseType, + Class requiredType) throws IOException { + Object value = node.getValue(); + logger.debug("Value of " + baseType.getQName().getNamespace() + ":" + baseType.getQName().getLocalName() + + " is not instance of " + requiredType.getClass() + " but is " + node.getValue().getClass()); + if (value == null) { + writer.value(""); + } else { + writer.value(String.valueOf(value)); + } + } + private void writeEmptyDataTypeToJson(JsonWriter writer) throws IOException { writer.beginArray(); writer.nullValue(); diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonReader.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonReader.java index f4c5034776..3fc402ca3a 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonReader.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonReader.java @@ -6,10 +6,11 @@ import java.net.URI; import java.util.Map.Entry; import java.util.Set; +import org.opendaylight.controller.sal.rest.impl.RestUtil.PrefixMapingFromJson; import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper; import org.opendaylight.controller.sal.restconf.impl.EmptyNodeWrapper; -import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper; import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO; +import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper; import com.google.common.collect.Lists; import com.google.gson.JsonElement; @@ -63,8 +64,7 @@ class JsonReader { private void addChildToParent(String childName, JsonElement childType, CompositeNodeWrapper parent) { if (childType.isJsonObject()) { - CompositeNodeWrapper child = new CompositeNodeWrapper(getNamespaceFor(childName), - getLocalNameFor(childName)); + CompositeNodeWrapper child = new CompositeNodeWrapper(getNamespaceFor(childName), getLocalNameFor(childName)); parent.addValue(child); for (Entry childOfChild : childType.getAsJsonObject().entrySet()) { addChildToParent(childOfChild.getKey(), childOfChild.getValue(), child); @@ -88,7 +88,8 @@ class JsonReader { private URI getNamespaceFor(String jsonElementName) { String[] moduleNameAndLocalName = jsonElementName.split(":"); - if (moduleNameAndLocalName.length != 2) { // it is not "moduleName:localName" + // it is not "moduleName:localName" + if (moduleNameAndLocalName.length != 2) { return null; } return URI.create(moduleNameAndLocalName[0]); @@ -96,21 +97,28 @@ class JsonReader { private String getLocalNameFor(String jsonElementName) { String[] moduleNameAndLocalName = jsonElementName.split(":"); - if (moduleNameAndLocalName.length != 2) { // it is not "moduleName:localName" + // it is not "moduleName:localName" + if (moduleNameAndLocalName.length != 2) { return jsonElementName; } return moduleNameAndLocalName[1]; } - /** - * @param value - * value of json element - * @return if value is "moduleName:localName" then {@link IdentityValuesDTO} else - * the same string as parameter "value" - */ private Object resolveValueOfElement(String value) { + // it could be instance-identifier Built-In Type + if (value.startsWith("/")) { + IdentityValuesDTO resolvedValue = RestUtil.asInstanceIdentifier(value, new PrefixMapingFromJson()); + if (resolvedValue != null) { + return resolvedValue; + } + } + // it could be identityref Built-In Type URI namespace = getNamespaceFor(value); - return namespace == null ? value : new IdentityValuesDTO(namespace.toString(), getLocalNameFor(value), null); + if (namespace != null) { + return new IdentityValuesDTO(namespace.toString(), getLocalNameFor(value), null); + } + // it is not "prefix:value" but just "value" + return value; } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestUtil.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestUtil.java index 6e70b9bddf..0c8c75839b 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestUtil.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestUtil.java @@ -1,8 +1,22 @@ package org.opendaylight.controller.sal.rest.impl; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.xml.stream.events.StartElement; + +import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO; +import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO.IdentityValue; +import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO.Predicate; import org.opendaylight.yangtools.yang.model.api.TypeDefinition; public final class RestUtil { + + public static final String SQUOTE = "'"; + public static final String DQUOTE = "\""; + private static final Pattern PREDICATE_PATTERN = Pattern.compile("\\[(.*?)\\]"); public final static TypeDefinition resolveBaseTypeFrom(TypeDefinition type) { TypeDefinition superType = type; @@ -12,4 +26,121 @@ public final class RestUtil { return superType; } + public static IdentityValuesDTO asInstanceIdentifier(String value, PrefixesMaping prefixMap) { + String valueTrimmed = value.trim(); + if (!valueTrimmed.startsWith("/")) { + return null; + } + String[] xPathParts = valueTrimmed.split("/"); + if (xPathParts.length < 2) { // must be at least "/pr:node" + return null; + } + IdentityValuesDTO identityValuesDTO = new IdentityValuesDTO(); + for (int i = 1; i < xPathParts.length; i++) { + String xPathPartTrimmed = xPathParts[i].trim(); + + String xPathPartStr = getIdAndPrefixAsStr(xPathPartTrimmed); + IdentityValue identityValue = toIdentity(xPathPartStr, prefixMap); + if (identityValue == null) { + return null; + } + + List predicates = toPredicates(xPathPartTrimmed, prefixMap); + if (predicates == null) { + return null; + } + identityValue.setPredicates(predicates); + + identityValuesDTO.add(identityValue); + } + return identityValuesDTO.getValuesWithNamespaces().isEmpty() ? null : identityValuesDTO; + } + + private static String getIdAndPrefixAsStr(String pathPart) { + int predicateStartIndex = pathPart.indexOf("["); + return predicateStartIndex == -1 ? pathPart : pathPart.substring(0, predicateStartIndex); + } + + private static IdentityValue toIdentity(String xPathPart, PrefixesMaping prefixMap) { + String xPathPartTrimmed = xPathPart.trim(); + if (xPathPartTrimmed.isEmpty()) { + return null; + } + String[] prefixAndIdentifier = xPathPartTrimmed.split(":"); + // it is not "prefix:value" + if (prefixAndIdentifier.length != 2) { + return null; + } + String prefix = prefixAndIdentifier[0].trim(); + String identifier = prefixAndIdentifier[1].trim(); + if (prefix.isEmpty() || identifier.isEmpty()) { + return null; + } + String namespace = prefixMap.getNamespace(prefix); + return new IdentityValue(namespace, identifier, namespace.equals(prefix) ? null : prefix); + } + + private static List toPredicates(String predicatesStr, PrefixesMaping prefixMap) { + List result = new ArrayList<>(); + List predicates = new ArrayList<>(); + Matcher matcher = PREDICATE_PATTERN.matcher(predicatesStr); + while (matcher.find()) { + predicates.add(matcher.group(1).trim()); + } + for (String predicate : predicates) { + int indexOfEqualityMark = predicate.indexOf("="); + if (indexOfEqualityMark != -1) { + String predicateValue = toPredicateValue(predicate.substring(indexOfEqualityMark + 1)); + if (predicate.startsWith(".")) { // it is leaf-list + if (predicateValue == null) { + return null; + } + result.add(new Predicate(null, predicateValue)); + } else { + IdentityValue identityValue = toIdentity(predicate.substring(0, indexOfEqualityMark), + prefixMap); + if (identityValue == null || predicateValue == null) { + return null; + } + result.add(new Predicate(identityValue, predicateValue)); + } + } + } + return result; + } + + private static String toPredicateValue(String predicatedValue) { + String predicatedValueTrimmed = predicatedValue.trim(); + if ((predicatedValueTrimmed.startsWith(DQUOTE) || predicatedValueTrimmed.startsWith(SQUOTE)) + && (predicatedValueTrimmed.endsWith(DQUOTE) || predicatedValueTrimmed.endsWith(SQUOTE))) { + return predicatedValueTrimmed.substring(1, predicatedValueTrimmed.length() - 1); + } + return null; + } + + public interface PrefixesMaping { + public String getNamespace(String prefix); + } + + public static class PrefixMapingFromXml implements PrefixesMaping { + StartElement startElement = null; + + public PrefixMapingFromXml(StartElement startElement) { + this.startElement = startElement; + } + + @Override + public String getNamespace(String prefix) { + return startElement.getNamespaceContext().getNamespaceURI(prefix); + } + } + + public static class PrefixMapingFromJson implements PrefixesMaping { + + @Override + public String getNamespace(String prefix) { + return prefix; + } + } + } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestconfProvider.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestconfProvider.java index 954644737a..09cf01091e 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestconfProvider.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestconfProvider.java @@ -8,11 +8,11 @@ import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; import org.opendaylight.controller.sal.core.api.Provider; import org.opendaylight.controller.sal.core.api.data.DataBrokerService; import org.opendaylight.controller.sal.core.api.model.SchemaService; -import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener; import org.opendaylight.controller.sal.core.api.mount.MountService; import org.opendaylight.controller.sal.restconf.impl.BrokerFacade; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlReader.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlReader.java index 014e839f26..d6f8a9874b 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlReader.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlReader.java @@ -14,8 +14,8 @@ import javax.xml.stream.events.StartElement; import javax.xml.stream.events.XMLEvent; import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper; -import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO; import org.opendaylight.controller.sal.restconf.impl.EmptyNodeWrapper; +import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO; import org.opendaylight.controller.sal.restconf.impl.NodeWrapper; import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper; import org.opendaylight.yangtools.yang.data.api.Node; @@ -148,6 +148,7 @@ public class XmlReader { final Characters chars = innerEvent.asCharacters(); if (!chars.isWhiteSpace()) { data = innerEvent.asCharacters().getData(); + data = data + getAdditionalData(eventReader.nextEvent()); } } else if (innerEvent.isEndElement()) { if (startElement.getLocation().getCharacterOffset() == innerEvent.getLocation().getCharacterOffset()) { @@ -160,6 +161,21 @@ public class XmlReader { return data; } + private String getAdditionalData(XMLEvent event) throws XMLStreamException { + String data = ""; + if (eventReader.hasNext()) { + final XMLEvent innerEvent = eventReader.peek(); + if (innerEvent.isCharacters() && !innerEvent.isEndElement()) { + final Characters chars = innerEvent.asCharacters(); + if (!chars.isWhiteSpace()) { + data = innerEvent.asCharacters().getData(); + data = data + getAdditionalData(eventReader.nextEvent()); + } + } + } + return data; + } + private String getLocalNameFor(StartElement startElement) { return startElement.getName().getLocalPart(); } @@ -169,23 +185,23 @@ public class XmlReader { return namespaceURI.isEmpty() ? null : URI.create(namespaceURI); } - /** - * @param value - * value of startElement - * @param startElement - * element containing value - * @return if value is "prefix:value" then {@link IdentityValuesDTO} else the same - * string as parameter "value" - */ private Object resolveValueOfElement(String value, StartElement startElement) { - String[] namespaceAndValue = value.split(":"); - if (namespaceAndValue.length != 2) { // it is not "prefix:value" - return value; + // it could be instance-identifier Built-In Type + if (value.startsWith("/")) { + IdentityValuesDTO iiValue = RestUtil.asInstanceIdentifier(value, new RestUtil.PrefixMapingFromXml(startElement)); + if (iiValue != null) { + return iiValue; + } } - String namespace = startElement.getNamespaceContext().getNamespaceURI(namespaceAndValue[0]); - if (namespace != null && !namespace.isEmpty()) { - return new IdentityValuesDTO(namespace, namespaceAndValue[1], namespaceAndValue[0]); + // it could be identityref Built-In Type + String[] namespaceAndValue = value.split(":"); + if (namespaceAndValue.length == 2) { + String namespace = startElement.getNamespaceContext().getNamespaceURI(namespaceAndValue[0]); + if (namespace != null && !namespace.isEmpty()) { + return new IdentityValuesDTO(namespace, namespaceAndValue[1], namespaceAndValue[0]); + } } + // it is not "prefix:value" but just "value" return value; } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/CompositeNodeWrapper.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/CompositeNodeWrapper.java index 74a32d452e..8c5870522e 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/CompositeNodeWrapper.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/CompositeNodeWrapper.java @@ -41,6 +41,11 @@ public final class CompositeNodeWrapper implements NodeWrapper, C Preconditions.checkState(compositeNode == null, "Cannot change the object, due to data inconsistencies."); this.name = name; } + + @Override + public QName getQname() { + return name; + } @Override public String getLocalName() { diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend index 9a61b43df5..ced272e00b 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend @@ -1,16 +1,18 @@ package org.opendaylight.controller.sal.restconf.impl +import com.google.common.base.Preconditions import com.google.common.collect.BiMap import com.google.common.collect.FluentIterable import com.google.common.collect.HashBiMap import java.net.URI import java.net.URLDecoder import java.net.URLEncoder +import java.util.ArrayList import java.util.HashMap import java.util.List import java.util.Map import java.util.concurrent.ConcurrentHashMap -import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener +import org.opendaylight.controller.sal.core.api.mount.MountInstance import org.opendaylight.controller.sal.core.api.mount.MountService import org.opendaylight.controller.sal.rest.impl.RestUtil import org.opendaylight.controller.sal.rest.impl.RestconfProvider @@ -32,12 +34,12 @@ import org.opendaylight.yangtools.yang.model.api.ListSchemaNode import org.opendaylight.yangtools.yang.model.api.Module import org.opendaylight.yangtools.yang.model.api.RpcDefinition import org.opendaylight.yangtools.yang.model.api.SchemaContext +import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition import org.slf4j.LoggerFactory import static com.google.common.base.Preconditions.* import static javax.ws.rs.core.Response.Status.* -import org.opendaylight.controller.sal.core.api.mount.MountInstance class ControllerContext implements SchemaServiceListener { val static LOG = LoggerFactory.getLogger(ControllerContext) @@ -49,7 +51,7 @@ class ControllerContext implements SchemaServiceListener { @Property var SchemaContext globalSchema; - + @Property var MountService mountService; @@ -104,7 +106,7 @@ class ControllerContext implements SchemaServiceListener { val modules = schema.modules.filter[m|m.name == moduleName] return modules.filterLatestModule } - + private def filterLatestModule(Iterable modules) { var latestModule = modules.head for (module : modules) { @@ -114,26 +116,26 @@ class ControllerContext implements SchemaServiceListener { } return latestModule } - + def findModuleByName(String moduleName) { checkPreconditions checkArgument(moduleName !== null && !moduleName.empty) return globalSchema.getLatestModule(moduleName) } - + def findModuleByName(MountInstance mountPoint, String moduleName) { checkArgument(moduleName !== null && mountPoint !== null) val mountPointSchema = mountPoint.schemaContext; return mountPointSchema?.getLatestModule(moduleName); } - + def findModuleByNamespace(URI namespace) { checkPreconditions checkArgument(namespace !== null) val moduleSchemas = globalSchema.findModuleByNamespace(namespace) return moduleSchemas?.filterLatestModule } - + def findModuleByNamespace(MountInstance mountPoint, URI namespace) { checkArgument(namespace !== null && mountPoint !== null) val mountPointSchema = mountPoint.schemaContext; @@ -180,7 +182,7 @@ class ControllerContext implements SchemaServiceListener { } return moduleName } - + def findModuleNameByNamespace(MountInstance mountPoint, URI namespace) { val module = mountPoint.findModuleByNamespace(namespace); return module?.name @@ -196,7 +198,7 @@ class ControllerContext implements SchemaServiceListener { } return namespace } - + def findNamespaceByModuleName(MountInstance mountPoint, String moduleName) { val module = mountPoint.findModuleByName(moduleName) return module?.namespace @@ -263,7 +265,7 @@ class ControllerContext implements SchemaServiceListener { if(object === null) return ""; return URLEncoder.encode(object.toString) } - + private def InstanceIdWithSchemaNode collectPathArguments(InstanceIdentifierBuilder builder, List strings, DataNodeContainer parentNode, MountInstance mountPoint) { checkNotNull(strings) @@ -273,7 +275,7 @@ class ControllerContext implements SchemaServiceListener { if (strings.empty) { return new InstanceIdWithSchemaNode(builder.toInstance, parentNode as DataSchemaNode, mountPoint) } - + val nodeName = strings.head.toNodeName val moduleName = strings.head.toModuleName var DataSchemaNode targetNode = null @@ -283,45 +285,45 @@ class ControllerContext implements SchemaServiceListener { if (mountPoint !== null) { throw new ResponseException(BAD_REQUEST, "Restconf supports just one mount point in URI.") } - + if (mountService === null) { - throw new ResponseException(SERVICE_UNAVAILABLE, "MountService was not found. " + throw new ResponseException(SERVICE_UNAVAILABLE, "MountService was not found. " + "Finding behind mount points does not work." ) } - + val partialPath = builder.toInstance; val mount = mountService.getMountPoint(partialPath) if (mount === null) { LOG.debug("Instance identifier to missing mount point: {}", partialPath) throw new ResponseException(BAD_REQUEST, "Mount point does not exist.") } - + val mountPointSchema = mount.schemaContext; if (mountPointSchema === null) { throw new ResponseException(BAD_REQUEST, "Mount point does not contain any schema with modules.") } - + if (strings.size == 1) { // any data node is not behind mount point return new InstanceIdWithSchemaNode(InstanceIdentifier.builder().toInstance, mountPointSchema, mount) } - + val moduleNameBehindMountPoint = strings.get(1).toModuleName() if (moduleNameBehindMountPoint === null) { throw new ResponseException(BAD_REQUEST, "First node after mount point in URI has to be in format \"moduleName:nodeName\"") } - + val moduleBehindMountPoint = mountPointSchema.getLatestModule(moduleNameBehindMountPoint) if (moduleBehindMountPoint === null) { throw new ResponseException(BAD_REQUEST, "URI has bad format. \"" + moduleName + "\" module does not exist in mount point.") } - + return collectPathArguments(InstanceIdentifier.builder(), strings.subList(1, strings.size), moduleBehindMountPoint, mount); } - + var Module module = null; if (mountPoint === null) { module = globalSchema.getLatestModule(moduleName) @@ -336,19 +338,32 @@ class ControllerContext implements SchemaServiceListener { "URI has bad format. \"" + moduleName + "\" module does not exist in mount point.") } } - targetNode = parentNode.findInstanceDataChild(nodeName, module.namespace) + targetNode = parentNode.findInstanceDataChildByNameAndNamespace(nodeName, module.namespace) if (targetNode === null) { - throw new ResponseException(BAD_REQUEST, "URI has bad format. Possible reasons:\n" + - "1. \"" + strings.head + "\" was not found in parent data node.\n" + + throw new ResponseException(BAD_REQUEST, "URI has bad format. Possible reasons:\n" + + "1. \"" + strings.head + "\" was not found in parent data node.\n" + "2. \"" + strings.head + "\" is behind mount point. Then it should be in format \"/" + MOUNT + "/" + strings.head + "\".") } } else { // string without module name - targetNode = parentNode.findInstanceDataChild(nodeName, null) + val potentialSchemaNodes = parentNode.findInstanceDataChildrenByName(nodeName) + if (potentialSchemaNodes.size > 1) { + val StringBuilder namespacesOfPotentialModules = new StringBuilder; + for (potentialNodeSchema : potentialSchemaNodes) { + namespacesOfPotentialModules.append(" ").append(potentialNodeSchema.QName.namespace.toString).append("\n") + } + throw new ResponseException(BAD_REQUEST, "URI has bad format. Node \"" + nodeName + "\" is added as augment from more than one module. " + + "Therefore the node must have module name and it has to be in format \"moduleName:nodeName\"." + + "\nThe node is added as augment from modules with namespaces:\n" + namespacesOfPotentialModules) + } + targetNode = potentialSchemaNodes.head if (targetNode === null) { throw new ResponseException(BAD_REQUEST, "URI has bad format. \"" + nodeName + "\" was not found in parent data node.\n") } } - + + if (!(targetNode instanceof ListSchemaNode) && !(targetNode instanceof ContainerSchemaNode)) { + throw new ResponseException(BAD_REQUEST,"URI has bad format. Node \"" + strings.head + "\" must be Container or List yang type.") + } // Number of consumed elements var consumed = 1; if (targetNode instanceof ListSchemaNode) { @@ -367,7 +382,7 @@ class ControllerContext implements SchemaServiceListener { // key value cannot be NULL if (uriKeyValue.equals(NULL_VALUE)) { - throw new ResponseException(BAD_REQUEST, "URI has bad format. List \"" + listNode.QName.localName + throw new ResponseException(BAD_REQUEST, "URI has bad format. List \"" + listNode.QName.localName + "\" cannot contain \"null\" value as a key." ) } @@ -390,28 +405,36 @@ class ControllerContext implements SchemaServiceListener { return new InstanceIdWithSchemaNode(builder.toInstance, targetNode, mountPoint) } - def DataSchemaNode findInstanceDataChild(DataNodeContainer container, String name, URI moduleNamespace) { - var DataSchemaNode potentialNode = null - if (moduleNamespace === null) { - potentialNode = container.getDataChildByName(name); - } else { - potentialNode = container.childNodes.filter[n|n.QName.localName == name && n.QName.namespace == moduleNamespace].head - } - - if (potentialNode.instantiatedDataSchema) { - return potentialNode; + def DataSchemaNode findInstanceDataChildByNameAndNamespace(DataNodeContainer container, + String name, URI namespace) { + Preconditions.checkNotNull(namespace) + val potentialSchemaNodes = container.findInstanceDataChildrenByName(name) + return potentialSchemaNodes.filter[n|n.QName.namespace == namespace].head + } + + def List findInstanceDataChildrenByName(DataNodeContainer container, String name) { + Preconditions.checkNotNull(container) + Preconditions.checkNotNull(name) + val instantiatedDataNodeContainers = new ArrayList + instantiatedDataNodeContainers.collectInstanceDataNodeContainers(container, name) + return instantiatedDataNodeContainers + } + + private def void collectInstanceDataNodeContainers(List potentialSchemaNodes, DataNodeContainer container, + String name) { + val nodes = container.childNodes.filter[n|n.QName.localName == name] + for (potentialNode : nodes) { + if (potentialNode.isInstantiatedDataSchema) { + potentialSchemaNodes.add(potentialNode) + } } val allCases = container.childNodes.filter(ChoiceNode).map[cases].flatten for (caze : allCases) { - potentialNode = caze.findInstanceDataChild(name, moduleNamespace); - if (potentialNode !== null) { - return potentialNode; - } + collectInstanceDataNodeContainers(potentialSchemaNodes, caze, name) } - return null; } - - static def boolean isInstantiatedDataSchema(DataSchemaNode node) { + + def boolean isInstantiatedDataSchema(DataSchemaNode node) { switch node { LeafSchemaNode: return true LeafListSchemaNode: return true @@ -420,13 +443,13 @@ class ControllerContext implements SchemaServiceListener { default: return false } } - + private def void addKeyValue(HashMap map, DataSchemaNode node, String uriValue) { checkNotNull(uriValue); checkArgument(node instanceof LeafSchemaNode); val urlDecoded = URLDecoder.decode(uriValue); val typedef = (node as LeafSchemaNode).type; - + var decoded = TypeDefinitionAwareCodec.from(typedef)?.deserialize(urlDecoded) if(decoded === null) { var baseType = RestUtil.resolveBaseTypeFrom(typedef) diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/EmptyNodeWrapper.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/EmptyNodeWrapper.java index cdb9599a46..c601414a61 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/EmptyNodeWrapper.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/EmptyNodeWrapper.java @@ -5,10 +5,7 @@ import java.util.Collections; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.CompositeNode; -import org.opendaylight.yangtools.yang.data.api.ModifyAction; -import org.opendaylight.yangtools.yang.data.api.MutableSimpleNode; import org.opendaylight.yangtools.yang.data.api.Node; -import org.opendaylight.yangtools.yang.data.api.SimpleNode; import org.opendaylight.yangtools.yang.data.impl.NodeFactory; import com.google.common.base.Preconditions; @@ -42,6 +39,11 @@ public final class EmptyNodeWrapper implements NodeWrapper>, Node this.name = name; } + @Override + public QName getQname() { + return name; + } + @Override public String getLocalName() { if (unwrapped != null) { diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/IdentityValuesDTO.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/IdentityValuesDTO.java index 6924fb620f..5fd36cb196 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/IdentityValuesDTO.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/IdentityValuesDTO.java @@ -11,20 +11,35 @@ public final class IdentityValuesDTO { public IdentityValuesDTO(String namespace, String value, String prefix) { elementData.add(new IdentityValue(namespace, value, prefix)); } + + public IdentityValuesDTO() { + + } public void add(String namespace, String value, String prefix) { elementData.add(new IdentityValue(namespace, value, prefix)); } + + public void add(IdentityValue identityValue) { + elementData.add(identityValue); + } + public List getValuesWithNamespaces() { return Collections.unmodifiableList(elementData); } + + @Override + public String toString() { + return elementData.toString(); + } public static final class IdentityValue { - private String namespace; - private String value; - private String prefix; + private final String namespace; + private final String value; + private final String prefix; + private List predicates; public IdentityValue(String namespace, String value, String prefix) { this.namespace = namespace; @@ -36,25 +51,83 @@ public final class IdentityValuesDTO { return namespace; } - public void setNamespace(String namespace) { - this.namespace = namespace; - } - public String getValue() { return value; } - public void setValue(String value) { - this.value = value; - } - public String getPrefix() { return prefix; } - public void setPrefix(String prefix) { - this.prefix = prefix; + public List getPredicates() { + if (predicates == null) { + return Collections.emptyList(); + } + return Collections.unmodifiableList(predicates); } + public void setPredicates(List predicates) { + this.predicates = predicates; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + if (namespace != null) { + sb.append(namespace); + } + if (prefix != null) { + sb.append("(").append(prefix).append(")"); + } + if (value != null) { + sb.append(" - ").append(value); + } + if (predicates != null && !predicates.isEmpty()) { + for (Predicate predicate : predicates) { + sb.append("["); + predicate.toString(); + sb.append("]"); + } + } + return sb.toString(); + } + + } + + public static final class Predicate { + + private final IdentityValue name; + private final String value; + + public Predicate(IdentityValue name, String value) { + super(); + this.name = name; + this.value = value; + } + + public IdentityValue getName() { + return name; + } + + public String getValue() { + return value; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + if (name != null) { + sb.append(name.toString()); + } + if (value != null) { + sb.append("=").append(value); + } + return sb.toString(); + } + + public boolean isLeafList() { + return name == null ? true : false; + } + } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/NodeWrapper.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/NodeWrapper.java index 6b8665f765..811e534b4a 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/NodeWrapper.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/NodeWrapper.java @@ -9,6 +9,8 @@ public interface NodeWrapper> { void setQname(QName name); + QName getQname(); + T unwrap(); boolean isChangeAllowed(); diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestCodec.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestCodec.java index 952b6ce1bb..096425d0a6 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestCodec.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestCodec.java @@ -1,22 +1,41 @@ package org.opendaylight.controller.sal.restconf.impl; import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.opendaylight.controller.sal.core.api.mount.MountInstance; import org.opendaylight.controller.sal.rest.impl.RestUtil; import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO.IdentityValue; +import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO.Predicate; import org.opendaylight.yangtools.concepts.Codec; 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.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.codec.IdentityrefCodec; +import org.opendaylight.yangtools.yang.data.api.codec.InstanceIdentifierCodec; import org.opendaylight.yangtools.yang.data.api.codec.LeafrefCodec; import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec; +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.ListSchemaNode; +import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.TypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition; +import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class RestCodec { + + private static final Logger logger = LoggerFactory.getLogger(RestCodec.class); private RestCodec() { } @@ -31,6 +50,7 @@ public class RestCodec { private final Logger logger = LoggerFactory.getLogger(RestCodec.class); public static final Codec LEAFREF_DEFAULT_CODEC = new LeafrefCodecImpl(); + private final Codec instanceIdentifier; private final Codec identityrefCodec; private final TypeDefinition type; @@ -42,6 +62,11 @@ public class RestCodec { } else { identityrefCodec = null; } + if (type instanceof InstanceIdentifierTypeDefinition) { + instanceIdentifier = new InstanceIdentifierCodecImpl(mountPoint); + } else { + instanceIdentifier = null; + } } @SuppressWarnings("unchecked") @@ -49,9 +74,23 @@ public class RestCodec { public Object deserialize(Object input) { try { if (type instanceof IdentityrefTypeDefinition) { - return identityrefCodec.deserialize(input); + if (input instanceof IdentityValuesDTO) { + return identityrefCodec.deserialize(input); + } + logger.info( + "Value is not instance of IdentityrefTypeDefinition but is {}. Therefore NULL is used as translation of - {}", + input == null ? "null" : input.getClass(), String.valueOf(input)); + return null; } else if (type instanceof LeafrefTypeDefinition) { return LEAFREF_DEFAULT_CODEC.deserialize(input); + } else if (type instanceof InstanceIdentifierTypeDefinition) { + if (input instanceof IdentityValuesDTO) { + return instanceIdentifier.deserialize(input); + } + logger.info( + "Value is not instance of InstanceIdentifierTypeDefinition but is {}. Therefore NULL is used as translation of - {}", + input == null ? "null" : input.getClass(), String.valueOf(input)); + return null; } else { TypeDefinitionAwareCodec> typeAwarecodec = TypeDefinitionAwareCodec .from(type); @@ -68,7 +107,7 @@ public class RestCodec { logger.error( "ClassCastException was thrown when codec is invoked with parameter " + String.valueOf(input), e); - return input; + return null; } } @@ -80,6 +119,8 @@ public class RestCodec { return identityrefCodec.serialize(input); } else if (type instanceof LeafrefTypeDefinition) { return LEAFREF_DEFAULT_CODEC.serialize(input); + } else if (type instanceof InstanceIdentifierTypeDefinition) { + return instanceIdentifier.serialize(input); } else { TypeDefinitionAwareCodec> typeAwarecodec = TypeDefinitionAwareCodec .from(type); @@ -104,12 +145,14 @@ public class RestCodec { public static class IdentityrefCodecImpl implements IdentityrefCodec { + private final Logger logger = LoggerFactory.getLogger(IdentityrefCodecImpl.class); + private final MountInstance mountPoint; - + public IdentityrefCodecImpl(MountInstance mountPoint) { this.mountPoint = mountPoint; } - + @Override public IdentityValuesDTO serialize(QName data) { return new IdentityValuesDTO(data.getNamespace().toString(), data.getLocalName(), data.getPrefix()); @@ -118,19 +161,16 @@ public class RestCodec { @Override public QName deserialize(IdentityValuesDTO data) { IdentityValue valueWithNamespace = data.getValuesWithNamespaces().get(0); - String namespace = valueWithNamespace.getNamespace(); - URI validNamespace; - if (mountPoint != null) { - validNamespace = ControllerContext.getInstance().findNamespaceByModuleName(mountPoint, namespace); - } else { - validNamespace = ControllerContext.getInstance().findNamespaceByModuleName(namespace); + Module module = getModuleByNamespace(valueWithNamespace.getNamespace(), mountPoint); + if (module == null) { + logger.info("Module was not found for namespace {}", valueWithNamespace.getNamespace()); + logger.info("Idenetityref will be translated as NULL for data - {}", String.valueOf(valueWithNamespace)); + return null; } - if (validNamespace == null) { - validNamespace = URI.create(namespace); - } - return QName.create(validNamespace, null, valueWithNamespace.getValue()); + + return QName.create(module.getNamespace(), module.getRevision(), valueWithNamespace.getValue()); } - + } public static class LeafrefCodecImpl implements LeafrefCodec { @@ -147,4 +187,142 @@ public class RestCodec { } + public static class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec { + private final Logger logger = LoggerFactory.getLogger(InstanceIdentifierCodecImpl.class); + private final MountInstance mountPoint; + + public InstanceIdentifierCodecImpl(MountInstance mountPoint) { + this.mountPoint = mountPoint; + } + + @Override + public IdentityValuesDTO serialize(InstanceIdentifier data) { + List pathArguments = data.getPath(); + IdentityValuesDTO identityValuesDTO = new IdentityValuesDTO(); + for (PathArgument pathArgument : pathArguments) { + IdentityValue identityValue = qNameToIdentityValue(pathArgument.getNodeType()); + if (pathArgument instanceof NodeIdentifierWithPredicates && identityValue != null) { + List predicates = keyValuesToPredicateList(((NodeIdentifierWithPredicates) pathArgument) + .getKeyValues()); + identityValue.setPredicates(predicates); + } + identityValuesDTO.add(identityValue); + } + return identityValuesDTO; + } + + @Override + public InstanceIdentifier deserialize(IdentityValuesDTO data) { + List result = new ArrayList(); + IdentityValue valueWithNamespace = data.getValuesWithNamespaces().get(0); + Module module = getModuleByNamespace(valueWithNamespace.getNamespace(), mountPoint); + if (module == null) { + logger.info("Module by namespace '{}' of first node in instance-identiefier was not found.", valueWithNamespace.getNamespace()); + logger.info("Instance-identifier will be translated as NULL for data - {}", String.valueOf(valueWithNamespace.getValue())); + return null; + } + + DataNodeContainer parentContainer = module; + List identities = data.getValuesWithNamespaces(); + for (int i = 0; i < identities.size(); i++) { + IdentityValue identityValue = identities.get(i); + URI validNamespace = resolveValidNamespace(identityValue.getNamespace(), mountPoint); + DataSchemaNode node = ControllerContext.getInstance().findInstanceDataChildByNameAndNamespace( + parentContainer, identityValue.getValue(), validNamespace); + if (node == null) { + logger.info("'{}' node was not found in {}", identityValue, parentContainer.getChildNodes()); + logger.info("Instance-identifier will be translated as NULL for data - {}", String.valueOf(identityValue.getValue())); + return null; + } + QName qName = node.getQName(); + PathArgument pathArgument = null; + if (identityValue.getPredicates().isEmpty()) { + pathArgument = new NodeIdentifier(qName); + } else { + if (node instanceof LeafListSchemaNode) { // predicate is value of leaf-list entry + Predicate leafListPredicate = identityValue.getPredicates().get(0); + if (!leafListPredicate.isLeafList()) { + logger.info("Predicate's data is not type of leaf-list. It should be in format \".='value'\""); + logger.info("Instance-identifier will be translated as NULL for data - {}", String.valueOf(identityValue.getValue())); + return null; + } + pathArgument = new NodeWithValue(qName, leafListPredicate.getValue()); + } else if (node instanceof ListSchemaNode) { // predicates are keys of list + DataNodeContainer listNode = (DataNodeContainer) node; + Map predicatesMap = new HashMap<>(); + for (Predicate predicate : identityValue.getPredicates()) { + validNamespace = resolveValidNamespace(predicate.getName().getNamespace(), mountPoint); + DataSchemaNode listKey = ControllerContext.getInstance().findInstanceDataChildByNameAndNamespace( + listNode, predicate.getName().getValue(), validNamespace); + predicatesMap.put(listKey.getQName(), predicate.getValue()); + } + pathArgument = new NodeIdentifierWithPredicates(qName, predicatesMap); + } else { + logger.info("Node {} is not List or Leaf-list.", node); + logger.info("Instance-identifier will be translated as NULL for data - {}", String.valueOf(identityValue.getValue())); + return null; + } + } + result.add(pathArgument); + if (i < identities.size() - 1) { // last element in instance-identifier can be other than DataNodeContainer + if (node instanceof DataNodeContainer) { + parentContainer = (DataNodeContainer) node; + } else { + logger.info("Node {} isn't instance of DataNodeContainer", node); + logger.info("Instance-identifier will be translated as NULL for data - {}", String.valueOf(identityValue.getValue())); + return null; + } + } + } + + return result.isEmpty() ? null : new InstanceIdentifier(result); + } + + private List keyValuesToPredicateList(Map keyValues) { + List result = new ArrayList<>(); + for (QName qName : keyValues.keySet()) { + Object value = keyValues.get(qName); + result.add(new Predicate(qNameToIdentityValue(qName), String.valueOf(value))); + } + return result; + } + + private IdentityValue qNameToIdentityValue(QName qName) { + if (qName != null) { + return new IdentityValue(qName.getNamespace().toString(), qName.getLocalName(), qName.getPrefix()); + } + return null; + } + } + + private static Module getModuleByNamespace(String namespace, MountInstance mountPoint) { + URI validNamespace = resolveValidNamespace(namespace, mountPoint); + + Module module = null; + if (mountPoint != null) { + module = ControllerContext.getInstance().findModuleByNamespace(mountPoint, validNamespace); + } else { + module = ControllerContext.getInstance().findModuleByNamespace(validNamespace); + } + if (module == null) { + logger.info("Module for namespace " + validNamespace + " wasn't found."); + return null; + } + return module; + } + + private static URI resolveValidNamespace(String namespace, MountInstance mountPoint) { + URI validNamespace; + if (mountPoint != null) { + validNamespace = ControllerContext.getInstance().findNamespaceByModuleName(mountPoint, namespace); + } else { + validNamespace = ControllerContext.getInstance().findNamespaceByModuleName(namespace); + } + if (validNamespace == null) { + validNamespace = URI.create(namespace); + } + + return validNamespace; + } + } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend index b134f9bf6b..db2342a35d 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend @@ -5,7 +5,6 @@ import java.net.URI import java.util.ArrayList import java.util.HashMap import java.util.List -import java.util.Set import javax.ws.rs.core.Response import org.opendaylight.controller.md.sal.common.api.TransactionStatus import org.opendaylight.controller.sal.core.api.mount.MountInstance @@ -17,7 +16,6 @@ import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.InstanceIdentifierBuilder import org.opendaylight.yangtools.yang.data.api.Node import org.opendaylight.yangtools.yang.data.impl.NodeFactory -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 @@ -26,11 +24,11 @@ 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.RpcDefinition +import org.opendaylight.yangtools.yang.model.api.SchemaContext import org.opendaylight.yangtools.yang.model.api.TypeDefinition import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition import static javax.ws.rs.core.Response.Status.* -import org.opendaylight.yangtools.yang.model.api.SchemaContext class RestconfImpl implements RestconfService { @@ -54,7 +52,8 @@ class RestconfImpl implements RestconfService { } override readAllData() { -// return broker.readOperationalData("".toInstanceIdentifier.getInstanceIdentifier); + + // return broker.readOperationalData("".toInstanceIdentifier.getInstanceIdentifier); throw new UnsupportedOperationException("Reading all data is currently not supported.") } @@ -69,11 +68,11 @@ class RestconfImpl implements RestconfService { override invokeRpc(String identifier, CompositeNode payload) { return callRpc(identifier.rpcDefinition, payload) } - + override invokeRpc(String identifier) { return callRpc(identifier.rpcDefinition, null) } - + private def StructuredData callRpc(RpcDefinition rpc, CompositeNode payload) { if (rpc === null) { throw new ResponseException(NOT_FOUND, "RPC does not exist."); @@ -164,7 +163,7 @@ class RestconfImpl implements RestconfService { if (payload.representsMountPointRootData) { // payload represents mount point data and URI represents path to the mount point if (identifier.endsWithMountPoint) { throw new ResponseException(BAD_REQUEST, - "URI has bad format. URI should be without \"" + ControllerContext.MOUNT + "\" for POST operation."); + "URI has bad format. URI should be without \"" + ControllerContext.MOUNT + "\" for POST operation."); } val completIdentifier = identifier.addMountPointIdentifier iiWithData = completIdentifier.toInstanceIdentifier @@ -172,8 +171,11 @@ class RestconfImpl implements RestconfService { } else { val uncompleteInstIdWithData = identifier.toInstanceIdentifier val parentSchema = uncompleteInstIdWithData.schemaNode as DataNodeContainer - val namespace = uncompleteInstIdWithData.mountPoint.findModule(payload)?.namespace - val schemaNode = parentSchema.findInstanceDataChild(payload.name, namespace) + val module = uncompleteInstIdWithData.mountPoint.findModule(payload) + if (module === null) { + throw new ResponseException(BAD_REQUEST, "Module was not found for \"" + payload.namespace + "\"") + } + val schemaNode = parentSchema.findInstanceDataChildByNameAndNamespace(payload.name, module.namespace) value = normalizeNode(payload, schemaNode, uncompleteInstIdWithData.mountPoint) iiWithData = uncompleteInstIdWithData.addLastIdentifierFromData(value, schemaNode) } @@ -192,7 +194,7 @@ class RestconfImpl implements RestconfService { default: Response.status(INTERNAL_SERVER_ERROR).build } } - + override createConfigurationData(CompositeNode payload) { if (payload.namespace === null) { throw new ResponseException(BAD_REQUEST, @@ -203,7 +205,7 @@ class RestconfImpl implements RestconfService { throw new ResponseException(BAD_REQUEST, "Data has bad format. Root element node has incorrect namespace (XML format) or module name(JSON format)"); } - val schemaNode = module.findInstanceDataChild(payload.name, module.namespace) + val schemaNode = module.findInstanceDataChildByNameAndNamespace(payload.name, module.namespace) val value = normalizeNode(payload, schemaNode, null) val iiWithData = addLastIdentifierFromData(null, value, schemaNode) var RpcResult status = null @@ -221,7 +223,7 @@ class RestconfImpl implements RestconfService { default: Response.status(INTERNAL_SERVER_ERROR).build } } - + override deleteConfigurationData(String identifier) { val iiWithData = identifier.toInstanceIdentifier var RpcResult status = null @@ -236,19 +238,19 @@ class RestconfImpl implements RestconfService { default: Response.status(INTERNAL_SERVER_ERROR).build } } - + private def dispatch URI namespace(CompositeNode data) { return data.nodeType.namespace } - + private def dispatch URI namespace(CompositeNodeWrapper data) { return data.namespace } - + private def dispatch String localName(CompositeNode data) { return data.nodeType.localName } - + private def dispatch String localName(CompositeNodeWrapper data) { return data.localName } @@ -277,15 +279,15 @@ class RestconfImpl implements RestconfService { } return module } - + private def dispatch getName(CompositeNode data) { return data.nodeType.localName } - + private def dispatch getName(CompositeNodeWrapper data) { return data.localName } - + private def InstanceIdWithSchemaNode addLastIdentifierFromData(InstanceIdWithSchemaNode identifierWithSchemaNode, CompositeNode data, DataSchemaNode schemaOfData) { val iiOriginal = identifierWithSchemaNode?.instanceIdentifier @@ -317,26 +319,27 @@ class RestconfImpl implements RestconfService { } return keyValues } - + private def endsWithMountPoint(String identifier) { return (identifier.endsWith(ControllerContext.MOUNT) || identifier.endsWith(ControllerContext.MOUNT + "/")) } - + private def representsMountPointRootData(CompositeNode data) { return ((data.namespace == SchemaContext.NAME.namespace || data.namespace == MOUNT_POINT_MODULE_NAME) && data.localName == SchemaContext.NAME.localName) } - + private def addMountPointIdentifier(String identifier) { if (identifier.endsWith("/")) { return identifier + ControllerContext.MOUNT } return identifier + "/" + ControllerContext.MOUNT } - + private def CompositeNode normalizeNode(CompositeNode node, DataSchemaNode schema, MountInstance mountPoint) { if (schema === null) { - throw new ResponseException(INTERNAL_SERVER_ERROR, "Data schema node was not found for " + node?.nodeType?.localName) + throw new ResponseException(INTERNAL_SERVER_ERROR, + "Data schema node was not found for " + node?.nodeType?.localName) } if (!(schema instanceof DataNodeContainer)) { throw new ResponseException(BAD_REQUEST, "Root element has to be container or list yang datatype."); @@ -349,44 +352,59 @@ class RestconfImpl implements RestconfService { } return node } - + private def void normalizeNode(NodeWrapper nodeBuilder, DataSchemaNode schema, QName previousAugment, MountInstance mountPoint) { if (schema === null) { throw new ResponseException(BAD_REQUEST, "Data has bad format.\n\"" + nodeBuilder.localName + "\" does not exist in yang schema."); } - var validQName = schema.QName - var currentAugment = previousAugment; - if (schema.augmenting) { - currentAugment = schema.QName - } else if (previousAugment !== null && schema.QName.namespace !== previousAugment.namespace) { - validQName = QName.create(currentAugment, schema.QName.localName); - } - var String moduleName = null; - if (mountPoint === null) { - moduleName = controllerContext.findModuleNameByNamespace(validQName.namespace); - } else { - moduleName = controllerContext.findModuleNameByNamespace(mountPoint, validQName.namespace) - } - if (nodeBuilder.namespace === null || nodeBuilder.namespace == validQName.namespace || - nodeBuilder.namespace.toString == moduleName || nodeBuilder.namespace == MOUNT_POINT_MODULE_NAME) { - nodeBuilder.qname = validQName + + var QName currentAugment; + if (nodeBuilder.qname !== null) { + currentAugment = previousAugment } else { - throw new ResponseException(BAD_REQUEST, - "Data has bad format.\nIf data is in XML format then namespace for \"" + nodeBuilder.localName + - "\" should be \"" + schema.QName.namespace + "\".\nIf data is in Json format then module name for \"" + - nodeBuilder.localName + "\" should be \"" + moduleName + "\"."); + currentAugment = normalizeNodeName(nodeBuilder, schema, previousAugment, mountPoint) + if (nodeBuilder.qname === null) { + throw new ResponseException(BAD_REQUEST, + "Data has bad format.\nIf data is in XML format then namespace for \"" + nodeBuilder.localName + + "\" should be \"" + schema.QName.namespace + "\".\n" + + "If data is in JSON format then module name for \"" + nodeBuilder.localName + + "\" should be corresponding to namespace \"" + schema.QName.namespace + "\"."); + } } if (nodeBuilder instanceof CompositeNodeWrapper) { val List> children = (nodeBuilder as CompositeNodeWrapper).getValues for (child : children) { - normalizeNode(child, - findFirstSchemaByLocalName(child.localName, (schema as DataNodeContainer).childNodes), - currentAugment, mountPoint) + val potentialSchemaNodes = (schema as DataNodeContainer).findInstanceDataChildrenByName(child.localName) + if (potentialSchemaNodes.size > 1 && child.namespace === null) { + val StringBuilder namespacesOfPotentialModules = new StringBuilder; + for (potentialSchemaNode : potentialSchemaNodes) { + namespacesOfPotentialModules.append(" ").append(potentialSchemaNode.QName.namespace.toString).append("\n") + } + throw new ResponseException(BAD_REQUEST, + "Node \"" + child.localName + "\" is added as augment from more than one module. " + + "Therefore node must have namespace (XML format) or module name (JSON format)." + + "\nThe node is added as augment from modules with namespaces:\n" + namespacesOfPotentialModules) + } + var rightNodeSchemaFound = false + for (potentialSchemaNode : potentialSchemaNodes) { + if (!rightNodeSchemaFound) { + val potentialCurrentAugment = normalizeNodeName(child, potentialSchemaNode, currentAugment, + mountPoint) + if (child.qname !== null) { + normalizeNode(child, potentialSchemaNode, potentialCurrentAugment, mountPoint) + rightNodeSchemaFound = true + } + } + } + if (!rightNodeSchemaFound) { + throw new ResponseException(BAD_REQUEST, + "Schema node \"" + child.localName + "\" was not found in module.") + } } - if(schema instanceof ListSchemaNode) { + if (schema instanceof ListSchemaNode) { val listKeys = (schema as ListSchemaNode).keyDefinition for (listKey : listKeys) { var foundKey = false @@ -397,7 +415,8 @@ class RestconfImpl implements RestconfService { } if (!foundKey) { throw new ResponseException(BAD_REQUEST, - "Missing key in URI \"" + listKey.localName + "\" of list \"" + schema.QName.localName + "\"") + "Missing key in URI \"" + listKey.localName + "\" of list \"" + schema.QName.localName + + "\"") } } } @@ -405,11 +424,11 @@ class RestconfImpl implements RestconfService { val simpleNode = (nodeBuilder as SimpleNodeWrapper) val value = simpleNode.value var inputValue = value; - + if (schema.typeDefinition instanceof IdentityrefTypeDefinition) { if (value instanceof String) { - inputValue = new IdentityValuesDTO(validQName.namespace.toString, value as String, null) - } // else value is instance of ValuesDTO + inputValue = new IdentityValuesDTO(nodeBuilder.namespace.toString, value as String, null) + } // else value is already instance of IdentityValuesDTO } val outputValue = RestCodec.from(schema.typeDefinition, mountPoint)?.deserialize(inputValue); @@ -441,25 +460,27 @@ class RestconfImpl implements RestconfService { } baseType } - - private def DataSchemaNode findFirstSchemaByLocalName(String localName, Set schemas) { - for (schema : schemas) { - if (schema instanceof ChoiceNode) { - for (caze : (schema as ChoiceNode).cases) { - val result = findFirstSchemaByLocalName(localName, caze.childNodes) - if (result !== null) { - return result - } - } - } else { - val result = schemas.findFirst[n|n.QName.localName.equals(localName)] - if (result !== null) { - return result; - - } - } + + private def QName normalizeNodeName(NodeWrapper nodeBuilder, DataSchemaNode schema, QName previousAugment, + MountInstance mountPoint) { + var validQName = schema.QName + var currentAugment = previousAugment; + if (schema.augmenting) { + currentAugment = schema.QName + } else if (previousAugment !== null && schema.QName.namespace !== previousAugment.namespace) { + validQName = QName.create(currentAugment, schema.QName.localName); + } + var String moduleName = null; + if (mountPoint === null) { + moduleName = controllerContext.findModuleNameByNamespace(validQName.namespace); + } else { + moduleName = controllerContext.findModuleNameByNamespace(mountPoint, validQName.namespace) + } + if (nodeBuilder.namespace === null || nodeBuilder.namespace == validQName.namespace || + nodeBuilder.namespace.toString == moduleName || nodeBuilder.namespace == MOUNT_POINT_MODULE_NAME) { + nodeBuilder.qname = validQName } - return null + return currentAugment } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/SimpleNodeWrapper.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/SimpleNodeWrapper.java index 6aa8ada5ee..b0a215f90b 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/SimpleNodeWrapper.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/SimpleNodeWrapper.java @@ -36,6 +36,11 @@ public final class SimpleNodeWrapper implements NodeWrapper>, Simp this.name = name; } + @Override + public QName getQname() { + return name; + } + @Override public String getLocalName() { if (simpleNode != null) { diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/iml/varioustests/VariousTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/iml/varioustests/VariousTest.java new file mode 100644 index 0000000000..04f2331ca3 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/iml/varioustests/VariousTest.java @@ -0,0 +1,37 @@ +package org.opendaylight.controller.sal.restconf.iml.varioustests; + +import org.junit.Ignore; +import org.junit.Test; +import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; +import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.w3c.dom.Document; + + +public class VariousTest { + + @Ignore + @Test + public void test() { + String[] split = "/something:dfsa/s:sda".split("/"); + System.out.println(split.length); + for (String str : split) { + System.out.println(">"+str+"<"); + } + + } + + @Test + public void loadXml() { + TestUtils.readInputToCnSn("/varioustest/xmldata.xml", XmlToCompositeNodeProvider.INSTANCE); +// TestUtils.normalizeCompositeNode(compositeNode, modules, schemaNodePath) + } + + @Test + public void buildXml() { +// Document doc; +// doc.createElementNS(namespaceURI, qualifiedName) + } + + +} diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnInstanceIdentifierToXmlTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnInstanceIdentifierToXmlTest.java new file mode 100644 index 0000000000..d1bcf9b5f5 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnInstanceIdentifierToXmlTest.java @@ -0,0 +1,54 @@ +package org.opendaylight.controller.sal.restconf.impl.cnsn.to.xml.test; + +import static org.junit.Assert.assertNotNull; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; + +import javax.ws.rs.WebApplicationException; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider; +import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper; +import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper; +import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; +import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; + +/** + * + * CnSn = Composite node and Simple node data structure Class contains test of + * serializing simple nodes data values according data types from YANG schema to + * XML file + * + */ +public class CnSnInstanceIdentifierToXmlTest extends YangAndXmlAndDataSchemaLoader { + + @BeforeClass + public static void initialization() throws URISyntaxException { + dataLoad("/instanceidentifier/yang", 3, "instance-identifier-module", "cont"); + } + + @Test + public void snAsYangInstanceIdentifier() throws WebApplicationException, IOException, URISyntaxException { + CompositeNode cnSnData = prepareCnStructForYangData( ); + String xmlOutput = TestUtils.writeCompNodeWithSchemaContextToOutput(cnSnData, modules, dataSchemaNode, + StructuredDataToXmlProvider.INSTANCE); + assertNotNull(xmlOutput); + } + + private CompositeNode prepareCnStructForYangData() throws URISyntaxException { + CompositeNodeWrapper cont = new CompositeNodeWrapper(new URI("instance:identifier:module"), "cont"); + CompositeNodeWrapper cont1 = new CompositeNodeWrapper(new URI("augment:module"), "cont1"); + cont.addValue(cont1); + SimpleNodeWrapper lf11 = new SimpleNodeWrapper(new URI("augment:augment:module"), "lf11", "/cont/cont1/lf12"); + SimpleNodeWrapper lf12 = new SimpleNodeWrapper(new URI("augment:augment:module"), "lf12", "lf12 value"); + cont1.addValue(lf11); + cont1.addValue(lf12); + cont.unwrap(); + return cont; + } + +} diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnToXmlTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnToXmlTest.java index 96e03a5a3c..af54c7de91 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnToXmlTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnToXmlTest.java @@ -13,7 +13,10 @@ import org.junit.Test; import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider; import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader; -import org.opendaylight.yangtools.yang.data.api.*; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.ModifyAction; +import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode; +import org.opendaylight.yangtools.yang.data.api.MutableSimpleNode; import org.opendaylight.yangtools.yang.data.impl.NodeFactory; import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec; @@ -51,6 +54,7 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader { serializeToXml(prepareLeafrefData(), "true", "true"); } + @Test public void snAsYangStringToXmlTest() { serializeToXml( diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CnSnToXmlAndJsonInstanceIdentifierTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CnSnToXmlAndJsonInstanceIdentifierTest.java new file mode 100644 index 0000000000..80cfb17026 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CnSnToXmlAndJsonInstanceIdentifierTest.java @@ -0,0 +1,136 @@ +package org.opendaylight.controller.sal.restconf.impl.test; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.ws.rs.WebApplicationException; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider; +import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider; +import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper; +import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper; +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.NodeIdentifierWithPredicates; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; + +public class CnSnToXmlAndJsonInstanceIdentifierTest extends YangAndXmlAndDataSchemaLoader { + + @BeforeClass + public static void initialize() { + dataLoad("/instanceidentifier/yang", 3, "instance-identifier-module", "cont"); + } + + @Test + public void saveCnSnToXml() throws WebApplicationException, IOException, URISyntaxException, XMLStreamException { + CompositeNode cnSn = prepareCnSn(); + String output = TestUtils.writeCompNodeWithSchemaContextToOutput(cnSn, modules, dataSchemaNode, + StructuredDataToXmlProvider.INSTANCE); + validateXmlOutput(output); + // System.out.println(output); + + } + + @Test + public void saveCnSnToJson() throws WebApplicationException, IOException, URISyntaxException { + CompositeNode cnSn = prepareCnSn(); + String output = TestUtils.writeCompNodeWithSchemaContextToOutput(cnSn, modules, dataSchemaNode, + StructuredDataToJsonProvider.INSTANCE); + assertTrue(output + .contains("\"augment-augment-module:lf111\": \"/instance-identifier-module:cont/instance-identifier-module:cont1/augment-module:lst11[augment-module:keyvalue111=\\\"value1\\\"][augment-module:keyvalue112=\\\"value2\\\"]/augment-augment-module:lf112\"")); + // System.out.println(output); + } + + private void validateXmlOutput(String xml) throws XMLStreamException { + XMLInputFactory xmlInFactory = XMLInputFactory.newInstance(); + XMLEventReader eventReader; + + eventReader = xmlInFactory.createXMLEventReader(new ByteArrayInputStream(xml.getBytes())); + String aaModulePrefix = null; + String aModulePrefix = null; + String iiModulePrefix = null; + while (eventReader.hasNext()) { + XMLEvent nextEvent = eventReader.nextEvent(); + if (nextEvent.isStartElement()) { + StartElement startElement = (StartElement) nextEvent; + if (startElement.getName().getLocalPart().equals("lf111")) { + Iterator prefixes = startElement.getNamespaceContext().getPrefixes("augment:augment:module"); + + while (prefixes.hasNext() && aaModulePrefix == null) { + String prefix = (String) prefixes.next(); + if (!prefix.isEmpty()) { + aaModulePrefix = prefix; + } + } + + aModulePrefix = startElement.getNamespaceContext().getPrefix("augment:module"); + iiModulePrefix = startElement.getNamespaceContext().getPrefix("instance:identifier:module"); + break; + } + } + } + + assertNotNull(aaModulePrefix); + assertNotNull(aModulePrefix); + assertNotNull(iiModulePrefix); + + String instanceIdentifierValue = "/" + iiModulePrefix + ":cont/" + iiModulePrefix + ":cont1/" + aModulePrefix + + ":lst11[" + aModulePrefix + ":keyvalue111='value1'][" + aModulePrefix + ":keyvalue112='value2']/" + + aaModulePrefix + ":lf112"; + +// System.out.println(xml); + assertTrue(xml.contains(instanceIdentifierValue)); + + } + + private CompositeNode prepareCnSn() throws URISyntaxException { + CompositeNodeWrapper cont = new CompositeNodeWrapper(new URI("instance:identifier:module"), "cont"); + CompositeNodeWrapper cont1 = new CompositeNodeWrapper(new URI("instance:identifier:module"), "cont1"); + CompositeNodeWrapper lst11 = new CompositeNodeWrapper(new URI("augment:module"), "lst11"); + InstanceIdentifier instanceIdentifier = createInstanceIdentifier(); + SimpleNodeWrapper lf111 = new SimpleNodeWrapper(new URI("augment:augment:module"), "lf111", instanceIdentifier); + + lst11.addValue(lf111); + cont1.addValue(lst11); + cont.addValue(cont1); + + return cont; + } + + private InstanceIdentifier createInstanceIdentifier() throws URISyntaxException { + List pathArguments = new ArrayList<>(); + pathArguments.add(new NodeIdentifier(new QName(new URI("instance:identifier:module"), "cont"))); + pathArguments.add(new NodeIdentifier(new QName(new URI("instance:identifier:module"), "cont1"))); + + QName qName = new QName(new URI("augment:module"), "lst11"); + Map keyValues = new HashMap<>(); + keyValues.put(new QName(new URI("augment:module"), "keyvalue111"), "value1"); + keyValues.put(new QName(new URI("augment:module"), "keyvalue112"), "value2"); + NodeIdentifierWithPredicates nodeIdentifierWithPredicates = new NodeIdentifierWithPredicates(qName, keyValues); + pathArguments.add(nodeIdentifierWithPredicates); + + pathArguments.add(new NodeIdentifier(new QName(new URI("augment:augment:module"), "lf112"))); + + return new InstanceIdentifier(pathArguments); + } + +} diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestCodecExceptionsTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestCodecExceptionsTest.java index 36da6d669a..2b6efbdc4d 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestCodecExceptionsTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestCodecExceptionsTest.java @@ -1,6 +1,6 @@ package org.opendaylight.controller.sal.restconf.impl.test; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; import static org.mockito.Mockito.mock; import org.junit.Test; @@ -24,10 +24,7 @@ public class RestCodecExceptionsTest { IdentityrefTypeDefinition mockedIidentityrefType = mock(IdentityrefTypeDefinition.class); Codec codec = RestCodec.from(mockedIidentityrefType, null); - String serializedValue = (String) codec.deserialize("incorrect value"); // IdentityValuesDTO - // object - // expected - assertEquals("incorrect value", serializedValue); + assertNull(codec.deserialize("incorrect value")); } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetAugmentedElementWhenEqualNamesTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetAugmentedElementWhenEqualNamesTest.java index 5650be57ce..94791cfe8d 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetAugmentedElementWhenEqualNamesTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetAugmentedElementWhenEqualNamesTest.java @@ -1,45 +1,50 @@ package org.opendaylight.controller.sal.restconf.impl.test; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import java.io.FileNotFoundException; -import java.io.UnsupportedEncodingException; -import java.net.URISyntaxException; -import org.junit.Ignore; +import org.junit.BeforeClass; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; import org.opendaylight.controller.sal.restconf.impl.InstanceIdWithSchemaNode; import org.opendaylight.controller.sal.restconf.impl.ResponseException; import org.opendaylight.yangtools.yang.model.api.SchemaContext; public class RestGetAugmentedElementWhenEqualNamesTest { - - @Ignore - @Test - public void getDataWithUrlMountPoint() throws UnsupportedEncodingException, URISyntaxException, - FileNotFoundException { - boolean exceptionCaught = false; - + + private static ControllerContext controllerContext = ControllerContext.getInstance(); + + @Rule + public ExpectedException exception = ExpectedException.none(); + + @BeforeClass + public static void init() throws FileNotFoundException { SchemaContext schemaContextTestModule = TestUtils.loadSchemaContext("/common/augment/yang"); - ControllerContext controllerContext = ControllerContext.getInstance(); controllerContext.setSchemas(schemaContextTestModule); + } + @Test + public void augmentedNodesInUri() { + InstanceIdWithSchemaNode iiWithData = controllerContext.toInstanceIdentifier("main:cont/augment-main-a:cont1"); + assertEquals("ns:augment:main:a", iiWithData.getSchemaNode().getQName().getNamespace().toString()); + iiWithData = controllerContext.toInstanceIdentifier("main:cont/augment-main-b:cont1"); + assertEquals("ns:augment:main:b", iiWithData.getSchemaNode().getQName().getNamespace().toString()); + } + + @Test + public void nodeWithoutNamespaceHasMoreAugments() { + boolean exceptionCaught = false; try { - InstanceIdWithSchemaNode instanceIdentifierA = controllerContext - .toInstanceIdentifier("main:cont/augment-main-a:cont1"); - InstanceIdWithSchemaNode instanceIdentifierB = controllerContext - .toInstanceIdentifier("main:cont/augment-main-b:cont1"); - - assertEquals("ns:augment:main:a", instanceIdentifierA.getSchemaNode().getQName().getNamespace().toString()); - assertEquals("ns:augment:main:b", instanceIdentifierB.getSchemaNode().getQName().getNamespace()); + controllerContext.toInstanceIdentifier("main:cont/cont1"); } catch (ResponseException e) { + assertTrue(((String) e.getResponse().getEntity()).contains("is added as augment from more than one module")); exceptionCaught = true; } - - assertFalse(exceptionCaught); - + assertTrue(exceptionCaught); } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URITest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URITest.java index 4e2f525d45..d7522706fd 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URITest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URITest.java @@ -47,8 +47,8 @@ public class URITest { .toInstanceIdentifier("simple-nodes:userWithoutClass/foo"); assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "userWithoutClass"); - instanceIdentifier = controllerContext.toInstanceIdentifier("simple-nodes:userWithoutClass/foo/full-name"); - assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "full-name"); + instanceIdentifier = controllerContext.toInstanceIdentifier("simple-nodes:userWithoutClass/foo"); + assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "userWithoutClass"); instanceIdentifier = controllerContext.toInstanceIdentifier("simple-nodes:user/foo/boo"); assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "user"); @@ -56,8 +56,6 @@ public class URITest { instanceIdentifier = controllerContext.toInstanceIdentifier("simple-nodes:user//boo"); assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "user"); - instanceIdentifier = controllerContext.toInstanceIdentifier("simple-nodes:users/user/foo"); - assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "user"); } @Test @@ -85,8 +83,8 @@ public class URITest { @Test public void testToInstanceIdentifierChoice() throws FileNotFoundException { InstanceIdWithSchemaNode instanceIdentifier = controllerContext - .toInstanceIdentifier("simple-nodes:food/nonalcoholic/beer"); - assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "beer"); + .toInstanceIdentifier("simple-nodes:food/nonalcoholic"); + assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "nonalcoholic"); } @Test diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnInstanceIdentifierTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnInstanceIdentifierTest.java new file mode 100644 index 0000000000..1608efbdf8 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnInstanceIdentifierTest.java @@ -0,0 +1,85 @@ +package org.opendaylight.controller.sal.restconf.impl.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; +import java.util.Map; + +import javax.ws.rs.WebApplicationException; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.opendaylight.controller.sal.rest.impl.JsonToCompositeNodeProvider; +import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; +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.NodeIdentifierWithPredicates; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.data.api.SimpleNode; + +public class XmlAndJsonToCnSnInstanceIdentifierTest extends YangAndXmlAndDataSchemaLoader { + + @BeforeClass + public static void initialize() { + dataLoad("/instanceidentifier/yang", 3, "instance-identifier-module", "cont"); + } + + @Test + public void loadXmlToCnSn() throws WebApplicationException, IOException, URISyntaxException { + CompositeNode cnSn = TestUtils.readInputToCnSn("/instanceidentifier/xml/xmldata.xml", + XmlToCompositeNodeProvider.INSTANCE); + TestUtils.normalizeCompositeNode(cnSn, modules, schemaNodePath); + verify(cnSn); + } + + @Test + public void loadJsonToCnSn() throws WebApplicationException, IOException, URISyntaxException { + CompositeNode cnSn = TestUtils.readInputToCnSn("/instanceidentifier/json/jsondata.json", + JsonToCompositeNodeProvider.INSTANCE); + TestUtils.normalizeCompositeNode(cnSn, modules, schemaNodePath); + verify(cnSn); + } + + private void verify(CompositeNode cnSn) throws URISyntaxException { + SimpleNode lf111 = getSnWithInstanceIdentifier(cnSn); + Object value = lf111.getValue(); + assertTrue(value instanceof InstanceIdentifier); + + InstanceIdentifier instanceIdentifier = (InstanceIdentifier) value; + List pathArguments = instanceIdentifier.getPath(); + assertEquals(4, pathArguments.size()); + String revisionDate = "2014-01-17"; + assertEquals(TestUtils.buildQName("cont", "instance:identifier:module", revisionDate), pathArguments.get(0) + .getNodeType()); + assertEquals(TestUtils.buildQName("cont1", "instance:identifier:module", revisionDate), pathArguments.get(1) + .getNodeType()); + assertEquals(TestUtils.buildQName("lst11", "augment:module", revisionDate), pathArguments.get(2).getNodeType()); + assertEquals(TestUtils.buildQName("lf112", "augment:augment:module", revisionDate), pathArguments.get(3) + .getNodeType()); + + assertTrue(pathArguments.get(2) instanceof NodeIdentifierWithPredicates); + Map predicates = ((NodeIdentifierWithPredicates) pathArguments.get(2)).getKeyValues(); + assertEquals(2, predicates.size()); + assertEquals("value1", predicates.get(TestUtils.buildQName("keyvalue111", "augment:module", revisionDate))); + assertEquals("value2", predicates.get(TestUtils.buildQName("keyvalue112", "augment:module", revisionDate))); + } + + private SimpleNode getSnWithInstanceIdentifier(CompositeNode cnSn) throws URISyntaxException { + CompositeNode cont1 = cnSn.getFirstCompositeByName(TestUtils.buildQName("cont1", "instance:identifier:module", + "2014-01-17")); + assertNotNull(cont1); + CompositeNode lst11 = cont1.getFirstCompositeByName(TestUtils.buildQName("lst11", "augment:module", + "2014-01-17")); + assertNotNull(lst11); + SimpleNode lf111 = lst11.getFirstSimpleByName(TestUtils.buildQName("lf111", "augment:augment:module", + "2014-01-17")); + assertNotNull(lf111); + return lf111; + } + +} diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlAugmentedElementToCnSnTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlAugmentedElementToCnSnTest.java index 421a936d2d..4a4f9f1bbf 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlAugmentedElementToCnSnTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlAugmentedElementToCnSnTest.java @@ -1,35 +1,23 @@ package org.opendaylight.controller.sal.restconf.impl.xml.to.cnsn.test; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import java.util.Set; -import org.junit.Ignore; import org.junit.Test; import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; -import org.opendaylight.controller.sal.restconf.impl.ResponseException; import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.model.api.Module; public class XmlAugmentedElementToCnSnTest { - @Ignore @Test public void loadDataAugmentedSchemaMoreEqualNamesTest() { - boolean exceptionCaught = false; - try { - loadAndNormalizeData("/common/augment/xml/dataa.xml", "/common/augment/yang", "main","cont"); - loadAndNormalizeData("/common/augment/xml/datab.xml", "/common/augment/yang", "main","cont"); - } catch (ResponseException e) { - exceptionCaught = true; - } - - assertFalse(exceptionCaught); + loadAndNormalizeData("/common/augment/xml/dataa.xml", "/common/augment/yang", "main","cont"); + loadAndNormalizeData("/common/augment/xml/datab.xml", "/common/augment/yang", "main","cont"); } - private void loadAndNormalizeData(String xmlPath, String yangPath, String topLevelElementName, String moduleName) { CompositeNode compNode = TestUtils.readInputToCnSn(xmlPath, false, XmlToCompositeNodeProvider.INSTANCE); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlLeafrefToCnSnTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlLeafrefToCnSnTest.java index beff5724eb..14818d02cd 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlLeafrefToCnSnTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlLeafrefToCnSnTest.java @@ -1,15 +1,20 @@ package org.opendaylight.controller.sal.restconf.impl.xml.to.cnsn.test; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import java.util.List; import java.util.Set; +import org.junit.Ignore; import org.junit.Test; import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.data.api.*; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.Node; +import org.opendaylight.yangtools.yang.data.api.SimpleNode; import org.opendaylight.yangtools.yang.model.api.Module; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -216,11 +221,11 @@ public class XmlLeafrefToCnSnTest { * Test case like * x:identity */ + @Ignore @Test public void testIdentityrefNmspcInParrentElement() { testIdentityrefToCnSn("/xml-to-cnsn/identityref/xml/data-nmspc-in-parrent-element.xml", "/xml-to-cnsn/identityref", "identityref-module", "cont", 2, "iden", "z:namespace"); - } /** diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-xml/yang/basic-module.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-xml/yang/basic-module.yang index 81d77329c6..020ff8fa50 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-xml/yang/basic-module.yang +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-xml/yang/basic-module.yang @@ -97,6 +97,10 @@ module basic-module { } } + leaf lfInIdentifier { + type instance-identifier; + } + } } \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/json/jsondata.json b/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/json/jsondata.json new file mode 100644 index 0000000000..f616a8a95b --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/json/jsondata.json @@ -0,0 +1,14 @@ +{ + "instance-identifier-module:cont": { + "cont1": { + "augment-module:lst11": [ + { + "keyvalue111":"value1", + "keyvalue112":"value2", + "augment-augment-module:lf111":"/instance-identifier-module:cont/instance-identifier-module:cont1/augment-module:lst11[augment-module:keyvalue111=\"value1\"][augment-module:keyvalue112=\"value2\"]/augment-augment-module:lf112", + "augment-augment-module:lf112":"lf112 value" + } + ] + } + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/xml/xmldata.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/xml/xmldata.xml new file mode 100644 index 0000000000..768cb663eb --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/xml/xmldata.xml @@ -0,0 +1,10 @@ + + + + value1 + value2 + /a:cont/a:cont1/b:lst11[b:keyvalue111="value1"][b:keyvalue112="value2"]/c:lf112 + lf112 value + + + diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/yang/augment-augment-module.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/yang/augment-augment-module.yang new file mode 100644 index 0000000000..546111c3d8 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/yang/augment-augment-module.yang @@ -0,0 +1,21 @@ +module augment-augment-module { + namespace "augment:augment:module"; + + prefix "aamodule"; + + import augment-module {prefix amodule; revision-date 2014-01-17;} + import instance-identifier-module {prefix imodule; revision-date 2014-01-17;} + + revision 2014-01-17 { + } + + augment "/imodule:cont/imodule:cont1/amodule:lst11" { + leaf lf111 { + type instance-identifier; + } + leaf lf112 { + type string; + } + } + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/yang/augment-module.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/yang/augment-module.yang new file mode 100644 index 0000000000..67b0086ee3 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/yang/augment-module.yang @@ -0,0 +1,23 @@ +module augment-module { + namespace "augment:module"; + + prefix "amodule"; + + import instance-identifier-module {prefix imodule; revision-date 2014-01-17;} + + revision 2014-01-17 { + } + + augment "/imodule:cont/imodule:cont1" { + list lst11 { + key "keyvalue111 keyvalue112"; + leaf keyvalue111 { + type string; + } + leaf keyvalue112 { + type string; + } + } + } + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/yang/instance-identifier-module.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/yang/instance-identifier-module.yang new file mode 100644 index 0000000000..7a95a5ff0f --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/yang/instance-identifier-module.yang @@ -0,0 +1,13 @@ +module instance-identifier-module { + namespace "instance:identifier:module"; + + prefix "iimodule"; + revision 2014-01-17 { + } + + container cont { + container cont1 { + } + } + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/varioustest/xmldata.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/varioustest/xmldata.xml new file mode 100644 index 0000000000..5d45980685 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/varioustest/xmldata.xml @@ -0,0 +1,5 @@ + + + /prefix:somepath1/prefix2:somepath2 + + \ No newline at end of file