Merge "One more fix to pass release-prepareonly"
authorAlessandro Boch <aboch@cisco.com>
Mon, 27 Jan 2014 03:40:40 +0000 (03:40 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Mon, 27 Jan 2014 03:40:40 +0000 (03:40 +0000)
43 files changed:
opendaylight/config/shutdown-api/pom.xml
opendaylight/distribution/opendaylight/src/main/resources/configuration/logback.xml
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend
opendaylight/md-sal/sal-binding-config/pom.xml
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/routing/AbstractDataReadRouter.java
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.xtend
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/NotificationRouterImpl.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonMapper.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonReader.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestUtil.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestconfProvider.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlReader.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/CompositeNodeWrapper.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/EmptyNodeWrapper.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/IdentityValuesDTO.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/NodeWrapper.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestCodec.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/SimpleNodeWrapper.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/iml/varioustests/VariousTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnInstanceIdentifierToXmlTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnToXmlTest.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CnSnToXmlAndJsonInstanceIdentifierTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestCodecExceptionsTest.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetAugmentedElementWhenEqualNamesTest.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URITest.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnInstanceIdentifierTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlAugmentedElementToCnSnTest.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlLeafrefToCnSnTest.java
opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-xml/yang/basic-module.yang
opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/json/jsondata.json [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/xml/xmldata.xml [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/yang/augment-augment-module.yang [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/yang/augment-module.yang [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/yang/instance-identifier-module.yang [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/varioustest/xmldata.xml [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsProvider.java
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiter.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationServiceFactoryImpl.java
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterActivator.java
opendaylight/switchmanager/implementation/src/main/java/org/opendaylight/controller/switchmanager/internal/SwitchManager.java

index 0603b2d82d6de4e553ee66e697dcd0a33204dbf7..625ac1425ab4ba5b8db1e3c34ce6d23b8e1553fd 100644 (file)
@@ -32,7 +32,8 @@
                     <instructions>
                         <Export-Package>
                             org.opendaylight.controller.config.shutdown,
-                            org.opendaylight.controller.config.yang.shutdown
+                            org.opendaylight.controller.config.yang.shutdown,
+                            org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.shutdown.rev131218
                         </Export-Package>
                     </instructions>
                 </configuration>
index 0345f188157d8e775be0b208839b76f6ca83f1ca..d1a5dcc416cc190dd3dabd80fdc5e8963a6af9a3 100644 (file)
     <appender-ref ref="opendaylight.log"/>
   </logger>
 
+  <!-- To debug MD-SAL schema loading issues, uncomment this -->
+  <!--logger name="org.opendaylight.yangtools.yang.parser.impl.util.URLSchemaContextResolver" level="DEBUG"/>
+  <logger name="org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl" level="TRACE"/-->
+
   <!-- additivity=false ensures analytics data only goes to the analytics log -->
   <logger name="audit" level="INFO" additivity="false">
        <appender-ref ref="audit-file"/>
index a3c8c5f232b0b6e7daae0350880eca7e790985a5..52aa8d029066b3093a90300f6bb078886b2b3d7b 100644 (file)
@@ -21,8 +21,8 @@ import org.opendaylight.yangtools.concepts.ListenerRegistration
 import org.opendaylight.yangtools.concepts.Registration\r
 import org.opendaylight.yangtools.yang.binding.Notification\r
 import org.slf4j.LoggerFactory\r
-import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder\r
-\r
+import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder\rimport com.google.common.collect.Multimaps
+
 class NotificationBrokerImpl implements NotificationProviderService, AutoCloseable {\r
 \r
     val Multimap<Class<? extends Notification>, NotificationListener<?>> listeners;\r
@@ -31,12 +31,12 @@ class NotificationBrokerImpl implements NotificationProviderService, AutoCloseab
     var ExecutorService executor;\r
 \r
     new() {\r
-        listeners = HashMultimap.create()\r
+        listeners = Multimaps.synchronizedSetMultimap(HashMultimap.create())\r
     }\r
 \r
     @Deprecated\r
     new(ExecutorService executor) {\r
-        listeners = HashMultimap.create()\r
+        listeners = Multimaps.synchronizedSetMultimap(HashMultimap.create())\r
         this.executor = executor;\r
     }\r
 \r
index be031a74100e7cf18a7ff4cbe412332ed87e2920..852314f4d4d93905912cb844a810a6b85bd0a622 100644 (file)
                         </goals>
                         <configuration>
                             <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>
+                                        org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl
+                                    </codeGeneratorClass>
+                                    <outputBaseDir>
+                                        target/generated-sources/sal
+                                    </outputBaseDir>
+                                </generator>
                                 <generator>
                                     <codeGeneratorClass>
                                         org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
index 9e6147359db58cc1ff60e9100feca555f3061333..4ddceb3b5f015a709e508f73cbb91e4cc46e66e0 100644 (file)
@@ -12,6 +12,7 @@ import com.google.common.base.Predicate;
 import com.google.common.collect.FluentIterable;
 import com.google.common.collect.HashMultimap;
 import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
 
 /**
  * Base abstract implementation of DataReadRouter, which performs
@@ -22,8 +23,8 @@ import com.google.common.collect.Multimap;
  */
 public abstract class AbstractDataReadRouter<P extends Path<P>, D> implements DataReader<P, D> {
 
-    Multimap<P, DataReaderRegistration<P, D>> configReaders = HashMultimap.create();
-    Multimap<P, DataReaderRegistration<P, D>> operationalReaders = HashMultimap.create();
+    Multimap<P, DataReaderRegistration<P, D>> configReaders = Multimaps.synchronizedSetMultimap(HashMultimap.<P, DataReaderRegistration<P, D>>create());
+    Multimap<P, DataReaderRegistration<P, D>> operationalReaders = Multimaps.synchronizedSetMultimap(HashMultimap.<P, DataReaderRegistration<P, D>>create());
 
     @Override
     public D readConfigurationData(P path) {
index d86547ab99087bba598c3b19c5cab628dfc6263f..cef88fc375518de22f25b225905311bbc02df0ee 100644 (file)
@@ -37,6 +37,7 @@ import org.opendaylight.yangtools.yang.common.RpcResult
 import org.slf4j.LoggerFactory\r
 \r
 import static com.google.common.base.Preconditions.*\rimport org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent
+import com.google.common.collect.Multimaps
 
 abstract class AbstractDataBroker<P extends Path<P>, D, DCL extends DataChangeListener<P, D>> implements DataModificationTransactionFactory<P, D>, //\r
 DataReader<P, D>, //\r
@@ -60,8 +61,8 @@ DataProvisionService<P, D> {
     @Property\r
     private val AtomicLong finishedTransactionsCount = new AtomicLong\r
 \r
-    Multimap<P, DataChangeListenerRegistration<P, D, DCL>> listeners = HashMultimap.create();\r
-    Multimap<P, DataCommitHandlerRegistrationImpl<P, D>> commitHandlers = HashMultimap.create();\r
+    Multimap<P, DataChangeListenerRegistration<P, D, DCL>> listeners = Multimaps.synchronizedSetMultimap(HashMultimap.create());\r
+    Multimap<P, DataCommitHandlerRegistrationImpl<P, D>> commitHandlers = Multimaps.synchronizedSetMultimap(HashMultimap.create());\r
     \r
     val ListenerRegistry<RegistrationListener<DataCommitHandlerRegistration<P,D>>> commitHandlerRegistrationListeners = new ListenerRegistry();\r
     public new() {\r
index 6242dee038661da6d4d79685bc6e0a35b7c720da..763407f23a671476c7f47a9c8f7e3d63e0b2b128 100644 (file)
@@ -34,11 +34,12 @@ import org.slf4j.LoggerFactory;
 import com.google.common.collect.HashMultimap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
 
 public class NotificationRouterImpl implements NotificationRouter {
     private static Logger log = LoggerFactory.getLogger(NotificationRouterImpl.class);
 
-    private Multimap<QName, Registration<NotificationListener>> listeners = HashMultimap.create();
+    private Multimap<QName, Registration<NotificationListener>> listeners = Multimaps.synchronizedSetMultimap(HashMultimap.<QName, Registration<NotificationListener>>create());
 
     private void sendNotification(CompositeNode notification) {
         QName type = notification.getNodeType();
index 627e2a9ce158083b192abc4c92827c91619be8ad..4c5fd9ff7ccb77fa17f781406db125ff26e2cc52 100644 (file)
@@ -14,9 +14,11 @@ import org.opendaylight.controller.sal.core.api.mount.MountInstance;
 import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
 import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO;
 import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO.IdentityValue;
+import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO.Predicate;
 import org.opendaylight.controller.sal.restconf.impl.RestCodec;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.Node;
 import org.opendaylight.yangtools.yang.data.api.SimpleNode;
 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
@@ -32,6 +34,7 @@ import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
 import org.slf4j.Logger;
@@ -47,12 +50,13 @@ class JsonMapper {
     private MountInstance mountPoint;
     private final Logger logger = LoggerFactory.getLogger(JsonMapper.class);
 
-    public void write(JsonWriter writer, CompositeNode data, DataNodeContainer schema, MountInstance mountPoint) throws IOException {
+    public void write(JsonWriter writer, CompositeNode data, DataNodeContainer schema, MountInstance mountPoint)
+            throws IOException {
         Preconditions.checkNotNull(writer);
         Preconditions.checkNotNull(data);
         Preconditions.checkNotNull(schema);
         this.mountPoint = mountPoint;
-        
+
         writer.beginObject();
 
         if (schema instanceof ContainerSchemaNode) {
@@ -195,7 +199,8 @@ class JsonMapper {
         // TODO check InstanceIdentifierTypeDefinition
         if (baseType instanceof IdentityrefTypeDefinition) {
             if (node.getValue() instanceof QName) {
-                IdentityValuesDTO valueDTO = (IdentityValuesDTO) RestCodec.from(baseType, mountPoint).serialize(node.getValue());
+                IdentityValuesDTO valueDTO = (IdentityValuesDTO) RestCodec.from(baseType, mountPoint).serialize(
+                        node.getValue());
                 IdentityValue valueFromDTO = valueDTO.getValuesWithNamespaces().get(0);
                 String moduleName;
                 if (mountPoint != null) {
@@ -207,19 +212,20 @@ class JsonMapper {
                 }
                 writer.value(moduleName + ":" + valueFromDTO.getValue());
             } else {
-                Object value = node.getValue();
-                logger.debug("Value of " + baseType.getQName().getNamespace() + ":"
-                        + baseType.getQName().getLocalName() + " is not instance of " + QName.class + " but is "
-                        + (value != null ? value.getClass() : "null"));
-                if (value == null) {
-                    writer.value("");
-                } else {
-                    writer.value(String.valueOf(value));
-                }
+                writeStringRepresentation(writer, node, baseType, QName.class);
+            }
+        } else if (baseType instanceof InstanceIdentifierTypeDefinition) {
+            if (node.getValue() instanceof InstanceIdentifier) {
+                IdentityValuesDTO valueDTO = (IdentityValuesDTO) RestCodec.from(baseType, mountPoint).serialize(
+                        node.getValue());
+                writeIdentityValuesDTOToJson(writer, valueDTO);
+            } else {
+                writeStringRepresentation(writer, node, baseType, InstanceIdentifier.class);
             }
         } else if (baseType instanceof DecimalTypeDefinition || baseType instanceof IntegerTypeDefinition
                 || baseType instanceof UnsignedIntegerTypeDefinition) {
-            writer.value(new NumberForJsonWriter((String) RestCodec.from(baseType, mountPoint).serialize(node.getValue())));
+            writer.value(new NumberForJsonWriter((String) RestCodec.from(baseType, mountPoint).serialize(
+                    node.getValue())));
         } else if (baseType instanceof BooleanTypeDefinition) {
             writer.value(Boolean.parseBoolean((String) RestCodec.from(baseType, mountPoint).serialize(node.getValue())));
         } else if (baseType instanceof EmptyTypeDefinition) {
@@ -233,6 +239,50 @@ class JsonMapper {
         }
     }
 
+    private void writeIdentityValuesDTOToJson(JsonWriter writer, IdentityValuesDTO valueDTO) throws IOException {
+        StringBuilder result = new StringBuilder();
+        for (IdentityValue identityValue : valueDTO.getValuesWithNamespaces()) {
+            result.append("/");
+
+            writeModuleNameAndIdentifier(result, identityValue);
+            if (identityValue.getPredicates() != null) {
+                for (Predicate predicate : identityValue.getPredicates()) {
+                    IdentityValue identityValuePredicate = predicate.getName();
+                    result.append("[");
+                    writeModuleNameAndIdentifier(result, identityValuePredicate);
+                    result.append("=\"");
+                    result.append(predicate.getValue());
+                    result.append("\"");
+                    result.append("]");
+                }
+            }
+        }
+
+        writer.value(result.toString());
+    }
+
+    private void writeModuleNameAndIdentifier(StringBuilder result, IdentityValue identityValue) {
+        String moduleName = ControllerContext.getInstance().findModuleNameByNamespace(
+                URI.create(identityValue.getNamespace()));
+        if (moduleName != null && !moduleName.isEmpty()) {
+            result.append(moduleName);
+            result.append(":");
+        }
+        result.append(identityValue.getValue());
+    }
+
+    private void writeStringRepresentation(JsonWriter writer, SimpleNode<?> node, TypeDefinition<?> baseType,
+            Class<?> requiredType) throws IOException {
+        Object value = node.getValue();
+        logger.debug("Value of " + baseType.getQName().getNamespace() + ":" + baseType.getQName().getLocalName()
+                + " is not instance of " + requiredType.getClass() + " but is " + node.getValue().getClass());
+        if (value == null) {
+            writer.value("");
+        } else {
+            writer.value(String.valueOf(value));
+        }
+    }
+
     private void writeEmptyDataTypeToJson(JsonWriter writer) throws IOException {
         writer.beginArray();
         writer.nullValue();
index f4c5034776ec1e83fa5022c7a68223d139d3060a..3fc402ca3af95b052099a66345b0bafde524ae79 100644 (file)
@@ -6,10 +6,11 @@ import java.net.URI;
 import java.util.Map.Entry;
 import java.util.Set;
 
+import org.opendaylight.controller.sal.rest.impl.RestUtil.PrefixMapingFromJson;
 import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper;
 import org.opendaylight.controller.sal.restconf.impl.EmptyNodeWrapper;
-import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper;
 import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO;
+import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper;
 
 import com.google.common.collect.Lists;
 import com.google.gson.JsonElement;
@@ -63,8 +64,7 @@ class JsonReader {
 
     private void addChildToParent(String childName, JsonElement childType, CompositeNodeWrapper parent) {
         if (childType.isJsonObject()) {
-            CompositeNodeWrapper child = new CompositeNodeWrapper(getNamespaceFor(childName),
-                    getLocalNameFor(childName));
+            CompositeNodeWrapper child = new CompositeNodeWrapper(getNamespaceFor(childName), getLocalNameFor(childName));
             parent.addValue(child);
             for (Entry<String, JsonElement> childOfChild : childType.getAsJsonObject().entrySet()) {
                 addChildToParent(childOfChild.getKey(), childOfChild.getValue(), child);
@@ -88,7 +88,8 @@ class JsonReader {
 
     private URI getNamespaceFor(String jsonElementName) {
         String[] moduleNameAndLocalName = jsonElementName.split(":");
-        if (moduleNameAndLocalName.length != 2) { // it is not "moduleName:localName"
+        // it is not "moduleName:localName"
+        if (moduleNameAndLocalName.length != 2) {
             return null;
         }
         return URI.create(moduleNameAndLocalName[0]);
@@ -96,21 +97,28 @@ class JsonReader {
 
     private String getLocalNameFor(String jsonElementName) {
         String[] moduleNameAndLocalName = jsonElementName.split(":");
-        if (moduleNameAndLocalName.length != 2) { // it is not "moduleName:localName"
+        // it is not "moduleName:localName"
+        if (moduleNameAndLocalName.length != 2) {
             return jsonElementName;
         }
         return moduleNameAndLocalName[1];
     }
 
-    /**
-     * @param value
-     *            value of json element
-     * @return if value is "moduleName:localName" then {@link IdentityValuesDTO} else
-     *         the same string as parameter "value"
-     */
     private Object resolveValueOfElement(String value) {
+        // it could be instance-identifier Built-In Type
+        if (value.startsWith("/")) {
+            IdentityValuesDTO resolvedValue = RestUtil.asInstanceIdentifier(value, new PrefixMapingFromJson());
+            if (resolvedValue != null) {
+                return resolvedValue;
+            }
+        }
+        // it could be identityref Built-In Type
         URI namespace = getNamespaceFor(value);
-        return namespace == null ? value : new IdentityValuesDTO(namespace.toString(), getLocalNameFor(value), null);
+        if (namespace != null) {
+            return new IdentityValuesDTO(namespace.toString(), getLocalNameFor(value), null);
+        }
+        // it is not "prefix:value" but just "value"
+        return value;
     }
 
 }
index 6e70b9bddf887cee1fd26b69abdafa6b15084843..0c8c75839bca19d590c3f58a1ce915563181e8e0 100644 (file)
@@ -1,8 +1,22 @@
 package org.opendaylight.controller.sal.rest.impl;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.xml.stream.events.StartElement;
+
+import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO;
+import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO.IdentityValue;
+import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO.Predicate;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
 
 public final class RestUtil {
+    
+    public static final String SQUOTE = "'";
+    public static final String DQUOTE = "\"";
+    private static final Pattern PREDICATE_PATTERN = Pattern.compile("\\[(.*?)\\]");
 
     public final static TypeDefinition<?> resolveBaseTypeFrom(TypeDefinition<?> type) {
         TypeDefinition<?> superType = type;
@@ -12,4 +26,121 @@ public final class RestUtil {
         return superType;
     }
 
+    public static IdentityValuesDTO asInstanceIdentifier(String value, PrefixesMaping prefixMap) {
+        String valueTrimmed = value.trim();
+        if (!valueTrimmed.startsWith("/")) {
+            return null;
+        }
+        String[] xPathParts = valueTrimmed.split("/");
+        if (xPathParts.length < 2) { // must be at least "/pr:node"
+            return null;
+        }
+        IdentityValuesDTO identityValuesDTO = new IdentityValuesDTO();
+        for (int i = 1; i < xPathParts.length; i++) {
+            String xPathPartTrimmed = xPathParts[i].trim();
+            
+            String xPathPartStr = getIdAndPrefixAsStr(xPathPartTrimmed);
+            IdentityValue identityValue = toIdentity(xPathPartStr, prefixMap);
+            if (identityValue == null) {
+                return null;
+            }
+            
+            List<Predicate> predicates = toPredicates(xPathPartTrimmed, prefixMap);
+            if (predicates == null) {
+                return null;
+            }
+            identityValue.setPredicates(predicates);
+            
+            identityValuesDTO.add(identityValue);
+        }
+        return identityValuesDTO.getValuesWithNamespaces().isEmpty() ? null : identityValuesDTO;
+    }
+    
+    private static String getIdAndPrefixAsStr(String pathPart) {
+        int predicateStartIndex = pathPart.indexOf("[");
+        return predicateStartIndex == -1 ? pathPart : pathPart.substring(0, predicateStartIndex);
+    }
+    
+    private static IdentityValue toIdentity(String xPathPart, PrefixesMaping prefixMap) {
+        String xPathPartTrimmed = xPathPart.trim();
+        if (xPathPartTrimmed.isEmpty()) {
+            return null;
+        }
+        String[] prefixAndIdentifier = xPathPartTrimmed.split(":");
+        // it is not "prefix:value"
+        if (prefixAndIdentifier.length != 2) {
+            return null;
+        }
+        String prefix = prefixAndIdentifier[0].trim();
+        String identifier = prefixAndIdentifier[1].trim();
+        if (prefix.isEmpty() || identifier.isEmpty()) {
+            return null;
+        }
+        String namespace = prefixMap.getNamespace(prefix);
+        return new IdentityValue(namespace, identifier, namespace.equals(prefix) ? null : prefix);
+    }
+
+    private static List<Predicate> toPredicates(String predicatesStr, PrefixesMaping prefixMap) {
+        List<Predicate> result = new ArrayList<>();
+        List<String> predicates = new ArrayList<>();
+        Matcher matcher = PREDICATE_PATTERN.matcher(predicatesStr);
+        while (matcher.find()) {
+            predicates.add(matcher.group(1).trim());
+        }
+        for (String predicate : predicates) {
+            int indexOfEqualityMark = predicate.indexOf("=");
+            if (indexOfEqualityMark != -1) {
+                String predicateValue = toPredicateValue(predicate.substring(indexOfEqualityMark + 1));
+                if (predicate.startsWith(".")) { // it is leaf-list
+                    if (predicateValue == null) {
+                        return null;
+                    }
+                    result.add(new Predicate(null, predicateValue));
+                } else {
+                    IdentityValue identityValue = toIdentity(predicate.substring(0, indexOfEqualityMark),
+                            prefixMap);
+                    if (identityValue == null || predicateValue == null) {
+                        return null;
+                    }
+                    result.add(new Predicate(identityValue, predicateValue));
+                }
+            }
+        }
+        return result;
+    }
+
+    private static String toPredicateValue(String predicatedValue) {
+        String predicatedValueTrimmed = predicatedValue.trim();
+        if ((predicatedValueTrimmed.startsWith(DQUOTE) || predicatedValueTrimmed.startsWith(SQUOTE))
+                && (predicatedValueTrimmed.endsWith(DQUOTE) || predicatedValueTrimmed.endsWith(SQUOTE))) {
+            return predicatedValueTrimmed.substring(1, predicatedValueTrimmed.length() - 1);
+        }
+        return null;
+    }
+
+    public interface PrefixesMaping {
+        public String getNamespace(String prefix);
+    }
+
+    public static class PrefixMapingFromXml implements PrefixesMaping {
+        StartElement startElement = null;
+
+        public PrefixMapingFromXml(StartElement startElement) {
+            this.startElement = startElement;
+        }
+
+        @Override
+        public String getNamespace(String prefix) {
+            return startElement.getNamespaceContext().getNamespaceURI(prefix);
+        }
+    }
+
+    public static class PrefixMapingFromJson implements PrefixesMaping {
+
+        @Override
+        public String getNamespace(String prefix) {
+            return prefix;
+        }
+    }
+
 }
index 954644737a7e3fb4678aa81a82f21ce2a4333e7e..09cf01091ed0deaa3c3ea5f86d35134d5ae89a84 100644 (file)
@@ -8,11 +8,11 @@ import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
 import org.opendaylight.controller.sal.core.api.Provider;
 import org.opendaylight.controller.sal.core.api.data.DataBrokerService;
 import org.opendaylight.controller.sal.core.api.model.SchemaService;
-import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener;
 import org.opendaylight.controller.sal.core.api.mount.MountService;
 import org.opendaylight.controller.sal.restconf.impl.BrokerFacade;
 import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
index 014e839f2665c7e9aa7c89c5a9f344aaef377b7b..d6f8a9874b963a90fa62e595e5bb7e6a9fcad8b0 100644 (file)
@@ -14,8 +14,8 @@ import javax.xml.stream.events.StartElement;
 import javax.xml.stream.events.XMLEvent;
 
 import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper;
-import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO;
 import org.opendaylight.controller.sal.restconf.impl.EmptyNodeWrapper;
+import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO;
 import org.opendaylight.controller.sal.restconf.impl.NodeWrapper;
 import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper;
 import org.opendaylight.yangtools.yang.data.api.Node;
@@ -148,6 +148,7 @@ public class XmlReader {
                 final Characters chars = innerEvent.asCharacters();
                 if (!chars.isWhiteSpace()) {
                     data = innerEvent.asCharacters().getData();
+                    data = data + getAdditionalData(eventReader.nextEvent());
                 }
             } else if (innerEvent.isEndElement()) {
                 if (startElement.getLocation().getCharacterOffset() == innerEvent.getLocation().getCharacterOffset()) {
@@ -160,6 +161,21 @@ public class XmlReader {
         return data;
     }
 
+    private String getAdditionalData(XMLEvent event) throws XMLStreamException {
+        String data = "";
+        if (eventReader.hasNext()) {
+            final XMLEvent innerEvent = eventReader.peek();
+            if (innerEvent.isCharacters() && !innerEvent.isEndElement()) {
+                final Characters chars = innerEvent.asCharacters();
+                if (!chars.isWhiteSpace()) {
+                    data = innerEvent.asCharacters().getData();
+                    data = data + getAdditionalData(eventReader.nextEvent());
+                }
+            }
+        }
+        return data;
+    }
+
     private String getLocalNameFor(StartElement startElement) {
         return startElement.getName().getLocalPart();
     }
@@ -169,23 +185,23 @@ public class XmlReader {
         return namespaceURI.isEmpty() ? null : URI.create(namespaceURI);
     }
 
-    /**
-     * @param value
-     *            value of startElement
-     * @param startElement
-     *            element containing value
-     * @return if value is "prefix:value" then {@link IdentityValuesDTO} else the same
-     *         string as parameter "value"
-     */
     private Object resolveValueOfElement(String value, StartElement startElement) {
-        String[] namespaceAndValue = value.split(":");
-        if (namespaceAndValue.length != 2) { // it is not "prefix:value"
-            return value;
+        // it could be instance-identifier Built-In Type
+        if (value.startsWith("/")) {
+            IdentityValuesDTO iiValue = RestUtil.asInstanceIdentifier(value, new RestUtil.PrefixMapingFromXml(startElement));
+            if (iiValue != null) {
+                return iiValue;
+            }
         }
-        String namespace = startElement.getNamespaceContext().getNamespaceURI(namespaceAndValue[0]);
-        if (namespace != null && !namespace.isEmpty()) {
-            return new IdentityValuesDTO(namespace, namespaceAndValue[1], namespaceAndValue[0]);
+        // it could be identityref Built-In Type
+        String[] namespaceAndValue = value.split(":");
+        if (namespaceAndValue.length == 2) {
+            String namespace = startElement.getNamespaceContext().getNamespaceURI(namespaceAndValue[0]);
+            if (namespace != null && !namespace.isEmpty()) {
+                return new IdentityValuesDTO(namespace, namespaceAndValue[1], namespaceAndValue[0]);
+            }
         }
+        // it is not "prefix:value" but just "value"
         return value;
     }
 
index 74a32d452e212682abee966adffad4f062577fcb..8c5870522ec2a53a6be3e89f7cf66477b6aed063 100644 (file)
@@ -41,6 +41,11 @@ public final class CompositeNodeWrapper implements NodeWrapper<CompositeNode>, C
         Preconditions.checkState(compositeNode == null, "Cannot change the object, due to data inconsistencies.");
         this.name = name;
     }
+    
+    @Override
+    public QName getQname() {
+        return name;
+    }
 
     @Override
     public String getLocalName() {
index 9a61b43df51467dbe76e40a6f10709e60089e4a0..ced272e00b90cdb4e2b6996ead43d5967195d45f 100644 (file)
@@ -1,16 +1,18 @@
 package org.opendaylight.controller.sal.restconf.impl
 
+import com.google.common.base.Preconditions
 import com.google.common.collect.BiMap
 import com.google.common.collect.FluentIterable
 import com.google.common.collect.HashBiMap
 import java.net.URI
 import java.net.URLDecoder
 import java.net.URLEncoder
+import java.util.ArrayList
 import java.util.HashMap
 import java.util.List
 import java.util.Map
 import java.util.concurrent.ConcurrentHashMap
-import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener
+import org.opendaylight.controller.sal.core.api.mount.MountInstance
 import org.opendaylight.controller.sal.core.api.mount.MountService
 import org.opendaylight.controller.sal.rest.impl.RestUtil
 import org.opendaylight.controller.sal.rest.impl.RestconfProvider
@@ -32,12 +34,12 @@ import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
 import org.opendaylight.yangtools.yang.model.api.Module
 import org.opendaylight.yangtools.yang.model.api.RpcDefinition
 import org.opendaylight.yangtools.yang.model.api.SchemaContext
+import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener
 import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition
 import org.slf4j.LoggerFactory
 
 import static com.google.common.base.Preconditions.*
 import static javax.ws.rs.core.Response.Status.*
-import org.opendaylight.controller.sal.core.api.mount.MountInstance
 
 class ControllerContext implements SchemaServiceListener {
     val static LOG = LoggerFactory.getLogger(ControllerContext)
@@ -49,7 +51,7 @@ class ControllerContext implements SchemaServiceListener {
 
     @Property
     var SchemaContext globalSchema;
-
+    
     @Property
     var MountService mountService;
 
@@ -104,7 +106,7 @@ class ControllerContext implements SchemaServiceListener {
         val modules = schema.modules.filter[m|m.name == moduleName]
         return modules.filterLatestModule
     }
-
+    
     private def filterLatestModule(Iterable<Module> modules) {
         var latestModule = modules.head
         for (module : modules) {
@@ -114,26 +116,26 @@ class ControllerContext implements SchemaServiceListener {
         }
         return latestModule
     }
-
+    
     def findModuleByName(String moduleName) {
         checkPreconditions
         checkArgument(moduleName !== null && !moduleName.empty)
         return globalSchema.getLatestModule(moduleName)
     }
-
+    
     def findModuleByName(MountInstance mountPoint, String moduleName) {
         checkArgument(moduleName !== null && mountPoint !== null)
         val mountPointSchema = mountPoint.schemaContext;
         return mountPointSchema?.getLatestModule(moduleName);
     }
-
+    
     def findModuleByNamespace(URI namespace) {
         checkPreconditions
         checkArgument(namespace !== null)
         val moduleSchemas = globalSchema.findModuleByNamespace(namespace)
         return moduleSchemas?.filterLatestModule
     }
-
+    
     def findModuleByNamespace(MountInstance mountPoint, URI namespace) {
         checkArgument(namespace !== null && mountPoint !== null)
         val mountPointSchema = mountPoint.schemaContext;
@@ -180,7 +182,7 @@ class ControllerContext implements SchemaServiceListener {
         }
         return moduleName
     }
-
+    
     def findModuleNameByNamespace(MountInstance mountPoint, URI namespace) {
         val module = mountPoint.findModuleByNamespace(namespace);
         return module?.name
@@ -196,7 +198,7 @@ class ControllerContext implements SchemaServiceListener {
         }
         return namespace
     }
-
+    
     def findNamespaceByModuleName(MountInstance mountPoint, String moduleName) {
         val module = mountPoint.findModuleByName(moduleName)
         return module?.namespace
@@ -263,7 +265,7 @@ class ControllerContext implements SchemaServiceListener {
         if(object === null) return "";
         return URLEncoder.encode(object.toString)
     }
-
+    
     private def InstanceIdWithSchemaNode collectPathArguments(InstanceIdentifierBuilder builder, List<String> strings,
         DataNodeContainer parentNode, MountInstance mountPoint) {
         checkNotNull(strings)
@@ -273,7 +275,7 @@ class ControllerContext implements SchemaServiceListener {
         if (strings.empty) {
             return new InstanceIdWithSchemaNode(builder.toInstance, parentNode as DataSchemaNode, mountPoint)
         }
-
+        
         val nodeName = strings.head.toNodeName
         val moduleName = strings.head.toModuleName
         var DataSchemaNode targetNode = null
@@ -283,45 +285,45 @@ class ControllerContext implements SchemaServiceListener {
                 if (mountPoint !== null) {
                     throw new ResponseException(BAD_REQUEST, "Restconf supports just one mount point in URI.")
                 }
-
+                
                 if (mountService === null) {
-                    throw new ResponseException(SERVICE_UNAVAILABLE, "MountService was not found. "
+                    throw new ResponseException(SERVICE_UNAVAILABLE, "MountService was not found. " 
                         + "Finding behind mount points does not work."
                     )
                 }
-
+                
                 val partialPath = builder.toInstance;
                 val mount = mountService.getMountPoint(partialPath)
                 if (mount === null) {
                     LOG.debug("Instance identifier to missing mount point: {}", partialPath)
                     throw new ResponseException(BAD_REQUEST, "Mount point does not exist.")
                 }
-
+                
                 val mountPointSchema = mount.schemaContext;
                 if (mountPointSchema === null) {
                     throw new ResponseException(BAD_REQUEST, "Mount point does not contain any schema with modules.")
                 }
-
+                
                 if (strings.size == 1) { // any data node is not behind mount point
                     return new InstanceIdWithSchemaNode(InstanceIdentifier.builder().toInstance, mountPointSchema, mount)
                 }
-
+                
                 val moduleNameBehindMountPoint = strings.get(1).toModuleName()
                 if (moduleNameBehindMountPoint === null) {
                     throw new ResponseException(BAD_REQUEST,
                         "First node after mount point in URI has to be in format \"moduleName:nodeName\"")
                 }
-
+                
                 val moduleBehindMountPoint = mountPointSchema.getLatestModule(moduleNameBehindMountPoint)
                 if (moduleBehindMountPoint === null) {
                     throw new ResponseException(BAD_REQUEST,
                         "URI has bad format. \"" + moduleName + "\" module does not exist in mount point.")
                 }
-
+                
                 return collectPathArguments(InstanceIdentifier.builder(), strings.subList(1, strings.size),
                     moduleBehindMountPoint, mount);
             }
-
+            
             var Module module = null;
             if (mountPoint === null) {
                 module = globalSchema.getLatestModule(moduleName)
@@ -336,19 +338,32 @@ class ControllerContext implements SchemaServiceListener {
                         "URI has bad format. \"" + moduleName + "\" module does not exist in mount point.")
                 }
             }
-            targetNode = parentNode.findInstanceDataChild(nodeName, module.namespace)
+            targetNode = parentNode.findInstanceDataChildByNameAndNamespace(nodeName, module.namespace)
             if (targetNode === null) {
-                throw new ResponseException(BAD_REQUEST, "URI has bad format. Possible reasons:\n" +
-                    "1. \"" + strings.head + "\" was not found in parent data node.\n" +
+                throw new ResponseException(BAD_REQUEST, "URI has bad format. Possible reasons:\n" + 
+                    "1. \"" + strings.head + "\" was not found in parent data node.\n" + 
                     "2. \"" + strings.head + "\" is behind mount point. Then it should be in format \"/" + MOUNT + "/" + strings.head + "\".")
             }
         } else { // string without module name
-            targetNode = parentNode.findInstanceDataChild(nodeName, null)
+            val potentialSchemaNodes = parentNode.findInstanceDataChildrenByName(nodeName)
+            if (potentialSchemaNodes.size > 1) {
+                val StringBuilder namespacesOfPotentialModules = new StringBuilder;
+                for (potentialNodeSchema : potentialSchemaNodes) {
+                    namespacesOfPotentialModules.append("   ").append(potentialNodeSchema.QName.namespace.toString).append("\n")
+                }
+                throw new ResponseException(BAD_REQUEST, "URI has bad format. Node \"" + nodeName + "\" is added as augment from more than one module. " 
+                        + "Therefore the node must have module name and it has to be in format \"moduleName:nodeName\"."
+                        + "\nThe node is added as augment from modules with namespaces:\n" + namespacesOfPotentialModules)
+            }
+            targetNode = potentialSchemaNodes.head
             if (targetNode === null) {
                 throw new ResponseException(BAD_REQUEST, "URI has bad format. \"" + nodeName + "\" was not found in parent data node.\n")
             }
         }
-
+        
+        if (!(targetNode instanceof ListSchemaNode) && !(targetNode instanceof ContainerSchemaNode)) {
+            throw new ResponseException(BAD_REQUEST,"URI has bad format. Node \"" + strings.head + "\" must be Container or List yang type.")
+        }
         // Number of consumed elements
         var consumed = 1;
         if (targetNode instanceof ListSchemaNode) {
@@ -367,7 +382,7 @@ class ControllerContext implements SchemaServiceListener {
 
                 // key value cannot be NULL
                 if (uriKeyValue.equals(NULL_VALUE)) {
-                    throw new ResponseException(BAD_REQUEST, "URI has bad format. List \"" + listNode.QName.localName
+                    throw new ResponseException(BAD_REQUEST, "URI has bad format. List \"" + listNode.QName.localName 
                         + "\" cannot contain \"null\" value as a key."
                     )
                 }
@@ -390,28 +405,36 @@ class ControllerContext implements SchemaServiceListener {
         return new InstanceIdWithSchemaNode(builder.toInstance, targetNode, mountPoint)
     }
 
-    def DataSchemaNode findInstanceDataChild(DataNodeContainer container, String name, URI moduleNamespace) {
-        var DataSchemaNode potentialNode = null
-        if (moduleNamespace === null) {
-            potentialNode = container.getDataChildByName(name);
-        } else {
-            potentialNode = container.childNodes.filter[n|n.QName.localName == name && n.QName.namespace == moduleNamespace].head
-        }
-
-        if (potentialNode.instantiatedDataSchema) {
-            return potentialNode;
+    def DataSchemaNode findInstanceDataChildByNameAndNamespace(DataNodeContainer container,
+        String name, URI namespace) {
+        Preconditions.checkNotNull(namespace)
+        val potentialSchemaNodes = container.findInstanceDataChildrenByName(name)
+        return potentialSchemaNodes.filter[n|n.QName.namespace == namespace].head
+    }
+    
+    def List<DataSchemaNode> findInstanceDataChildrenByName(DataNodeContainer container, String name) {
+        Preconditions.checkNotNull(container)
+        Preconditions.checkNotNull(name)
+        val instantiatedDataNodeContainers = new ArrayList
+        instantiatedDataNodeContainers.collectInstanceDataNodeContainers(container, name)
+        return instantiatedDataNodeContainers
+    }
+    
+    private def void collectInstanceDataNodeContainers(List<DataSchemaNode> potentialSchemaNodes, DataNodeContainer container,
+        String name) {
+        val nodes = container.childNodes.filter[n|n.QName.localName == name]
+        for (potentialNode : nodes) {
+            if (potentialNode.isInstantiatedDataSchema) {
+                potentialSchemaNodes.add(potentialNode)
+            }
         }
         val allCases = container.childNodes.filter(ChoiceNode).map[cases].flatten
         for (caze : allCases) {
-            potentialNode = caze.findInstanceDataChild(name, moduleNamespace);
-            if (potentialNode !== null) {
-                return potentialNode;
-            }
+            collectInstanceDataNodeContainers(potentialSchemaNodes, caze, name)
         }
-        return null;
     }
-
-    static def boolean isInstantiatedDataSchema(DataSchemaNode node) {
+    
+    def boolean isInstantiatedDataSchema(DataSchemaNode node) {
         switch node {
             LeafSchemaNode: return true
             LeafListSchemaNode: return true
@@ -420,13 +443,13 @@ class ControllerContext implements SchemaServiceListener {
             default: return false
         }
     }
-
+    
     private def void addKeyValue(HashMap<QName, Object> map, DataSchemaNode node, String uriValue) {
         checkNotNull(uriValue);
         checkArgument(node instanceof LeafSchemaNode);
         val urlDecoded = URLDecoder.decode(uriValue);
         val typedef = (node as LeafSchemaNode).type;
-
+        
         var decoded = TypeDefinitionAwareCodec.from(typedef)?.deserialize(urlDecoded)
         if(decoded === null) {
             var baseType = RestUtil.resolveBaseTypeFrom(typedef)
index cdb9599a4674e3691815eb6c3ad2895caddb029d..c601414a61ca2dea3d2f897db287c272b7db81a1 100644 (file)
@@ -5,10 +5,7 @@ import java.util.Collections;
 
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.data.api.ModifyAction;
-import org.opendaylight.yangtools.yang.data.api.MutableSimpleNode;
 import org.opendaylight.yangtools.yang.data.api.Node;
-import org.opendaylight.yangtools.yang.data.api.SimpleNode;
 import org.opendaylight.yangtools.yang.data.impl.NodeFactory;
 
 import com.google.common.base.Preconditions;
@@ -42,6 +39,11 @@ public final class EmptyNodeWrapper implements NodeWrapper<Node<?>>, Node<Void>
         this.name = name;
     }
     
+    @Override
+    public QName getQname() {
+        return name;
+    }
+    
     @Override
     public String getLocalName() {
         if (unwrapped != null) {
index 6924fb620f17d21d9734fc4ade3faf1bf9977c67..5fd36cb19681323f695445c43a6542ccc5866826 100644 (file)
@@ -11,20 +11,35 @@ public final class IdentityValuesDTO {
     public IdentityValuesDTO(String namespace, String value, String prefix) {
         elementData.add(new IdentityValue(namespace, value, prefix));
     }
+    
+    public IdentityValuesDTO() {
+        
+    }
 
     public void add(String namespace, String value, String prefix) {
         elementData.add(new IdentityValue(namespace, value, prefix));
     }
+    
+    public void add(IdentityValue identityValue) {
+        elementData.add(identityValue);
+    }
+    
 
     public List<IdentityValue> getValuesWithNamespaces() {
         return Collections.unmodifiableList(elementData);
     }
+    
+    @Override
+    public String toString() {
+        return elementData.toString();
+    }
 
     public static final class IdentityValue {
 
-        private String namespace;
-        private String value;
-        private String prefix;
+        private final String namespace;
+        private final String value;
+        private final String prefix;
+        private List<Predicate> predicates;
 
         public IdentityValue(String namespace, String value, String prefix) {
             this.namespace = namespace;
@@ -36,25 +51,83 @@ public final class IdentityValuesDTO {
             return namespace;
         }
 
-        public void setNamespace(String namespace) {
-            this.namespace = namespace;
-        }
-
         public String getValue() {
             return value;
         }
 
-        public void setValue(String value) {
-            this.value = value;
-        }
-
         public String getPrefix() {
             return prefix;
         }
 
-        public void setPrefix(String prefix) {
-            this.prefix = prefix;
+        public List<Predicate> getPredicates() {
+            if (predicates == null) {
+                return Collections.emptyList();
+            }
+            return Collections.unmodifiableList(predicates);
         }
 
+        public void setPredicates(List<Predicate> predicates) {
+            this.predicates = predicates;
+        }
+        
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            if (namespace != null) {
+                sb.append(namespace);
+            }
+            if (prefix != null) {
+                sb.append("(").append(prefix).append(")");
+            }
+            if (value != null) {
+                sb.append(" - ").append(value);
+            }
+            if (predicates != null && !predicates.isEmpty()) {
+                for (Predicate predicate : predicates) {
+                    sb.append("[");
+                    predicate.toString();
+                    sb.append("]");
+                }
+            }
+            return sb.toString();
+        }
+
+    }
+    
+    public static final class Predicate {
+        
+        private final IdentityValue name;
+        private final String value;
+        
+        public Predicate(IdentityValue name, String value) {
+            super();
+            this.name = name;
+            this.value = value;
+        }
+        
+        public IdentityValue getName() {
+            return name;
+        }
+        
+        public String getValue() {
+            return value;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            if (name != null) {
+                sb.append(name.toString());
+            }
+            if (value != null) {
+                sb.append("=").append(value);
+            }
+            return sb.toString();
+        }
+        
+        public boolean isLeafList() {
+            return name == null ? true : false;
+        }
+        
     }
 }
index 6b8665f7653c26e8881c685aa0e507231a0d8db6..811e534b4ad75bb8086d40fe159bec760da69ed5 100644 (file)
@@ -9,6 +9,8 @@ public interface NodeWrapper<T extends Node<?>> {
 
     void setQname(QName name);
     
+    QName getQname();
+    
     T unwrap();
     
     boolean isChangeAllowed();
index 952b6ce1bb0345823e6794bf378a92865c3bf5cf..096425d0a643ab1737847707ea802258e6500a8e 100644 (file)
@@ -1,22 +1,41 @@
 package org.opendaylight.controller.sal.restconf.impl;
 
 import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 import org.opendaylight.controller.sal.core.api.mount.MountInstance;
 import org.opendaylight.controller.sal.rest.impl.RestUtil;
 import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO.IdentityValue;
+import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO.Predicate;
 import org.opendaylight.yangtools.concepts.Codec;
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.codec.IdentityrefCodec;
+import org.opendaylight.yangtools.yang.data.api.codec.InstanceIdentifierCodec;
 import org.opendaylight.yangtools.yang.data.api.codec.LeafrefCodec;
 import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class RestCodec {
+    
+    private static final Logger logger = LoggerFactory.getLogger(RestCodec.class);
 
     private RestCodec() {
     }
@@ -31,6 +50,7 @@ public class RestCodec {
         private final Logger logger = LoggerFactory.getLogger(RestCodec.class);
 
         public static final Codec LEAFREF_DEFAULT_CODEC = new LeafrefCodecImpl();
+        private final Codec instanceIdentifier;
         private final Codec identityrefCodec;
 
         private final TypeDefinition<?> type;
@@ -42,6 +62,11 @@ public class RestCodec {
             } else {
                 identityrefCodec = null;
             }
+            if (type instanceof InstanceIdentifierTypeDefinition) {
+                instanceIdentifier = new InstanceIdentifierCodecImpl(mountPoint);
+            } else {
+                instanceIdentifier = null;
+            }
         }
 
         @SuppressWarnings("unchecked")
@@ -49,9 +74,23 @@ public class RestCodec {
         public Object deserialize(Object input) {
             try {
                 if (type instanceof IdentityrefTypeDefinition) {
-                    return identityrefCodec.deserialize(input);
+                    if (input instanceof IdentityValuesDTO) {
+                        return identityrefCodec.deserialize(input);
+                    }
+                    logger.info(
+                            "Value is not instance of IdentityrefTypeDefinition but is {}. Therefore NULL is used as translation of  - {}",
+                            input == null ? "null" : input.getClass(), String.valueOf(input));
+                    return null;
                 } else if (type instanceof LeafrefTypeDefinition) {
                     return LEAFREF_DEFAULT_CODEC.deserialize(input);
+                } else if (type instanceof InstanceIdentifierTypeDefinition) {
+                    if (input instanceof IdentityValuesDTO) {
+                        return instanceIdentifier.deserialize(input);
+                    }
+                    logger.info(
+                            "Value is not instance of InstanceIdentifierTypeDefinition but is {}. Therefore NULL is used as translation of  - {}",
+                            input == null ? "null" : input.getClass(), String.valueOf(input));
+                    return null;
                 } else {
                     TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> typeAwarecodec = TypeDefinitionAwareCodec
                             .from(type);
@@ -68,7 +107,7 @@ public class RestCodec {
                 logger.error(
                         "ClassCastException was thrown when codec is invoked with parameter " + String.valueOf(input),
                         e);
-                return input;
+                return null;
             }
         }
 
@@ -80,6 +119,8 @@ public class RestCodec {
                     return identityrefCodec.serialize(input);
                 } else if (type instanceof LeafrefTypeDefinition) {
                     return LEAFREF_DEFAULT_CODEC.serialize(input);
+                } else if (type instanceof InstanceIdentifierTypeDefinition) {
+                    return instanceIdentifier.serialize(input);
                 } else {
                     TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> typeAwarecodec = TypeDefinitionAwareCodec
                             .from(type);
@@ -104,12 +145,14 @@ public class RestCodec {
 
     public static class IdentityrefCodecImpl implements IdentityrefCodec<IdentityValuesDTO> {
 
+        private final Logger logger = LoggerFactory.getLogger(IdentityrefCodecImpl.class);
+
         private final MountInstance mountPoint;
-        
+
         public IdentityrefCodecImpl(MountInstance mountPoint) {
             this.mountPoint = mountPoint;
         }
-        
+
         @Override
         public IdentityValuesDTO serialize(QName data) {
             return new IdentityValuesDTO(data.getNamespace().toString(), data.getLocalName(), data.getPrefix());
@@ -118,19 +161,16 @@ public class RestCodec {
         @Override
         public QName deserialize(IdentityValuesDTO data) {
             IdentityValue valueWithNamespace = data.getValuesWithNamespaces().get(0);
-            String namespace = valueWithNamespace.getNamespace();
-            URI validNamespace;
-            if (mountPoint != null) {
-                validNamespace = ControllerContext.getInstance().findNamespaceByModuleName(mountPoint, namespace);
-            } else {
-                validNamespace = ControllerContext.getInstance().findNamespaceByModuleName(namespace);
+            Module module = getModuleByNamespace(valueWithNamespace.getNamespace(), mountPoint);
+            if (module == null) {
+                logger.info("Module was not found for namespace {}", valueWithNamespace.getNamespace());
+                logger.info("Idenetityref will be translated as NULL for data - {}", String.valueOf(valueWithNamespace));
+                return null;
             }
-            if (validNamespace == null) {
-                validNamespace = URI.create(namespace);
-            }
-            return QName.create(validNamespace, null, valueWithNamespace.getValue());
+            
+            return QName.create(module.getNamespace(), module.getRevision(), valueWithNamespace.getValue());
         }
-        
+
     }
 
     public static class LeafrefCodecImpl implements LeafrefCodec<String> {
@@ -147,4 +187,142 @@ public class RestCodec {
 
     }
 
+    public static class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec<IdentityValuesDTO> {
+        private final Logger logger = LoggerFactory.getLogger(InstanceIdentifierCodecImpl.class);
+        private final MountInstance mountPoint;
+
+        public InstanceIdentifierCodecImpl(MountInstance mountPoint) {
+            this.mountPoint = mountPoint;
+        }
+
+        @Override
+        public IdentityValuesDTO serialize(InstanceIdentifier data) {
+            List<PathArgument> pathArguments = data.getPath();
+            IdentityValuesDTO identityValuesDTO = new IdentityValuesDTO();
+            for (PathArgument pathArgument : pathArguments) {
+                IdentityValue identityValue = qNameToIdentityValue(pathArgument.getNodeType());
+                if (pathArgument instanceof NodeIdentifierWithPredicates && identityValue != null) {
+                    List<Predicate> predicates = keyValuesToPredicateList(((NodeIdentifierWithPredicates) pathArgument)
+                            .getKeyValues());
+                    identityValue.setPredicates(predicates);
+                }
+                identityValuesDTO.add(identityValue);
+            }
+            return identityValuesDTO;
+        }
+
+        @Override
+        public InstanceIdentifier deserialize(IdentityValuesDTO data) {
+            List<PathArgument> result = new ArrayList<PathArgument>();
+            IdentityValue valueWithNamespace = data.getValuesWithNamespaces().get(0);
+            Module module = getModuleByNamespace(valueWithNamespace.getNamespace(), mountPoint);
+            if (module == null) {
+                logger.info("Module by namespace '{}' of first node in instance-identiefier was not found.", valueWithNamespace.getNamespace());
+                logger.info("Instance-identifier will be translated as NULL for data - {}", String.valueOf(valueWithNamespace.getValue()));
+                return null;
+            }
+
+            DataNodeContainer parentContainer = module;
+            List<IdentityValue> identities = data.getValuesWithNamespaces();
+            for (int i = 0; i < identities.size(); i++) {
+                IdentityValue identityValue = identities.get(i);
+                URI validNamespace = resolveValidNamespace(identityValue.getNamespace(), mountPoint);
+                DataSchemaNode node = ControllerContext.getInstance().findInstanceDataChildByNameAndNamespace(
+                        parentContainer, identityValue.getValue(), validNamespace);
+                if (node == null) {
+                    logger.info("'{}' node was not found in {}", identityValue, parentContainer.getChildNodes());
+                    logger.info("Instance-identifier will be translated as NULL for data - {}", String.valueOf(identityValue.getValue()));
+                    return null;
+                }
+                QName qName = node.getQName();
+                PathArgument pathArgument = null;
+                if (identityValue.getPredicates().isEmpty()) {
+                    pathArgument = new NodeIdentifier(qName);
+                } else {
+                    if (node instanceof LeafListSchemaNode) { // predicate is value of leaf-list entry
+                        Predicate leafListPredicate = identityValue.getPredicates().get(0);
+                        if (!leafListPredicate.isLeafList()) {
+                            logger.info("Predicate's data is not type of leaf-list. It should be in format \".='value'\"");
+                            logger.info("Instance-identifier will be translated as NULL for data - {}", String.valueOf(identityValue.getValue()));
+                            return null;
+                        }
+                        pathArgument = new NodeWithValue(qName, leafListPredicate.getValue());
+                    } else if (node instanceof ListSchemaNode) { // predicates are keys of list
+                        DataNodeContainer listNode = (DataNodeContainer) node;
+                        Map<QName, Object> predicatesMap = new HashMap<>();
+                        for (Predicate predicate : identityValue.getPredicates()) {
+                            validNamespace = resolveValidNamespace(predicate.getName().getNamespace(), mountPoint);
+                            DataSchemaNode listKey = ControllerContext.getInstance().findInstanceDataChildByNameAndNamespace(
+                                    listNode, predicate.getName().getValue(), validNamespace);
+                            predicatesMap.put(listKey.getQName(), predicate.getValue());
+                        }
+                        pathArgument = new NodeIdentifierWithPredicates(qName, predicatesMap);
+                    } else {
+                        logger.info("Node {} is not List or Leaf-list.", node);
+                        logger.info("Instance-identifier will be translated as NULL for data - {}", String.valueOf(identityValue.getValue()));
+                        return null;
+                    }
+                }
+                result.add(pathArgument);
+                if (i < identities.size() - 1) { // last element in instance-identifier can be other than DataNodeContainer
+                    if (node instanceof DataNodeContainer) {
+                        parentContainer = (DataNodeContainer) node;
+                    } else {
+                        logger.info("Node {} isn't instance of DataNodeContainer", node);
+                        logger.info("Instance-identifier will be translated as NULL for data - {}", String.valueOf(identityValue.getValue()));
+                        return null;
+                    }
+                }
+            }
+            
+            return result.isEmpty() ? null : new InstanceIdentifier(result);
+        }
+
+        private List<Predicate> keyValuesToPredicateList(Map<QName, Object> keyValues) {
+            List<Predicate> result = new ArrayList<>();
+            for (QName qName : keyValues.keySet()) {
+                Object value = keyValues.get(qName);
+                result.add(new Predicate(qNameToIdentityValue(qName), String.valueOf(value)));
+            }
+            return result;
+        }
+
+        private IdentityValue qNameToIdentityValue(QName qName) {
+            if (qName != null) {
+                return new IdentityValue(qName.getNamespace().toString(), qName.getLocalName(), qName.getPrefix());
+            }
+            return null;
+        }
+    }
+    
+    private static Module getModuleByNamespace(String namespace, MountInstance mountPoint) {
+        URI validNamespace = resolveValidNamespace(namespace, mountPoint);
+
+        Module module = null;
+        if (mountPoint != null) {
+            module = ControllerContext.getInstance().findModuleByNamespace(mountPoint, validNamespace);
+        } else {
+            module = ControllerContext.getInstance().findModuleByNamespace(validNamespace);
+        }
+        if (module == null) {
+            logger.info("Module for namespace " + validNamespace + " wasn't found.");
+            return null;
+        }
+        return module;
+    }
+    
+    private static URI resolveValidNamespace(String namespace, MountInstance mountPoint) {
+        URI validNamespace;
+        if (mountPoint != null) {
+            validNamespace = ControllerContext.getInstance().findNamespaceByModuleName(mountPoint, namespace);
+        } else {
+            validNamespace = ControllerContext.getInstance().findNamespaceByModuleName(namespace);
+        }
+        if (validNamespace == null) {
+            validNamespace = URI.create(namespace);
+        }
+
+        return validNamespace;
+    }
+
 }
index b134f9bf6b8acefb82974a2e0203da22e4063a97..db2342a35dc3b48d3837a843abbde88315796886 100644 (file)
@@ -5,7 +5,6 @@ import java.net.URI
 import java.util.ArrayList
 import java.util.HashMap
 import java.util.List
-import java.util.Set
 import javax.ws.rs.core.Response
 import org.opendaylight.controller.md.sal.common.api.TransactionStatus
 import org.opendaylight.controller.sal.core.api.mount.MountInstance
@@ -17,7 +16,6 @@ import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.InstanceIdentifierBuilder
 import org.opendaylight.yangtools.yang.data.api.Node
 import org.opendaylight.yangtools.yang.data.impl.NodeFactory
-import org.opendaylight.yangtools.yang.model.api.ChoiceNode
 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
@@ -26,11 +24,11 @@ import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
 import org.opendaylight.yangtools.yang.model.api.Module
 import org.opendaylight.yangtools.yang.model.api.RpcDefinition
+import org.opendaylight.yangtools.yang.model.api.SchemaContext
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition
 import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition
 
 import static javax.ws.rs.core.Response.Status.*
-import org.opendaylight.yangtools.yang.model.api.SchemaContext
 
 class RestconfImpl implements RestconfService {
 
@@ -54,7 +52,8 @@ class RestconfImpl implements RestconfService {
     }
 
     override readAllData() {
-//        return broker.readOperationalData("".toInstanceIdentifier.getInstanceIdentifier);
+
+        //        return broker.readOperationalData("".toInstanceIdentifier.getInstanceIdentifier);
         throw new UnsupportedOperationException("Reading all data is currently not supported.")
     }
 
@@ -69,11 +68,11 @@ class RestconfImpl implements RestconfService {
     override invokeRpc(String identifier, CompositeNode payload) {
         return callRpc(identifier.rpcDefinition, payload)
     }
-    
+
     override invokeRpc(String identifier) {
         return callRpc(identifier.rpcDefinition, null)
     }
-    
+
     private def StructuredData callRpc(RpcDefinition rpc, CompositeNode payload) {
         if (rpc === null) {
             throw new ResponseException(NOT_FOUND, "RPC does not exist.");
@@ -164,7 +163,7 @@ class RestconfImpl implements RestconfService {
         if (payload.representsMountPointRootData) { // payload represents mount point data and URI represents path to the mount point
             if (identifier.endsWithMountPoint) {
                 throw new ResponseException(BAD_REQUEST,
-                "URI has bad format. URI should be without \"" + ControllerContext.MOUNT + "\" for POST operation.");
+                    "URI has bad format. URI should be without \"" + ControllerContext.MOUNT + "\" for POST operation.");
             }
             val completIdentifier = identifier.addMountPointIdentifier
             iiWithData = completIdentifier.toInstanceIdentifier
@@ -172,8 +171,11 @@ class RestconfImpl implements RestconfService {
         } else {
             val uncompleteInstIdWithData = identifier.toInstanceIdentifier
             val parentSchema = uncompleteInstIdWithData.schemaNode as DataNodeContainer
-            val namespace = uncompleteInstIdWithData.mountPoint.findModule(payload)?.namespace
-            val schemaNode = parentSchema.findInstanceDataChild(payload.name, namespace)
+            val module = uncompleteInstIdWithData.mountPoint.findModule(payload)
+            if (module === null) {
+                throw new ResponseException(BAD_REQUEST, "Module was not found for \"" + payload.namespace + "\"")
+            }
+            val schemaNode = parentSchema.findInstanceDataChildByNameAndNamespace(payload.name, module.namespace)
             value = normalizeNode(payload, schemaNode, uncompleteInstIdWithData.mountPoint)
             iiWithData = uncompleteInstIdWithData.addLastIdentifierFromData(value, schemaNode)
         }
@@ -192,7 +194,7 @@ class RestconfImpl implements RestconfService {
             default: Response.status(INTERNAL_SERVER_ERROR).build
         }
     }
-    
+
     override createConfigurationData(CompositeNode payload) {
         if (payload.namespace === null) {
             throw new ResponseException(BAD_REQUEST,
@@ -203,7 +205,7 @@ class RestconfImpl implements RestconfService {
             throw new ResponseException(BAD_REQUEST,
                 "Data has bad format. Root element node has incorrect namespace (XML format) or module name(JSON format)");
         }
-        val schemaNode = module.findInstanceDataChild(payload.name, module.namespace)
+        val schemaNode = module.findInstanceDataChildByNameAndNamespace(payload.name, module.namespace)
         val value = normalizeNode(payload, schemaNode, null)
         val iiWithData = addLastIdentifierFromData(null, value, schemaNode)
         var RpcResult<TransactionStatus> status = null
@@ -221,7 +223,7 @@ class RestconfImpl implements RestconfService {
             default: Response.status(INTERNAL_SERVER_ERROR).build
         }
     }
-    
+
     override deleteConfigurationData(String identifier) {
         val iiWithData = identifier.toInstanceIdentifier
         var RpcResult<TransactionStatus> status = null
@@ -236,19 +238,19 @@ class RestconfImpl implements RestconfService {
             default: Response.status(INTERNAL_SERVER_ERROR).build
         }
     }
-    
+
     private def dispatch URI namespace(CompositeNode data) {
         return data.nodeType.namespace
     }
-    
+
     private def dispatch URI namespace(CompositeNodeWrapper data) {
         return data.namespace
     }
-    
+
     private def dispatch String localName(CompositeNode data) {
         return data.nodeType.localName
     }
-    
+
     private def dispatch String localName(CompositeNodeWrapper data) {
         return data.localName
     }
@@ -277,15 +279,15 @@ class RestconfImpl implements RestconfService {
         }
         return module
     }
-    
+
     private def dispatch getName(CompositeNode data) {
         return data.nodeType.localName
     }
-    
+
     private def dispatch getName(CompositeNodeWrapper data) {
         return data.localName
     }
-    
+
     private def InstanceIdWithSchemaNode addLastIdentifierFromData(InstanceIdWithSchemaNode identifierWithSchemaNode,
         CompositeNode data, DataSchemaNode schemaOfData) {
         val iiOriginal = identifierWithSchemaNode?.instanceIdentifier
@@ -317,26 +319,27 @@ class RestconfImpl implements RestconfService {
         }
         return keyValues
     }
-    
+
     private def endsWithMountPoint(String identifier) {
         return (identifier.endsWith(ControllerContext.MOUNT) || identifier.endsWith(ControllerContext.MOUNT + "/"))
     }
-    
+
     private def representsMountPointRootData(CompositeNode data) {
         return ((data.namespace == SchemaContext.NAME.namespace || data.namespace == MOUNT_POINT_MODULE_NAME) &&
             data.localName == SchemaContext.NAME.localName)
     }
-    
+
     private def addMountPointIdentifier(String identifier) {
         if (identifier.endsWith("/")) {
             return identifier + ControllerContext.MOUNT
         }
         return identifier + "/" + ControllerContext.MOUNT
     }
-    
+
     private def CompositeNode normalizeNode(CompositeNode node, DataSchemaNode schema, MountInstance mountPoint) {
         if (schema === null) {
-            throw new ResponseException(INTERNAL_SERVER_ERROR, "Data schema node was not found for " + node?.nodeType?.localName)
+            throw new ResponseException(INTERNAL_SERVER_ERROR,
+                "Data schema node was not found for " + node?.nodeType?.localName)
         }
         if (!(schema instanceof DataNodeContainer)) {
             throw new ResponseException(BAD_REQUEST, "Root element has to be container or list yang datatype.");
@@ -349,44 +352,59 @@ class RestconfImpl implements RestconfService {
         }
         return node
     }
-    
+
     private def void normalizeNode(NodeWrapper<?> nodeBuilder, DataSchemaNode schema, QName previousAugment,
         MountInstance mountPoint) {
         if (schema === null) {
             throw new ResponseException(BAD_REQUEST,
                 "Data has bad format.\n\"" + nodeBuilder.localName + "\" does not exist in yang schema.");
         }
-        var validQName = schema.QName
-        var currentAugment = previousAugment;
-        if (schema.augmenting) {
-            currentAugment = schema.QName
-        } else if (previousAugment !== null && schema.QName.namespace !== previousAugment.namespace) {
-            validQName = QName.create(currentAugment, schema.QName.localName);
-        }
-        var String moduleName = null;
-        if (mountPoint === null) {
-            moduleName = controllerContext.findModuleNameByNamespace(validQName.namespace);
-        } else {
-            moduleName = controllerContext.findModuleNameByNamespace(mountPoint, validQName.namespace)
-        }
-        if (nodeBuilder.namespace === null || nodeBuilder.namespace == validQName.namespace ||
-            nodeBuilder.namespace.toString == moduleName || nodeBuilder.namespace == MOUNT_POINT_MODULE_NAME) {
-            nodeBuilder.qname = validQName
+
+        var QName currentAugment;
+        if (nodeBuilder.qname !== null) {
+            currentAugment = previousAugment
         } else {
-            throw new ResponseException(BAD_REQUEST,
-                "Data has bad format.\nIf data is in XML format then namespace for \"" + nodeBuilder.localName +
-                    "\" should be \"" + schema.QName.namespace + "\".\nIf data is in Json format then module name for \"" +
-                    nodeBuilder.localName + "\" should be \"" + moduleName + "\".");
+            currentAugment = normalizeNodeName(nodeBuilder, schema, previousAugment, mountPoint)
+            if (nodeBuilder.qname === null) {
+                throw new ResponseException(BAD_REQUEST,
+                    "Data has bad format.\nIf data is in XML format then namespace for \"" + nodeBuilder.localName +
+                        "\" should be \"" + schema.QName.namespace + "\".\n" +
+                        "If data is in JSON format then module name for \"" + nodeBuilder.localName +
+                         "\" should be corresponding to namespace \"" + schema.QName.namespace + "\".");
+            }
         }
 
         if (nodeBuilder instanceof CompositeNodeWrapper) {
             val List<NodeWrapper<?>> children = (nodeBuilder as CompositeNodeWrapper).getValues
             for (child : children) {
-                normalizeNode(child,
-                    findFirstSchemaByLocalName(child.localName, (schema as DataNodeContainer).childNodes),
-                    currentAugment, mountPoint)
+                val potentialSchemaNodes = (schema as DataNodeContainer).findInstanceDataChildrenByName(child.localName)
+                if (potentialSchemaNodes.size > 1 && child.namespace === null) {
+                    val StringBuilder namespacesOfPotentialModules = new StringBuilder;
+                    for (potentialSchemaNode : potentialSchemaNodes) {
+                        namespacesOfPotentialModules.append("   ").append(potentialSchemaNode.QName.namespace.toString).append("\n")
+                    }
+                    throw new ResponseException(BAD_REQUEST,
+                        "Node \"" + child.localName + "\" is added as augment from more than one module. " 
+                        + "Therefore node must have namespace (XML format) or module name (JSON format)."
+                        + "\nThe node is added as augment from modules with namespaces:\n" + namespacesOfPotentialModules)
+                }
+                var rightNodeSchemaFound = false
+                for (potentialSchemaNode : potentialSchemaNodes) {
+                    if (!rightNodeSchemaFound) {
+                        val potentialCurrentAugment = normalizeNodeName(child, potentialSchemaNode, currentAugment,
+                            mountPoint)
+                        if (child.qname !== null) {
+                            normalizeNode(child, potentialSchemaNode, potentialCurrentAugment, mountPoint)
+                            rightNodeSchemaFound = true
+                        }
+                    }
+                }
+                if (!rightNodeSchemaFound) {
+                    throw new ResponseException(BAD_REQUEST,
+                        "Schema node \"" + child.localName + "\" was not found in module.")
+                }
             }
-            if(schema instanceof ListSchemaNode) {
+            if (schema instanceof ListSchemaNode) {
                 val listKeys = (schema as ListSchemaNode).keyDefinition
                 for (listKey : listKeys) {
                     var foundKey = false
@@ -397,7 +415,8 @@ class RestconfImpl implements RestconfService {
                     }
                     if (!foundKey) {
                         throw new ResponseException(BAD_REQUEST,
-                            "Missing key in URI \"" + listKey.localName + "\" of list \"" + schema.QName.localName + "\"")
+                            "Missing key in URI \"" + listKey.localName + "\" of list \"" + schema.QName.localName +
+                                "\"")
                     }
                 }
             }
@@ -405,11 +424,11 @@ class RestconfImpl implements RestconfService {
             val simpleNode = (nodeBuilder as SimpleNodeWrapper)
             val value = simpleNode.value
             var inputValue = value;
-            
+
             if (schema.typeDefinition instanceof IdentityrefTypeDefinition) {
                 if (value instanceof String) {
-                    inputValue = new IdentityValuesDTO(validQName.namespace.toString, value as String, null)
-                } // else value is instance of ValuesDTO
+                    inputValue = new IdentityValuesDTO(nodeBuilder.namespace.toString, value as String, null)
+                } // else value is already instance of IdentityValuesDTO
             }
             
             val outputValue = RestCodec.from(schema.typeDefinition, mountPoint)?.deserialize(inputValue);
@@ -441,25 +460,27 @@ class RestconfImpl implements RestconfService {
         }
         baseType
     }
-
-    private def DataSchemaNode findFirstSchemaByLocalName(String localName, Set<DataSchemaNode> schemas) {
-        for (schema : schemas) {
-            if (schema instanceof ChoiceNode) {
-                for (caze : (schema as ChoiceNode).cases) {
-                    val result = findFirstSchemaByLocalName(localName, caze.childNodes)
-                    if (result !== null) {
-                        return result
-                    }
-                }
-            } else {
-                val result = schemas.findFirst[n|n.QName.localName.equals(localName)]
-                if (result !== null) {
-                    return result;
-
-                }
-            }
+    
+    private def QName normalizeNodeName(NodeWrapper<?> nodeBuilder, DataSchemaNode schema, QName previousAugment,
+        MountInstance mountPoint) {
+        var validQName = schema.QName
+        var currentAugment = previousAugment;
+        if (schema.augmenting) {
+            currentAugment = schema.QName
+        } else if (previousAugment !== null && schema.QName.namespace !== previousAugment.namespace) {
+            validQName = QName.create(currentAugment, schema.QName.localName);
+        }
+        var String moduleName = null;
+        if (mountPoint === null) {
+            moduleName = controllerContext.findModuleNameByNamespace(validQName.namespace);
+        } else {
+            moduleName = controllerContext.findModuleNameByNamespace(mountPoint, validQName.namespace)
+        }
+        if (nodeBuilder.namespace === null || nodeBuilder.namespace == validQName.namespace ||
+            nodeBuilder.namespace.toString == moduleName || nodeBuilder.namespace == MOUNT_POINT_MODULE_NAME) {
+            nodeBuilder.qname = validQName
         }
-        return null
+        return currentAugment
     }
 
 }
index 6aa8ada5ee3135fa0ac7025d9efe0564205f78d8..b0a215f90bfd91a79dfb649478315cc15110f3bb 100644 (file)
@@ -36,6 +36,11 @@ public final class SimpleNodeWrapper implements NodeWrapper<SimpleNode<?>>, Simp
         this.name = name;
     }
     
+    @Override
+    public QName getQname() {
+        return name;
+    }
+    
     @Override
     public String getLocalName() {
         if (simpleNode != null) {
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/iml/varioustests/VariousTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/iml/varioustests/VariousTest.java
new file mode 100644 (file)
index 0000000..04f2331
--- /dev/null
@@ -0,0 +1,37 @@
+package org.opendaylight.controller.sal.restconf.iml.varioustests;
+
+import org.junit.Ignore;
+import org.junit.Test;
+import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider;
+import org.opendaylight.controller.sal.restconf.impl.test.TestUtils;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.w3c.dom.Document;
+
+
+public class VariousTest {
+
+    @Ignore
+    @Test
+    public void test() {
+        String[] split = "/something:dfsa/s:sda".split("/");
+        System.out.println(split.length);
+        for (String str : split) {
+            System.out.println(">"+str+"<");    
+        }        
+        
+    }
+    
+    @Test
+    public void loadXml() {
+        TestUtils.readInputToCnSn("/varioustest/xmldata.xml", XmlToCompositeNodeProvider.INSTANCE);
+//        TestUtils.normalizeCompositeNode(compositeNode, modules, schemaNodePath)
+    }
+    
+    @Test
+    public void buildXml() {
+//        Document doc;
+//        doc.createElementNS(namespaceURI, qualifiedName)
+    }
+    
+
+}
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnInstanceIdentifierToXmlTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnInstanceIdentifierToXmlTest.java
new file mode 100644 (file)
index 0000000..d1bcf9b
--- /dev/null
@@ -0,0 +1,54 @@
+package org.opendaylight.controller.sal.restconf.impl.cnsn.to.xml.test;
+
+import static org.junit.Assert.assertNotNull;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import javax.ws.rs.WebApplicationException;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider;
+import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper;
+import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper;
+import org.opendaylight.controller.sal.restconf.impl.test.TestUtils;
+import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+
+/**
+ * 
+ * CnSn = Composite node and Simple node data structure Class contains test of
+ * serializing simple nodes data values according data types from YANG schema to
+ * XML file
+ * 
+ */
+public class CnSnInstanceIdentifierToXmlTest extends YangAndXmlAndDataSchemaLoader {
+    
+    @BeforeClass
+    public static void initialization() throws URISyntaxException {
+        dataLoad("/instanceidentifier/yang", 3, "instance-identifier-module", "cont");
+    }
+
+    @Test
+    public void snAsYangInstanceIdentifier() throws WebApplicationException, IOException, URISyntaxException {
+        CompositeNode cnSnData = prepareCnStructForYangData( );
+        String xmlOutput = TestUtils.writeCompNodeWithSchemaContextToOutput(cnSnData, modules, dataSchemaNode,
+                StructuredDataToXmlProvider.INSTANCE);
+        assertNotNull(xmlOutput);
+    }
+
+    private CompositeNode prepareCnStructForYangData() throws URISyntaxException {
+        CompositeNodeWrapper cont = new CompositeNodeWrapper(new URI("instance:identifier:module"), "cont");
+        CompositeNodeWrapper cont1 = new CompositeNodeWrapper(new URI("augment:module"), "cont1");
+        cont.addValue(cont1);
+        SimpleNodeWrapper lf11 = new SimpleNodeWrapper(new URI("augment:augment:module"), "lf11", "/cont/cont1/lf12");
+        SimpleNodeWrapper lf12 = new SimpleNodeWrapper(new URI("augment:augment:module"), "lf12", "lf12 value");
+        cont1.addValue(lf11);
+        cont1.addValue(lf12);
+        cont.unwrap();
+        return cont;
+    }
+
+}
index 96e03a5a3ca4b8b6b0d619232457a8669f3dae06..af54c7de916303fb61768297c1c3c57f86118813 100644 (file)
@@ -13,7 +13,10 @@ import org.junit.Test;
 import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider;
 import org.opendaylight.controller.sal.restconf.impl.test.TestUtils;
 import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader;
-import org.opendaylight.yangtools.yang.data.api.*;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.ModifyAction;
+import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode;
+import org.opendaylight.yangtools.yang.data.api.MutableSimpleNode;
 import org.opendaylight.yangtools.yang.data.impl.NodeFactory;
 import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec;
 
@@ -51,6 +54,7 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader {
         serializeToXml(prepareLeafrefData(), "<lfBoolean>true</lfBoolean>", "<lfLfref>true</lfLfref>");
     }
 
+
     @Test
     public void snAsYangStringToXmlTest() {
         serializeToXml(
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CnSnToXmlAndJsonInstanceIdentifierTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CnSnToXmlAndJsonInstanceIdentifierTest.java
new file mode 100644 (file)
index 0000000..80cfb17
--- /dev/null
@@ -0,0 +1,136 @@
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.WebApplicationException;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider;
+import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider;
+import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper;
+import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+
+public class CnSnToXmlAndJsonInstanceIdentifierTest extends YangAndXmlAndDataSchemaLoader {
+
+    @BeforeClass
+    public static void initialize() {
+        dataLoad("/instanceidentifier/yang", 3, "instance-identifier-module", "cont");
+    }
+
+    @Test
+    public void saveCnSnToXml() throws WebApplicationException, IOException, URISyntaxException, XMLStreamException {
+        CompositeNode cnSn = prepareCnSn();
+        String output = TestUtils.writeCompNodeWithSchemaContextToOutput(cnSn, modules, dataSchemaNode,
+                StructuredDataToXmlProvider.INSTANCE);
+        validateXmlOutput(output);
+        // System.out.println(output);
+
+    }
+
+    @Test
+    public void saveCnSnToJson() throws WebApplicationException, IOException, URISyntaxException {
+        CompositeNode cnSn = prepareCnSn();
+        String output = TestUtils.writeCompNodeWithSchemaContextToOutput(cnSn, modules, dataSchemaNode,
+                StructuredDataToJsonProvider.INSTANCE);
+        assertTrue(output
+                .contains("\"augment-augment-module:lf111\": \"/instance-identifier-module:cont/instance-identifier-module:cont1/augment-module:lst11[augment-module:keyvalue111=\\\"value1\\\"][augment-module:keyvalue112=\\\"value2\\\"]/augment-augment-module:lf112\""));
+        // System.out.println(output);
+    }
+
+    private void validateXmlOutput(String xml) throws XMLStreamException {
+        XMLInputFactory xmlInFactory = XMLInputFactory.newInstance();
+        XMLEventReader eventReader;
+
+        eventReader = xmlInFactory.createXMLEventReader(new ByteArrayInputStream(xml.getBytes()));
+        String aaModulePrefix = null;
+        String aModulePrefix = null;
+        String iiModulePrefix = null;
+        while (eventReader.hasNext()) {
+            XMLEvent nextEvent = eventReader.nextEvent();
+            if (nextEvent.isStartElement()) {
+                StartElement startElement = (StartElement) nextEvent;
+                if (startElement.getName().getLocalPart().equals("lf111")) {
+                    Iterator prefixes = startElement.getNamespaceContext().getPrefixes("augment:augment:module");
+
+                    while (prefixes.hasNext() && aaModulePrefix == null) {
+                        String prefix = (String) prefixes.next();
+                        if (!prefix.isEmpty()) {
+                            aaModulePrefix = prefix;
+                        }
+                    }
+
+                    aModulePrefix = startElement.getNamespaceContext().getPrefix("augment:module");
+                    iiModulePrefix = startElement.getNamespaceContext().getPrefix("instance:identifier:module");
+                    break;
+                }
+            }
+        }
+
+        assertNotNull(aaModulePrefix);
+        assertNotNull(aModulePrefix);
+        assertNotNull(iiModulePrefix);
+
+        String instanceIdentifierValue = "/" + iiModulePrefix + ":cont/" + iiModulePrefix + ":cont1/" + aModulePrefix
+                + ":lst11[" + aModulePrefix + ":keyvalue111='value1'][" + aModulePrefix + ":keyvalue112='value2']/"
+                + aaModulePrefix + ":lf112";
+
+//        System.out.println(xml);
+        assertTrue(xml.contains(instanceIdentifierValue));
+
+    }
+
+    private CompositeNode prepareCnSn() throws URISyntaxException {
+        CompositeNodeWrapper cont = new CompositeNodeWrapper(new URI("instance:identifier:module"), "cont");
+        CompositeNodeWrapper cont1 = new CompositeNodeWrapper(new URI("instance:identifier:module"), "cont1");
+        CompositeNodeWrapper lst11 = new CompositeNodeWrapper(new URI("augment:module"), "lst11");
+        InstanceIdentifier instanceIdentifier = createInstanceIdentifier();
+        SimpleNodeWrapper lf111 = new SimpleNodeWrapper(new URI("augment:augment:module"), "lf111", instanceIdentifier);
+
+        lst11.addValue(lf111);
+        cont1.addValue(lst11);
+        cont.addValue(cont1);
+
+        return cont;
+    }
+
+    private InstanceIdentifier createInstanceIdentifier() throws URISyntaxException {
+        List<PathArgument> pathArguments = new ArrayList<>();
+        pathArguments.add(new NodeIdentifier(new QName(new URI("instance:identifier:module"), "cont")));
+        pathArguments.add(new NodeIdentifier(new QName(new URI("instance:identifier:module"), "cont1")));
+
+        QName qName = new QName(new URI("augment:module"), "lst11");
+        Map<QName, Object> keyValues = new HashMap<>();
+        keyValues.put(new QName(new URI("augment:module"), "keyvalue111"), "value1");
+        keyValues.put(new QName(new URI("augment:module"), "keyvalue112"), "value2");
+        NodeIdentifierWithPredicates nodeIdentifierWithPredicates = new NodeIdentifierWithPredicates(qName, keyValues);
+        pathArguments.add(nodeIdentifierWithPredicates);
+
+        pathArguments.add(new NodeIdentifier(new QName(new URI("augment:augment:module"), "lf112")));
+
+        return new InstanceIdentifier(pathArguments);
+    }
+
+}
index 36da6d669a237b963f8b550e2b5fe6762dd83b97..2b6efbdc4d40363577a7d024eb563fc204d05838 100644 (file)
@@ -1,6 +1,6 @@
 package org.opendaylight.controller.sal.restconf.impl.test;
 
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.*;
 import static org.mockito.Mockito.mock;
 
 import org.junit.Test;
@@ -24,10 +24,7 @@ public class RestCodecExceptionsTest {
         IdentityrefTypeDefinition mockedIidentityrefType = mock(IdentityrefTypeDefinition.class);
 
         Codec<Object, Object> codec = RestCodec.from(mockedIidentityrefType, null);
-        String serializedValue = (String) codec.deserialize("incorrect value"); // IdentityValuesDTO
-                                                                                // object
-        // expected
-        assertEquals("incorrect value", serializedValue);
+        assertNull(codec.deserialize("incorrect value"));
     }
 
 }
index 5650be57ce49dbb45719652fb31cd8ba8658d7ab..94791cfe8d878b7c8e6ef73a5ac6829e7b2a9555 100644 (file)
@@ -1,45 +1,50 @@
 package org.opendaylight.controller.sal.restconf.impl.test;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import java.io.FileNotFoundException;
-import java.io.UnsupportedEncodingException;
-import java.net.URISyntaxException;
 
-import org.junit.Ignore;
+import org.junit.BeforeClass;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
 import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
 import org.opendaylight.controller.sal.restconf.impl.InstanceIdWithSchemaNode;
 import org.opendaylight.controller.sal.restconf.impl.ResponseException;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
 public class RestGetAugmentedElementWhenEqualNamesTest {
-
-    @Ignore
-    @Test
-    public void getDataWithUrlMountPoint() throws UnsupportedEncodingException, URISyntaxException,
-            FileNotFoundException {
-        boolean exceptionCaught = false;
-
+    
+    private static ControllerContext controllerContext = ControllerContext.getInstance();
+    
+    @Rule
+    public ExpectedException exception = ExpectedException.none();
+    
+    @BeforeClass
+    public static void init() throws FileNotFoundException {
         SchemaContext schemaContextTestModule = TestUtils.loadSchemaContext("/common/augment/yang");
-        ControllerContext controllerContext = ControllerContext.getInstance();
         controllerContext.setSchemas(schemaContextTestModule);
+    }
 
+    @Test
+    public void augmentedNodesInUri() {
+        InstanceIdWithSchemaNode iiWithData = controllerContext.toInstanceIdentifier("main:cont/augment-main-a:cont1");
+        assertEquals("ns:augment:main:a", iiWithData.getSchemaNode().getQName().getNamespace().toString());
+        iiWithData = controllerContext.toInstanceIdentifier("main:cont/augment-main-b:cont1");
+        assertEquals("ns:augment:main:b", iiWithData.getSchemaNode().getQName().getNamespace().toString());
+    }
+    
+    @Test
+    public void nodeWithoutNamespaceHasMoreAugments() {
+        boolean exceptionCaught = false;
         try {
-            InstanceIdWithSchemaNode instanceIdentifierA = controllerContext
-                    .toInstanceIdentifier("main:cont/augment-main-a:cont1");
-            InstanceIdWithSchemaNode instanceIdentifierB = controllerContext
-                    .toInstanceIdentifier("main:cont/augment-main-b:cont1");
-
-            assertEquals("ns:augment:main:a", instanceIdentifierA.getSchemaNode().getQName().getNamespace().toString());
-            assertEquals("ns:augment:main:b", instanceIdentifierB.getSchemaNode().getQName().getNamespace());
+            controllerContext.toInstanceIdentifier("main:cont/cont1");
         } catch (ResponseException e) {
+            assertTrue(((String) e.getResponse().getEntity()).contains("is added as augment from more than one module"));
             exceptionCaught = true;
         }
-
-        assertFalse(exceptionCaught);
-
+        assertTrue(exceptionCaught);
     }
 
 }
index 4e2f525d451787cc5f658495ff39e373cfaab22b..d7522706fd3d1963b3e8f9826294fd6786decde6 100644 (file)
@@ -47,8 +47,8 @@ public class URITest {
                 .toInstanceIdentifier("simple-nodes:userWithoutClass/foo");
         assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "userWithoutClass");
 
-        instanceIdentifier = controllerContext.toInstanceIdentifier("simple-nodes:userWithoutClass/foo/full-name");
-        assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "full-name");
+        instanceIdentifier = controllerContext.toInstanceIdentifier("simple-nodes:userWithoutClass/foo");
+        assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "userWithoutClass");
 
         instanceIdentifier = controllerContext.toInstanceIdentifier("simple-nodes:user/foo/boo");
         assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "user");
@@ -56,8 +56,6 @@ public class URITest {
         instanceIdentifier = controllerContext.toInstanceIdentifier("simple-nodes:user//boo");
         assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "user");
 
-        instanceIdentifier = controllerContext.toInstanceIdentifier("simple-nodes:users/user/foo");
-        assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "user");
     }
 
     @Test
@@ -85,8 +83,8 @@ public class URITest {
     @Test
     public void testToInstanceIdentifierChoice() throws FileNotFoundException {
         InstanceIdWithSchemaNode instanceIdentifier = controllerContext
-                .toInstanceIdentifier("simple-nodes:food/nonalcoholic/beer");
-        assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "beer");
+                .toInstanceIdentifier("simple-nodes:food/nonalcoholic");
+        assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "nonalcoholic");
     }
 
     @Test
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnInstanceIdentifierTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnInstanceIdentifierTest.java
new file mode 100644 (file)
index 0000000..1608efb
--- /dev/null
@@ -0,0 +1,85 @@
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.WebApplicationException;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.sal.rest.impl.JsonToCompositeNodeProvider;
+import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.SimpleNode;
+
+public class XmlAndJsonToCnSnInstanceIdentifierTest extends YangAndXmlAndDataSchemaLoader {
+
+    @BeforeClass
+    public static void initialize() {
+        dataLoad("/instanceidentifier/yang", 3, "instance-identifier-module", "cont");
+    }
+
+    @Test
+    public void loadXmlToCnSn() throws WebApplicationException, IOException, URISyntaxException {
+        CompositeNode cnSn = TestUtils.readInputToCnSn("/instanceidentifier/xml/xmldata.xml",
+                XmlToCompositeNodeProvider.INSTANCE);
+        TestUtils.normalizeCompositeNode(cnSn, modules, schemaNodePath);
+        verify(cnSn);
+    }
+
+    @Test
+    public void loadJsonToCnSn() throws WebApplicationException, IOException, URISyntaxException {
+        CompositeNode cnSn = TestUtils.readInputToCnSn("/instanceidentifier/json/jsondata.json",
+                JsonToCompositeNodeProvider.INSTANCE);
+        TestUtils.normalizeCompositeNode(cnSn, modules, schemaNodePath);
+        verify(cnSn);
+    }
+
+    private void verify(CompositeNode cnSn) throws URISyntaxException {
+        SimpleNode<?> lf111 = getSnWithInstanceIdentifier(cnSn);
+        Object value = lf111.getValue();
+        assertTrue(value instanceof InstanceIdentifier);
+
+        InstanceIdentifier instanceIdentifier = (InstanceIdentifier) value;
+        List<PathArgument> pathArguments = instanceIdentifier.getPath();
+        assertEquals(4, pathArguments.size());
+        String revisionDate = "2014-01-17";
+        assertEquals(TestUtils.buildQName("cont", "instance:identifier:module", revisionDate), pathArguments.get(0)
+                .getNodeType());
+        assertEquals(TestUtils.buildQName("cont1", "instance:identifier:module", revisionDate), pathArguments.get(1)
+                .getNodeType());
+        assertEquals(TestUtils.buildQName("lst11", "augment:module", revisionDate), pathArguments.get(2).getNodeType());
+        assertEquals(TestUtils.buildQName("lf112", "augment:augment:module", revisionDate), pathArguments.get(3)
+                .getNodeType());
+
+        assertTrue(pathArguments.get(2) instanceof NodeIdentifierWithPredicates);
+        Map<QName, Object> predicates = ((NodeIdentifierWithPredicates) pathArguments.get(2)).getKeyValues();
+        assertEquals(2, predicates.size());
+        assertEquals("value1", predicates.get(TestUtils.buildQName("keyvalue111", "augment:module", revisionDate)));
+        assertEquals("value2", predicates.get(TestUtils.buildQName("keyvalue112", "augment:module", revisionDate)));
+    }
+
+    private SimpleNode<?> getSnWithInstanceIdentifier(CompositeNode cnSn) throws URISyntaxException {
+        CompositeNode cont1 = cnSn.getFirstCompositeByName(TestUtils.buildQName("cont1", "instance:identifier:module",
+                "2014-01-17"));
+        assertNotNull(cont1);
+        CompositeNode lst11 = cont1.getFirstCompositeByName(TestUtils.buildQName("lst11", "augment:module",
+                "2014-01-17"));
+        assertNotNull(lst11);
+        SimpleNode<?> lf111 = lst11.getFirstSimpleByName(TestUtils.buildQName("lf111", "augment:augment:module",
+                "2014-01-17"));
+        assertNotNull(lf111);
+        return lf111;
+    }
+
+}
index 421a936d2d534ba32f227ab47d47de78100618b4..4a4f9f1bbff9bfbcef8af7253aeebede8bfbcc35 100644 (file)
@@ -1,35 +1,23 @@
 package org.opendaylight.controller.sal.restconf.impl.xml.to.cnsn.test;
 
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 
 import java.util.Set;
 
-import org.junit.Ignore;
 import org.junit.Test;
 import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider;
-import org.opendaylight.controller.sal.restconf.impl.ResponseException;
 import org.opendaylight.controller.sal.restconf.impl.test.TestUtils;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 import org.opendaylight.yangtools.yang.model.api.Module;
 
 public class XmlAugmentedElementToCnSnTest {
 
-    @Ignore
     @Test
     public void loadDataAugmentedSchemaMoreEqualNamesTest() {
-        boolean exceptionCaught = false;
-        try {
-            loadAndNormalizeData("/common/augment/xml/dataa.xml", "/common/augment/yang", "main","cont");
-            loadAndNormalizeData("/common/augment/xml/datab.xml", "/common/augment/yang", "main","cont");
-        } catch (ResponseException e) {
-            exceptionCaught = true;
-        }
-        
-        assertFalse(exceptionCaught);        
+        loadAndNormalizeData("/common/augment/xml/dataa.xml", "/common/augment/yang", "main","cont");
+        loadAndNormalizeData("/common/augment/xml/datab.xml", "/common/augment/yang", "main","cont");
     }
     
-    
     private void loadAndNormalizeData(String xmlPath, String yangPath, String topLevelElementName, String moduleName) {
         CompositeNode compNode = TestUtils.readInputToCnSn(xmlPath, false,
                 XmlToCompositeNodeProvider.INSTANCE);
index beff5724eb2da85c2f457d72a30fff70c0fac9d8..14818d02cdb33deefd3cd694b2c1dab0c51c11e1 100644 (file)
@@ -1,15 +1,20 @@
 package org.opendaylight.controller.sal.restconf.impl.xml.to.cnsn.test;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 import java.util.List;
 import java.util.Set;
 
+import org.junit.Ignore;
 import org.junit.Test;
 import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider;
 import org.opendaylight.controller.sal.restconf.impl.test.TestUtils;
 import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.*;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.api.SimpleNode;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -216,11 +221,11 @@ public class XmlLeafrefToCnSnTest {
      * Test case like <cont1 xmlns="namespace1" xmlns:x="namespace">
      * <lf11>x:identity</lf11> </cont1>
      */
+    @Ignore
     @Test
     public void testIdentityrefNmspcInParrentElement() {
         testIdentityrefToCnSn("/xml-to-cnsn/identityref/xml/data-nmspc-in-parrent-element.xml",
                 "/xml-to-cnsn/identityref", "identityref-module", "cont", 2, "iden", "z:namespace");
-
     }
 
     /**
index 81d77329c69eaa74d28c19d942ec1b2593a538ec..020ff8fa5062d640830202ae84ba56d42cb017c8 100644 (file)
@@ -97,6 +97,10 @@ module basic-module {
                  }    
                }
                
+               leaf lfInIdentifier {
+                 type instance-identifier;
+               }
+               
        }
          
 }
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/json/jsondata.json b/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/json/jsondata.json
new file mode 100644 (file)
index 0000000..f616a8a
--- /dev/null
@@ -0,0 +1,14 @@
+{
+    "instance-identifier-module:cont": {
+        "cont1": {
+            "augment-module:lst11": [ 
+                {
+                    "keyvalue111":"value1",
+                    "keyvalue112":"value2",
+                    "augment-augment-module:lf111":"/instance-identifier-module:cont/instance-identifier-module:cont1/augment-module:lst11[augment-module:keyvalue111=\"value1\"][augment-module:keyvalue112=\"value2\"]/augment-augment-module:lf112",
+                    "augment-augment-module:lf112":"lf112 value"
+                }
+            ]
+        }
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/xml/xmldata.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/xml/xmldata.xml
new file mode 100644 (file)
index 0000000..768cb66
--- /dev/null
@@ -0,0 +1,10 @@
+<cont xmlns="instance:identifier:module">
+    <cont1>
+           <lst11 xmlns="augment:module" xmlns:c="augment:augment:module">
+               <keyvalue111>value1</keyvalue111>
+               <keyvalue112>value2</keyvalue112>
+               <lf111 xmlns="augment:augment:module" xmlns:a="instance:identifier:module" xmlns:b="augment:module" >/a:cont/a:cont1/b:lst11[b:keyvalue111="value1"][b:keyvalue112="value2"]/c:lf112</lf111>
+               <lf112 xmlns="augment:augment:module">lf112 value</lf112>
+           </lst11>
+    </cont1>
+</cont>
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/yang/augment-augment-module.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/yang/augment-augment-module.yang
new file mode 100644 (file)
index 0000000..546111c
--- /dev/null
@@ -0,0 +1,21 @@
+module augment-augment-module {
+  namespace "augment:augment:module";  
+
+  prefix "aamodule";
+  
+  import augment-module {prefix amodule; revision-date 2014-01-17;}
+  import instance-identifier-module {prefix imodule; revision-date 2014-01-17;}
+   
+  revision 2014-01-17 {    
+  }
+  
+       augment "/imodule:cont/imodule:cont1/amodule:lst11" {
+        leaf lf111 {
+            type instance-identifier;
+        }
+        leaf lf112 {
+            type string;
+        }
+       }
+         
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/yang/augment-module.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/yang/augment-module.yang
new file mode 100644 (file)
index 0000000..67b0086
--- /dev/null
@@ -0,0 +1,23 @@
+module augment-module {
+  namespace "augment:module";  
+
+  prefix "amodule";
+  
+  import instance-identifier-module {prefix imodule; revision-date 2014-01-17;}
+   
+  revision 2014-01-17 {    
+  }
+  
+       augment "/imodule:cont/imodule:cont1" {
+          list lst11 {
+              key "keyvalue111 keyvalue112";
+              leaf keyvalue111 {
+                  type string;
+              }
+              leaf keyvalue112 {
+                  type string;
+              }
+          }       
+       }
+         
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/yang/instance-identifier-module.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/yang/instance-identifier-module.yang
new file mode 100644 (file)
index 0000000..7a95a5f
--- /dev/null
@@ -0,0 +1,13 @@
+module instance-identifier-module {
+  namespace "instance:identifier:module";  
+
+  prefix "iimodule";
+  revision 2014-01-17 {    
+  }
+
+    container cont {
+        container cont1 {
+        }
+    }
+  
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/varioustest/xmldata.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/varioustest/xmldata.xml
new file mode 100644 (file)
index 0000000..5d45980
--- /dev/null
@@ -0,0 +1,5 @@
+<cont xmlns="generalnamespace">
+    <cont1>
+        <lf1 xmlns:prefix="prefix:name" xmlns:prefix2="prefix2:name">/prefix:somepath1/prefix2:somepath2</lf1>
+    </cont1>
+</cont>
\ No newline at end of file
index b925ebdc99738b72aa98e2a3186cc6d57f9578cb..325b342cd88bdb71d6d2138169f2f7ae36c83785 100644 (file)
@@ -293,23 +293,27 @@ public class StatisticsProvider implements AutoCloseable {
         NodeRef targetNodeRef = new NodeRef(targetInstanceId);
     
         try{
-            sendAggregateFlowsStatsFromAllTablesRequest(targetNode.getKey());
-        
-            sendAllFlowsStatsFromAllTablesRequest(targetNodeRef);
-
-            sendAllNodeConnectorsStatisticsRequest(targetNodeRef);
-        
-            sendAllFlowTablesStatisticsRequest(targetNodeRef);
-        
-            sendAllQueueStatsFromAllNodeConnector (targetNodeRef);
-
-            sendAllGroupStatisticsRequest(targetNodeRef);
-            
-            sendAllMeterStatisticsRequest(targetNodeRef);
-            
-            sendGroupDescriptionRequest(targetNodeRef);
-            
-            sendMeterConfigStatisticsRequest(targetNodeRef);
+            if(flowStatsService != null){
+                sendAggregateFlowsStatsFromAllTablesRequest(targetNode.getKey());
+                sendAllFlowsStatsFromAllTablesRequest(targetNodeRef);
+            }
+            if(flowTableStatsService != null){
+                sendAllFlowTablesStatisticsRequest(targetNodeRef);
+            }
+            if(portStatsService != null){
+                sendAllNodeConnectorsStatisticsRequest(targetNodeRef);
+            }
+            if(groupStatsService != null){
+                sendAllGroupStatisticsRequest(targetNodeRef);
+                sendGroupDescriptionRequest(targetNodeRef);
+            }
+            if(meterStatsService != null){
+                sendAllMeterStatisticsRequest(targetNodeRef);
+                sendMeterConfigStatisticsRequest(targetNodeRef);
+            }
+            if(queueStatsService != null){
+                sendAllQueueStatsFromAllNodeConnector (targetNodeRef);
+            }
         }catch(Exception e){
             spLogger.error("Exception occured while sending statistics requests : {}", e);
         }
@@ -366,23 +370,28 @@ public class StatisticsProvider implements AutoCloseable {
         if(tablesId.size() != 0){
             for(Short id : tablesId){
                 
-                spLogger.debug("Send aggregate stats request for flow table {} to node {}",id,targetNodeKey);
-                GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder input = 
-                        new GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder();
-                
-                input.setNode(new NodeRef(InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey).toInstance()));
-                input.setTableId(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableId(id));
-                Future<RpcResult<GetAggregateFlowStatisticsFromFlowTableForAllFlowsOutput>> response = 
-                        flowStatsService.getAggregateFlowStatisticsFromFlowTableForAllFlows(input.build());
-                
-                multipartMessageManager.setTxIdAndTableIdMapEntry(targetNodeKey.getId(), response.get().getResult().getTransactionId(), id);
-                this.multipartMessageManager.addTxIdToRequestTypeEntry(targetNodeKey.getId(), response.get().getResult().getTransactionId()
-                        , StatsRequestType.AGGR_FLOW);
+                sendAggregateFlowsStatsFromTableRequest(targetNodeKey,id);
             }
         }else{
             spLogger.debug("No details found in data store for flow tables associated with Node {}",targetNodeKey);
         }
     }
+    
+    public void sendAggregateFlowsStatsFromTableRequest(NodeKey targetNodeKey,Short tableId) throws InterruptedException, ExecutionException{
+        
+        spLogger.debug("Send aggregate stats request for flow table {} to node {}",tableId,targetNodeKey);
+        GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder input = 
+                new GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder();
+                
+        input.setNode(new NodeRef(InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey).toInstance()));
+        input.setTableId(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableId(tableId));
+        Future<RpcResult<GetAggregateFlowStatisticsFromFlowTableForAllFlowsOutput>> response = 
+                flowStatsService.getAggregateFlowStatisticsFromFlowTableForAllFlows(input.build());
+                
+        multipartMessageManager.setTxIdAndTableIdMapEntry(targetNodeKey.getId(), response.get().getResult().getTransactionId(), tableId);
+        this.multipartMessageManager.addTxIdToRequestTypeEntry(targetNodeKey.getId(), response.get().getResult().getTransactionId()
+                , StatsRequestType.AGGR_FLOW);
+    }
 
     public void sendAllNodeConnectorsStatisticsRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{
         
index d14f7cf503c0c26b5086696473dee506f2fd26f8..19f25944b45f0ce34a94c9224ce4b107da4f467b 100644 (file)
@@ -7,12 +7,16 @@
  */
 package org.opendaylight.controller.md.statistics.manager;
 
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
 import java.util.List;
 import java.util.concurrent.ConcurrentMap;
 
 import org.opendaylight.controller.md.statistics.manager.NodeStatisticsAger.FlowEntry;
 import org.opendaylight.controller.md.statistics.manager.NodeStatisticsAger.QueueEntry;
 import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
@@ -88,6 +92,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterStatisticsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsData;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsDataBuilder;
@@ -445,11 +451,13 @@ public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsList
             //TODO: Not a good way to do it, need to figure out better way.
             //TODO: major issue in any alternate approach is that flow key is incrementally assigned 
             //to the flows stored in data store.
+            // Augment same statistics to all the matching masked flow
             if(table != null){
 
                 for(Flow existingFlow : table.getFlow()){
                     sucLogger.debug("Existing flow in data store : {}",existingFlow.toString());
                     if(flowEquals(flowRule,existingFlow)){
+                        it = this.statisticsManager.startChange();
                         InstanceIdentifier<Flow> flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
                                 .augmentation(FlowCapableNode.class)
                                 .child(Table.class, new TableKey(tableId))
@@ -460,7 +468,6 @@ public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsList
                         foundOriginalFlow = true;
                         it.putOperationalData(flowRef, flowBuilder.build());
                         it.commit();
-                        break;
                     }
                 }
             }
@@ -500,7 +507,7 @@ public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsList
                         .child(Flow.class,newFlowKey).toInstance();
                 flowBuilder.setKey(newFlowKey);
                 flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
-                sucLogger.info("Flow {} is not present in config data store, augmenting statistics as an unaccounted flow",flowBuilder.build());
+                sucLogger.debug("Flow {} is not present in config data store, augmenting statistics as an unaccounted flow",flowBuilder.build());
                 it.putOperationalData(flowRef, flowBuilder.build());
                 it.commit();
             }
@@ -703,8 +710,8 @@ public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsList
         else if(!matchEquals(statsFlow.getMatch(), storedFlow.getMatch())) {
             return false;
         }
-        if (statsFlow.getPriority() == null) {
-            if (storedFlow.getPriority() != null) {
+        if (storedFlow.getPriority() == null) {
+            if (statsFlow.getPriority() != null && statsFlow.getPriority()!= 0x8000) {
                 return false;
             }
         } else if(!statsFlow.getPriority().equals(storedFlow.getPriority())) {
@@ -722,24 +729,23 @@ public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsList
     
     /**
      * Explicit equals method to compare the 'match' for flows stored in the data-stores and flow fetched from the switch.
-     * Usecase: e.g If user don't set any ethernet source and destination address for match,data store will store null for 
-     * these address.
-     * e.g [_ethernetMatch=EthernetMatch [_ethernetDestination=null, _ethernetSource=null, _ethernetType=
-     * EthernetType [_type=EtherType [_value=2048], _mask=null, augmentation=[]]
+     * Flow installation process has three steps 
+     * 1) Store flow in config data store 
+     * 2) and send it to plugin for installation
+     * 3) Flow gets installed in switch
      * 
-     * But when you fetch the flows from switch, openflow driver library converts all zero bytes of mac address in the 
-     * message stream to 00:00:00:00:00:00. Following string shows how library interpret the zero mac address bytes and 
-     * eventually when translator convert it to MD-SAL match, this is how it looks 
-     * [_ethernetDestination=EthernetDestination [_address=MacAddress [_value=00:00:00:00:00:00], _mask=null, augmentation=[]], 
-     * _ethernetSource=EthernetSource [_address=MacAddress [_value=00:00:00:00:00:00], _mask=null, augmentation=[]], 
-     * _ethernetType=EthernetType [_type=EtherType [_value=2048], _mask=null, augmentation=[]]
+     * The flow user wants to install and what finally gets installed in switch can be slightly different. 
+     * E.g, If user installs flow with src/dst ip=10.0.0.1/24, when it get installed in the switch
+     * src/dst ip will be changes to 10.0.0.0/24 because of netmask of 24. When statistics manager fetch 
+     * stats it gets 10.0.0.0/24 rather then 10.0.0.1/24. Custom match takes care of by using masked ip
+     * while comparing two ip addresses.
      * 
-     * Similarly for inPort, if user/application don't set any value for it, FRM will store null value for it in data store. 
-     * When we fetch the same flow (with its statistics) from switch, plugin converts its value to openflow:X:0.
-     *  e.g _inPort=Uri [_value=openflow:1:0]  
+     * Sometimes when user don't provide few values that is required by flow installation request, like 
+     * priority,hard timeout, idle timeout, cookies etc, plugin usages default values before sending 
+     * request to the switch. So when statistics manager gets flow statistics, it gets the default value.
+     * But the flow stored in config data store don't have those defaults value. I included those checks 
+     * in the customer flow/match equal function. 
      * 
-     * So this custom equals method add additional check to take care of these scenario, in case any match element is null in data-store-flow, but not
-     * in the flow fetched from switch.
      * 
      * @param statsFlow
      * @param storedFlow
@@ -799,7 +805,7 @@ public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsList
             if (statsFlow.getLayer3Match() != null) {
                     return false;
             }
-        } else if(!storedFlow.getLayer3Match().equals(statsFlow.getLayer3Match())) {
+        } else if(!layer3MatchEquals(statsFlow.getLayer3Match(),storedFlow.getLayer3Match())) {
             return false;
         }
         if (storedFlow.getLayer4Match()== null) {
@@ -839,4 +845,100 @@ public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsList
         }
         return true;
     }
+
+    private boolean layer3MatchEquals(Layer3Match statsLayer3Match, Layer3Match storedLayer3Match){
+
+        if(statsLayer3Match instanceof Ipv4Match && storedLayer3Match instanceof Ipv4Match){
+            Ipv4Match statsIpv4Match = (Ipv4Match)statsLayer3Match;
+            Ipv4Match storedIpv4Match = (Ipv4Match)storedLayer3Match;
+            
+            if (storedIpv4Match.getIpv4Destination()== null) {
+                if (statsIpv4Match.getIpv4Destination()!= null) {
+                    return false;
+                }
+            } else if(!IpAddressEquals(statsIpv4Match.getIpv4Destination(),storedIpv4Match.getIpv4Destination())){
+                return false;
+            }
+            if (storedIpv4Match.getIpv4Source() == null) {
+                if (statsIpv4Match.getIpv4Source() != null) {
+                    return false;
+                }
+            } else if(!IpAddressEquals(statsIpv4Match.getIpv4Source(),storedIpv4Match.getIpv4Source())) {
+                return false;
+            }
+            
+            return true;
+        }else{
+            return storedLayer3Match.equals(statsLayer3Match);
+        }
+    }
+    
+    private boolean IpAddressEquals(Ipv4Prefix statsIpAddress, Ipv4Prefix storedIpAddress) {
+        IntegerIpAddress statsIpAddressInt = StrIpToIntIp(statsIpAddress.getValue());
+        IntegerIpAddress storedIpAddressInt = StrIpToIntIp(storedIpAddress.getValue());
+
+        if(IpAndMaskBasedMatch(statsIpAddressInt,storedIpAddressInt)){
+            return true;
+        }
+        if(IpBasedMatch(statsIpAddressInt,storedIpAddressInt)){
+            return true;
+        }
+        return false;
+    }
+
+    private boolean IpAndMaskBasedMatch(IntegerIpAddress statsIpAddressInt,IntegerIpAddress storedIpAddressInt){
+        return ((statsIpAddressInt.getIp() & statsIpAddressInt.getMask()) ==  (storedIpAddressInt.getIp() & storedIpAddressInt.getMask()));
+    }
+
+    private boolean IpBasedMatch(IntegerIpAddress statsIpAddressInt,IntegerIpAddress storedIpAddressInt){
+        return (statsIpAddressInt.getIp() == storedIpAddressInt.getIp());
+    }
+    
+    /*
+     * Method return integer version of ip address. Converted int will be mask if 
+     * mask specified
+     */
+    private IntegerIpAddress StrIpToIntIp(String ipAddresss){
+        
+        String[] parts = ipAddresss.split("/");
+        String ip = parts[0];
+        int prefix;
+
+        if (parts.length < 2) {
+            prefix = 32;
+        } else {
+            prefix = Integer.parseInt(parts[1]);
+        }
+
+        Inet4Address addr =null;
+        try {
+            addr = (Inet4Address) InetAddress.getByName(ip);
+        } catch (UnknownHostException e){}
+
+        byte[] addrBytes = addr.getAddress();
+        int ipInt = ((addrBytes[0] & 0xFF) << 24) |
+                         ((addrBytes[1] & 0xFF) << 16) |
+                         ((addrBytes[2] & 0xFF) << 8)  |
+                         ((addrBytes[3] & 0xFF) << 0);
+
+        int mask = 0xffffffff << 32 - prefix;
+
+        return new IntegerIpAddress(ipInt, mask);
+    }
+    
+    class IntegerIpAddress{
+        int ip;
+        int mask;
+        public IntegerIpAddress(int ip, int mask) {
+            this.ip = ip;
+            this.mask = mask;
+        }
+        public int getIp() {
+            return ip;
+        }
+        public int getMask() {
+            return mask;
+        }
+    }
 }
+
index 2db3c9d4f1d538893da1b9de420c696ef555e242..034b39a8066b0fbf631c4159558efdd15a362a2a 100644 (file)
@@ -21,6 +21,7 @@ import java.lang.management.ManagementFactory;
 public class NetconfOperationServiceFactoryImpl implements NetconfOperationServiceFactory {
 
     public static final int ATTEMPT_TIMEOUT_MS = 1000;
+    private static final int SILENT_ATTEMPTS = 30;
 
     private final YangStoreService yangStoreService;
     private final ConfigRegistryJMXClient jmxClient;
@@ -34,25 +35,35 @@ public class NetconfOperationServiceFactoryImpl implements NetconfOperationServi
     public NetconfOperationServiceFactoryImpl(YangStoreService yangStoreService, MBeanServer mBeanServer) {
         this.yangStoreService = yangStoreService;
 
+        ConfigRegistryJMXClient configRegistryJMXClient;
+        int i = 0;
         // Config registry might not be present yet, but will be eventually
         while(true) {
 
-            final ConfigRegistryJMXClient configRegistryJMXClient;
             try {
                 configRegistryJMXClient = new ConfigRegistryJMXClient(mBeanServer);
+                break;
             } catch (IllegalStateException e) {
-                logger.debug("Jmx client could not be created, reattempting");
+                ++i;
+                if (i > SILENT_ATTEMPTS) {
+                    logger.info("JMX client not created after {} attempts, still trying", i, e);
+                } else {
+                    logger.debug("JMX client could not be created, reattempting, try {}", i, e);
+                }
                 try {
                     Thread.sleep(ATTEMPT_TIMEOUT_MS);
                 } catch (InterruptedException e1) {
                     Thread.currentThread().interrupt();
-                    throw new RuntimeException(e1);
+                    throw new RuntimeException("Interrupted while reattempting connection", e1);
                 }
-                continue;
             }
+        }
 
-            jmxClient = configRegistryJMXClient;
-            break;
+        jmxClient = configRegistryJMXClient;
+        if (i > SILENT_ATTEMPTS) {
+            logger.info("Created JMX client after {} attempts", i);
+        } else {
+            logger.debug("Created JMX client after {} attempts", i);
         }
     }
 
index 3c968f8e2013423d4c405e1e95b8c4c711e5640e..c8af4ccd831bb306b563913a3af86d631a92b031 100644 (file)
@@ -77,7 +77,10 @@ public class ConfigPusher {
         // start pushing snapshots:
         for (ConfigSnapshotHolder configSnapshotHolder: configs){
             netconfClient = pushSnapshotWithRetries(configSnapshotHolder, Optional.of(netconfClient));
+            logger.debug("Config snapshot pushed successfully: {}", configSnapshotHolder);
         }
+
+        logger.debug("All configuration snapshots have been pushed successfully.");
         return netconfClient;
     }
 
index 857912021b0e21d07f60d740bbc6f6372ef0f6b6..179c9681fc4b21732286442251f5029e19e6958c 100644 (file)
@@ -90,6 +90,7 @@ public class ConfigPersisterActivator implements BundleActivator {
                     // uncaught exception handler will deal with this failure
                     throw new RuntimeException("Interrupted while waiting for netconf connection", e);
                 }
+                logger.info("Configuration Persister initialization completed.");
             }
         };
         initializationThread = new Thread(initializationRunnable, "ConfigPersister-registrator");
index 674da37afb5676a971905aefc3caf2a84eb2c761..d8e6a7412f1d6e75fd9a0c1ba9a5b5bbbe2135ca 100644 (file)
@@ -1436,7 +1436,10 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
         if (macAddress == null) {
             log.warn("Failed to acquire controller MAC: No physical interface found");
             // This happens when running controller on windows VM, for example
-            // Try parsing the OS command output
+            // TODO: Try parsing the OS command output
+            // For now provide a quick fix for the release
+            macAddress = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x0c, (byte) 0x60, (byte) 0x0D, (byte) 0x10 };
+            log.debug("Assigning custom MAC address to controller");
         }
         return macAddress;
     }