Merge "NETCONF-557: Add support for URL capability"
[netconf.git] / netconf / mdsal-netconf-connector / src / main / java / org / opendaylight / netconf / mdsal / connector / MdsalNetconfOperationServiceFactory.java
index b450a9d0c8310cc5fd9a738d5b179f8372eaa9ec..b4b03355b127fe0963336b312585f0109cc641fd 100644 (file)
@@ -5,63 +5,86 @@
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
-
 package org.opendaylight.netconf.mdsal.connector;
 
-import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.io.CharStreams;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.nio.charset.StandardCharsets;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.Optional;
 import java.util.Set;
-import org.opendaylight.controller.config.util.capability.Capability;
-import org.opendaylight.controller.config.util.capability.YangModuleCapability;
+import java.util.concurrent.ExecutionException;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
 import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
-import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
-import org.opendaylight.controller.sal.core.api.Consumer;
-import org.opendaylight.controller.sal.core.api.model.SchemaService;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.mdsal.dom.api.DOMYangTextSourceProvider;
+import org.opendaylight.netconf.api.capability.BasicCapability;
+import org.opendaylight.netconf.api.capability.Capability;
+import org.opendaylight.netconf.api.capability.YangModuleCapability;
 import org.opendaylight.netconf.api.monitoring.CapabilityListener;
 import org.opendaylight.netconf.mapping.api.NetconfOperationServiceFactory;
