Merge "Startup archetype: remove 'Impl' from config subsystem Module name."
[controller.git] / opendaylight / netconf / mdsal-netconf-connector / src / main / java / org / opendaylight / controller / netconf / mdsal / connector / ops / get / AbstractGet.java
1 /*
2  * Copyright (c) 2015 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
9 package org.opendaylight.controller.netconf.mdsal.connector.ops.get;
10
11 import com.google.common.base.Function;
12 import com.google.common.base.Optional;
13 import com.google.common.base.Throwables;
14 import com.google.common.collect.Iterables;
15 import java.io.IOException;
16 import javax.xml.stream.XMLOutputFactory;
17 import javax.xml.stream.XMLStreamException;
18 import javax.xml.stream.XMLStreamWriter;
19 import javax.xml.transform.dom.DOMResult;
20 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
21 import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
22 import org.opendaylight.controller.netconf.mdsal.connector.CurrentSchemaContext;
23 import org.opendaylight.controller.netconf.mdsal.connector.ops.Datastore;
24 import org.opendaylight.controller.netconf.util.mapping.AbstractLastNetconfOperation;
25 import org.opendaylight.controller.netconf.util.xml.XmlElement;
26 import org.opendaylight.yangtools.yang.common.QName;
27 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
28 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
29 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
30 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
31 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
32 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
33 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
34 import org.opendaylight.yangtools.yang.data.impl.codec.xml.XMLStreamNormalizedNodeStreamWriter;
35 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
36 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
37 import org.w3c.dom.Document;
38 import org.w3c.dom.Node;
39
40 public abstract class AbstractGet extends AbstractLastNetconfOperation {
41
42     protected static final YangInstanceIdentifier ROOT = YangInstanceIdentifier.builder().build();
43
44     protected final CurrentSchemaContext schemaContext;
45
46
47     public AbstractGet(final String netconfSessionIdForReporting, final CurrentSchemaContext schemaContext) {
48         super(netconfSessionIdForReporting);
49         this.schemaContext = schemaContext;
50     }
51
52     private static final XMLOutputFactory XML_OUTPUT_FACTORY;
53
54     static {
55         XML_OUTPUT_FACTORY = XMLOutputFactory.newFactory();
56         XML_OUTPUT_FACTORY.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
57     }
58
59     protected Node transformNormalizedNode(final Document document, final NormalizedNode<?, ?> data, final YangInstanceIdentifier dataRoot) {
60 //        boolean isDataRoot = true;
61
62         final DOMResult result = new DOMResult(document.createElement(XmlNetconfConstants.DATA_KEY));
63
64         final XMLStreamWriter xmlWriter = getXmlStreamWriter(result);
65
66         final NormalizedNodeStreamWriter nnStreamWriter = XMLStreamNormalizedNodeStreamWriter.create(xmlWriter,
67                 schemaContext.getCurrentContext(), getSchemaPath(dataRoot));
68
69         final NormalizedNodeWriter nnWriter = NormalizedNodeWriter.forStreamWriter(nnStreamWriter);
70
71 //        if (isDataRoot) {
72         writeRootElement(xmlWriter, nnWriter, (ContainerNode) data);
73 //        } else {
74 //            if (data instanceof MapEntryNode) {
75 //                // Restconf allows returning one list item. We need to wrap it
76 //                // in map node in order to serialize it properly
77 //                data = ImmutableNodes.mapNodeBuilder(data.getNodeType()).addChild((MapEntryNode) data).build();
78 //            }
79 //            nnWriter.write(data);
80 //            nnWriter.flush();
81 //        }
82         return result.getNode();
83     }
84
85     private XMLStreamWriter getXmlStreamWriter(final DOMResult result) {
86         try {
87             return XML_OUTPUT_FACTORY.createXMLStreamWriter(result);
88         } catch (final XMLStreamException e) {
89             throw new RuntimeException(e);
90         }
91     }
92
93     private static final Function<PathArgument, QName> PATH_ARG_TO_QNAME = new Function<YangInstanceIdentifier.PathArgument, QName>() {
94         @Override
95         public QName apply(final YangInstanceIdentifier.PathArgument input) {
96             return input.getNodeType();
97         }
98     };
99
100     private SchemaPath getSchemaPath(final YangInstanceIdentifier dataRoot) {
101         return SchemaPath.create(Iterables.transform(dataRoot.getPathArguments(), PATH_ARG_TO_QNAME), dataRoot.equals(ROOT));
102     }
103
104     // TODO this code is located in Restconf already
105     private void writeRootElement(final XMLStreamWriter xmlWriter, final NormalizedNodeWriter nnWriter, final ContainerNode data) {
106         try {
107             final QName name = SchemaContext.NAME;
108             for (final DataContainerChild<? extends PathArgument, ?> child : data.getValue()) {
109                 nnWriter.write(child);
110             }
111             nnWriter.flush();
112             xmlWriter.flush();
113         } catch (XMLStreamException | IOException e) {
114             Throwables.propagate(e);
115         }
116     }
117
118     protected static final class GetConfigExecution {
119         private final Optional<Datastore> datastore;
120
121         public GetConfigExecution(final Optional<Datastore> datastore) {
122             this.datastore = datastore;
123         }
124
125         public Optional<Datastore> getDatastore() {
126             return datastore;
127         }
128
129         static GetConfigExecution fromXml(final XmlElement xml, final String operationName) throws NetconfDocumentedException {
130             try {
131                 validateInputRpc(xml, operationName);
132             } catch (final NetconfDocumentedException e) {
133                 throw new NetconfDocumentedException("Incorrect RPC: " + e.getMessage(), e.getErrorType(), e.getErrorTag(), e.getErrorSeverity(), e.getErrorInfo());
134             }
135
136             final Optional<Datastore> sourceDatastore;
137             try {
138                 sourceDatastore = parseSource(xml);
139             } catch (final NetconfDocumentedException e) {
140                 throw new NetconfDocumentedException("Get-config source attribute error: " + e.getMessage(), e.getErrorType(), e.getErrorTag(), e.getErrorSeverity(), e.getErrorInfo());
141             }
142
143             // Add filter
144
145             return new GetConfigExecution(sourceDatastore);
146         }
147
148         private static Optional<Datastore> parseSource(final XmlElement xml) throws NetconfDocumentedException {
149             final Optional<XmlElement> sourceElement = xml.getOnlyChildElementOptionally(XmlNetconfConstants.SOURCE_KEY,
150                     XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
151
152             return  sourceElement.isPresent() ?
153                     Optional.of(Datastore.valueOf(sourceElement.get().getOnlyChildElement().getName())) : Optional.<Datastore>absent();
154         }
155
156         private static void validateInputRpc(final XmlElement xml, String operationName) throws NetconfDocumentedException{
157             xml.checkName(operationName);
158             xml.checkNamespace(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
159         }
160     }
161
162 }