Merge "Bug 4577 Allow specification of a distinct schema cache directory per netconf...
authorTony Tkacik <ttkacik@cisco.com>
Mon, 25 Jan 2016 16:50:53 +0000 (16:50 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Mon, 25 Jan 2016 16:50:53 +0000 (16:50 +0000)
opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImpl.java
opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/impl/TopologyNodeWriter.java
opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java

index 73d238d1d3cf1edde28367fa51e381239d9f5813..0a147409038fa6e0597ef090eadab2d7466594c3 100644 (file)
@@ -10,6 +10,8 @@ package org.opendaylight.netconf.topology.impl;
 
 import akka.actor.ActorContext;
 import akka.actor.ActorRef;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
 import io.netty.util.concurrent.EventExecutor;
 import java.util.Collection;
 import javax.annotation.Nonnull;
@@ -20,6 +22,7 @@ import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
 import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
@@ -32,9 +35,16 @@ import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
 import org.opendaylight.netconf.topology.AbstractNetconfTopology;
 import org.opendaylight.netconf.topology.SchemaRepositoryProvider;
 import org.opendaylight.netconf.topology.pipeline.TopologyMountPointFacade.ConnectionStatusListenerRegistration;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopologyBuilder;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -97,10 +107,27 @@ public class NetconfTopologyImpl extends AbstractNetconfTopology implements Data
     public void onSessionInitiated(ProviderContext session) {
         dataBroker = session.getSALService(DataBroker.class);
 
-        LOG.warn("Registering datastore listener");
+        final WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
+        initTopology(wtx, LogicalDatastoreType.CONFIGURATION);
+        initTopology(wtx, LogicalDatastoreType.OPERATIONAL);
+        Futures.addCallback(wtx.submit(), new FutureCallback<Void>() {
+            @Override
+            public void onSuccess(Void result) {
+                LOG.debug("topology initialization successful");
+            }
+
+            @Override
+            public void onFailure(Throwable t) {
+                LOG.error("Unable to initialize netconf-topology, {}", t);
+            }
+        });
+
+        LOG.debug("Registering datastore listener");
         datastoreListenerRegistration =
                 dataBroker.registerDataTreeChangeListener(
                         new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, createTopologyId(topologyId).child(Node.class)), this);
+
+
     }
 
     @Override
@@ -129,4 +156,12 @@ public class NetconfTopologyImpl extends AbstractNetconfTopology implements Data
         }
     }
 
+    private void initTopology(final WriteTransaction wtx, final LogicalDatastoreType datastoreType) {
+        final NetworkTopology networkTopology = new NetworkTopologyBuilder().build();
+        final InstanceIdentifier<NetworkTopology> networkTopologyId = InstanceIdentifier.builder(NetworkTopology.class).build();
+        wtx.merge(datastoreType, networkTopologyId, networkTopology);
+        final Topology topology = new TopologyBuilder().setTopologyId(new TopologyId(topologyId)).build();
+        wtx.merge(datastoreType, networkTopologyId.child(Topology.class, new TopologyKey(new TopologyId(topologyId))), topology);
+    }
+
 }
index b0a84a9e54d3a32c310fbeb11a580deb75b77b21..a659db80f166ad950f8966f21891d2d577ece5e5 100644 (file)
@@ -72,7 +72,8 @@ public class TopologyNodeWriter implements NodeWriter{
 
         // write an empty topology container at the start
         final WriteTransaction wTx = txChain.newWriteOnlyTransaction();
-        createNetworkTopologyIfNotPresent(wTx);
+        createNetworkTopologyIfNotPresent(wTx, LogicalDatastoreType.OPERATIONAL);
+        createNetworkTopologyIfNotPresent(wTx, LogicalDatastoreType.CONFIGURATION);
         commitTransaction(wTx, "init topology container", new NodeId("topology-netconf"));
     }
 
