Merge "Add support for identity-ref config attributes to config/netconf subsystem"
authorEd Warnicke <eaw@cisco.com>
Sun, 26 Jan 2014 03:41:08 +0000 (03:41 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Sun, 26 Jan 2014 03:41:08 +0000 (03:41 +0000)
19 files changed:
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/AttributeIfcSwitchStatement.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/ObjectXmlReader.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/SimpleAttributeReadingStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/SimpleBinaryAttributeReadingStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/SimpleCompositeAttributeReadingStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/SimpleIdentityRefAttributeReadingStrategy.java [new file with mode: 0644]
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/SimpleUnionAttributeReadingStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/ObjectXmlWriter.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/SimpleAttributeWritingStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/SimpleIdentityRefAttributeWritingStrategy.java [new file with mode: 0644]
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Config.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/InstanceConfig.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/ModuleConfig.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/ServiceRegistryWrapper.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/rpc/InstanceRuntimeRpc.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfig.java
opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/xml/XmlUtil.java
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_identities.xml [new file with mode: 0644]

index cf0e71e67a52ab9983b5a2599519cf9f3014118c..502d58122082c8a9f60df8d5626c8d37f5374f3f 100644 (file)
@@ -37,6 +37,8 @@ public abstract class AttributeIfcSwitchStatement<T> {
                     return caseJavaBinaryAttribute(openType);
                 } else if(((JavaAttribute)attributeIfc).isUnion()) {
                     return caseJavaUnionAttribute(openType);
+                } else if(((JavaAttribute)attributeIfc).isIdentityRef()) {
+                    return caseJavaIdentityRefAttribute(openType);
                 } else
                     return caseJavaAttribute(openType);
             } catch (UnknownOpenTypeException e) {
@@ -56,6 +58,10 @@ public abstract class AttributeIfcSwitchStatement<T> {
         throw getIllegalArgumentException(attributeIfc);
     }
 
+    protected T caseJavaIdentityRefAttribute(OpenType<?> openType) {
+        return caseJavaAttribute(openType);
+    }
+
     protected T caseJavaUnionAttribute(OpenType<?> openType) {
         return caseJavaAttribute(openType);
     }
index 97c0f4d834ba7d7a810d9d36a08a1a74deb748e7..61db74feb570bc1f0c20e3ee24a938cce0d849ea 100644 (file)
@@ -16,20 +16,25 @@ import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribu
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributeIfcSwitchStatement;
+import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
 
 import javax.management.openmbean.ArrayType;
 import javax.management.openmbean.CompositeType;
 import javax.management.openmbean.OpenType;
 import javax.management.openmbean.SimpleType;
+import java.util.Date;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Set;
 
 public class ObjectXmlReader extends AttributeIfcSwitchStatement<AttributeReadingStrategy> {
 
     private String key;
+    private Map<String, Map<Date, EditConfig.IdentityMapping>> identityMap;
 
-    public Map<String, AttributeReadingStrategy> prepareReading(Map<String, AttributeIfc> yangToAttrConfig) {
+    public Map<String, AttributeReadingStrategy> prepareReading(Map<String, AttributeIfc> yangToAttrConfig, Map<String, Map<Date,EditConfig.IdentityMapping>> identityMap) {
         Map<String, AttributeReadingStrategy> strategies = Maps.newHashMap();
+        this.identityMap = identityMap;
 
         for (Entry<String, AttributeIfc> attributeEntry : yangToAttrConfig.entrySet()) {
             AttributeReadingStrategy strat = prepareReadingStrategy(attributeEntry.getKey(), attributeEntry.getValue());
@@ -72,6 +77,15 @@ public class ObjectXmlReader extends AttributeIfcSwitchStatement<AttributeReadin
         return new SimpleCompositeAttributeReadingStrategy(lastAttribute.getNullableDefault(), mappingKey);
     }
 
+    @Override
+    protected AttributeReadingStrategy caseJavaIdentityRefAttribute(OpenType<?> openType) {
+        Preconditions.checkState(openType instanceof CompositeType);
+        Set<String> keys = ((CompositeType) openType).keySet();
+        Preconditions.checkState(keys.size() == 1, "Unexpected number of elements for open type %s, should be 1", openType);
+        String mappingKey = keys.iterator().next();
+        return new SimpleIdentityRefAttributeReadingStrategy(lastAttribute.getNullableDefault(), mappingKey, identityMap);
+    }
+
     @Override
     protected AttributeReadingStrategy caseDependencyAttribute(SimpleType<?> openType) {
         return new ObjectNameAttributeReadingStrategy(lastAttribute.getNullableDefault());
index 625e4ab3dfe9f8c4a7aeb28879eb8daad31e1bfa..3765a135080adbd7e5a4af7742bd069bf6b5b2c7 100644 (file)
@@ -31,7 +31,7 @@ public class SimpleAttributeReadingStrategy extends AbstractAttributeReadingStra
 
         String textContent = "";
         try{
-            textContent = xmlElement.getTextContent();
+            textContent = readElementContent(xmlElement);
         }catch(IllegalStateException | NullPointerException e) {
             // yuma sends <attribute /> for empty value instead of <attribute></attribute>
             logger.warn("Ignoring exception caused by failure to read text element", e);
@@ -42,6 +42,10 @@ public class SimpleAttributeReadingStrategy extends AbstractAttributeReadingStra
                 postprocessParsedValue(textContent));
     }
 
+    protected String readElementContent(XmlElement xmlElement) {
+        return xmlElement.getTextContent();
+    }
+
     @Override
     protected Object postprocessNullableDefault(String nullableDefault) {
         return nullableDefault;
diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/SimpleIdentityRefAttributeReadingStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/SimpleIdentityRefAttributeReadingStrategy.java
new file mode 100644 (file)
index 0000000..1205597
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * 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.controller.netconf.confignetconfconnector.mapping.attributes.fromxml;
+
+import java.net.URI;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
+import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.yangtools.yang.common.QName;
+
+
+public class SimpleIdentityRefAttributeReadingStrategy extends SimpleAttributeReadingStrategy {
+
+    private final String key;
+    private final Map<String, Map<Date, EditConfig.IdentityMapping>> identityMap;
+
+    public SimpleIdentityRefAttributeReadingStrategy(String nullableDefault, String key, Map<String, Map<Date,EditConfig.IdentityMapping>> identityMap) {
+        super(nullableDefault);
+        this.key = key;
+        this.identityMap = identityMap;
+    }
+
+    @Override
+    protected String readElementContent(XmlElement xmlElement) {
+        // TODO test
+        Map.Entry<String, String> namespaceOfTextContent = xmlElement.findNamespaceOfTextContent();
+        String content = xmlElement.getTextContent();
+
+        String prefix = namespaceOfTextContent.getKey() + ":";
+        Preconditions.checkArgument(content.startsWith(prefix), "Identity ref should be prefixed");
+
+        String localName = content.substring(prefix.length());
+        String namespace = namespaceOfTextContent.getValue();
+
+        Date revision = null;
+        Map<Date, EditConfig.IdentityMapping> revisions = identityMap.get(namespace);
+        if(revisions.keySet().size() > 1) {
+            for (Date date : revisions.keySet()) {
+                if(revisions.get(date).containsIdName(localName)) {
+                    Preconditions.checkState(revision == null, "Duplicate identity %s, in namespace %s, with revisions: %s, %s detected. Cannot map attribute",
+                            localName, namespace, revision, date);
+                    revision = date;
+                }
+            }
+        } else
+            revision = revisions.keySet().iterator().next();
+
+
+        return QName.create(URI.create(namespace), revision, localName).toString();
+    }
+
+    @Override
+    protected Object postprocessParsedValue(String textContent) {
+        HashMap<String,String> map = Maps.newHashMap();
+        map.put(key, textContent);
+        return map;
+    }
+
+    @Override
+    protected Object postprocessNullableDefault(String nullableDefault) {
+        return nullableDefault == null ? null : postprocessParsedValue(nullableDefault);
+    }
+}
index 2e8b459b70c77fdfc7073e47dcc6a953470451c5..44cb1e761574a69e9c01d1757ac6a96bf0101473 100644 (file)
@@ -23,6 +23,7 @@ public class SimpleUnionAttributeReadingStrategy extends SimpleAttributeReadingS
         this.key = key;
     }
 
+    @Override
     protected Object postprocessParsedValue(String textContent) {
         char[] charArray = textContent.toCharArray();
         List<String> chars = Lists.newArrayListWithCapacity(charArray.length);
index 4e870f042d8cf45605546750d0f99868772fa897..8d63bb05d8b8a275dc8984d4ebb2f438772d7ab4 100644 (file)
@@ -68,6 +68,11 @@ public class ObjectXmlWriter extends AttributeIfcSwitchStatement<AttributeWritin
         return new ArrayAttributeWritingStrategy(innerStrategy);
     }
 
+    @Override
+    protected AttributeWritingStrategy caseJavaIdentityRefAttribute(OpenType<?> openType) {
+        return new SimpleIdentityRefAttributeWritingStrategy(document, key);
+    }
+
     @Override
     protected AttributeWritingStrategy caseJavaCompositeAttribute(CompositeType openType) {
         return new SimpleCompositeAttributeWritingStrategy(document, key);
index 62ff682a7fd7bbd2760e156150e22f1fb4457f51..b327f8ebeff06733fd48ba7483d938b689ef477d 100644 (file)
@@ -31,11 +31,15 @@ public class SimpleAttributeWritingStrategy implements AttributeWritingStrategy
     public void writeElement(Element parentElement, String namespace, Object value) {
         value = preprocess(value);
         Util.checkType(value, String.class);
-        Element innerNode = XmlUtil.createTextElement(document, key, (String) value);
+        Element innerNode = createElement(document, key, (String) value);
         XmlUtil.addNamespaceAttr(innerNode, namespace);
         parentElement.appendChild(innerNode);
     }
 
+    protected Element createElement(Document document, String key, String value) {
+        return XmlUtil.createTextElement(document, key, (String) value);
+    }
+
     protected Object preprocess(Object value) {
         return value;
     }
diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/SimpleIdentityRefAttributeWritingStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/SimpleIdentityRefAttributeWritingStrategy.java
new file mode 100644 (file)
index 0000000..7c90355
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * 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.controller.netconf.confignetconfconnector.mapping.attributes.toxml;
+
+import java.util.Map;
+
+import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.w3c.dom.Document;
+
+import com.google.common.base.Preconditions;
+import org.w3c.dom.Element;
+
+public class SimpleIdentityRefAttributeWritingStrategy extends SimpleAttributeWritingStrategy {
+
+    private static final char QNAME_SEPARATOR = ':';
+    private static final String PREFIX = "prefix";
+
+    /**
+     * @param document
+     * @param key
+     */
+    public SimpleIdentityRefAttributeWritingStrategy(Document document, String key) {
+        super(document, key);
+    }
+
+    protected Object preprocess(Object value) {
+        Util.checkType(value, Map.class);
+        Preconditions.checkArgument(((Map)value).size() == 1, "Unexpected number of values in %s, expected 1", value);
+        Object stringValue = ((Map) value).values().iterator().next();
+        Util.checkType(stringValue, String.class);
+
+        return stringValue;
+    }
+
+    @Override
+    protected Element createElement(Document doc, String key, String value) {
+        QName qName = QName.create(value);
+        String identity = qName.getLocalName();
+        Element element = XmlUtil.createPrefixedTextElement(doc, key, PREFIX, identity);
+
+        String identityNamespace = qName.getNamespace().toString();
+        XmlUtil.addPrefixedNamespaceAttr(element, PREFIX, identityNamespace);
+        return element;
+    }
+}
index ec73cd6068662f825e9d115457174c05ef49726d..449cfbb4cd4782b7a6e607cbc4258b7d48705968 100644 (file)
@@ -15,6 +15,7 @@ import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Multimap;
 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditStrategyType;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
 import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
@@ -27,6 +28,7 @@ import org.w3c.dom.Element;
 import javax.management.ObjectName;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -43,13 +45,20 @@ public class Config {
             Map<String /* Name of module entry from yang file */, ModuleConfig>> moduleConfigs;
     private final Map<String, ModuleConfig> moduleNamesToConfigs;
 
+    private final Map<String, Map<Date, EditConfig.IdentityMapping>> identityMap;
+
     public Config(Map<String, Map<String, ModuleConfig>> moduleConfigs) {
+        this(moduleConfigs, Collections.<String, Map<Date, EditConfig.IdentityMapping>>emptyMap());
+    }
+
+    public Config(Map<String, Map<String, ModuleConfig>> moduleConfigs, Map<String, Map<Date,EditConfig.IdentityMapping>> identityMap) {
         this.moduleConfigs = moduleConfigs;
         Map<String, ModuleConfig> moduleNamesToConfigs = new HashMap<>();
         for (Entry<String, Map<String, ModuleConfig>> entry : moduleConfigs.entrySet()) {
             moduleNamesToConfigs.putAll(entry.getValue());
         }
         this.moduleNamesToConfigs = Collections.unmodifiableMap(moduleNamesToConfigs);
+        this.identityMap = identityMap;
     }
 
     public static Map<String, Map<String, Collection<ObjectName>>> getMappedInstances(Set<ObjectName> instancesToMap,
@@ -149,7 +158,7 @@ public class Config {
                 @Override
                 public ModuleElementResolved resolveElement(ModuleConfig moduleMapping, XmlElement moduleElement, ServiceRegistryWrapper serviceTracker, String instanceName, String moduleNamespace, EditStrategyType defaultStrategy) {
                     return moduleMapping.fromXml(moduleElement, serviceTracker,
-                            instanceName, moduleNamespace, defaultStrategy);
+                            instanceName, moduleNamespace, defaultStrategy, identityMap);
                 }
             };
 
index b8870e51ce8bd0907655054a0b9c4566e1343cf4..a940be7e77f0cb71ea8d41253048f6818dff8a73 100644 (file)
@@ -25,6 +25,7 @@ import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attrib
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.resolving.ObjectResolver;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.toxml.AttributeWritingStrategy;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.toxml.ObjectXmlWriter;
+import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditStrategyType;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
 import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
@@ -35,6 +36,7 @@ import org.w3c.dom.Element;
 
 import javax.management.ObjectName;
 import javax.management.openmbean.OpenType;
+import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -129,10 +131,10 @@ public final class InstanceConfig {
     }
 
     public InstanceConfigElementResolved fromXml(XmlElement moduleElement, ServiceRegistryWrapper services, String moduleNamespace,
-            EditStrategyType defaultStrategy, Multimap<String, String> providedServices) {
+                                                 EditStrategyType defaultStrategy, Multimap<String, String> providedServices, Map<String, Map<Date,EditConfig.IdentityMapping>> identityMap) {
         Map<String, AttributeConfigElement> retVal = Maps.newHashMap();
 
-        Map<String, AttributeReadingStrategy> strats = new ObjectXmlReader().prepareReading(yangToAttrConfig);
+        Map<String, AttributeReadingStrategy> strats = new ObjectXmlReader().prepareReading(yangToAttrConfig, identityMap);
         List<XmlElement> recognisedChildren = Lists.newArrayList();
 
         XmlElement type = moduleElement.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.TYPE_KEY);
index 48ff835a451e789d51826c4a9c65ba4241d3329b..bf625ea0e26aece140ef6a6f329cfef0bb92fcae 100644 (file)
@@ -11,6 +11,7 @@ package org.opendaylight.controller.netconf.confignetconfconnector.mapping.confi
 import com.google.common.collect.HashMultimap;
 import com.google.common.collect.Multimap;
 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditStrategyType;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
 import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
@@ -21,6 +22,8 @@ import org.w3c.dom.Element;
 
 import javax.management.ObjectName;
 import java.util.Collection;
+import java.util.Date;
+import java.util.Map;
 
 public class ModuleConfig {
 
@@ -85,9 +88,9 @@ public class ModuleConfig {
     }
 
     public ModuleElementResolved fromXml(XmlElement moduleElement, ServiceRegistryWrapper depTracker, String instanceName,
-            String moduleNamespace, EditStrategyType defaultStrategy) {
+                                         String moduleNamespace, EditStrategyType defaultStrategy, Map<String, Map<Date,EditConfig.IdentityMapping>> identityMap) {
 
-        InstanceConfigElementResolved ice = instanceConfig.fromXml(moduleElement, depTracker, moduleNamespace, defaultStrategy, providedServices);
+        InstanceConfigElementResolved ice = instanceConfig.fromXml(moduleElement, depTracker, moduleNamespace, defaultStrategy, providedServices, identityMap);
         return new ModuleElementResolved(instanceName, ice);
     }
 
index 7df671297c4f38272a1b391ecfc97d4d72c8e132..8d2d149822011ccc856e934e84271550846b1ed1 100644 (file)
@@ -12,6 +12,7 @@ import com.google.common.base.Preconditions;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
+import org.opendaylight.yangtools.yang.common.QName;
 
 import javax.management.InstanceNotFoundException;
 import javax.management.ObjectName;
@@ -19,8 +20,6 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.Map;
 import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 public class ServiceRegistryWrapper {
 
@@ -77,27 +76,15 @@ public class ServiceRegistryWrapper {
                 ObjectName on = serviceMapping.get(serviceQName).get(refName);
                 Services.ServiceInstance si = Services.ServiceInstance.fromObjectName(on);
 
-                // FIXME use QName's new String constructor, after it is fixed
-//                QName qname;
-//                try {
-//                    qname = new QName(serviceQName);
-//                } catch (ParseException e) {
-//                    throw new IllegalStateException("Unable to parse qname of a service " + serviceQName, e);
-//                }
-                Pattern p = Pattern.compile("\\(([^\\(\\?]+)\\?[^\\?\\)]*\\)([^\\)]+)");
-                Matcher matcher = p.matcher(serviceQName);
-                Preconditions.checkArgument(matcher.matches());
-                String namespace = matcher.group(1);
-                String localName = matcher.group(2);
-
-//                String namespace = qname.getNamespace().toString();
+                QName qname = QName.create(serviceQName);
+                String namespace = qname.getNamespace().toString();
                 Map<String, Map<String, String>> serviceToRefs = retVal.get(namespace);
                 if(serviceToRefs==null) {
                     serviceToRefs = Maps.newHashMap();
                     retVal.put(namespace, serviceToRefs);
                 }
 
-//                String localName = qname.getLocalName();
+                String localName = qname.getLocalName();
                 Map<String, String> refsToSis = serviceToRefs.get(localName);
                 if(refsToSis==null) {
                     refsToSis = Maps.newHashMap();
index 4b05135eaf4d5bc3e9c751588b13a0848cb930c0..b7f5fc780bcc4c47a5428b00549629f39d9688b8 100644 (file)
@@ -17,9 +17,12 @@ import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attrib
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.ObjectXmlReader;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.resolving.AttributeResolvingStrategy;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.resolving.ObjectResolver;
+import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
 
 import javax.management.openmbean.OpenType;
+import java.util.Collections;
+import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -67,7 +70,9 @@ public final class InstanceRuntimeRpc {
     public Map<String, AttributeConfigElement> fromXml(XmlElement configRootNode) {
         Map<String, AttributeConfigElement> retVal = Maps.newHashMap();
 
-        Map<String, AttributeReadingStrategy> strats = new ObjectXmlReader().prepareReading(yangToAttrConfig);
+        // FIXME add identity map to runtime data
+        Map<String, AttributeReadingStrategy> strats = new ObjectXmlReader().prepareReading(yangToAttrConfig,
+                Collections.<String, Map<Date, EditConfig.IdentityMapping>> emptyMap());
 
         for (Entry<String, AttributeReadingStrategy> readStratEntry : strats.entrySet()) {
             List<XmlElement> configNodes = configRootNode.getChildElements(readStratEntry.getKey());
index a61d4633a2dd7d6ae00bd7cfaa351ff83aa94a49..97535ba1e2a6a576dd4f21444e7ce5f8e418d8c9 100644 (file)
@@ -9,6 +9,7 @@
 package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig;
 
 import com.google.common.annotations.VisibleForTesting;
+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;
@@ -33,6 +34,8 @@ import org.opendaylight.controller.netconf.confignetconfconnector.operations.edi
 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.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;
@@ -40,9 +43,11 @@ import org.w3c.dom.Element;
 
 import javax.management.InstanceNotFoundException;
 import javax.management.ObjectName;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Set;
 
 public class EditConfig extends AbstractConfigNetconfOperation {
 
@@ -207,12 +212,64 @@ 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();
+        }
 
-        return new Config(factories);
+        void addIdSchemaNode(IdentitySchemaNode node) {
+            String name = node.getQName().getLocalName();
+            Preconditions.checkState(identityNameToSchemaNode.containsKey(name) == false);
+            identityNameToSchemaNode.put(name, node);
+        }
+
+        public boolean containsIdName(String idName) {
+            return identityNameToSchemaNode.containsKey(idName);
+        }
+
+        public IdentitySchemaNode getIdentitySchemaNode(String idName) {
+            Preconditions.checkState(identityNameToSchemaNode.containsKey(idName), "No identity under name %s", idName);
+            return identityNameToSchemaNode.get(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) == false,
+                    "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 mappedIds;
     }
 
     public static Map<String/* Namespace from yang file */,
@@ -253,7 +310,7 @@ public class EditConfig extends AbstractConfigNetconfOperation {
     protected Element handle(Document document, XmlElement xml) throws NetconfDocumentedException {
 
         EditConfigXmlParser.EditConfigExecution editConfigExecution;
-        Config cfg = getConfigMapping(configRegistryClient, yangStoreSnapshot.getModuleMXBeanEntryMap());
+        Config cfg = getConfigMapping(configRegistryClient, yangStoreSnapshot);
         try {
             editConfigExecution = editConfigXmlParser.fromXml(xml, cfg, transactionProvider, configRegistryClient);
         } catch (IllegalStateException e) {
@@ -278,4 +335,5 @@ public class EditConfig extends AbstractConfigNetconfOperation {
 
         return getResponseInternal(document, editConfigExecution);
     }
+
 }
index f236a8d36ecda2d706c59eb425470cbda0799028..d699d224bbc1bfd387d5fc6d2974b670e7b83412 100644 (file)
@@ -8,11 +8,33 @@
 
 package org.opendaylight.controller.netconf.confignetconfconnector;
 
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+import javax.xml.parsers.ParserConfigurationException;
+
 import org.apache.commons.lang3.StringUtils;
 import org.junit.Before;
 import org.junit.Ignore;
@@ -35,6 +57,7 @@ import org.opendaylight.controller.config.yang.test.impl.DtoAInner;
 import org.opendaylight.controller.config.yang.test.impl.DtoAInnerInner;
 import org.opendaylight.controller.config.yang.test.impl.DtoC;
 import org.opendaylight.controller.config.yang.test.impl.DtoD;
+import org.opendaylight.controller.config.yang.test.impl.IdentityTestModuleFactory;
 import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleFactory;
 import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleMXBean;
 import org.opendaylight.controller.config.yang.test.impl.Peers;
@@ -55,6 +78,13 @@ import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
 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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.test.impl.rev130403.TestIdentity1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.test.impl.rev130403.TestIdentity2;
+import org.opendaylight.yangtools.yang.data.impl.codec.CodecRegistry;
+import org.opendaylight.yangtools.yang.data.impl.codec.IdentityCodec;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
@@ -62,30 +92,11 @@ import org.w3c.dom.Element;
 import org.w3c.dom.NodeList;
 import org.xml.sax.SAXException;
 
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.InstanceNotFoundException;
-import javax.management.ObjectName;
-import javax.xml.parsers.ParserConfigurationException;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.math.BigInteger;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
 
 
 public class NetconfMappingTest extends AbstractConfigTest {
@@ -95,6 +106,7 @@ public class NetconfMappingTest extends AbstractConfigTest {
     private static final String NETCONF_SESSION_ID = "foo";
     private NetconfTestImplModuleFactory factory;
     private DepTestImplModuleFactory factory2;
+    private IdentityTestModuleFactory factory3;
 
     @Mock
     YangStoreSnapshot yangStoreSnapshot;
@@ -107,9 +119,13 @@ public class NetconfMappingTest extends AbstractConfigTest {
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
         doReturn(getMbes()).when(this.yangStoreSnapshot).getModuleMXBeanEntryMap();
+        doReturn(getModules()).when(this.yangStoreSnapshot).getModules();
+
         this.factory = new NetconfTestImplModuleFactory();
         this.factory2 = new DepTestImplModuleFactory();
-        super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(this.factory, this.factory2));
+        this.factory3 = new IdentityTestModuleFactory();
+        super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(this.factory, this.factory2,
+                this.factory3));
 
         transactionProvider = new TransactionProvider(this.configRegistryClient, NETCONF_SESSION_ID);
     }
@@ -133,6 +149,25 @@ public class NetconfMappingTest extends AbstractConfigTest {
         return on;
     }
 
+    @Test
+    public void testIdentityRefs() throws Exception {
+        edit("netconfMessages/editConfig_identities.xml");
+
+        commit();
+        getConfigRunning();
+    }
+
+    @Override
+    protected CodecRegistry getCodecRegistry() {
+        IdentityCodec<?> idCodec = mock(IdentityCodec.class);
+        doReturn(TestIdentity1.class).when(idCodec).deserialize(TestIdentity1.QNAME);
+        doReturn(TestIdentity2.class).when(idCodec).deserialize(TestIdentity2.QNAME);
+
+        CodecRegistry codecReg = super.getCodecRegistry();
+        doReturn(idCodec).when(codecReg).getIdentityCodec();
+        return codecReg;
+    }
+
     @Test
     public void testServicePersistance() throws Exception {
         createModule(INSTANCE_NAME);
@@ -236,7 +271,6 @@ public class NetconfMappingTest extends AbstractConfigTest {
 
         edit("netconfMessages/editConfig.xml");
         Element configCandidate = getConfigCandidate();
-        System.err.println(XmlUtil.toString(configCandidate));
         checkBinaryLeafEdited(configCandidate);
 
 
@@ -554,6 +588,21 @@ public class NetconfMappingTest extends AbstractConfigTest {
         return mBeanEntries;
     }
 
+    private Set<org.opendaylight.yangtools.yang.model.api.Module> getModules() throws Exception {
+        SchemaContext resolveSchemaContext = getSchemaContext();
+        return resolveSchemaContext.getModules();
+    }
+
+    private SchemaContext getSchemaContext() throws Exception {
+        final List<InputStream> yangDependencies = getYangs();
+        YangParserImpl parser = new YangParserImpl();
+
+        Set<Module> allYangModules = parser.parseYangModelsFromStreams(yangDependencies);
+
+        return parser.resolveSchemaContext(Sets
+                .newHashSet(allYangModules));
+    }
+
     @Test
     public void testConfigNetconfRuntime() throws Exception {
 
index 5e3a7ac54f49444ac8a2278f85ed82c20a052a7a..137e215a31eb13423b6438671faed529a2fc7ce3 100644 (file)
@@ -111,8 +111,8 @@ public class XmlUtil {
         root.setAttribute(concat(XMLNS_ATTRIBUTE_KEY, prefix), namespace);
     }
 
-    public static Element createPrefixedTextElement(Document document, String key, String prefix, String moduleName) {
-        return createTextElement(document, key, concat(prefix, moduleName));
+    public static Element createPrefixedTextElement(Document document, String key, String prefix, String content) {
+        return createTextElement(document, key, concat(prefix, content));
     }
 
     private static String concat(String prefix, String value) {
diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_identities.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_identities.xml
new file mode 100644 (file)
index 0000000..62c6a20
--- /dev/null
@@ -0,0 +1,37 @@
+<rpc message-id="a" a="64" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <edit-config>
+        <target>
+            <candidate/>
+        </target>
+        <test-option>
+            set
+        </test-option>
+        <default-operation>merge</default-operation>
+        <config>
+            <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+                <module>
+                    <type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+                        test-impl:impl-identity-test
+                    </type>
+                    <name>id-test</name>
+                    <identities>
+                        <afi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test:impl">prefix:test-identity1</afi>
+                        <safi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test:impl">prefix:test-identity2</safi>
+                    </identities>
+                    <identities>
+                        <afi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test:impl">prefix:test-identity2</afi>
+                        <safi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test:impl">prefix:test-identity1</safi>
+                    </identities>
+                    <identities-container>
+                        <afi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test:impl">prefix:test-identity2</afi>
+                    </identities-container>
+                    <afi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test:impl">prefix:test-identity1</afi>
+                </module>
+            </modules>
+
+            <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+
+            </services>
+        </config>
+    </edit-config>
+</rpc>