Bug 1062 - Disallow implicit serviceref creation.
[controller.git] / opendaylight / netconf / config-netconf-connector / src / main / java / org / opendaylight / controller / netconf / confignetconfconnector / operations / editconfig / EditConfig.java
index 709573c2414c3249917aae4e03851e0f9ada4da8..ffc69eb8efd2baa4fc1b6399a2a66e9ac058331f 100644 (file)
@@ -9,13 +9,19 @@
 package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig;
 
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Multimap;
-import org.opendaylight.controller.config.api.JmxAttributeValidationException;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
 import org.opendaylight.controller.config.api.ValidationException;
 import org.opendaylight.controller.config.util.ConfigRegistryClient;
 import org.opendaylight.controller.config.util.ConfigTransactionClient;
-import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
 import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
@@ -30,20 +36,18 @@ import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfigXmlParser.EditConfigExecution;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreSnapshot;
 import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
 import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
-import javax.management.InstanceNotFoundException;
-import javax.management.ObjectName;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-
 public class EditConfig extends AbstractConfigNetconfOperation {
 
     private static final Logger logger = LoggerFactory.getLogger(EditConfig.class);
@@ -66,29 +70,21 @@ public class EditConfig extends AbstractConfigNetconfOperation {
             final EditConfigXmlParser.EditConfigExecution editConfigExecution) throws NetconfDocumentedException {
 
         if (editConfigExecution.shouldTest()) {
-            executeTests(configRegistryClient, editConfigExecution);
+            executeTests(getConfigRegistryClient(), editConfigExecution);
         }
 
         if (editConfigExecution.shouldSet()) {
-            executeSet(configRegistryClient, editConfigExecution);
+            executeSet(getConfigRegistryClient(), editConfigExecution);
         }
 
-        logger.info("Operation {} successful", EditConfigXmlParser.EDIT_CONFIG);
+        logger.trace("Operation {} successful", EditConfigXmlParser.EDIT_CONFIG);
 
-        return document.createElement(XmlNetconfConstants.OK);
+        return XmlUtil.createElement(document, XmlNetconfConstants.OK, Optional.<String>absent());
     }
 
     private void executeSet(ConfigRegistryClient configRegistryClient,
             EditConfigXmlParser.EditConfigExecution editConfigExecution) throws NetconfDocumentedException {
-        try {
-            set(configRegistryClient, editConfigExecution);
-        } catch (IllegalStateException | JmxAttributeValidationException | ValidationException e) {
-            logger.warn("Set phase for {} failed", EditConfigXmlParser.EDIT_CONFIG, e);
-            final Map<String, String> errorInfo = new HashMap<>();
-            errorInfo.put(ErrorTag.operation_failed.name(), e.getMessage());
-            throw new NetconfDocumentedException("Test phase: " + e.getMessage(), e, ErrorType.application,
-                    ErrorTag.operation_failed, ErrorSeverity.error, errorInfo);
-        }
+        set(configRegistryClient, editConfigExecution);
         logger.debug("Set phase for {} operation successful", EditConfigXmlParser.EDIT_CONFIG);
     }
 
@@ -96,7 +92,7 @@ public class EditConfig extends AbstractConfigNetconfOperation {
             EditConfigExecution editConfigExecution) throws NetconfDocumentedException {
         try {
             test(configRegistryClient, editConfigExecution, editConfigExecution.getDefaultStrategy());
-        } catch (IllegalStateException | JmxAttributeValidationException | ValidationException e) {
+        } catch (final ValidationException e) {
             logger.warn("Test phase for {} failed", EditConfigXmlParser.EDIT_CONFIG, e);
             final Map<String, String> errorInfo = new HashMap<>();
             errorInfo.put(ErrorTag.operation_failed.name(), e.getMessage());
@@ -107,10 +103,9 @@ public class EditConfig extends AbstractConfigNetconfOperation {
     }
 
     private void test(ConfigRegistryClient configRegistryClient, EditConfigExecution execution,
-            EditStrategyType editStrategyType) {
+            EditStrategyType editStrategyType) throws ValidationException, NetconfDocumentedException {
         ObjectName taON = transactionProvider.getTestTransaction();
         try {
-
             // default strategy = replace wipes config
             if (editStrategyType == EditStrategyType.replace) {
                 transactionProvider.wipeTestTransaction(taON);
@@ -128,7 +123,7 @@ public class EditConfig extends AbstractConfigNetconfOperation {
     }
 
     private void set(ConfigRegistryClient configRegistryClient,
-            EditConfigXmlParser.EditConfigExecution editConfigExecution) {
+            EditConfigXmlParser.EditConfigExecution editConfigExecution) throws NetconfDocumentedException {
         ObjectName taON = transactionProvider.getOrCreateTransaction();
 
         // default strategy = replace wipes config
@@ -143,7 +138,7 @@ public class EditConfig extends AbstractConfigNetconfOperation {
         setOnTransaction(ta, editConfigExecution);
     }
 
-    private void setServicesOnTransaction(ConfigTransactionClient ta, EditConfigExecution execution) {
+    private void setServicesOnTransaction(ConfigTransactionClient ta, EditConfigExecution execution) throws NetconfDocumentedException {
 
         Services services = execution.getServices();
 
@@ -164,7 +159,10 @@ public class EditConfig extends AbstractConfigNetconfOperation {
                         logger.debug("Saving service {} with on {} under name {} with service on {}", qnameOfService,
                                 on, refName, saved);
                     } catch (InstanceNotFoundException e) {
-                        throw new IllegalStateException("Unable to save ref name " + refName + " for instance " + on, e);
+                        throw new NetconfDocumentedException(String.format("Unable to save ref name " + refName + " for instance " + on, e),
+                                ErrorType.application,
+                                ErrorTag.operation_failed,
+                                ErrorSeverity.error);
                     }
                 }
             }
@@ -175,11 +173,11 @@ public class EditConfig extends AbstractConfigNetconfOperation {
         return ta.getServiceInterfaceName(namespace, serviceName);
     }
 
-    private void setOnTransaction(ConfigTransactionClient ta, EditConfigExecution execution) {
+    private void setOnTransaction(ConfigTransactionClient ta, EditConfigExecution execution) throws NetconfDocumentedException {
 
         for (Multimap<String, ModuleElementResolved> modulesToResolved : execution.getResolvedXmlElements(ta).values()) {
 
-            for (Entry<String, ModuleElementResolved> moduleToResolved : modulesToResolved.entries()) {
+            for (Map.Entry<String, ModuleElementResolved> moduleToResolved : modulesToResolved.entries()) {
                 String moduleName = moduleToResolved.getKey();
 
                 ModuleElementResolved moduleElementResolved = moduleToResolved.getValue();
@@ -193,10 +191,10 @@ public class EditConfig extends AbstractConfigNetconfOperation {
     }
 
     private void handleMisssingInstancesOnTransaction(ConfigTransactionClient ta,
-            EditConfigExecution execution) {
+            EditConfigExecution execution) throws NetconfDocumentedException {
 
         for (Multimap<String,ModuleElementDefinition> modulesToResolved : execution.getModulesDefinition(ta).values()) {
-            for (Entry<String, ModuleElementDefinition> moduleToResolved : modulesToResolved.entries()) {
+            for (Map.Entry<String, ModuleElementDefinition> moduleToResolved : modulesToResolved.entries()) {
                 String moduleName = moduleToResolved.getKey();
 
                 ModuleElementDefinition moduleElementDefinition = moduleToResolved.getValue();
@@ -207,12 +205,60 @@ public class EditConfig extends AbstractConfigNetconfOperation {
         }
     }
 
-    public static Config getConfigMapping(ConfigRegistryClient configRegistryClient,
-            Map<String/* Namespace from yang file */,
-                    Map<String /* Name of module entry from yang file */, ModuleMXBeanEntry>> mBeanEntries) {
-        Map<String, Map<String, ModuleConfig>> factories = transformMbeToModuleConfigs(configRegistryClient, mBeanEntries);
+    public static Config getConfigMapping(ConfigRegistryClient configRegistryClient, YangStoreSnapshot yangStoreSnapshot) {
+        Map<String, Map<String, ModuleConfig>> factories = transformMbeToModuleConfigs(configRegistryClient,
+                yangStoreSnapshot.getModuleMXBeanEntryMap());
+        Map<String, Map<Date, IdentityMapping>> identitiesMap = transformIdentities(yangStoreSnapshot.getModules());
+        return new Config(factories, identitiesMap);
+    }
+
+
+    public static class IdentityMapping {
+        private final Map<String, IdentitySchemaNode> identityNameToSchemaNode;
+
+        IdentityMapping() {
+            this.identityNameToSchemaNode = Maps.newHashMap();
+        }
+
+        void addIdSchemaNode(IdentitySchemaNode node) {
+            String name = node.getQName().getLocalName();
+            Preconditions.checkState(!identityNameToSchemaNode.containsKey(name));
+            identityNameToSchemaNode.put(name, node);
+        }
+
+        public boolean containsIdName(String idName) {
+            return identityNameToSchemaNode.containsKey(idName);
+        }
+
+    }
+
+    private static Map<String, Map<Date, IdentityMapping>> transformIdentities(Set<Module> modules) {
+        Map<String, Map<Date, IdentityMapping>> mappedIds = Maps.newHashMap();
+        for (Module module : modules) {
+            String namespace = module.getNamespace().toString();
+            Map<Date, IdentityMapping> revisionsByNamespace= mappedIds.get(namespace);
+            if(revisionsByNamespace == null) {
+                revisionsByNamespace = Maps.newHashMap();
+                mappedIds.put(namespace, revisionsByNamespace);
+            }
+
+            Date revision = module.getRevision();
+            Preconditions.checkState(!revisionsByNamespace.containsKey(revision),
+                    "Duplicate revision %s for namespace %s", revision, namespace);
+
+            IdentityMapping identityMapping = revisionsByNamespace.get(revision);
+            if(identityMapping == null) {
+                identityMapping = new IdentityMapping();
+                revisionsByNamespace.put(revision, identityMapping);
+            }
+
+            for (IdentitySchemaNode identitySchemaNode : module.getIdentities()) {
+                identityMapping.addIdSchemaNode(identitySchemaNode);
+            }
 
-        return new Config(factories);
+        }
+
+        return mappedIds;
     }
 
     public static Map<String/* Namespace from yang file */,
@@ -223,13 +269,12 @@ public class EditConfig extends AbstractConfigNetconfOperation {
         Map<String, Map<String, ModuleConfig>> namespaceToModuleNameToModuleConfig = Maps.newHashMap();
 
         for (String namespace : mBeanEntries.keySet()) {
-            for (Entry<String, ModuleMXBeanEntry> moduleNameToMbe : mBeanEntries.get(namespace).entrySet()) {
+            for (Map.Entry<String, ModuleMXBeanEntry> moduleNameToMbe : mBeanEntries.get(namespace).entrySet()) {
                 String moduleName = moduleNameToMbe.getKey();
                 ModuleMXBeanEntry moduleMXBeanEntry = moduleNameToMbe.getValue();
 
                 ModuleConfig moduleConfig = new ModuleConfig(moduleName, new InstanceConfig(configRegistryClient,
-                        moduleMXBeanEntry.getAttributes()), moduleMXBeanEntry
-                        .getProvidedServices().values());
+                        moduleMXBeanEntry.getAttributes()));
 
                 Map<String, ModuleConfig> moduleNameToModuleConfig = namespaceToModuleNameToModuleConfig.get(namespace);
                 if(moduleNameToModuleConfig == null) {
@@ -250,32 +295,15 @@ public class EditConfig extends AbstractConfigNetconfOperation {
     }
 
     @Override
-    protected Element handle(Document document, XmlElement xml) throws NetconfDocumentedException {
+    protected Element handleWithNoSubsequentOperations(Document document, XmlElement xml) throws NetconfDocumentedException {
 
         EditConfigXmlParser.EditConfigExecution editConfigExecution;
-        Config cfg = getConfigMapping(configRegistryClient, yangStoreSnapshot.getModuleMXBeanEntryMap());
-        try {
-            editConfigExecution = editConfigXmlParser.fromXml(xml, cfg, transactionProvider, configRegistryClient);
-        } catch (IllegalStateException e) {
-            logger.warn("Error parsing xml", e);
-            final Map<String, String> errorInfo = new HashMap<>();
-            errorInfo.put(ErrorTag.missing_attribute.name(), "Error parsing xml: " + e.getMessage());
-            throw new NetconfDocumentedException(e.getMessage(), ErrorType.rpc, ErrorTag.missing_attribute,
-                    ErrorSeverity.error, errorInfo);
-        } catch (final IllegalArgumentException e) {
-            logger.warn("Error parsing xml", e);
-            final Map<String, String> errorInfo = new HashMap<>();
-            errorInfo.put(ErrorTag.bad_attribute.name(), e.getMessage());
-            throw new NetconfDocumentedException(e.getMessage(), ErrorType.rpc, ErrorTag.bad_attribute,
-                    ErrorSeverity.error, errorInfo);
-        } catch (final UnsupportedOperationException e) {
-            logger.warn("Unsupported", e);
-            final Map<String, String> errorInfo = new HashMap<>();
-            errorInfo.put(ErrorTag.operation_not_supported.name(), "Unsupported option for 'edit-config'");
-            throw new NetconfDocumentedException(e.getMessage(), ErrorType.application,
-                    ErrorTag.operation_not_supported, ErrorSeverity.error, errorInfo);
-        }
+        Config cfg = getConfigMapping(getConfigRegistryClient(), yangStoreSnapshot);
+        editConfigExecution = editConfigXmlParser.fromXml(xml, cfg);
 
-        return getResponseInternal(document, editConfigExecution);
+        Element responseInternal;
+        responseInternal = getResponseInternal(document, editConfigExecution);
+        return responseInternal;
     }
+
 }