[ONOS-5884]YANG Serializer: Implement XML serializer.
Change-Id: Idffda88938d9c6c7b7c7814127a340bd2dc35039
diff --git a/model/src/main/java/org/onosproject/yang/model/ResourceId.java b/model/src/main/java/org/onosproject/yang/model/ResourceId.java
index c873cb1..a3bffaa 100644
--- a/model/src/main/java/org/onosproject/yang/model/ResourceId.java
+++ b/model/src/main/java/org/onosproject/yang/model/ResourceId.java
@@ -20,11 +20,9 @@
import java.util.List;
import static com.google.common.base.MoreObjects.toStringHelper;
-import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.Objects.hash;
import static org.onosproject.yang.model.ModelConstants.LEAF_IS_TERMINAL;
import static org.onosproject.yang.model.ModelConstants.NON_KEY_LEAF;
-import static org.onosproject.yang.model.ModelConstants.NO_KEY_SET;
/**
* Representation of an entity which identifies a resource in the logical tree
@@ -234,12 +232,24 @@
* @return built resource identifier
*/
public ResourceId build() {
- checkNotNull(curKeyBuilder, NO_KEY_SET);
- nodeKeyList.add(curKeyBuilder.build());
+ if (curKeyBuilder != null) {
+ nodeKeyList.add(curKeyBuilder.build());
+ curKeyBuilder = null;
+ }
return new ResourceId(this);
}
/**
+ * Removes last key in the node key list.
+ *
+ * @return updated builder
+ */
+ public Builder removeLastKey() {
+ nodeKeyList.remove(nodeKeyList.size() - 1);
+ return this;
+ }
+
+ /**
* Returns application information. This enables application to use
* this builder as there work bench.
*
diff --git a/runtime/src/main/java/org/onosproject/yang/runtime/DefaultAnnotation.java b/runtime/src/main/java/org/onosproject/yang/runtime/DefaultAnnotation.java
index 9c011e7..0f75340 100644
--- a/runtime/src/main/java/org/onosproject/yang/runtime/DefaultAnnotation.java
+++ b/runtime/src/main/java/org/onosproject/yang/runtime/DefaultAnnotation.java
@@ -35,7 +35,7 @@
* @param n annotation name
* @param v annotation value
*/
- protected DefaultAnnotation(String n, String v) {
+ public DefaultAnnotation(String n, String v) {
name = n;
value = v;
}
diff --git a/runtime/src/test/resources/schemaProviderTestYangFiles/food.yang b/runtime/src/test/resources/schemaProviderTestYangFiles/food.yang
index b340438..4c87fa0 100644
--- a/runtime/src/test/resources/schemaProviderTestYangFiles/food.yang
+++ b/runtime/src/test/resources/schemaProviderTestYangFiles/food.yang
@@ -17,7 +17,6 @@
container food {
choice snack {
case sportsarena {
-
leaf pretzel {
type empty;
}
@@ -44,6 +43,18 @@
}
}
}
+ leaf p1 {
+ type string;
+ }
+ leaf-list p2 {
+ type string;
+ }
+ }
+
+ container c2 {
+ leaf p3 {
+ type string;
+ }
}
leaf bool {
diff --git a/runtime/src/test/resources/xmlAttributes.yang b/runtime/src/test/resources/xmlAttributes.yang
new file mode 100644
index 0000000..f9f3f93
--- /dev/null
+++ b/runtime/src/test/resources/xmlAttributes.yang
@@ -0,0 +1,23 @@
+module attributes {
+ yang-version 1;
+ namespace "http://example.com/schema/1.2/config";
+ prefix "attr";
+ container top {
+ container interface {
+ leaf name {
+ type string;
+ }
+ leaf mtu {
+ type string;
+ }
+ container address {
+ leaf name {
+ type string;
+ }
+ leaf prefix-length {
+ type string;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/serializers/json/pom.xml b/serializers/json/pom.xml
index 7a9fc74..e512f8a 100644
--- a/serializers/json/pom.xml
+++ b/serializers/json/pom.xml
@@ -60,6 +60,11 @@
<artifactId>jackson-annotations</artifactId>
<version>2.8.6</version>
</dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-yang-serializers-utils</artifactId>
+ <version>1.12-SNAPSHOT</version>
+ </dependency>
<!-- TODO: remove
<dependency>
<groupId>org.onosproject</groupId>
diff --git a/serializers/json/src/main/java/org/onosproject/yang/serializers/json/DecoderUtils.java b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/DecoderUtils.java
index 753b699..1e91cd7 100644
--- a/serializers/json/src/main/java/org/onosproject/yang/serializers/json/DecoderUtils.java
+++ b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/DecoderUtils.java
@@ -17,66 +17,22 @@
package org.onosproject.yang.serializers.json;
import com.fasterxml.jackson.databind.node.ObjectNode;
-import com.google.common.base.Splitter;
-import com.google.common.collect.Lists;
import org.onosproject.yang.model.DataNode;
import org.onosproject.yang.model.ResourceId;
import org.onosproject.yang.runtime.YangSerializerContext;
import org.onosproject.yang.runtime.helperutils.SerializerHelper;
-import java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
-import java.util.ArrayList;
-import java.util.List;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
/**
* Utilities for parsing URI and JSON strings.
*/
public final class DecoderUtils {
- private static final Splitter SLASH_SPLITTER = Splitter.on('/');
- private static final Splitter COMMA_SPLITTER = Splitter.on(',');
- private static final String EQUAL = "=";
- private static final String COMMA = ",";
- private static final String COLON = ":";
- private static final String SLASH = "/";
- private static final String URI_ENCODING_CHAR_SET = "ISO-8859-1";
- private static final String ERROR_LIST_MSG = "List/Leaf-list node should be " +
- "in format \"nodeName=key\"or \"nodeName=instance-value\"";
-
// no instantiation
private DecoderUtils() {
}
/**
- * Converts a URI string to resource identifier.
- *
- * @param uriString given URI
- * @param context YANG schema context information
- * @return resource ID
- */
- public static ResourceId convertUriToRid(String uriString,
- YangSerializerContext context) {
- if (uriString == null || uriString.isEmpty()) {
- return null;
- }
-
- List<String> paths = urlPathArgsDecode(SLASH_SPLITTER.split(uriString));
-
- if (!paths.isEmpty()) {
- ResourceId.Builder ridBuilder =
- SerializerHelper.initializeResourceId(context);
- processPathSegments(paths, ridBuilder);
- return ridBuilder.build();
- }
-
- return null;
- }
-
- /**
* Converts JSON data to a data node. This method should be used when
* the URI corresponding to the JSON body is null (Thus the caller can
* only provide a serializer context rather than a resource ID).
@@ -125,157 +81,4 @@
return dataNodeBuilder.build();
}
-
- /**
- * Converts a list of path from the original format to ISO-8859-1 code.
- *
- * @param paths the original paths
- * @return list of decoded paths
- */
- public static List<String> urlPathArgsDecode(Iterable<String> paths) {
- try {
- List<String> decodedPathArgs = new ArrayList<>();
- for (String pathArg : paths) {
- String decode = URLDecoder.decode(pathArg,
- URI_ENCODING_CHAR_SET);
- decodedPathArgs.add(decode);
- }
- return decodedPathArgs;
- } catch (UnsupportedEncodingException e) {
- throw new SerializerException("Invalid URL path arg '" +
- paths + "': ", e);
- }
- }
-
- private static ResourceId.Builder processPathSegments(List<String> paths,
- ResourceId.Builder builder) {
- if (paths.isEmpty()) {
- return builder;
- }
-
- boolean isLastSegment = paths.size() == 1;
-
- String segment = paths.iterator().next();
- processSinglePathSegment(segment, builder);
-
- if (isLastSegment) {
- // We have hit the base case of recursion.
- return builder;
- }
-
- /*
- * Chop off the first segment, and recursively process the rest
- * of the path segments.
- */
- List<String> remainPaths = paths.subList(1, paths.size());
- processPathSegments(remainPaths, builder);
-
- return builder;
- }
-
- private static void processSinglePathSegment(String pathSegment,
- ResourceId.Builder builder) {
- if (pathSegment.contains(COLON)) {
- processPathSegmentWithNamespace(pathSegment, builder);
- } else {
- processPathSegmentWithoutNamespace(pathSegment, builder);
- }
- }
-
- private static void processPathSegmentWithNamespace(String pathSegment,
- ResourceId.Builder builder) {
-
- String nodeName = getLatterSegment(pathSegment, COLON);
- String namespace = getPreSegment(pathSegment, COLON);
- addNodeNameToRid(nodeName, namespace, builder);
- }
-
- private static void processPathSegmentWithoutNamespace(String nodeName,
- ResourceId.Builder builder) {
- addNodeNameToRid(nodeName, null, builder);
- }
-
- private static void addNodeNameToRid(String nodeName,
- String namespace,
- ResourceId.Builder builder) {
- if (nodeName.contains(EQUAL)) {
- addListOrLeafList(nodeName, namespace, builder);
- } else {
- addLeaf(nodeName, namespace, builder);
- }
- }
-
- private static void addListOrLeafList(String path,
- String namespace,
- ResourceId.Builder builder) {
- String nodeName = getPreSegment(path, EQUAL);
- String keyStr = getLatterSegment(path, EQUAL);
- if (keyStr == null) {
- throw new SerializerException(ERROR_LIST_MSG);
- }
-
- if (keyStr.contains(COMMA)) {
- List<String> keys = Lists.
- newArrayList(COMMA_SPLITTER.split(keyStr));
- SerializerHelper.addToResourceId(builder, nodeName, namespace, keys);
- } else {
- SerializerHelper.addToResourceId(builder, nodeName, namespace,
- Lists.newArrayList(keyStr));
- }
- }
-
- private static void addLeaf(String nodeName,
- String namespace,
- ResourceId.Builder builder) {
- checkNotNull(nodeName);
- SerializerHelper.addToResourceId(builder, nodeName, namespace, "");
- }
-
- /**
- * Returns the previous segment of a path which is separated by a split char.
- * For example:
- * <pre>
- * "foo:bar", ":" --> "foo"
- * </pre>
- *
- * @param path the original path string
- * @param splitChar char used to split the path
- * @return the previous segment of the path
- */
- private static String getPreSegment(String path, String splitChar) {
- int idx = path.indexOf(splitChar);
- if (idx == -1) {
- return null;
- }
-
- if (path.indexOf(splitChar, idx + 1) != -1) {
- return null;
- }
-
- return path.substring(0, idx);
- }
-
- /**
- * Returns the latter segment of a path which is separated by a split char.
- * For example:
- * <pre>
- * "foo:bar", ":" --> "bar"
- * </pre>
- *
- * @param path the original path string
- * @param splitChar char used to split the path
- * @return the latter segment of the path
- */
- private static String getLatterSegment(String path, String splitChar) {
- int idx = path.indexOf(splitChar);
- if (idx == -1) {
- return path;
- }
-
- if (path.indexOf(splitChar, idx + 1) != -1) {
- return null;
- }
-
- return path.substring(idx + 1);
- }
}
diff --git a/serializers/json/src/main/java/org/onosproject/yang/serializers/json/EncoderUtils.java b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/EncoderUtils.java
index 00022e5..c0e7ccc 100644
--- a/serializers/json/src/main/java/org/onosproject/yang/serializers/json/EncoderUtils.java
+++ b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/EncoderUtils.java
@@ -17,17 +17,11 @@
package org.onosproject.yang.serializers.json;
import com.fasterxml.jackson.databind.node.ObjectNode;
-import com.google.common.base.Splitter;
import org.onosproject.yang.model.DataNode;
import org.onosproject.yang.model.InnerNode;
-import org.onosproject.yang.model.KeyLeaf;
-import org.onosproject.yang.model.LeafListKey;
-import org.onosproject.yang.model.ListKey;
import org.onosproject.yang.model.NodeKey;
-import org.onosproject.yang.model.ResourceId;
import java.util.Iterator;
-import java.util.List;
import java.util.Map;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -45,98 +39,12 @@
* Utilities for converting Data Nodes into JSON format.
*/
public final class EncoderUtils {
- private static final Splitter SLASH_SPLITTER = Splitter.on('/');
- private static final Splitter COMMA_SPLITTER = Splitter.on(',');
- private static final String EQUAL = "=";
- private static final String COMMA = ",";
- private static final String COLON = ":";
- private static final String SLASH = "/";
// no instantiation
private EncoderUtils() {
}
/**
- * Converts a resource identifier to URI string.
- *
- * @param rid resource identifier
- * @return URI
- */
- public static String convertRidToUri(ResourceId rid) {
- if (rid == null) {
- return null;
- }
-
- StringBuilder uriBuilder = new StringBuilder();
- List<NodeKey> nodeKeyList = rid.nodeKeys();
- String curNameSpace = null;
- for (NodeKey key : nodeKeyList) {
- curNameSpace = addNodeKeyToUri(key, curNameSpace, uriBuilder);
- }
- return uriBuilder.toString();
- }
-
- private static String addNodeKeyToUri(NodeKey key,
- String curNameSpace,
- StringBuilder uriBuilder) {
- String newNameSpace;
- if (key instanceof LeafListKey) {
- newNameSpace = addLeafListNodeToUri((LeafListKey) key, curNameSpace, uriBuilder);
- } else if (key instanceof ListKey) {
- newNameSpace = addListNodeToUri((ListKey) key, curNameSpace, uriBuilder);
- } else {
- uriBuilder.append(SLASH);
- newNameSpace = addNodeNameToUri(key, curNameSpace, uriBuilder);
- }
- return newNameSpace;
- }
-
- private static String addLeafListNodeToUri(LeafListKey key,
- String curNameSpace,
- StringBuilder uriBuilder) {
-
- String newNameSpace = addNodeNameToUri(key, curNameSpace, uriBuilder);
- uriBuilder.append(EQUAL);
- uriBuilder.append(key.asString());
- return newNameSpace;
- }
-
- private static String addListNodeToUri(ListKey key,
- String curNameSpace,
- StringBuilder uriBuilder) {
- String newNameSpace = addNodeNameToUri(key, curNameSpace, uriBuilder);
- uriBuilder.append(EQUAL);
- String prefix = "";
- for (KeyLeaf keyLeaf : key.keyLeafs()) {
- uriBuilder.append(prefix);
- prefix = COMMA;
- uriBuilder.append(keyLeaf.leafValue().toString());
- }
-
- return newNameSpace;
- }
-
- private static String addNodeNameToUri(NodeKey key,
- String curNameSpace,
- StringBuilder uriBuilder) {
- String nodeName = key.schemaId().name();
- String newNameSpace = key.schemaId().namespace();
-
- uriBuilder.append(nodeName);
-
- if (newNameSpace == null) {
- return curNameSpace;
- }
-
- if (!newNameSpace.equals(curNameSpace)) {
- uriBuilder.append(COLON);
- uriBuilder.append(newNameSpace);
- }
-
- return newNameSpace;
- }
-
- /**
* Converts a data node to JSON data.
*
* @param dataNode given data node
diff --git a/serializers/json/src/main/java/org/onosproject/yang/serializers/json/JsonSerializer.java b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/JsonSerializer.java
index f635a50..40608b7 100644
--- a/serializers/json/src/main/java/org/onosproject/yang/serializers/json/JsonSerializer.java
+++ b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/JsonSerializer.java
@@ -37,9 +37,9 @@
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onosproject.yang.serializers.json.DecoderUtils.convertJsonToDataNode;
-import static org.onosproject.yang.serializers.json.DecoderUtils.convertUriToRid;
import static org.onosproject.yang.serializers.json.EncoderUtils.convertDataNodeToJson;
-import static org.onosproject.yang.serializers.json.EncoderUtils.convertRidToUri;
+import static org.onosproject.yang.serializers.utils.SerializersUtil.convertRidToUri;
+import static org.onosproject.yang.serializers.utils.SerializersUtil.convertUriToRid;
import static org.slf4j.LoggerFactory.getLogger;
/**
@@ -64,8 +64,8 @@
public CompositeData decode(CompositeStream compositeStream,
YangSerializerContext yangSerializerContext) {
try {
- ResourceId rid = convertUriToRid(compositeStream.resourceId(),
- yangSerializerContext);
+ ResourceId.Builder rIdBuilder = convertUriToRid(
+ compositeStream.resourceId(), yangSerializerContext);
ObjectNode rootNode = null;
@@ -83,9 +83,9 @@
* and in this case the resourceId builder which was constructed
* for a URL, needs to be given as an Input parameter.
*/
- if (rid != null) {
+ if (rIdBuilder != null) {
dataNode = convertJsonToDataNode(rootNode,
- new ResourceId.Builder(rid));
+ rIdBuilder);
} else {
dataNode = convertJsonToDataNode(rootNode,
@@ -93,13 +93,8 @@
}
ResourceData resourceData = DefaultResourceData.builder().
- addDataNode(dataNode).resourceId(rid).build();
+ addDataNode(dataNode).resourceId(rIdBuilder.build()).build();
return DefaultCompositeData.builder().resourceData(resourceData).build();
- } catch (CloneNotSupportedException e) {
- log.error("ERROR: JsonProcessingException {}",
- e.getMessage());
- log.debug("Exception in decode:", e);
- throw new SerializerException("JSON serializer decode failure");
} catch (JsonProcessingException e) {
log.error("ERROR: JsonProcessingException {}",
e.getMessage());
diff --git a/serializers/pom.xml b/serializers/pom.xml
index 6846261..1740256 100644
--- a/serializers/pom.xml
+++ b/serializers/pom.xml
@@ -31,6 +31,8 @@
<modules>
<module>json</module>
+ <module>xml</module>
+ <module>utils</module>
</modules>
<description>Serializers for various codecs</description>
diff --git a/serializers/utils/pom.xml b/serializers/utils/pom.xml
new file mode 100644
index 0000000..b1866f9
--- /dev/null
+++ b/serializers/utils/pom.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright 2017-present Open Networking Laboratory
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-yang-serializers</artifactId>
+ <version>1.12-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>onos-yang-serializers-utils</artifactId>
+ <packaging>jar</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-yang-runtime</artifactId>
+ <version>1.12-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.servicemix.bundles</groupId>
+ <artifactId>org.apache.servicemix.bundles.dom4j</artifactId>
+ <version>1.6.1_5</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>3.0.2</version>
+ <configuration>
+ <skipIfEmpty>true</skipIfEmpty>
+ </configuration>
+ <executions>
+ <execution>
+ <id>default</id>
+ <goals>
+ <goal>test-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/serializers/utils/src/main/java/org/onosproject/yang/serializers/utils/SerializerUtilException.java b/serializers/utils/src/main/java/org/onosproject/yang/serializers/utils/SerializerUtilException.java
new file mode 100644
index 0000000..eef46dc
--- /dev/null
+++ b/serializers/utils/src/main/java/org/onosproject/yang/serializers/utils/SerializerUtilException.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yang.serializers.utils;
+
+/**
+ * Represents class of errors related to serializer utils.
+ */
+public class SerializerUtilException extends RuntimeException {
+
+ /**
+ * Constructs an exception with the specified message.
+ *
+ * @param message the message describing the specific nature of the error
+ */
+ public SerializerUtilException(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructs an exception with the specified message and the underlying
+ * cause.
+ *
+ * @param message the message describing the specific nature of the error
+ * @param cause the underlying cause of this error
+ */
+ public SerializerUtilException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/serializers/utils/src/main/java/org/onosproject/yang/serializers/utils/SerializersUtil.java b/serializers/utils/src/main/java/org/onosproject/yang/serializers/utils/SerializersUtil.java
new file mode 100644
index 0000000..dbb0222
--- /dev/null
+++ b/serializers/utils/src/main/java/org/onosproject/yang/serializers/utils/SerializersUtil.java
@@ -0,0 +1,378 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yang.serializers.utils;
+
+import com.google.common.base.Splitter;
+import com.google.common.collect.Lists;
+import org.dom4j.Attribute;
+import org.dom4j.DocumentException;
+import org.dom4j.Element;
+import org.onosproject.yang.model.KeyLeaf;
+import org.onosproject.yang.model.LeafListKey;
+import org.onosproject.yang.model.ListKey;
+import org.onosproject.yang.model.NodeKey;
+import org.onosproject.yang.model.ResourceId;
+import org.onosproject.yang.runtime.AnnotatedNodeInfo;
+import org.onosproject.yang.runtime.Annotation;
+import org.onosproject.yang.runtime.DefaultAnnotatedNodeInfo;
+import org.onosproject.yang.runtime.DefaultAnnotation;
+import org.onosproject.yang.runtime.YangSerializerContext;
+import org.onosproject.yang.runtime.helperutils.SerializerHelper;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Utilities for serializers.
+ */
+public final class SerializersUtil {
+ private static final Splitter SLASH_SPLITTER = Splitter.on('/');
+ private static final Splitter COMMA_SPLITTER = Splitter.on(',');
+ private static final String QUOTES = "\"";
+ private static final String ROOT_ELEMENT_START = "<root ";
+ private static final String ROOT_ELEMENT_END = "</root>";
+ private static final String URI_ENCODING_CHAR_SET = "ISO-8859-1";
+ private static final String ERROR_LIST_MSG = "List/Leaf-list node should be " +
+ "in format \"nodeName=key\"or \"nodeName=instance-value\"";
+ private static final String EQUAL = "=";
+ private static final String COMMA = ",";
+ private static final String COLON = ":";
+ private static final String SLASH = "/";
+
+ // no instantiation
+ private SerializersUtil() {
+ }
+
+ /**
+ * Converts XML atrtibutes into annotated node info.
+ *
+ * @param element XML element
+ * @param id resource id of an element
+ * @return annotated node info
+ */
+ public static AnnotatedNodeInfo convertXmlAttributesToAnnotations(Element element,
+ ResourceId id) {
+ Iterator iter = element.attributeIterator();
+ if (!iter.hasNext()) {
+ // element does not have any attributes
+ return null;
+ }
+ AnnotatedNodeInfo.Builder builder = DefaultAnnotatedNodeInfo.builder();
+ builder = builder.resourceId(id);
+ while (iter.hasNext()) {
+ Attribute attr = (Attribute) iter.next();
+ DefaultAnnotation annotation = new DefaultAnnotation(
+ attr.getQualifiedName(), attr.getValue());
+ builder = builder.addAnnotation(annotation);
+ }
+ return builder.build();
+ }
+
+
+ /**
+ * Appends the XML data with root element.
+ *
+ * @param inputStream XML data
+ * @param protocolAnnotation list of annoations for root element
+ * @return XML with root element
+ * @throws DocumentException if root element cannot be created
+ * @throws IOException if input data cannot be read
+ */
+ public static String addRootElementWithAnnotation(InputStream inputStream,
+ List<Annotation>
+ protocolAnnotation)
+ throws DocumentException, IOException {
+ BufferedReader br;
+ StringBuilder sb = new StringBuilder();
+ String xmlData;
+ // Parse composite stream resourceData
+ br = new BufferedReader(new InputStreamReader(inputStream));
+ while ((xmlData = br.readLine()) != null) {
+ sb.append(xmlData);
+ }
+
+ StringBuilder rootElement = new StringBuilder(ROOT_ELEMENT_START);
+ if (protocolAnnotation != null) {
+ for (Annotation annotation : protocolAnnotation) {
+ rootElement.append(annotation.name()).append(EQUAL)
+ .append(QUOTES).append(annotation.value()).append(QUOTES);
+ }
+ }
+ rootElement.append(">").append(sb.toString()).append(ROOT_ELEMENT_END);
+ return rootElement.toString();
+ }
+
+ /**
+ * Converts a URI string to resource identifier.
+ *
+ * @param uriString given URI
+ * @param context YANG schema context information
+ * @return resource ID
+ */
+ public static ResourceId.Builder convertUriToRid(String uriString,
+ YangSerializerContext context) {
+ if (uriString == null || uriString.isEmpty()) {
+ return null;
+ }
+
+ List<String> paths = urlPathArgsDecode(SLASH_SPLITTER.split(uriString));
+
+ if (!paths.isEmpty()) {
+ ResourceId.Builder ridBuilder =
+ SerializerHelper.initializeResourceId(context);
+ processPathSegments(paths, ridBuilder);
+ return ridBuilder;
+ }
+
+ return null;
+ }
+
+ /**
+ * Converts a list of path from the original format to ISO-8859-1 code.
+ *
+ * @param paths the original paths
+ * @return list of decoded paths
+ */
+ public static List<String> urlPathArgsDecode(Iterable<String> paths) {
+ try {
+ List<String> decodedPathArgs = new ArrayList<>();
+ for (String pathArg : paths) {
+ String decode = URLDecoder.decode(pathArg,
+ URI_ENCODING_CHAR_SET);
+ decodedPathArgs.add(decode);
+ }
+ return decodedPathArgs;
+ } catch (UnsupportedEncodingException e) {
+ throw new SerializerUtilException("Invalid URL path arg '" +
+ paths + "': ", e);
+ }
+ }
+
+ private static ResourceId.Builder processPathSegments(List<String> paths,
+ ResourceId.Builder builder) {
+ if (paths.isEmpty()) {
+ return builder;
+ }
+
+ boolean isLastSegment = paths.size() == 1;
+
+ String segment = paths.iterator().next();
+ processSinglePathSegment(segment, builder);
+
+ if (isLastSegment) {
+ // We have hit the base case of recursion.
+ return builder;
+ }
+
+ /*
+ * Chop off the first segment, and recursively process the rest
+ * of the path segments.
+ */
+ List<String> remainPaths = paths.subList(1, paths.size());
+ processPathSegments(remainPaths, builder);
+
+ return builder;
+ }
+
+ private static void processSinglePathSegment(String pathSegment,
+ ResourceId.Builder builder) {
+ if (pathSegment.contains(COLON)) {
+ processPathSegmentWithNamespace(pathSegment, builder);
+ } else {
+ processPathSegmentWithoutNamespace(pathSegment, builder);
+ }
+ }
+
+ private static void processPathSegmentWithNamespace(String pathSegment,
+ ResourceId.Builder builder) {
+
+ String nodeName = getLatterSegment(pathSegment, COLON);
+ String namespace = getPreSegment(pathSegment, COLON);
+ addNodeNameToRid(nodeName, namespace, builder);
+ }
+
+ private static void processPathSegmentWithoutNamespace(String nodeName,
+ ResourceId.Builder builder) {
+ addNodeNameToRid(nodeName, null, builder);
+ }
+
+ private static void addNodeNameToRid(String nodeName,
+ String namespace,
+ ResourceId.Builder builder) {
+ if (nodeName.contains(EQUAL)) {
+ addListOrLeafList(nodeName, namespace, builder);
+ } else {
+ addLeaf(nodeName, namespace, builder);
+ }
+ }
+
+ private static void addListOrLeafList(String path,
+ String namespace,
+ ResourceId.Builder builder) {
+ String nodeName = getPreSegment(path, EQUAL);
+ String keyStr = getLatterSegment(path, EQUAL);
+ if (keyStr == null) {
+ throw new SerializerUtilException(ERROR_LIST_MSG);
+ }
+
+ if (keyStr.contains(COMMA)) {
+ List<String> keys = Lists.
+ newArrayList(COMMA_SPLITTER.split(keyStr));
+ SerializerHelper.addToResourceId(builder, nodeName, namespace, keys);
+ } else {
+ SerializerHelper.addToResourceId(builder, nodeName, namespace,
+ Lists.newArrayList(keyStr));
+ }
+ }
+
+ private static void addLeaf(String nodeName,
+ String namespace,
+ ResourceId.Builder builder) {
+ checkNotNull(nodeName);
+ String value = null;
+ SerializerHelper.addToResourceId(builder, nodeName, namespace, value);
+ }
+
+ /**
+ * Returns the previous segment of a path which is separated by a split char.
+ * For example:
+ * <pre>
+ * "foo:bar", ":" --> "foo"
+ * </pre>
+ *
+ * @param path the original path string
+ * @param splitChar char used to split the path
+ * @return the previous segment of the path
+ */
+ private static String getPreSegment(String path, String splitChar) {
+ int idx = path.lastIndexOf(splitChar);
+ if (idx == -1) {
+ return null;
+ }
+ return path.substring(0, idx);
+ }
+
+ /**
+ * Returns the latter segment of a path which is separated by a split char.
+ * For example:
+ * <pre>
+ * "foo:bar", ":" --> "bar"
+ * </pre>
+ *
+ * @param path the original path string
+ * @param splitChar char used to split the path
+ * @return the latter segment of the path
+ */
+ private static String getLatterSegment(String path, String splitChar) {
+ int idx = path.lastIndexOf(splitChar);
+ if (idx == -1) {
+ return path;
+ }
+
+ return path.substring(idx + 1);
+ }
+
+ /**
+ * Converts a resource identifier to URI string.
+ *
+ * @param rid resource identifier
+ * @return URI
+ */
+ public static String convertRidToUri(ResourceId rid) {
+ if (rid == null) {
+ return null;
+ }
+
+ StringBuilder uriBuilder = new StringBuilder();
+ List<NodeKey> nodeKeyList = rid.nodeKeys();
+ String curNameSpace = null;
+ for (NodeKey key : nodeKeyList) {
+ curNameSpace = addNodeKeyToUri(key, curNameSpace, uriBuilder);
+ }
+ return uriBuilder.toString();
+ }
+
+ private static String addNodeKeyToUri(NodeKey key,
+ String curNameSpace,
+ StringBuilder uriBuilder) {
+ String newNameSpace;
+ if (key instanceof LeafListKey) {
+ newNameSpace = addLeafListNodeToUri((LeafListKey) key, curNameSpace, uriBuilder);
+ } else if (key instanceof ListKey) {
+ newNameSpace = addListNodeToUri((ListKey) key, curNameSpace, uriBuilder);
+ } else {
+ uriBuilder.append(SLASH);
+ newNameSpace = addNodeNameToUri(key, curNameSpace, uriBuilder);
+ }
+ return newNameSpace;
+ }
+
+ private static String addLeafListNodeToUri(LeafListKey key,
+ String curNameSpace,
+ StringBuilder uriBuilder) {
+
+ String newNameSpace = addNodeNameToUri(key, curNameSpace, uriBuilder);
+ uriBuilder.append(EQUAL);
+ uriBuilder.append(key.asString());
+ return newNameSpace;
+ }
+
+ private static String addListNodeToUri(ListKey key,
+ String curNameSpace,
+ StringBuilder uriBuilder) {
+ String newNameSpace = addNodeNameToUri(key, curNameSpace, uriBuilder);
+ uriBuilder.append(EQUAL);
+ String prefix = "";
+ for (KeyLeaf keyLeaf : key.keyLeafs()) {
+ uriBuilder.append(prefix);
+ prefix = COMMA;
+ uriBuilder.append(keyLeaf.leafValue().toString());
+ }
+
+ return newNameSpace;
+ }
+
+ private static String addNodeNameToUri(NodeKey key,
+ String curNameSpace,
+ StringBuilder uriBuilder) {
+ String nodeName = key.schemaId().name();
+ String newNameSpace = key.schemaId().namespace();
+
+ uriBuilder.append(nodeName);
+
+ if (newNameSpace == null) {
+ return curNameSpace;
+ }
+
+ if (!newNameSpace.equals(curNameSpace)) {
+ uriBuilder.append(COLON);
+ uriBuilder.append(newNameSpace);
+ }
+
+ return newNameSpace;
+ }
+
+}
diff --git a/serializers/utils/src/main/java/org/onosproject/yang/serializers/utils/package-info.java b/serializers/utils/src/main/java/org/onosproject/yang/serializers/utils/package-info.java
new file mode 100644
index 0000000..65d177b
--- /dev/null
+++ b/serializers/utils/src/main/java/org/onosproject/yang/serializers/utils/package-info.java
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2017. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
+ * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
+ * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
+ * Vestibulum commodo. Ut rhoncus gravida arcu.
+ */
+
+/**
+ * The XML codec implementation of the YangSerializer interface.
+ */
+package org.onosproject.yang.serializers.utils;
diff --git a/serializers/xml/pom.xml b/serializers/xml/pom.xml
new file mode 100644
index 0000000..d757e5b
--- /dev/null
+++ b/serializers/xml/pom.xml
@@ -0,0 +1,96 @@
+<!--
+ ~ Copyright 2017-present Open Networking Laboratory
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-yang-serializers</artifactId>
+ <version>1.12-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>onos-yang-serializers-xml</artifactId>
+ <packaging>jar</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>1.7.21</version>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-yang-runtime</artifactId>
+ <version>1.12-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.servicemix.bundles</groupId>
+ <artifactId>org.apache.servicemix.bundles.dom4j</artifactId>
+ <version>1.6.1_5</version>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-yang-serializers-utils</artifactId>
+ <version>1.12-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>RELEASE</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-yang-compiler-maven-plugin</artifactId>
+ <version>${project.version}</version>
+ <configuration>
+ <yangFilesDir>src/test/resources</yangFilesDir>
+ </configuration>
+ <executions>
+ <execution>
+ <id>default</id>
+ <goals>
+ <goal>yang2java</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>3.0.2</version>
+ <configuration>
+ <skipIfEmpty>true</skipIfEmpty>
+ </configuration>
+ <executions>
+ <execution>
+ <id>default</id>
+ <goals>
+ <goal>test-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/DataNodeXmlListener.java b/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/DataNodeXmlListener.java
new file mode 100644
index 0000000..4b13bbe
--- /dev/null
+++ b/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/DataNodeXmlListener.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yang.serializers.xml;
+
+import org.dom4j.Element;
+import org.onosproject.yang.model.DataNode;
+import org.onosproject.yang.model.KeyLeaf;
+import org.onosproject.yang.model.LeafNode;
+import org.onosproject.yang.model.ListKey;
+import org.onosproject.yang.model.NodeKey;
+import org.onosproject.yang.model.ResourceId;
+import org.onosproject.yang.model.SchemaId;
+import org.onosproject.yang.runtime.Annotation;
+import org.onosproject.yang.runtime.helperutils.DataNodeListener;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+
+/**
+ * Represents implementation of data node listener.
+ */
+class DataNodeXmlListener implements DataNodeListener {
+
+ /**
+ * Stack for element is maintained for hierarchical references, this is
+ * used during data node walker and preparation of XML.
+ */
+ private final Stack<Element> elementStack = new Stack<>();
+
+ /**
+ * Root element of XML.
+ */
+ private Element rootElement;
+
+ /**
+ * XML string for data node.
+ */
+ private String xmlData = EMPTY_STRING;
+
+ /**
+ * Annotation map used to search list of annotations associated with
+ * resource id.
+ */
+ private Map<ResourceId, List<Annotation>> annotationMap;
+
+ /**
+ * Resource id builder.
+ */
+ private ResourceId.Builder rIdBuilder;
+
+ private static final String FORWARD_SLASH = "/";
+ private static final String EMPTY_STRING = "";
+
+ /**
+ * Creates a new data node XML serializer listener.
+ *
+ * @param annotations annotation map with resource id as key
+ * @param ridBuilder resource id builder
+ */
+ DataNodeXmlListener(Map<ResourceId, List<Annotation>> annotations,
+ ResourceId.Builder ridBuilder) {
+ annotationMap = annotations;
+ rIdBuilder = ridBuilder;
+ }
+
+ /**
+ * Sets the root XML element.
+ *
+ * @param rootElement root element
+ */
+ public void rootElement(Element rootElement) {
+ this.rootElement = rootElement;
+ }
+
+ /**
+ * Returns XML string.
+ *
+ * @return XML string
+ */
+ public String xmlData() {
+ return xmlData;
+ }
+
+ @Override
+ public void enterDataNode(DataNode node) {
+ if (!isRootDataNode(node)) {
+ SerializerHandlerFactory factory = SerializerHandlerFactory.instance();
+ XmlSerializerHandler handler =
+ factory.getSerializerHandlerForContext(node);
+ try {
+ if (handler != null) {
+ Element element = handler.processXmlContext(node,
+ elementStack);
+ if (elementStack.isEmpty()) {
+ rootElement(element);
+ }
+ elementStack.push(element);
+
+ // search in map whether there is entry for this resource id
+ ResourceId id = getResourceId(node);
+ List<Annotation> annotations = annotationMap.get(id);
+
+ /**
+ * If there is annotations for given resource id then get
+ * list of annotations and add as attribute
+ */
+ if (annotations != null) {
+ for (Annotation annotation : annotations) {
+ element.addAttribute(annotation.name(),
+ annotation.value());
+ }
+ }
+ }
+ } catch (Exception e) {
+ throw new XmlSerializerException(e.getMessage());
+ }
+
+ if (handler != null) {
+ handler.setXmlValue(node, elementStack);
+ }
+ }
+ }
+
+ @Override
+ public void exitDataNode(DataNode dataNode) {
+ if (!elementStack.isEmpty() &&
+ elementStack.peek().equals(rootElement)) {
+ xmlData = xmlData + rootElement.asXML();
+ }
+
+ if (!isRootDataNode(dataNode)) {
+ elementStack.pop();
+ rIdBuilder.removeLastKey();
+ }
+ }
+
+ /**
+ * Returns resource id for the data node.
+ *
+ * @param dataNode data node
+ * @return resource id for the data node
+ */
+ private ResourceId getResourceId(DataNode dataNode) {
+ SchemaId schemaId = dataNode.key().schemaId();
+ switch (dataNode.type()) {
+ case MULTI_INSTANCE_LEAF_VALUE_NODE:
+ Object valObject = ((LeafNode) dataNode).value();
+ rIdBuilder = rIdBuilder.addLeafListBranchPoint(schemaId.name(),
+ schemaId.namespace(),
+ valObject);
+ break;
+ case MULTI_INSTANCE_NODE:
+ rIdBuilder = rIdBuilder.addBranchPointSchema(schemaId.name(),
+ schemaId.namespace());
+ NodeKey key = dataNode.key();
+ if (key instanceof ListKey) {
+ List<KeyLeaf> keyLeaves = ((ListKey) key).keyLeafs();
+ if (keyLeaves != null) {
+ for (KeyLeaf keyLeaf : keyLeaves) {
+ SchemaId leafSchema = keyLeaf.leafSchema();
+ rIdBuilder = rIdBuilder.addKeyLeaf(leafSchema.name(),
+ leafSchema.namespace(),
+ keyLeaf.leafValue());
+ }
+ }
+ }
+ break;
+ case SINGLE_INSTANCE_LEAF_VALUE_NODE:
+ case SINGLE_INSTANCE_NODE:
+ rIdBuilder = rIdBuilder.addBranchPointSchema(schemaId.name(),
+ schemaId.namespace());
+ break;
+ default:
+ throw new XmlSerializerException("Unsupported type" +
+ dataNode.type());
+ }
+ return rIdBuilder.build();
+ }
+
+ /**
+ * Returns true if it is root data node.
+ *
+ * @param node data node
+ * @return true if it is root data node, false otherwise
+ */
+ private static boolean isRootDataNode(DataNode node) {
+ return node.key().schemaId().name().equals(FORWARD_SLASH);
+ }
+}
diff --git a/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/DefaultXmlWalker.java b/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/DefaultXmlWalker.java
new file mode 100644
index 0000000..1623aed
--- /dev/null
+++ b/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/DefaultXmlWalker.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yang.serializers.xml;
+
+import org.dom4j.Element;
+
+import java.util.Iterator;
+
+import static org.onosproject.yang.serializers.xml.XmlNodeType.OBJECT_NODE;
+import static org.onosproject.yang.serializers.xml.XmlNodeType.TEXT_NODE;
+
+/**
+ * Represents implementation of xml walker.
+ */
+public class DefaultXmlWalker implements XmlWalker {
+
+ @Override
+ public void walk(XmlListener listener, Element element,
+ Element rootElement) {
+ try {
+
+ listener.enterXmlElement(element, getElementType(element),
+ rootElement);
+
+ if (element.hasContent() && !element.isTextOnly()) {
+ Iterator i = element.elementIterator();
+ while (i.hasNext()) {
+ Element childElement = (Element) i.next();
+ walk(listener, childElement, rootElement);
+ }
+ }
+
+ listener.exitXmlElement(element, getElementType(element),
+ rootElement);
+ } catch (Exception e) {
+ throw new XmlSerializerException(e.getMessage());
+ }
+ }
+
+ /**
+ * Determine the type of an element.
+ *
+ * @param element to be analysed
+ * @return type of the element
+ */
+ private XmlNodeType getElementType(Element element) {
+ Element newElement = element.createCopy();
+ newElement.remove(element.getNamespace());
+ return newElement.hasContent() && newElement.isTextOnly() ?
+ TEXT_NODE : OBJECT_NODE;
+ }
+}
diff --git a/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/SerializerHandlerFactory.java b/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/SerializerHandlerFactory.java
new file mode 100644
index 0000000..eb6199e
--- /dev/null
+++ b/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/SerializerHandlerFactory.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yang.serializers.xml;
+
+
+import org.onosproject.yang.model.DataNode;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.onosproject.yang.model.DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE;
+import static org.onosproject.yang.model.DataNode.Type.MULTI_INSTANCE_NODE;
+import static org.onosproject.yang.model.DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE;
+import static org.onosproject.yang.model.DataNode.Type.SINGLE_INSTANCE_NODE;
+
+/**
+ * Represents an xml serializer handle factory to create different types of
+ * data node.
+ */
+public final class SerializerHandlerFactory {
+
+ /**
+ * Map of xml codec handler.
+ */
+ private final Map<DataNode.Type, XmlSerializerHandler> handlerMap;
+
+ /**
+ * Creates a new codec handler factory.
+ */
+ private SerializerHandlerFactory() {
+ handlerMap = new HashMap<>();
+ handlerMap.put(SINGLE_INSTANCE_NODE,
+ new XmlSerializerNodeHandler());
+ handlerMap.put(MULTI_INSTANCE_NODE,
+ new XmlSerializerNodeHandler());
+ handlerMap.put(SINGLE_INSTANCE_LEAF_VALUE_NODE,
+ new XmlSerializerLeafHandler());
+ handlerMap.put(MULTI_INSTANCE_LEAF_VALUE_NODE,
+ new XmlSerializerLeafHandler());
+ }
+
+ /**
+ * Returns serializer instance handler node instance.
+ *
+ * @param node data node
+ * @return returns serializer handler node instance
+ */
+ public XmlSerializerHandler getSerializerHandlerForContext(
+ DataNode node) {
+ XmlSerializerHandler handler = handlerMap.get(node.type());
+ if (handler == null) {
+ throw new XmlSerializerException("Unsupported node type " + node
+ .type());
+ }
+ return handler;
+ }
+
+ /*
+ * Bill Pugh Singleton pattern. INSTANCE won't be instantiated until the
+ * LazyHolder class is loaded via a call to the instance() method below.
+ */
+ private static class LazyHolder {
+ private static final SerializerHandlerFactory INSTANCE =
+ new SerializerHandlerFactory();
+ }
+
+ /**
+ * Returns a reference to the Singleton Codec Handler factory.
+ *
+ * @return the singleton codec handler factory
+ */
+ public static SerializerHandlerFactory instance() {
+ return LazyHolder.INSTANCE;
+ }
+}
diff --git a/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/XmlListener.java b/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/XmlListener.java
new file mode 100644
index 0000000..3f1b466
--- /dev/null
+++ b/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/XmlListener.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yang.serializers.xml;
+
+import org.dom4j.Element;
+
+/**
+ * Abstraction of an entity which provide call back methods which are called
+ * by xml walker while walking the xml data tree. This interface needs to be
+ * implemented by protocol implementing listener's based call backs while
+ * xml walk.
+ */
+interface XmlListener {
+
+ /**
+ * Callback invoked during a node entry. All the related information
+ * about the node can be obtained from the element.
+ *
+ * @param element current xml node(element)
+ * @param nodeType xml node type
+ * @param rootElement root element
+ */
+ void enterXmlElement(Element element, XmlNodeType nodeType,
+ Element rootElement);
+
+ /**
+ * Callback invoked during a node exit. All the related information
+ * about the node can be obtained from the element.
+ *
+ * @param element current xml node(element)
+ * @param nodeType xml node type
+ * @param rootElement root element
+ */
+ void exitXmlElement(Element element, XmlNodeType nodeType,
+ Element rootElement);
+}
diff --git a/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/XmlNodeType.java b/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/XmlNodeType.java
new file mode 100644
index 0000000..eb70c17
--- /dev/null
+++ b/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/XmlNodeType.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yang.serializers.xml;
+
+/**
+ * Represents type of node in xml data tree.
+ */
+enum XmlNodeType {
+
+ /**
+ * An object node has at least one child node.
+ */
+ OBJECT_NODE,
+
+ /**
+ * A text node has no child node, and has a text value.
+ */
+ TEXT_NODE
+}
diff --git a/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/XmlSerializer.java b/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/XmlSerializer.java
new file mode 100644
index 0000000..5872e51
--- /dev/null
+++ b/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/XmlSerializer.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yang.serializers.xml;
+
+import org.apache.commons.io.IOUtils;
+import org.dom4j.Document;
+import org.dom4j.DocumentException;
+import org.dom4j.DocumentHelper;
+import org.dom4j.Element;
+import org.onosproject.yang.model.DataNode;
+import org.onosproject.yang.model.ResourceData;
+import org.onosproject.yang.model.ResourceId;
+import org.onosproject.yang.runtime.AnnotatedNodeInfo;
+import org.onosproject.yang.runtime.Annotation;
+import org.onosproject.yang.runtime.CompositeData;
+import org.onosproject.yang.runtime.CompositeStream;
+import org.onosproject.yang.runtime.DefaultCompositeData;
+import org.onosproject.yang.runtime.DefaultCompositeStream;
+import org.onosproject.yang.runtime.DefaultResourceData;
+import org.onosproject.yang.runtime.YangSerializer;
+import org.onosproject.yang.runtime.YangSerializerContext;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import static org.onosproject.yang.runtime.helperutils.DefaultDataNodeWalker.walk;
+import static org.onosproject.yang.runtime.helperutils.SerializerHelper.initializeDataNode;
+import static org.onosproject.yang.runtime.helperutils.SerializerHelper.initializeResourceId;
+import static org.onosproject.yang.serializers.utils.SerializersUtil.addRootElementWithAnnotation;
+import static org.onosproject.yang.serializers.utils.SerializersUtil.convertRidToUri;
+import static org.onosproject.yang.serializers.utils.SerializersUtil.convertUriToRid;
+
+/**
+ * Represents an implementation of XML serializer.
+ */
+public class XmlSerializer implements YangSerializer {
+ private static final String XML = "xml";
+
+ @Override
+ public String supportsFormat() {
+ return XML;
+ }
+
+ @Override
+ public CompositeData decode(CompositeStream external,
+ YangSerializerContext context) {
+
+ try {
+ //parse XML input
+ String xmlInput = addRootElementWithAnnotation(
+ external.resourceData(), context.getProtocolAnnotations());
+ Document document = DocumentHelper.parseText(xmlInput);
+
+ // initialize all the required builders
+ CompositeData.Builder cBuilder = DefaultCompositeData.builder();
+ ResourceData.Builder rdBuilder = DefaultResourceData.builder();
+ XmlWalker walker = new DefaultXmlWalker();
+ XmlSerializerListener listener = new XmlSerializerListener();
+ listener.cBuilder(cBuilder);
+
+ String uri = external.resourceId();
+ if (uri == null) {
+ listener.dnBuilder(initializeDataNode(context));
+ walker.walk(listener, document.getRootElement(),
+ document.getRootElement());
+ rdBuilder = rdBuilder.addDataNode(listener.dnBuilder().build());
+ } else {
+ /*
+ * If URI is not null, then each first level elements is
+ * converted to data node and added to list of data nodes in
+ * resource data
+ */
+ ResourceId.Builder rIdBuilder = convertUriToRid(uri, context);
+ Element rootElement = document.getRootElement();
+ if (rootElement.hasContent() && !rootElement.isTextOnly()) {
+ Iterator i = rootElement.elementIterator();
+ while (i.hasNext()) {
+ Element childElement = (Element) i.next();
+ listener.dnBuilder(initializeDataNode(rIdBuilder));
+ walker.walk(listener, childElement, rootElement);
+ rdBuilder = rdBuilder.addDataNode(listener.dnBuilder()
+ .build());
+ }
+ }
+ rdBuilder.resourceId(rIdBuilder.build());
+ }
+ return cBuilder.resourceData(rdBuilder.build()).build();
+ } catch (DocumentException e) {
+ throw new XmlSerializerException(e.getMessage());
+ } catch (IOException e) {
+ throw new XmlSerializerException(e.getMessage());
+ }
+ }
+
+ @Override
+ public CompositeStream encode(CompositeData internal,
+ YangSerializerContext context) {
+ String uriString = null;
+ ResourceId.Builder builder;
+
+ ResourceId resourceId = internal.resourceData().resourceId();
+ if (resourceId != null) {
+ uriString = convertRidToUri(resourceId);
+ try {
+ builder = resourceId.copyBuilder();
+ } catch (CloneNotSupportedException e) {
+ throw new XmlSerializerException(e.getMessage());
+ }
+ } else {
+ /*
+ * If resource id is null, initialise resource id with context
+ * and get the resource id builder. Resource id is built for each
+ * data node and checked in annotation map for annotations
+ * associated with resource id.
+ */
+ builder = initializeResourceId(context);
+ }
+
+ // Store annotations in map with resource id as key
+ Map<ResourceId, List<Annotation>> annotations = new HashMap<>();
+ List<AnnotatedNodeInfo> annotationList = internal.annotatedNodesInfo();
+ if (annotationList != null) {
+ for (AnnotatedNodeInfo annotationInfo : annotationList) {
+ annotations.put(annotationInfo.resourceId(),
+ annotationInfo.annotations());
+ }
+ }
+
+ // Walk through data node and build the XML
+ List<DataNode> dataNodes = internal.resourceData().dataNodes();
+ StringBuilder sb = new StringBuilder();
+ for (DataNode dataNode : dataNodes) {
+ DataNodeXmlListener listener = new DataNodeXmlListener(annotations,
+ builder);
+ walk(listener, dataNode);
+ sb.append(listener.xmlData());
+ }
+
+ // convert XML to input stream and build composite stream
+ InputStream inputStream = IOUtils.toInputStream(sb.toString());
+ return new DefaultCompositeStream(uriString, inputStream);
+ }
+}
diff --git a/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/XmlSerializerException.java b/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/XmlSerializerException.java
new file mode 100644
index 0000000..b543519
--- /dev/null
+++ b/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/XmlSerializerException.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yang.serializers.xml;
+
+/**
+ * Represents base class for exceptions in XML serializer operations.
+ */
+public class XmlSerializerException extends RuntimeException {
+ private static final long serialVersionUID = 20160211L;
+
+ /**
+ * Creates a new XML serializer exception.
+ */
+ public XmlSerializerException() {
+ }
+
+ /**
+ * Creates a new XML serializer exception with given message.
+ *
+ * @param message the detail of exception in string
+ */
+ public XmlSerializerException(String message) {
+ super(message);
+ }
+
+ /**
+ * Creates a new XML serializer exception from given message and cause.
+ *
+ * @param message the detail of exception in string
+ * @param cause underlying cause of the error
+ */
+ public XmlSerializerException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Creates a new XML serializer exception from cause.
+ *
+ * @param cause underlying cause of the error
+ */
+ public XmlSerializerException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/XmlSerializerHandler.java b/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/XmlSerializerHandler.java
new file mode 100644
index 0000000..5f706ac
--- /dev/null
+++ b/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/XmlSerializerHandler.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yang.serializers.xml;
+
+import org.dom4j.DocumentHelper;
+import org.dom4j.Element;
+import org.dom4j.Namespace;
+import org.onosproject.yang.model.DataNode;
+
+import java.util.Stack;
+
+/**
+ * Represents an serializer handler to process the XML content and add
+ * element to the stack.
+ */
+public abstract class XmlSerializerHandler {
+
+ /**
+ * Sets the namespace and tag name in element tree maintained in stack.
+ *
+ * @param elementStack element tree stack
+ */
+ Element processXmlContext(DataNode dataNode,
+ Stack<Element> elementStack) {
+
+ Element newElement = updateNameAndNamespace(dataNode,
+ elementStack);
+ return newElement;
+ }
+
+ /**
+ * Returns the new element name by updating tag name and namespace.
+ *
+ * @param node YDT context node
+ * @return new element name by updating tag name and namespace
+ */
+ Element updateNameAndNamespace(DataNode node,
+ Stack<Element> elementStack) {
+ String nameSpace = null;
+ String name = null;
+ if (node.key() != null && node.key().schemaId() != null) {
+ nameSpace = node.key().schemaId().namespace();
+ name = node.key().schemaId().name();
+ }
+
+ if (elementStack.isEmpty()) {
+ Element rootElement = DocumentHelper.createDocument()
+ .addElement(name);
+ if (nameSpace != null) {
+ rootElement.add(Namespace.get(nameSpace));
+ }
+ return rootElement;
+ } else {
+ /*
+ * If element stack is not empty then root element is already
+ * created.
+ */
+ Element xmlElement = elementStack.peek();
+ Element newElement;
+ if (nameSpace != null) {
+ newElement = xmlElement.addElement(name,
+ nameSpace);
+ } else {
+ newElement = xmlElement.addElement(name);
+ }
+ return newElement;
+ }
+ }
+
+ /**
+ * Sets the leaf value in the current element maintained in stack.
+ * Default behaviour is to do nothing.
+ *
+ * @param domElementStack current element node in the stack
+ * @param dataNode data node
+ */
+ public void setXmlValue(DataNode dataNode,
+ Stack<Element> domElementStack) {
+ }
+}
diff --git a/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/XmlSerializerLeafHandler.java b/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/XmlSerializerLeafHandler.java
new file mode 100644
index 0000000..cdde0f6
--- /dev/null
+++ b/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/XmlSerializerLeafHandler.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yang.serializers.xml;
+
+import org.dom4j.Element;
+import org.onosproject.yang.model.DataNode;
+import org.onosproject.yang.model.LeafNode;
+
+import java.util.Stack;
+
+/**
+ * Represents a leaf node handler in XML serializer.
+ */
+public class XmlSerializerLeafHandler extends XmlSerializerHandler {
+
+ @Override
+ public void setXmlValue(DataNode node, Stack<Element> elementStack) {
+ Object value = ((LeafNode) node).value();
+ if (value != null) {
+ elementStack.peek().setText(value.toString());
+ }
+ }
+}
diff --git a/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/XmlSerializerListener.java b/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/XmlSerializerListener.java
new file mode 100644
index 0000000..b062ac9
--- /dev/null
+++ b/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/XmlSerializerListener.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yang.serializers.xml;
+
+import org.dom4j.Element;
+import org.onosproject.yang.model.DataNode;
+import org.onosproject.yang.model.ResourceId;
+import org.onosproject.yang.runtime.AnnotatedNodeInfo;
+import org.onosproject.yang.runtime.CompositeData;
+import org.onosproject.yang.runtime.helperutils.HelperContext;
+
+import static org.onosproject.yang.runtime.helperutils.SerializerHelper.addDataNode;
+import static org.onosproject.yang.runtime.helperutils.SerializerHelper.exitDataNode;
+import static org.onosproject.yang.runtime.helperutils.SerializerHelper.getResourceId;
+import static org.onosproject.yang.serializers.utils.SerializersUtil.convertXmlAttributesToAnnotations;
+import static org.onosproject.yang.serializers.xml.XmlNodeType.OBJECT_NODE;
+import static org.onosproject.yang.serializers.xml.XmlNodeType.TEXT_NODE;
+
+/**
+ * Default implementation of XML listener.
+ */
+class XmlSerializerListener implements XmlListener {
+
+ /**
+ * Data node builder.
+ */
+ private DataNode.Builder dnBuilder;
+
+ /**
+ * Composite data builder.
+ */
+ private CompositeData.Builder cBuilder;
+
+ /**
+ * Sets the data node builder.
+ *
+ * @param builder data node builder
+ */
+ void dnBuilder(DataNode.Builder builder) {
+ dnBuilder = builder;
+ }
+
+ /**
+ * Returns data node builder.
+ *
+ * @return data node builder
+ */
+ DataNode.Builder dnBuilder() {
+ return dnBuilder;
+ }
+
+ /**
+ * Sets the composite data node builder.
+ *
+ * @return composite data builder
+ */
+ public CompositeData.Builder cBuilder() {
+ return cBuilder;
+ }
+
+ /**
+ * Returns composite data builder.
+ *
+ * @return composite data builder
+ */
+ public void cBuilder(CompositeData.Builder cBuilder) {
+ this.cBuilder = cBuilder;
+ }
+
+
+ @Override
+ public void enterXmlElement(Element element, XmlNodeType nodeType,
+ Element rootElement) {
+
+ // root element should not be added to data node
+ if (element.equals(rootElement)) {
+ return;
+ }
+
+ if (nodeType == OBJECT_NODE && element.content() == null ||
+ element.content().isEmpty()) {
+ nodeType = TEXT_NODE;
+ }
+
+ if (nodeType == OBJECT_NODE) {
+ if (dnBuilder != null) {
+ dnBuilder = addDataNode(dnBuilder, element.getName(),
+ element.getNamespace().getURI(),
+ null, null);
+ }
+ } else if (nodeType == TEXT_NODE) {
+ if (dnBuilder != null) {
+ dnBuilder = addDataNode(dnBuilder, element.getName(),
+ element.getNamespace().getURI(),
+ element.getText(), null);
+ }
+ }
+ }
+
+ @Override
+ public void exitXmlElement(Element element, XmlNodeType nodeType,
+ Element rootElement) {
+ // Ignore the root element as it is not added to data node
+ if (element.equals(rootElement)) {
+ return;
+ }
+
+ // Build resource Id for annotations
+ ResourceId id = getResourceId(dnBuilder);
+ AnnotatedNodeInfo annotatedNodeInfo =
+ convertXmlAttributesToAnnotations(element, id);
+ if (annotatedNodeInfo != null) {
+ cBuilder.addAnnotatedNodeInfo(annotatedNodeInfo);
+ }
+
+ /*
+ * Since we need to build data node from top node, we should not
+ * traverse back to parent for top node.
+ */
+ HelperContext info = (HelperContext) dnBuilder.appInfo();
+ if (info.getParentResourceIdBldr() == null) {
+ dnBuilder = exitDataNode(dnBuilder);
+ }
+ }
+}
diff --git a/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/XmlSerializerNodeHandler.java b/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/XmlSerializerNodeHandler.java
new file mode 100644
index 0000000..0ae3539
--- /dev/null
+++ b/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/XmlSerializerNodeHandler.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yang.serializers.xml;
+
+/**
+ * Represents a single instance node and multi instance node handler.
+ */
+public class XmlSerializerNodeHandler extends XmlSerializerHandler {
+}
diff --git a/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/XmlWalker.java b/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/XmlWalker.java
new file mode 100644
index 0000000..81c920a
--- /dev/null
+++ b/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/XmlWalker.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yang.serializers.xml;
+
+import org.dom4j.Element;
+
+/**
+ * Abstraction of an entity which provides interfaces for XML walk.
+ * This interface serve as common tools for anyone who needs to parse the XML
+ * node with depth-first algorithm.
+ */
+interface XmlWalker {
+
+ /**
+ * Walks the XML data tree. Protocols implements XML listener service
+ * and walks XML tree with input as implemented object. XML walker provides
+ * call backs to implemented methods.
+ *
+ * @param listener XML listener implemented by the protocol
+ * @param walkElement node(element) of the XML data tree
+ * @param rootElement root node(element) of the XML data tree
+ */
+ void walk(XmlListener listener, Element walkElement,
+ Element rootElement);
+}
diff --git a/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/package-info.java b/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/package-info.java
new file mode 100644
index 0000000..43b4abc
--- /dev/null
+++ b/serializers/xml/src/main/java/org/onosproject/yang/serializers/xml/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * The XML serializer implementation of the YangSerializer interface.
+ */
+package org.onosproject.yang.serializers.xml;
diff --git a/serializers/xml/src/test/java/org/onosproject/yang/serializers/xml/MockYangSchemaNodeProvider.java b/serializers/xml/src/test/java/org/onosproject/yang/serializers/xml/MockYangSchemaNodeProvider.java
new file mode 100644
index 0000000..138d22d
--- /dev/null
+++ b/serializers/xml/src/test/java/org/onosproject/yang/serializers/xml/MockYangSchemaNodeProvider.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yang.serializers.xml;
+
+import org.onosproject.yang.YangModel;
+import org.onosproject.yang.compiler.datamodel.YangNode;
+import org.onosproject.yang.compiler.datamodel.YangSchemaNode;
+import org.onosproject.yang.runtime.AppModuleInfo;
+import org.onosproject.yang.runtime.DefaultAppModuleInfo;
+import org.onosproject.yang.runtime.DefaultModelRegistrationParam;
+import org.onosproject.yang.runtime.ModelRegistrationParam;
+import org.onosproject.yang.runtime.YangModelRegistry;
+import org.onosproject.yang.runtime.ymrimpl.DefaultYangModelRegistry;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import static org.onosproject.yang.compiler.datamodel.utils.DataModelUtils.deSerializeDataModel;
+import static org.onosproject.yang.compiler.plugin.utils.YangApacheUtils.processModuleId;
+import static org.onosproject.yang.compiler.plugin.utils.YangApacheUtils.processYangModel;
+import static org.onosproject.yang.compiler.utils.UtilConstants.TEMP;
+import static org.onosproject.yang.compiler.utils.io.impl.YangIoUtils.deleteDirectory;
+import static org.onosproject.yang.runtime.helperutils.RuntimeHelper.getInterfaceClassName;
+
+/**
+ * Represents mock bundle context. provides bundle context for YSR to do unit
+ * testing.
+ */
+public class MockYangSchemaNodeProvider {
+
+ private static final String FS = File.separator;
+ private static final String PATH = System.getProperty("user.dir") +
+ FS + "target" + FS + "classes" + FS;
+ private static final String SER_FILE_PATH = "yang" + FS + "resources" +
+ FS + "YangMetaData.ser";
+ private static final String META_PATH = PATH + SER_FILE_PATH;
+ private static final String TEMP_FOLDER_PATH = PATH + TEMP;
+ private YangModelRegistry reg = new DefaultYangModelRegistry();
+ private List<YangNode> nodes = new ArrayList<>();
+
+ /**
+ * Creates an instance of mock bundle context.
+ */
+ public MockYangSchemaNodeProvider() {
+ }
+
+ /**
+ * Process YANG schema node for a application.
+ */
+ public void processSchemaRegistry() {
+ try {
+ //Need to deserialize generated meta data file for unit tests.
+ Set<YangNode> appNode = deSerializeDataModel(META_PATH);
+ nodes.addAll(appNode);
+ reg.registerModel(prepareParam(nodes));
+ deleteDirectory(TEMP_FOLDER_PATH);
+ } catch (IOException e) {
+ }
+ }
+
+ /**
+ * Unregister given nodes from runtime service.
+ *
+ * @param nodes list of nodes
+ */
+ public void unRegister(List<YangNode> nodes) {
+ reg.unregisterModel(prepareParam(nodes));
+ }
+
+ /**
+ * Prepares model registration parameter.
+ *
+ * @param nodes list of nodes
+ * @return model registration parameter
+ */
+ private ModelRegistrationParam prepareParam(List<YangNode> nodes) {
+ //Process loading class file.
+ String appName;
+ ClassLoader classLoader = getClass().getClassLoader();
+
+ //Create model registration param.
+ ModelRegistrationParam.Builder b =
+ DefaultModelRegistrationParam.builder();
+
+ //create a new YANG model
+ YangModel model = processYangModel(META_PATH, nodes);
+ //set YANG model
+ b.setYangModel(model);
+
+ Iterator<YangNode> it = nodes.iterator();
+ while (it.hasNext()) {
+ YangSchemaNode node = it.next();
+
+ //If service class is not generated then use
+ // interface file to load this class.
+ appName = getInterfaceClassName(node);
+ Class<?> cls;
+ try {
+ cls = classLoader.loadClass(appName);
+ } catch (ClassNotFoundException e) {
+ continue;
+ }
+
+ //generate app info.
+ AppModuleInfo info = new DefaultAppModuleInfo(cls, null);
+ b.addAppModuleInfo(processModuleId((YangNode) node), info);
+ }
+ return b.build();
+ }
+
+ /**
+ * Returns schema registry.
+ *
+ * @return schema registry
+ */
+ public DefaultYangModelRegistry registry() {
+ return (DefaultYangModelRegistry) reg;
+ }
+}
diff --git a/serializers/xml/src/test/java/org/onosproject/yang/serializers/xml/MockYangSerializerContext.java b/serializers/xml/src/test/java/org/onosproject/yang/serializers/xml/MockYangSerializerContext.java
new file mode 100644
index 0000000..dfc8d06
--- /dev/null
+++ b/serializers/xml/src/test/java/org/onosproject/yang/serializers/xml/MockYangSerializerContext.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yang.serializers.xml;
+
+import org.onosproject.yang.model.SchemaContext;
+import org.onosproject.yang.runtime.Annotation;
+import org.onosproject.yang.runtime.DefaultAnnotation;
+import org.onosproject.yang.runtime.YangSerializerContext;
+import org.onosproject.yang.runtime.ymrimpl.DefaultYangModelRegistry;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Tests the default schema context provider methods.
+ */
+public class MockYangSerializerContext implements YangSerializerContext {
+
+ private static MockYangSchemaNodeProvider schemaProvider =
+ new MockYangSchemaNodeProvider();
+ private static final String NETCONF_NS =
+ "urn:ietf:params:xml:ns:netconf:base:1.0";
+ private static final String XMNLS_NC = "xmlns:xc";
+
+
+ @Override
+ public SchemaContext getContext() {
+ schemaProvider.processSchemaRegistry();
+ DefaultYangModelRegistry registry = schemaProvider.registry();
+ return registry;
+ }
+
+ @Override
+ public List<Annotation> getProtocolAnnotations() {
+ Annotation annotation = new DefaultAnnotation(XMNLS_NC, NETCONF_NS);
+ List<Annotation> protocolAnnotation = new LinkedList<>();
+ protocolAnnotation.add(annotation);
+ return protocolAnnotation;
+ }
+}
diff --git a/serializers/xml/src/test/java/org/onosproject/yang/serializers/xml/XmlSerializerTest.java b/serializers/xml/src/test/java/org/onosproject/yang/serializers/xml/XmlSerializerTest.java
new file mode 100644
index 0000000..1f53ac5
--- /dev/null
+++ b/serializers/xml/src/test/java/org/onosproject/yang/serializers/xml/XmlSerializerTest.java
@@ -0,0 +1,451 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yang.serializers.xml;
+
+import org.apache.commons.io.IOUtils;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.onosproject.yang.model.DataNode;
+import org.onosproject.yang.model.InnerNode;
+import org.onosproject.yang.model.LeafListKey;
+import org.onosproject.yang.model.LeafNode;
+import org.onosproject.yang.model.ListKey;
+import org.onosproject.yang.model.NodeKey;
+import org.onosproject.yang.model.ResourceData;
+import org.onosproject.yang.model.SchemaId;
+import org.onosproject.yang.runtime.AnnotatedNodeInfo;
+import org.onosproject.yang.runtime.Annotation;
+import org.onosproject.yang.runtime.CompositeData;
+import org.onosproject.yang.runtime.CompositeStream;
+import org.onosproject.yang.runtime.DefaultCompositeStream;
+import org.onosproject.yang.runtime.YangSerializer;
+import org.onosproject.yang.runtime.YangSerializerContext;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+/**
+ *
+ */
+public class XmlSerializerTest {
+
+ private static YangSerializerContext context;
+ private static YangSerializer xmlSerializer;
+
+ @BeforeClass
+ public static void prepare() {
+ context = new MockYangSerializerContext();
+ xmlSerializer = new XmlSerializer();
+ }
+
+ /**
+ * Validates data node in which XML element is of type YANG container.
+ */
+ @Test
+ public void testContainer() {
+ String path = "src/test/resources/testContainer.xml";
+
+ DefaultCompositeStream external =
+ new DefaultCompositeStream(null, parseInput(path));
+ CompositeData compositeData = xmlSerializer.decode(external, context);
+ DataNode rootNode = validateRootDataNode(compositeData.resourceData());
+ DataNode food = validateContainerDataNode(rootNode, "food", "yrt:food");
+ validateLeafDataNode(food, "p1", "yrt:food", "p1_value");
+ validateLeafListDataNode(food, "p2", "yrt:food", "p2_value");
+ validateLeafListDataNode(food, "p2", "yrt:food", "p2_value1");
+ DataNode c2 = validateContainerDataNode(rootNode, "c2", "yrt:food");
+ validateLeafDataNode(c2, "p3", "yrt:food", "p3_value");
+
+ // encode test
+ CompositeStream compositeStream = xmlSerializer.encode(compositeData,
+ context);
+ InputStream inputStream = compositeStream.resourceData();
+ assertThat(convertInputStreamToString(inputStream), is(parseXml(path)));
+ }
+
+ /**
+ * Validates data node in which XML element is of type YANG leaf.
+ */
+ @Test
+ public void testModuleLevelLeaf() {
+ String path = "src/test/resources/testModuleLevelLeaf.xml";
+
+ DefaultCompositeStream external =
+ new DefaultCompositeStream(null, parseInput(path));
+ CompositeData compositeData = xmlSerializer.decode(external, context);
+ DataNode rootNode = validateRootDataNode(compositeData.resourceData());
+ validateLeafDataNode(rootNode, "bool", "yrt:food", "true");
+
+ // encode test
+ CompositeStream compositeStream = xmlSerializer.encode(compositeData,
+ context);
+ InputStream inputStream = compositeStream.resourceData();
+ assertThat(convertInputStreamToString(inputStream), is(parseXml(path)));
+ }
+
+ /**
+ * Validates data node in which XML element is of type YANG list.
+ */
+ @Test
+ public void testListWithKeyleaves() {
+ String path = "src/test/resources/testListWithKeyleaves.xml";
+ DefaultCompositeStream external =
+ new DefaultCompositeStream(null, parseInput(path));
+ CompositeData compositeData = xmlSerializer.decode(external, context);
+ DataNode rootNode = validateRootDataNode(compositeData.resourceData());
+ List<String> keyNames = new LinkedList<>();
+ keyNames.add("k1");
+ keyNames.add("k2");
+ keyNames.add("k3");
+
+ List<String> keyNs = new LinkedList<>();
+ keyNs.add("yrt:list");
+ keyNs.add("yrt:list");
+ keyNs.add("yrt:list");
+
+ List<Object> values = new LinkedList<>();
+ values.add("k1_Value");
+ values.add("k2_Value");
+ values.add("k3_Value");
+
+ DataNode listl1 = validateListDataNode(rootNode, "l1", "yrt:list",
+ keyNames, keyNs, values);
+ validateLeafDataNode(listl1, "k1", "yrt:list", "k1_Value");
+ validateLeafDataNode(listl1, "k2", "yrt:list", "k2_Value");
+ validateLeafDataNode(listl1, "k3", "yrt:list", "k3_Value");
+ DataNode c1 = validateContainerDataNode(listl1, "c1", "yrt:list");
+ validateLeafDataNode(c1, "leaf_c1", "yrt:list", "l1_value");
+
+ values = new LinkedList<>();
+ values.add("k1_Value1");
+ values.add("k2_Value2");
+ values.add("k3_Value3");
+
+ DataNode listl2 = validateListDataNode(rootNode, "l1", "yrt:list",
+ keyNames, keyNs, values);
+ validateLeafDataNode(listl2, "k1", "yrt:list", "k1_Value1");
+ validateLeafDataNode(listl2, "k2", "yrt:list", "k2_Value2");
+ validateLeafDataNode(listl2, "k3", "yrt:list", "k3_Value3");
+ c1 = validateContainerDataNode(listl2, "c1", "yrt:list");
+ validateLeafDataNode(c1, "leaf_c1", "yrt:list", "l1_value1");
+
+ // encode test
+ CompositeStream compositeStream = xmlSerializer.encode(compositeData,
+ context);
+ InputStream inputStream = compositeStream.resourceData();
+ assertThat(convertInputStreamToString(inputStream), is(parseXml(path)));
+ }
+
+ /**
+ * Validates data node in which XML element is child of YANG
+ * choice-case.
+ */
+ @Test
+ public void testChoiceCase() {
+ String path = "src/test/resources/testChoiceCase.xml";
+
+ DefaultCompositeStream external =
+ new DefaultCompositeStream(null, parseInput(path));
+ CompositeData compositeData = xmlSerializer.decode(external, context);
+ DataNode rootNode = validateRootDataNode(compositeData.resourceData());
+ DataNode list1 = validateListDataNode(rootNode, "banana",
+ "yrt:choice-case", null, null, null);
+ validateLeafDataNode(list1, "l1", "yrt:choice-case", "value2");
+ DataNode coldDrink = validateContainerDataNode(rootNode, "cold-drink",
+ "yrt:choice-case");
+ validateLeafListDataNode(coldDrink, "flavor", "yrt:choice-case",
+ "value3");
+
+ // encode test
+ CompositeStream compositeStream = xmlSerializer.encode(compositeData,
+ context);
+ InputStream inputStream = compositeStream.resourceData();
+ assertThat(convertInputStreamToString(inputStream), is(parseXml(path)));
+ }
+
+ /**
+ * Validates data node in which XML element is of YANG augmented nodes.
+ */
+ @Test
+ public void testAugment() {
+ String path = "src/test/resources/testAugment.xml";
+
+ String uri = "urn:ietf:params:xml:ns:yang:yrt-ietf-network:networks/network/node";
+ DefaultCompositeStream external =
+ new DefaultCompositeStream(uri, parseInput(path));
+ CompositeData compositeData = xmlSerializer.decode(external, context);
+ ResourceData resourceData = compositeData.resourceData();
+ List<DataNode> dataNodes = resourceData.dataNodes();
+ DataNode dataNode = dataNodes.get(0);
+ SchemaId schemaId = dataNode.key().schemaId();
+ assertThat(schemaId.name(), is("t-point"));
+ assertThat(schemaId.namespace(), is("urn:ietf:params:xml:ns:yang:yrt-ietf-network-topology"));
+ validateLeafDataNode(dataNode, "tp-id",
+ "urn:ietf:params:xml:ns:yang:yrt-ietf-network-topology", "Stub");
+
+ // encode test
+ CompositeStream compositeStream = xmlSerializer.encode(compositeData,
+ context);
+ InputStream inputStream = compositeStream.resourceData();
+ assertThat(convertInputStreamToString(inputStream), is(parseXml(path)));
+ }
+
+ /**
+ * Validates data node in which XML element is child of YANG grouping.
+ */
+ @Test
+ public void testGroupingUsesDataNode() {
+ String path = "src/test/resources/testGroupingUses.xml";
+
+ String uri = "urn:ietf:params:xml:ns:yang:yrt-ietf-network:networks-state/network";
+ DefaultCompositeStream external =
+ new DefaultCompositeStream(uri, parseInput(path));
+ CompositeData compositeData = xmlSerializer.decode(external, context);
+ ResourceData resourceData = compositeData.resourceData();
+ List<DataNode> dataNodes = resourceData.dataNodes();
+ LeafNode dataNode = ((LeafNode) dataNodes.get(0));
+ SchemaId schemaId = dataNode.key().schemaId();
+ assertThat(schemaId.name(), is("network-ref"));
+ assertThat(schemaId.namespace(), is("urn:ietf:params:xml:ns:yang:yrt-ietf-network"));
+ assertThat(dataNode.value().toString(), is("abc"));
+
+ // encode test
+ CompositeStream compositeStream = xmlSerializer.encode(compositeData,
+ context);
+ InputStream inputStream = compositeStream.resourceData();
+ assertThat(convertInputStreamToString(inputStream), is(parseXml(path)));
+ }
+
+ /**
+ * Validates whether XML attributes is converted to annotations.
+ */
+ @Test
+ public void testXmlAttributes() {
+ String path = "src/test/resources/testXmlAttributes.xml";
+ String namespace = "http://example.com/schema/1.2/config";
+
+ DefaultCompositeStream external =
+ new DefaultCompositeStream(null, parseInput(path));
+ CompositeData compositeData = xmlSerializer.decode(external, context);
+ DataNode rootNode = validateRootDataNode(compositeData.resourceData());
+ DataNode top = validateContainerDataNode(rootNode, "top", namespace);
+ DataNode interfaceDn = validateContainerDataNode(top, "interface",
+ namespace);
+ validateLeafDataNode(interfaceDn, "name", namespace, "Ethernet0/0");
+ validateLeafDataNode(interfaceDn, "mtu", namespace, "1500");
+ DataNode address = validateContainerDataNode(interfaceDn, "address",
+ namespace);
+ validateLeafDataNode(address, "name", namespace, "192.0.2.4");
+ validateLeafDataNode(address, "prefix-length", namespace, "24");
+
+ List<AnnotatedNodeInfo> annotatedNodeInfos = compositeData
+ .annotatedNodesInfo();
+ AnnotatedNodeInfo annotatedNodeInfo = annotatedNodeInfos.get(0);
+ List<Annotation> annotationList = annotatedNodeInfo.annotations();
+ Annotation annotation = annotationList.get(0);
+ assertThat(annotation.name(), is("xc:operation"));
+ assertThat(annotation.value(), is("replace"));
+
+ // encode test
+ CompositeStream compositeStream = xmlSerializer.encode(compositeData,
+ context);
+ InputStream inputStream = compositeStream.resourceData();
+ assertThat(convertInputStreamToString(inputStream), is(parseXml(path)));
+ }
+
+ /**
+ * Validates and returns container data node.
+ *
+ * @param parent data node holding container
+ * @param name name of the container
+ * @param namespace namespace of the container
+ * @return container data node
+ */
+ private static DataNode validateContainerDataNode(DataNode parent,
+ String name,
+ String namespace) {
+ Map<NodeKey, DataNode> childNodes = ((InnerNode) parent).childNodes();
+ NodeKey key = NodeKey.builder().schemaId(name, namespace).build();
+ DataNode dataNode = childNodes.get(key);
+ SchemaId schemaId = dataNode.key().schemaId();
+ assertThat(schemaId.name(), is(name));
+ assertThat(schemaId.namespace(), is(namespace));
+ return dataNode;
+ }
+
+ /**
+ * Validates and returns list data node.
+ *
+ * @param parent data node holding list
+ * @param name name of the list
+ * @param namespace namespace of the list
+ * @param keynames list of key leaf names
+ * @param keyNs list of key leaf namespace
+ * @param keyVal list of key leaf values
+ * @return list data node
+ */
+ private static DataNode validateListDataNode(DataNode parent,
+ String name, String namespace,
+ List<String> keynames,
+ List<String> keyNs,
+ List<Object> keyVal) {
+ Map<NodeKey, DataNode> childNodes = ((InnerNode) parent).childNodes();
+ NodeKey key = NodeKey.builder().schemaId(name, namespace).build();
+ DataNode dataNode;
+ if (keynames != null && !keynames.isEmpty()) {
+ ListKey.ListKeyBuilder listKeyBldr = new ListKey.ListKeyBuilder();
+ listKeyBldr.schemaId(key.schemaId());
+ for (int i = 0; i < keynames.size(); i++) {
+ listKeyBldr.addKeyLeaf(keynames.get(i), keyNs.get(i),
+ keyVal.get(i));
+ }
+ dataNode = childNodes.get(listKeyBldr.build());
+ } else {
+ dataNode = childNodes.get(key);
+ }
+ SchemaId schemaId = dataNode.key().schemaId();
+ assertThat(schemaId.name(), is(name));
+ assertThat(schemaId.namespace(), is(namespace));
+ return dataNode;
+ }
+
+ /**
+ * Validates leaf data node.
+ *
+ * @param parent data node holding leaf
+ * @param name name of the leaf
+ * @param namespace namespace of the leaf
+ * @param value leaf value
+ */
+ private static void validateLeafDataNode(DataNode parent,
+ String name, String namespace,
+ Object value) {
+ Map<NodeKey, DataNode> childNodes = ((InnerNode) parent).childNodes();
+ NodeKey key = NodeKey.builder().schemaId(name, namespace).build();
+ LeafNode dataNode = ((LeafNode) childNodes.get(key));
+ SchemaId schemaId = dataNode.key().schemaId();
+ assertThat(schemaId.name(), is(name));
+ assertThat(schemaId.namespace(), is(namespace));
+ assertThat(dataNode.value().toString(), is(value));
+ }
+
+ /**
+ * Validates leaf-list data node.
+ *
+ * @param parent data node holding leaf-list
+ * @param name name of the leaf-list
+ * @param namespace namespace of the leaf-list
+ * @param value leaf-list value
+ */
+ private static void validateLeafListDataNode(DataNode parent,
+ String name, String namespace,
+ Object value) {
+ Map<NodeKey, DataNode> childNodes = ((InnerNode) parent).childNodes();
+ NodeKey key = NodeKey.builder().schemaId(name, namespace).build();
+ LeafListKey.LeafListKeyBuilder leafListBldr =
+ new LeafListKey.LeafListKeyBuilder();
+ leafListBldr.schemaId(key.schemaId());
+ leafListBldr.value(value);
+ DataNode leafListNode = childNodes.get(leafListBldr.build());
+ SchemaId schemaId = leafListNode.key().schemaId();
+ assertThat(schemaId.name(), is(name));
+ assertThat(schemaId.namespace(), is(namespace));
+ assertThat(((LeafNode) leafListNode).value().toString(), is(value));
+ }
+
+ /**
+ * Validates root data node.
+ *
+ * @param resourceData resource data which holds data node
+ * @return root data node
+ */
+ private static DataNode validateRootDataNode(ResourceData resourceData) {
+ List<DataNode> dataNodes = resourceData.dataNodes();
+ DataNode rootNode = dataNodes.get(0);
+ SchemaId rootSchemaId = rootNode.key().schemaId();
+ assertThat(rootSchemaId.name(), is("/"));
+ return rootNode;
+ }
+
+ /**
+ * Reads XML contents from file path and returns input stream.
+ *
+ * @param path path of XML file
+ * @return input stream
+ */
+ private static InputStream parseInput(String path) {
+ String temp;
+ StringBuilder sb = new StringBuilder();
+ try (BufferedReader br = new BufferedReader(new FileReader(path))) {
+ while ((temp = br.readLine()) != null) {
+ sb.append(temp);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return IOUtils.toInputStream(sb);
+ }
+
+ /**
+ * Reads XML contents from file path and returns input stream.
+ *
+ * @param path path of XML file
+ * @return input stream
+ */
+ private static String parseXml(String path) {
+ String temp;
+ StringBuilder sb = new StringBuilder();
+ try (BufferedReader br = new BufferedReader(new FileReader(path))) {
+ while ((temp = br.readLine()) != null) {
+ sb.append(temp);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Converts input stream to string format.
+ *
+ * @param inputStream input stream of xml
+ * @return XML string
+ */
+ private static String convertInputStreamToString(InputStream inputStream) {
+ BufferedReader br;
+ StringBuilder sb = new StringBuilder();
+ String xmlData;
+ br = new BufferedReader(new InputStreamReader(inputStream));
+ try {
+ while ((xmlData = br.readLine()) != null) {
+ sb.append(xmlData);
+ }
+ } catch (IOException e) {
+ throw new XmlSerializerException(e.getMessage());
+ }
+ return sb.toString();
+ }
+}
diff --git a/serializers/xml/src/test/java/org/onosproject/yang/serializers/xml/package-info.java b/serializers/xml/src/test/java/org/onosproject/yang/serializers/xml/package-info.java
new file mode 100644
index 0000000..43b4abc
--- /dev/null
+++ b/serializers/xml/src/test/java/org/onosproject/yang/serializers/xml/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * The XML serializer implementation of the YangSerializer interface.
+ */
+package org.onosproject.yang.serializers.xml;
diff --git a/serializers/xml/src/test/resources/testAugment.xml b/serializers/xml/src/test/resources/testAugment.xml
new file mode 100644
index 0000000..4c883f6
--- /dev/null
+++ b/serializers/xml/src/test/resources/testAugment.xml
@@ -0,0 +1,3 @@
+<t-point xmlns="urn:ietf:params:xml:ns:yang:yrt-ietf-network-topology">
+<tp-id>Stub</tp-id>
+</t-point>
\ No newline at end of file
diff --git a/serializers/xml/src/test/resources/testChoiceCase.xml b/serializers/xml/src/test/resources/testChoiceCase.xml
new file mode 100644
index 0000000..22590a1
--- /dev/null
+++ b/serializers/xml/src/test/resources/testChoiceCase.xml
@@ -0,0 +1,6 @@
+<banana xmlns="yrt:choice-case">
+<l1>value2</l1>
+</banana>
+<cold-drink xmlns="yrt:choice-case">
+<flavor>value3</flavor>
+</cold-drink>
diff --git a/serializers/xml/src/test/resources/testContainer.xml b/serializers/xml/src/test/resources/testContainer.xml
new file mode 100644
index 0000000..ee679b8
--- /dev/null
+++ b/serializers/xml/src/test/resources/testContainer.xml
@@ -0,0 +1,8 @@
+<food xmlns="yrt:food">
+<p1>p1_value</p1>
+<p2>p2_value</p2>
+<p2>p2_value1</p2>
+</food>
+<c2 xmlns="yrt:food">
+<p3>p3_value</p3>
+</c2>
\ No newline at end of file
diff --git a/serializers/xml/src/test/resources/testGroupingUses.xml b/serializers/xml/src/test/resources/testGroupingUses.xml
new file mode 100644
index 0000000..45d3d05
--- /dev/null
+++ b/serializers/xml/src/test/resources/testGroupingUses.xml
@@ -0,0 +1,2 @@
+<network-ref xmlns="urn:ietf:params:xml:ns:yang:yrt-ietf-network">abc
+</network-ref>
\ No newline at end of file
diff --git a/serializers/xml/src/test/resources/testListWithKeyleaves.xml b/serializers/xml/src/test/resources/testListWithKeyleaves.xml
new file mode 100644
index 0000000..1f9616a
--- /dev/null
+++ b/serializers/xml/src/test/resources/testListWithKeyleaves.xml
@@ -0,0 +1,16 @@
+<l1 xmlns="yrt:list" operation="replace">
+<k1>k1_Value</k1>
+<k2>k2_Value</k2>
+<k3>k3_Value</k3>
+<c1>
+<leaf_c1>l1_value</leaf_c1>
+</c1>
+</l1>
+<l1 xmlns="yrt:list" operation="replace">
+<k1>k1_Value1</k1>
+<k2>k2_Value2</k2>
+<k3>k3_Value3</k3>
+<c1>
+<leaf_c1>l1_value1</leaf_c1>
+</c1>
+</l1>
diff --git a/serializers/xml/src/test/resources/testModuleLevelLeaf.xml b/serializers/xml/src/test/resources/testModuleLevelLeaf.xml
new file mode 100644
index 0000000..13da6e6
--- /dev/null
+++ b/serializers/xml/src/test/resources/testModuleLevelLeaf.xml
@@ -0,0 +1,2 @@
+<bool xmlns="yrt:food">true</bool>
+<boolean xmlns="yrt:food">true</boolean>
\ No newline at end of file
diff --git a/serializers/xml/src/test/resources/testMultipleLevelAugment.xml b/serializers/xml/src/test/resources/testMultipleLevelAugment.xml
new file mode 100644
index 0000000..ab31d06
--- /dev/null
+++ b/serializers/xml/src/test/resources/testMultipleLevelAugment.xml
@@ -0,0 +1,6 @@
+<interface xmlns="ser.ospf" operation="replace">
+<area-type>Stub</area-type>
+</interface>
+<statistics xmlns="ser.ospf" operation="replace">
+<spf-runs-count>3</spf-runs-count>
+</statistics>
\ No newline at end of file
diff --git a/serializers/xml/src/test/resources/testXmlAttributes.xml b/serializers/xml/src/test/resources/testXmlAttributes.xml
new file mode 100644
index 0000000..0ca9a71
--- /dev/null
+++ b/serializers/xml/src/test/resources/testXmlAttributes.xml
@@ -0,0 +1,10 @@
+<top xmlns="http://example.com/schema/1.2/config">
+<interface xc:operation="replace">
+<name>Ethernet0/0</name>
+<mtu>1500</mtu>
+<address>
+<name>192.0.2.4</name>
+<prefix-length>24</prefix-length>
+</address>
+</interface>
+</top>
\ No newline at end of file