45871f5402e437c459b34beb0ea9b43d107008f8
[controller.git] / opendaylight / md-sal / sal-remoterpc-connector / src / main / java / org / opendaylight / controller / remote / rpc / utils / XmlUtils.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.controller.remote.rpc.utils;
9
10 import com.google.common.base.Optional;
11 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
12 import org.opendaylight.yangtools.yang.common.QName;
13 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
14 import org.opendaylight.yangtools.yang.data.api.Node;
15 import org.opendaylight.yangtools.yang.data.api.SimpleNode;
16 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
17 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
18 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
19 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
20 import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
21 import org.opendaylight.yangtools.yang.data.impl.XmlTreeBuilder;
22 import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec;
23 import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlCodecProvider;
24 import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder;
25 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
26 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
27 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30 import org.w3c.dom.Document;
31 import org.w3c.dom.Element;
32 import org.xml.sax.SAXException;
33
34 import javax.activation.UnsupportedDataTypeException;
35 import javax.annotation.Nonnull;
36 import javax.xml.stream.XMLStreamException;
37 import javax.xml.transform.OutputKeys;
38 import javax.xml.transform.Transformer;
39 import javax.xml.transform.TransformerException;
40 import javax.xml.transform.TransformerFactory;
41 import javax.xml.transform.dom.DOMSource;
42 import javax.xml.transform.stream.StreamResult;
43 import java.io.ByteArrayInputStream;
44 import java.io.IOException;
45 import java.io.StringWriter;
46 import java.util.List;
47 import java.util.Map;
48 import java.util.Set;
49
50 /**
51  * Common XML-related utility methods, which are not specific to a particular
52  * JAXP API.
53  */
54 public class XmlUtils {
55
56     public static final XmlCodecProvider DEFAULT_XML_CODEC_PROVIDER = new XmlCodecProvider() {
57         @Override
58         public TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> codecFor(final TypeDefinition<?> baseType) {
59             return TypeDefinitionAwareCodec.from(baseType);
60         }
61     };
62
63     private XmlUtils() {
64     }
65   private static final Logger LOG = LoggerFactory.getLogger(XmlUtils.class);
66
67   public static String inputCompositeNodeToXml(CompositeNode cNode, SchemaContext schemaContext){
68     if (cNode == null) return new String();
69
70     Document domTree = null;
71     try {
72       Set<RpcDefinition> rpcs =  schemaContext.getOperations();
73       for(RpcDefinition rpc : rpcs) {
74         if(rpc.getQName().equals(cNode.getNodeType())){
75           CompositeNode inputContainer = cNode.getFirstCompositeByName(QName.create(cNode.getNodeType(), "input"));
76           domTree = XmlDocumentUtils.toDocument(inputContainer, rpc.getInput(), XmlDocumentUtils.defaultValueCodecProvider());
77           break;
78         }
79       }
80
81     } catch (UnsupportedDataTypeException e) {
82       LOG.error("Error during translation of CompositeNode to Document", e);
83     }
84     return domTransformer(domTree);
85   }
86
87   public static String outputCompositeNodeToXml(CompositeNode cNode, SchemaContext schemaContext){
88     if (cNode == null) return new String();
89
90     Document domTree = null;
91     try {
92       Set<RpcDefinition> rpcs =  schemaContext.getOperations();
93       for(RpcDefinition rpc : rpcs) {
94         if(rpc.getQName().equals(cNode.getNodeType())){
95           domTree = XmlDocumentUtils.toDocument(cNode, rpc.getOutput(), XmlDocumentUtils.defaultValueCodecProvider());
96           break;
97         }
98       }
99
100     } catch (UnsupportedDataTypeException e) {
101       LOG.error("Error during translation of CompositeNode to Document", e);
102     }
103     return domTransformer(domTree);
104   }
105
106   private static String domTransformer(Document domTree) {
107     StringWriter writer = new StringWriter();
108     try {
109       TransformerFactory tf = TransformerFactory.newInstance();
110       Transformer transformer = tf.newTransformer();
111       transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
112       transformer.transform(new DOMSource(domTree), new StreamResult(writer));
113     } catch (TransformerException e) {
114
115       LOG.error("Error during translation of Document to OutputStream", e);
116     }
117     LOG.debug("compositeNodeToXml " + writer.toString());
118
119     return writer.toString();
120   }
121
122   public static CompositeNode xmlToCompositeNode(String xml){
123     if (xml==null || xml.length()==0) return null;
124
125     Node<?> dataTree;
126     try {
127       dataTree = XmlTreeBuilder.buildDataTree(new ByteArrayInputStream(xml.getBytes()));
128     } catch (XMLStreamException e) {
129       LOG.error("Error during building data tree from XML", e);
130       return null;
131     }
132     if (dataTree == null) {
133       LOG.error("data tree is null");
134       return null;
135     }
136     if (dataTree instanceof SimpleNode) {
137       LOG.error("RPC XML was resolved as SimpleNode");
138       return null;
139     }
140     return (CompositeNode) dataTree;
141   }
142
143   public static CompositeNode inputXmlToCompositeNode(QName rpc, String xml,  SchemaContext schemaContext){
144     if (xml==null || xml.length()==0) return null;
145
146     CompositeNode compositeNode = null;
147     try {
148
149       Document doc = XmlUtil.readXmlToDocument(xml);
150       LOG.debug("xmlToCompositeNode Document is " + xml );
151       Set<RpcDefinition> rpcs =  schemaContext.getOperations();
152       for(RpcDefinition rpcDef : rpcs) {
153         if(rpcDef.getQName().equals(rpc)){
154           QName input = rpcDef.getInput().getQName();
155           Element xmlData = (Element) doc.getElementsByTagNameNS(input.getNamespace().toString(), "input").item(0);
156           List<Node<?>> dataNodes = XmlDocumentUtils.toDomNodes(xmlData,
157               Optional.of(rpcDef.getInput().getChildNodes()), schemaContext);
158           final CompositeNodeBuilder<ImmutableCompositeNode> it = ImmutableCompositeNode.builder();
159           it.setQName(input);
160           it.add(ImmutableCompositeNode.create(input, dataNodes));
161           compositeNode = it.toInstance();
162           break;
163         }
164       }
165     } catch (SAXException e) {
166       LOG.error("Error during building data tree from XML", e);
167     } catch (IOException e) {
168       LOG.error("Error during building data tree from XML", e);
169     }
170
171     LOG.debug("xmlToCompositeNode " + compositeNode.toString());
172     return compositeNode;
173   }
174
175     public static TypeDefinition<?> resolveBaseTypeFrom(final @Nonnull TypeDefinition<?> type) {
176         TypeDefinition<?> superType = type;
177         while (superType.getBaseType() != null) {
178             superType = superType.getBaseType();
179         }
180         return superType;
181     }
182
183     static String encodeIdentifier(final RandomPrefix prefixes, final YangInstanceIdentifier id) {
184         StringBuilder textContent = new StringBuilder();
185         for (PathArgument pathArgument : id.getPathArguments()) {
186             textContent.append('/');
187             textContent.append(prefixes.encodeQName(pathArgument.getNodeType()));
188             if (pathArgument instanceof NodeIdentifierWithPredicates) {
189                 Map<QName, Object> predicates = ((NodeIdentifierWithPredicates) pathArgument).getKeyValues();
190
191                 for (QName keyValue : predicates.keySet()) {
192                   Object value = predicates.get(keyValue);
193                   String type = value.getClass().getName();
194                   String predicateValue = String.valueOf(value);
195                     textContent.append('[');
196                     textContent.append(prefixes.encodeQName(keyValue));
197                     textContent.append("='");
198                     textContent.append(predicateValue);
199                     textContent.append("@");
200                     textContent.append(type);
201                     textContent.append("']");
202                 }
203             } else if (pathArgument instanceof NodeWithValue) {
204                 textContent.append("[.='");
205                 textContent.append(((NodeWithValue) pathArgument).getValue());
206                 textContent.append("']");
207             }
208         }
209
210         return textContent.toString();
211     }
212 }