@@ -82,7 +83,7 @@ public class TopologyNodeWriter implements NodeWriter{
         try {
             final WriteTransaction writeTx = txChain.newWriteOnlyTransaction();
 
-            createNetworkTopologyIfNotPresent(writeTx);
+            createNetworkTopologyIfNotPresent(writeTx, LogicalDatastoreType.OPERATIONAL);
             final InstanceIdentifier<Node> path = createBindingPathForTopology(new NodeKey(id), topologyId);
 
             LOG.trace("{}: Init device state transaction {} putting if absent operational data started. Putting data on path {}",
@@ -160,17 +161,17 @@ public class TopologyNodeWriter implements NodeWriter{
         });
     }
 
-    private void createNetworkTopologyIfNotPresent(final WriteTransaction writeTx) {
+    private void createNetworkTopologyIfNotPresent(final WriteTransaction writeTx, final LogicalDatastoreType datastoreType) {
 
         final NetworkTopology networkTopology = new NetworkTopologyBuilder().build();
         LOG.trace("{}: Merging {} container to ensure its presence", topologyId,
                 NetworkTopology.QNAME, writeTx.getIdentifier());
-        writeTx.merge(LogicalDatastoreType.OPERATIONAL, networkTopologyPath, networkTopology);
+        writeTx.merge(datastoreType, networkTopologyPath, networkTopology);
 
         final Topology topology = new TopologyBuilder().setTopologyId(new TopologyId(topologyId)).build();
         LOG.trace("{}: Merging {} container to ensure its presence", topologyId,
                 Topology.QNAME, writeTx.getIdentifier());
-        writeTx.merge(LogicalDatastoreType.OPERATIONAL, topologyListPath, topology);
+        writeTx.merge(datastoreType, topologyListPath, topology);
     }
 
     private static InstanceIdentifier<Node> createBindingPathForTopology(final NodeKey key, final String topologyId) {
index 92346c983ff162c51e167a5d8ee0166ffbaa4b98..2ac01caffce792270c774ab1bde8ef6ddab52268 100644 (file)
@@ -11,7 +11,6 @@ import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTr
 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_RPC_QNAME;
 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_URI;
 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.toPath;
-
 import com.google.common.base.Function;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
@@ -27,7 +26,6 @@ import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 import javax.annotation.Nonnull;
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamWriter;
@@ -138,18 +136,28 @@ public class NetconfMessageTransformer implements MessageTransformer<NetconfMess
 
         // We wrap the notification as a container node in order to reuse the parsers and builders for container node
         final ContainerSchemaNode notificationAsContainerSchemaNode = NetconfMessageTransformUtil.createSchemaForNotification(next);
-        final ContainerNode content = parserFactory.getContainerNodeParser().parse(Collections.singleton(stripped.getValue().getDomElement()),
+
+        final Element element = stripped.getValue().getDomElement();
+        final ContainerNode content;
+        try {
+            content = parserFactory.getContainerNodeParser().parse(Collections.singleton(element),
                 notificationAsContainerSchemaNode);
+        } catch (IllegalArgumentException e) {
+            throw new IllegalArgumentException(String.format("Failed to parse notification %s", element), e);
+        }
         return new NetconfDeviceNotification(content, stripped.getKey());
     }
 
     private static final ThreadLocal<SimpleDateFormat> EVENT_TIME_FORMAT = new ThreadLocal<SimpleDateFormat>() {
+        @Override
         protected SimpleDateFormat initialValue() {
 
             final SimpleDateFormat withMillis = new SimpleDateFormat(
                 NetconfNotification.RFC3339_DATE_FORMAT_WITH_MILLIS_BLUEPRINT);
 
             return new SimpleDateFormat(NetconfNotification.RFC3339_DATE_FORMAT_BLUEPRINT) {
+                private static final long serialVersionUID = 1L;
+
                 @Override public Date parse(final String source) throws ParseException {
                     try {
                         return super.parse(source);
@@ -161,7 +169,8 @@ public class NetconfMessageTransformer implements MessageTransformer<NetconfMess
             };
         }
 
-        public void set(SimpleDateFormat value) {
+        @Override
+        public void set(final SimpleDateFormat value) {
             throw new UnsupportedOperationException();
         }
     };
@@ -219,7 +228,7 @@ public class NetconfMessageTransformer implements MessageTransformer<NetconfMess
                 "Transforming an rpc with input: %s, payload has to be a container, but was: %s", rpcQName, payload);
 
         // Set the path to the input of rpc for the node stream writer
-        rpc = rpc.createChild(QName.cachedReference(QName.create(rpcQName, "input")));
+        rpc = rpc.createChild(QName.create(rpcQName, "input").intern());
         final DOMResult result = prepareDomResultForRpcRequest(rpcQName);
 
         try {
@@ -250,25 +259,22 @@ public class NetconfMessageTransformer implements MessageTransformer<NetconfMess
         return new DOMResult(elementNS);
     }
 
-    private void writeNormalizedRpc(final ContainerNode normalized, final DOMResult result, final SchemaPath schemaPath, final SchemaContext baseNetconfCtx) throws IOException, XMLStreamException {
-        final OrderedNormalizedNodeWriter normalizedNodeWriter;
-        NormalizedNodeStreamWriter normalizedNodeStreamWriter = null;
-        XMLStreamWriter writer = null;
+    private static void writeNormalizedRpc(final ContainerNode normalized, final DOMResult result,
+            final SchemaPath schemaPath, final SchemaContext baseNetconfCtx) throws IOException, XMLStreamException {
+        final XMLStreamWriter writer = NetconfMessageTransformUtil.XML_FACTORY.createXMLStreamWriter(result);
         try {
-            writer = NetconfMessageTransformUtil.XML_FACTORY.createXMLStreamWriter(result);
-            normalizedNodeStreamWriter = XMLStreamNormalizedNodeStreamWriter.create(writer, baseNetconfCtx, schemaPath);
-            normalizedNodeWriter = new OrderedNormalizedNodeWriter(normalizedNodeStreamWriter, baseNetconfCtx, schemaPath);
-            Collection<DataContainerChild<?, ?>> value = (Collection) normalized.getValue();
-            normalizedNodeWriter.write(value);
-            normalizedNodeWriter.flush();
+            try (final NormalizedNodeStreamWriter normalizedNodeStreamWriter =
+                    XMLStreamNormalizedNodeStreamWriter.create(writer, baseNetconfCtx, schemaPath)) {
+                try (final OrderedNormalizedNodeWriter normalizedNodeWriter =
+                        new OrderedNormalizedNodeWriter(normalizedNodeStreamWriter, baseNetconfCtx, schemaPath)) {
+                    Collection<DataContainerChild<?, ?>> value = normalized.getValue();
+                    normalizedNodeWriter.write(value);
+                    normalizedNodeWriter.flush();
+                }
+            }
         } finally {
             try {
-                if(normalizedNodeStreamWriter != null) {
-                    normalizedNodeStreamWriter.close();
-                }
-                if(writer != null) {
-                    writer.close();
-                }
+                writer.close();
             } catch (final Exception e) {
                 LOG.warn("Unable to close resource properly", e);
             }
@@ -282,12 +288,17 @@ public class NetconfMessageTransformer implements MessageTransformer<NetconfMess
         if (NetconfMessageTransformUtil.isDataRetrievalOperation(rpcQName)) {
             final Element xmlData = NetconfMessageTransformUtil.getDataSubtree(message.getDocument());
             final ContainerSchemaNode schemaForDataRead = NetconfMessageTransformUtil.createSchemaForDataRead(schemaContext);
-            final ContainerNode dataNode = parserFactory.getContainerNodeParser().parse(Collections.singleton(xmlData), schemaForDataRead);
+            final ContainerNode dataNode;
+
+            try {
+                dataNode = parserFactory.getContainerNodeParser().parse(Collections.singleton(xmlData), schemaForDataRead);
+            } catch (IllegalArgumentException e) {
+                throw new IllegalArgumentException(String.format("Failed to parse data response %s", xmlData), e);
+            }
 
             normalizedNode = Builders.containerBuilder().withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(NetconfMessageTransformUtil.NETCONF_RPC_REPLY_QNAME))
                     .withChild(dataNode).build();
         } else {
-            final Set<Element> documentElement = Collections.singleton(message.getDocument().getDocumentElement());
 
             Map<QName, RpcDefinition> currentMappedRpcs = mappedRpcs;
 
@@ -303,11 +314,18 @@ public class NetconfMessageTransformer implements MessageTransformer<NetconfMess
 
             // In case no input for rpc is defined, we can simply construct the payload here
             if (rpcDefinition.getOutput() == null) {
-                Preconditions.checkArgument(XmlElement.fromDomDocument(message.getDocument()).getOnlyChildElementWithSameNamespaceOptionally("ok").isPresent(),
-                        "Unexpected content in response of rpc: %s, %s", rpcDefinition.getQName(), message);
+                Preconditions.checkArgument(XmlElement.fromDomDocument(
+                    message.getDocument()).getOnlyChildElementWithSameNamespaceOptionally("ok").isPresent(),
+                    "Unexpected content in response of rpc: %s, %s", rpcDefinition.getQName(), message);
                 normalizedNode = null;
             } else {
-                normalizedNode = parserFactory.getContainerNodeParser().parse(documentElement, rpcDefinition.getOutput());
+                final Element element = message.getDocument().getDocumentElement();
+                try {
+                    normalizedNode = parserFactory.getContainerNodeParser().parse(Collections.singleton(element),
+                        rpcDefinition.getOutput());
+                } catch (IllegalArgumentException e) {
+                    throw new IllegalArgumentException(String.format("Failed to parse RPC response %s", element), e);
+                }
             }
         }
         return new DefaultDOMRpcResult(normalizedNode);