-import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
+import org.opendaylight.netconf.mapping.api.NetconfOperationServiceFactoryListener;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
+import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier;
 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
 import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceProvider;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class MdsalNetconfOperationServiceFactory implements NetconfOperationServiceFactory, Consumer, AutoCloseable {
+public class MdsalNetconfOperationServiceFactory implements NetconfOperationServiceFactory, AutoCloseable {
 
     private static final Logger LOG = LoggerFactory.getLogger(MdsalNetconfOperationServiceFactory.class);
+    private static final BasicCapability VALIDATE_CAPABILITY =
+        new BasicCapability("urn:ietf:params:netconf:capability:validate:1.0");
+
+    private final DOMDataBroker dataBroker;
+    private final DOMRpcService rpcService;
 
-    private ConsumerSession session = null;
-    private DOMDataBroker dataBroker = null;
-    private DOMRpcService rpcService = null;
     private final CurrentSchemaContext currentSchemaContext;
     private final SchemaSourceProvider<YangTextSchemaSource> rootSchemaSourceProviderDependency;
-
-    public MdsalNetconfOperationServiceFactory(final SchemaService schemaService, final SchemaSourceProvider<YangTextSchemaSource> rootSchemaSourceProviderDependency) {
-        this.rootSchemaSourceProviderDependency = rootSchemaSourceProviderDependency;
-        this.currentSchemaContext = new CurrentSchemaContext(Preconditions.checkNotNull(schemaService), rootSchemaSourceProviderDependency);
+    private final NetconfOperationServiceFactoryListener netconfOperationServiceFactoryListener;
+
+    public MdsalNetconfOperationServiceFactory(
+            final DOMSchemaService schemaService,
+            final NetconfOperationServiceFactoryListener netconfOperationServiceFactoryListener,
+            final DOMDataBroker dataBroker,
+            final DOMRpcService rpcService) {
+
+        this.dataBroker = dataBroker;
+        this.rpcService = rpcService;
+
+        this.rootSchemaSourceProviderDependency = schemaService.getExtensions()
+                .getInstance(DOMYangTextSourceProvider.class);
+        this.currentSchemaContext = new CurrentSchemaContext(Preconditions.checkNotNull(schemaService),
+                rootSchemaSourceProviderDependency);
+        this.netconfOperationServiceFactoryListener = netconfOperationServiceFactoryListener;
+        this.netconfOperationServiceFactoryListener.onAddNetconfOperationServiceFactory(this);
     }
 
     @Override
     public MdsalNetconfOperationService createService(final String netconfSessionIdForReporting) {
         Preconditions.checkState(dataBroker != null, "MD-SAL provider not yet initialized");
-        return new MdsalNetconfOperationService(currentSchemaContext, netconfSessionIdForReporting, dataBroker, rpcService);
+        return new MdsalNetconfOperationService(currentSchemaContext, netconfSessionIdForReporting, dataBroker,
+                rpcService);
     }
 
+    @SuppressWarnings("checkstyle:IllegalCatch")
     @Override
-    public void close() throws Exception {
-        currentSchemaContext.close();
+    public void close() {
+        try {
+            currentSchemaContext.close();
+            if (netconfOperationServiceFactoryListener != null) {
+                netconfOperationServiceFactoryListener.onRemoveNetconfOperationServiceFactory(this);
+            }
+        } catch (Exception e) {
+            LOG.error("Failed to close resources correctly - ignore", e);
+        }
     }
 
     @Override
@@ -69,21 +92,23 @@ public class MdsalNetconfOperationServiceFactory implements NetconfOperationServ
         return transformCapabilities(currentSchemaContext.getCurrentContext(), rootSchemaSourceProviderDependency);
     }
 
-    static Set<Capability> transformCapabilities(final SchemaContext currentContext, final SchemaSourceProvider<YangTextSchemaSource> rootSchemaSourceProviderDependency) {
+    static Set<Capability> transformCapabilities(
+            final SchemaContext currentContext,
+            final SchemaSourceProvider<YangTextSchemaSource> rootSchemaSourceProviderDependency) {
         final Set<Capability> capabilities = new HashSet<>();
 
         // Added by netconf-impl by default
-//        capabilities.add(new BasicCapability("urn:ietf:params:netconf:capability:candidate:1.0"));
+        // capabilities.add(new BasicCapability("urn:ietf:params:netconf:capability:candidate:1.0"));
 
         final Set<Module> modules = currentContext.getModules();
         for (final Module module : modules) {
             Optional<YangModuleCapability> cap = moduleToCapability(module, rootSchemaSourceProviderDependency);
-            if(cap.isPresent()) {
+            if (cap.isPresent()) {
                 capabilities.add(cap.get());
             }
             for (final Module submodule : module.getSubmodules()) {
                 cap = moduleToCapability(submodule, rootSchemaSourceProviderDependency);
-                if(cap.isPresent()) {
+                if (cap.isPresent()) {
                     capabilities.add(cap.get());
                 }
             }
@@ -95,16 +120,15 @@ public class MdsalNetconfOperationServiceFactory implements NetconfOperationServ
     private static Optional<YangModuleCapability> moduleToCapability(
             final Module module, final SchemaSourceProvider<YangTextSchemaSource> rootSchemaSourceProviderDependency) {
 
-        final SourceIdentifier moduleSourceIdentifier = SourceIdentifier.create(module.getName(),
-                (SimpleDateFormatUtil.DEFAULT_DATE_REV == module.getRevision() ? Optional.absent() :
-                        Optional.of(SimpleDateFormatUtil.getRevisionFormat().format(module.getRevision()))));
+        final SourceIdentifier moduleSourceIdentifier = RevisionSourceIdentifier.create(module.getName(),
+                module.getRevision());
 
         InputStream sourceStream = null;
         String source;
         try {
-            sourceStream = rootSchemaSourceProviderDependency.getSource(moduleSourceIdentifier).checkedGet().openStream();
+            sourceStream = rootSchemaSourceProviderDependency.getSource(moduleSourceIdentifier).get().openStream();
             source = CharStreams.toString(new InputStreamReader(sourceStream, StandardCharsets.UTF_8));
-        } catch (IOException | SchemaSourceException e) {
+        } catch (ExecutionException | InterruptedException | IOException e) {
             LOG.warn("Ignoring source for module {}. Unable to read content", moduleSourceIdentifier, e);
             source = null;
         }
@@ -117,29 +141,22 @@ public class MdsalNetconfOperationServiceFactory implements NetconfOperationServ
             LOG.warn("Error closing yang source stream {}. Ignoring", moduleSourceIdentifier, e);
         }
 
-        if(source !=null) {
+        if (source != null) {
             return Optional.of(new YangModuleCapability(module, source));
-        } else {
-            LOG.warn("Missing source for module {}. This module will not be available from netconf server",
-                    moduleSourceIdentifier);
         }
-        return Optional.absent();
+
+        LOG.warn("Missing source for module {}. This module will not be available from netconf server",
+            moduleSourceIdentifier);
+        return Optional.empty();
     }
 
     @Override
     public AutoCloseable registerCapabilityListener(final CapabilityListener listener) {
+        // Advertise validate capability only if DOMDataBroker provides DOMDataTransactionValidator
+        if (dataBroker.getSupportedExtensions().get(DOMDataTransactionValidator.class) != null) {
+            listener.onCapabilitiesChanged(Collections.singleton(VALIDATE_CAPABILITY), Collections.emptySet());
+        }
+        // Advertise namespaces of supported YANG models as NETCONF capabilities
         return currentSchemaContext.registerCapabilityListener(listener);
     }
-
-    @Override
-    public void onSessionInitiated(ConsumerSession session) {
-        this.session = Preconditions.checkNotNull(session);
-        this.dataBroker = this.session.getService(DOMDataBroker.class);
-        this.rpcService = this.session.getService(DOMRpcService.class);
-    }
-
-    @Override
-    public Collection<ConsumerFunctionality> getConsumerFunctionality() {
-        return Collections.emptySet();
-    }
 }