2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.yangtools.restconf.utils;
10 import java.io.IOException;
11 import java.io.InputStream;
13 import java.net.URLEncoder;
14 import java.util.AbstractMap.SimpleEntry;
15 import java.util.Arrays;
16 import java.util.Date;
17 import java.util.HashSet;
18 import java.util.List;
20 import java.util.Map.Entry;
23 import javax.xml.parsers.DocumentBuilder;
24 import javax.xml.parsers.DocumentBuilderFactory;
25 import javax.xml.parsers.ParserConfigurationException;
27 import org.opendaylight.yangtools.yang.binding.DataObject;
28 import org.opendaylight.yangtools.yang.binding.RpcService;
29 import org.opendaylight.yangtools.yang.common.QName;
30 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
31 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
32 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
33 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
34 import org.opendaylight.yangtools.yang.data.api.Node;
35 import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
36 import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
37 import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
38 import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlCodecProvider;
39 import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils;
40 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
41 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
42 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
43 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
44 import org.opendaylight.yangtools.yang.model.api.Module;
45 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48 import org.w3c.dom.Document;
49 import org.w3c.dom.Element;
50 import org.xml.sax.SAXException;
52 import com.google.common.base.Optional;
53 import com.google.common.base.Preconditions;
54 import com.google.common.collect.BiMap;
55 import com.google.common.collect.HashBiMap;
56 import com.google.common.collect.Iterables;
58 public class RestconfUtils {
60 private static final Logger logger = LoggerFactory.getLogger(RestconfUtils.class);
62 private static final BiMap<URI,String> uriToModuleName = HashBiMap.<URI, String>create();
64 public static Entry<String,DataSchemaNode> toRestconfIdentifier(org.opendaylight.yangtools.yang.binding.InstanceIdentifier<?> bindingIdentifier, BindingIndependentMappingService mappingService, SchemaContext schemaContext) {
65 InstanceIdentifier domIdentifier = mappingService.toDataDom(bindingIdentifier);
66 return toRestconfIdentifier(domIdentifier, schemaContext);
70 public static Entry<String,DataSchemaNode> toRestconfIdentifier(
71 InstanceIdentifier xmlInstanceIdentifier,
72 SchemaContext schemaContext) {
74 final List<InstanceIdentifier.PathArgument> elements = xmlInstanceIdentifier.getPath();
75 final StringBuilder ret = new StringBuilder();
76 final QName startQName = elements.iterator().next().getNodeType();
77 URI _namespace = startQName.getNamespace();
78 Date _revision = startQName.getRevision();
79 final Module initialModule = schemaContext.findModuleByNamespaceAndRevision(_namespace, _revision);
80 DataNodeContainer node = (initialModule);
81 DataSchemaNode schemaNode = null;
82 for (final InstanceIdentifier.PathArgument element : elements) {
84 final DataSchemaNode potentialNode = node.getDataChildByName(element.getNodeType());
85 if (!isListOrContainer(potentialNode)) {
88 node = ((DataNodeContainer) potentialNode);
89 schemaNode = potentialNode;
90 ret.append(convertToRestconfIdentifier(element, node,schemaContext));
93 return new SimpleEntry<>(ret.toString(),schemaNode);
96 private static CharSequence convertContainerToRestconfIdentifier(final InstanceIdentifier.NodeIdentifier argument, SchemaContext schemaContext) {
97 return "/" + toRestconfIdentifier(argument.getNodeType(), schemaContext);
100 private static CharSequence convertListToRestconfIdentifier(final InstanceIdentifier.NodeIdentifierWithPredicates argument, final ListSchemaNode node,SchemaContext schemaContext) {
101 QName _nodeType = argument.getNodeType();
102 final CharSequence nodeIdentifier = toRestconfIdentifier(_nodeType,schemaContext);
103 final Map<QName,Object> keyValues = argument.getKeyValues();
105 StringBuilder sb = new StringBuilder("/");
106 sb.append(nodeIdentifier);
109 List<QName> _keyDefinition = node.getKeyDefinition();
110 boolean _hasElements = false;
111 for(final QName key : _keyDefinition) {
117 Object _get = keyValues.get(key);
118 sb.append(toUriString(_get));
121 return sb.toString();
123 private static String toUriString(final Object object) {
124 boolean _tripleEquals = (object == null);
128 String _string = object.toString();
129 return URLEncoder.encode(_string);
132 public static CharSequence toRestconfIdentifier(final QName qname,SchemaContext schemaContext) {
133 URI _namespace = qname.getNamespace();
134 String module = uriToModuleName.get(_namespace);
135 boolean _tripleEquals = (module == null);
137 URI _namespace_1 = qname.getNamespace();
138 Date _revision = qname.getRevision();
139 final Module moduleSchema = schemaContext.findModuleByNamespaceAndRevision(_namespace_1, _revision);
140 boolean _tripleEquals_1 = (moduleSchema == null);
141 if (_tripleEquals_1) {
144 URI _namespace_2 = qname.getNamespace();
145 String _name = moduleSchema.getName();
146 uriToModuleName.put(_namespace_2, _name);
147 String _name_1 = moduleSchema.getName();
151 return module + ':' + qname.getLocalName();
153 private static CharSequence convertToRestconfIdentifier(final InstanceIdentifier.PathArgument argument, final DataNodeContainer node, SchemaContext schemaContext) {
154 if (argument instanceof InstanceIdentifier.NodeIdentifier) {
155 return convertContainerToRestconfIdentifier((NodeIdentifier)argument, schemaContext);
156 } else if (argument instanceof InstanceIdentifier.NodeIdentifierWithPredicates
157 && node instanceof ListSchemaNode) {
158 return convertListToRestconfIdentifier((NodeIdentifierWithPredicates) argument,(ListSchemaNode) node,schemaContext);
160 throw new IllegalArgumentException("Unhandled parameter types: " +
161 Arrays.<Object>asList(argument, node).toString());
164 private static boolean isListOrContainer(final DataSchemaNode node) {
166 if ((node instanceof ListSchemaNode)) {
169 _or = ((node instanceof ListSchemaNode) || (node instanceof ContainerSchemaNode));
174 public static Module findModuleByNamespace(final URI namespace,SchemaContext schemaContext) {
175 boolean _tripleNotEquals = (namespace != null);
176 Preconditions.checkArgument(_tripleNotEquals);
177 final Set<Module> moduleSchemas = schemaContext.findModuleByNamespace(namespace);
178 Module _filterLatestModule = null;
179 if (moduleSchemas!=null) {
180 _filterLatestModule=filterLatestModule(moduleSchemas);
182 return _filterLatestModule;
185 private static Module filterLatestModule(final Iterable<Module> modules) {
186 Module latestModule = Iterables.getFirst(modules, null);
187 for (final Module module : modules) {
188 Date _revision = module.getRevision();
189 Date _revision_1 = latestModule.getRevision();
190 boolean _after = _revision.after(_revision_1);
192 latestModule = module;
198 public String findModuleNameByNamespace(final URI namespace,SchemaContext schemaContext) {
199 String moduleName = uriToModuleName.get(namespace);
200 boolean _tripleEquals = (moduleName == null);
202 final Module module = findModuleByNamespace(namespace, schemaContext);
203 boolean _tripleEquals_1 = (module == null);
204 if (_tripleEquals_1) {
207 String _name = module.getName();
209 uriToModuleName.put(namespace, moduleName);
215 * Parse rpc services from input stream.
218 * stream containing rpc services definition in xml
220 * @param mappingService
221 * current mapping service
222 * @param schemaContext
223 * parsed yang data context
224 * @return Set of classes representing rpc services parsed from input stream
226 public static Set<Class<? extends RpcService>> rpcServicesFromInputStream(InputStream inputStream, BindingIndependentMappingService mappingService,SchemaContext schemaContext){
228 DocumentBuilderFactory documentBuilder = DocumentBuilderFactory.newInstance();
229 documentBuilder.setNamespaceAware(true);
230 DocumentBuilder builder = documentBuilder.newDocumentBuilder();
231 Document doc = builder.parse(inputStream);
232 Element rootElement = doc.getDocumentElement();
234 List<Node<?>> domNodes = XmlDocumentUtils.toDomNodes(rootElement, Optional.of(schemaContext.getChildNodes()));
235 Set<Class<? extends RpcService>> rpcServices = new HashSet<Class<? extends RpcService>>();
236 for (Node<?> node:domNodes){
237 if (node instanceof ImmutableCompositeNode){
238 ImmutableCompositeNode icNode = (ImmutableCompositeNode)node;
239 QName namespace = null;
240 QName revision = null;
242 for (QName q:icNode.keySet()){
243 if (q.getLocalName().equals("namespace")){
246 if (q.getLocalName().equals("revision")){
249 if (q.getLocalName().equals("name")){
255 //FIXME: Method getRpcServiceClassFor has been modified and fixed to follow API contract. This call MUST be updated to follow
256 // contract i.e. pass correct parameters: "NAMESPACE" and "REVISION"
257 Optional<Class<? extends RpcService>> rpcService = mappingService.getRpcServiceClassFor(icNode.get(name).get(0).getValue().toString(),icNode.get(revision).get(0).getValue().toString());
258 if (rpcService.isPresent()){
259 rpcServices.add(rpcService.get());
265 } catch (ParserConfigurationException e) {
266 logger.trace("Parse configuration exception {}",e);
267 } catch (SAXException e) {
268 logger.trace("SAX exception {}",e);
269 } catch (IOException e) {
270 logger.trace("IOException {}",e);
276 * Parse DataObject from input stream.
279 * identifier of expected result object
281 * stream containing xml data to parse
282 * @param schemaContext
283 * parsed yang data context
284 * @param mappingService
285 * current mapping service
287 * yang data schema node representation of resulting data object
288 * @return DataObject instance parsed from input stream
290 public static DataObject dataObjectFromInputStream(org.opendaylight.yangtools.yang.binding.InstanceIdentifier<?> path, InputStream inputStream, SchemaContext schemaContext, BindingIndependentMappingService mappingService, DataSchemaNode dataSchema) {
291 // Parse stream into w3c Document
293 DocumentBuilderFactory documentBuilder = DocumentBuilderFactory.newInstance();
294 documentBuilder.setNamespaceAware(true);
295 DocumentBuilder builder = documentBuilder.newDocumentBuilder();
296 Document doc = builder.parse(inputStream);
297 Element rootElement = doc.getDocumentElement();
298 Node<?> domNode = XmlDocumentUtils.toDomNode(rootElement, Optional.of(dataSchema), Optional.<XmlCodecProvider>absent());
299 DataObject dataObject = mappingService.dataObjectFromDataDom(path, (CompositeNode) domNode); //getDataFromResponse
301 } catch (DeserializationException e) {
302 logger.trace("Deserialization exception {}",e);
303 } catch (ParserConfigurationException e) {
304 logger.trace("Parse configuration exception {}",e);
305 } catch (SAXException e) {
306 logger.trace("SAX exception {}", e);
307 } catch (IOException e) {
308 logger.trace("IOException {}", e);