Merge "Added support for annotations in generated APIs."
authorGiovanni Meo <gmeo@cisco.com>
Fri, 26 Apr 2013 14:55:12 +0000 (14:55 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Fri, 26 Apr 2013 14:55:12 +0000 (14:55 +0000)
59 files changed:
opendaylight/clustering/services_implementation/src/main/java/org/opendaylight/controller/clustering/services_implementation/internal/ClusterManager.java
opendaylight/clustering/services_implementation/src/main/resources/config/infinispan-config.xml
opendaylight/clustering/services_implementation/src/test/java/org/opendaylight/controller/clustering/services_implementation/internal/ClusterManagerTest.java [new file with mode: 0644]
opendaylight/forwardingrulesmanager/api/src/main/java/org/opendaylight/controller/forwardingrulesmanager/FlowEntryInstall.java
opendaylight/forwardingrulesmanager/api/src/main/java/org/opendaylight/controller/forwardingrulesmanager/IForwardingRulesManager.java
opendaylight/forwardingrulesmanager/api/src/main/java/org/opendaylight/controller/forwardingrulesmanager/IForwardingRulesManagerAware.java
opendaylight/forwardingrulesmanager/implementation/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManagerImpl.java
opendaylight/logging/bridge/src/main/java/org/opendaylight/controller/logging/bridge/internal/Activator.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/Controller.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/ControllerIO.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SwitchHandler.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DescStatisticsConverter.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowConverter.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerService.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowStatisticsConverter.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/OFStatisticsManager.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/PortConverter.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/PortStatisticsConverter.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/Utils.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IFlowProgrammerService.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/Status.java
opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/FlowProgrammerService.java
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/pom.xml
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/antlr/YangParser.g4
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/impl/IdentitySchemaNodeBuilder.java
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/impl/ModuleBuilder.java
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/impl/YangModelParserImpl.java
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/impl/YangModelParserListenerImpl.java
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/impl/YangModelValidationListener.java [deleted file]
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/util/ParserUtils.java
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/util/YangModelBuilderUtil.java
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/util/YangValidationException.java [moved from opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/impl/YangValidationException.java with 78% similarity]
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/validator/BasicValidations.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/validator/ValidationUtil.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/validator/YangModelBasicValidationListener.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/validator/YangModelBasicValidator.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/impl/YangModelParserTest.java
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/impl/YangModelValidationListenerTest_Module.java [deleted file]
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/impl/YangModelValidationListenerTest_SubModule.java [deleted file]
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/validator/YangModelValidationListTest.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/validator/YangModelValidationModuleTest.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/validator/YangModelValidationSubModuleTest.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/validator/YangModelValidationTest.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/yang/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/AbstractSignedInteger.java
opendaylight/sal/yang-prototype/yang/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/AbstractUnsignedInteger.java
opendaylight/sal/yang-prototype/yang/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/Decimal64.java
opendaylight/sal/yang-prototype/yang/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/Int16.java
opendaylight/sal/yang-prototype/yang/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/Int32.java
opendaylight/sal/yang-prototype/yang/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/Int64.java
opendaylight/sal/yang-prototype/yang/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/Int8.java
opendaylight/sal/yang-prototype/yang/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/StringType.java
opendaylight/sal/yang-prototype/yang/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/Uint16.java
opendaylight/sal/yang-prototype/yang/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/Uint32.java
opendaylight/sal/yang-prototype/yang/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/Uint64.java
opendaylight/sal/yang-prototype/yang/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/Uint8.java
opendaylight/sal/yang-prototype/yang/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/YangTypesConverter.java
opendaylight/web/flows/src/main/java/org/opendaylight/controller/flows/web/Flows.java.rej [deleted file]
opendaylight/web/root/src/main/resources/WEB-INF/jsp/main.jsp
opendaylight/web/root/src/main/resources/js/lib.js

index 3034d3c..0b26107 100644 (file)
@@ -248,7 +248,7 @@ public class ClusterManager implements IClusterServices {
         logger.info("Starting the ClusterManager");
         try {
             //FIXME keeps throwing FileNotFoundException
-            this.cm = new DefaultCacheManager("/config/infinispan-config.xml");
+            this.cm = new DefaultCacheManager("config/infinispan-config.xml");
             logger.debug("Allocated ClusterManager");
             if (this.cm != null) {
                 this.cm.start();
index 96eff96..03a9b4d 100644 (file)
@@ -2,7 +2,7 @@
   <global>
     <transport>
       <properties>
-        <property name="configurationFile" value="/config/jgroups.xml"/>
+        <property name="configurationFile" value="config/jgroups.xml"/>
       </properties>
     </transport>
     <!-- Enable JMX statistics -->
diff --git a/opendaylight/clustering/services_implementation/src/test/java/org/opendaylight/controller/clustering/services_implementation/internal/ClusterManagerTest.java b/opendaylight/clustering/services_implementation/src/test/java/org/opendaylight/controller/clustering/services_implementation/internal/ClusterManagerTest.java
new file mode 100644 (file)
index 0000000..736a2b2
--- /dev/null
@@ -0,0 +1,160 @@
+package org.opendaylight.controller.clustering.services_implementation.internal;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Properties;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.infinispan.CacheImpl;
+import org.junit.Assert;
+import org.junit.Test;
+import org.opendaylight.controller.clustering.services.CacheConfigException;
+import org.opendaylight.controller.clustering.services.CacheExistException;
+import org.opendaylight.controller.clustering.services.IClusterServices;
+import org.opendaylight.controller.clustering.services.IClusterServices.cacheMode;
+
+public class ClusterManagerTest {
+
+    @Test
+    public void NoManagerSetTest() throws CacheExistException,
+            CacheConfigException {
+        ClusterManager cm = new ClusterManager();
+        CacheImpl<String, Integer> c1 = null;
+        CacheImpl<String, Integer> c2 = null;
+        Assert.assertNull(cm.createCache("Container", "Cache", null));
+        Assert.assertNull(cm.getCacheProperties("Container", "Cache"));
+        Assert.assertNull(cm.getCache("Container", "Cache"));
+        Assert.assertFalse(cm.existCache("Container", "Cache"));
+        Assert.assertNull(cm.getCacheList("Container"));
+        Assert.assertTrue(cm.amIStandby());
+        Assert.assertNull(cm.getActiveAddress());
+        Assert.assertNull(cm.getMyAddress());
+        Assert.assertNull(cm.getClusteredControllers());
+    }
+
+    @Test
+    public void WithManagerTest() throws CacheExistException,
+            CacheConfigException {
+
+        ClusterManager cm = new ClusterManager();
+        CacheImpl<String, Integer> c1 = null;
+        CacheImpl<String, Integer> c2 = null;
+
+        cm.start();
+
+        // Check no cache created yet
+        assertFalse(cm.existCache("NonExistantContainerName",
+                "NonExistantCacheName"));
+
+        // Create cache with no cacheMode set, expecting it to fail
+        HashSet<cacheMode> cacheModeSet = new HashSet<cacheMode>();
+        Assert.assertNull(cm.createCache("Container1", "Cache1", cacheModeSet));
+
+        // Create first cache as transactional
+        cacheModeSet.add(cacheMode.TRANSACTIONAL);
+        try {
+            c1 = (CacheImpl<String, Integer>) cm.createCache("Container1",
+                    "Cache1", cacheModeSet);
+        } catch (CacheExistException cee) {
+            Assert.assertTrue(false);
+        } catch (CacheConfigException cce) {
+            Assert.assertTrue(false);
+        }
+
+        // Try creating exact same cache again
+        try {
+            c1 = (CacheImpl<String, Integer>) cm.createCache("Container1",
+                    "Cache1", cacheModeSet);
+        } catch (CacheExistException cee) {
+            Assert.assertTrue(true);
+        } catch (CacheConfigException cce) {
+            Assert.assertTrue(false);
+        }
+
+        // Create second cache with both types of cacheMode, expecting it to
+        // complain
+        cacheModeSet.add(cacheMode.NON_TRANSACTIONAL);
+        try {
+            c2 = (CacheImpl<String, Integer>) cm.createCache("Container1",
+                    "Cache2", cacheModeSet);
+        } catch (CacheExistException cee) {
+            Assert.assertTrue(false);
+        } catch (CacheConfigException cce) {
+            Assert.assertTrue(true);
+        }
+
+        // Create second cache properly this time, as non_transactional
+        cacheModeSet.remove(cacheMode.TRANSACTIONAL);
+        try {
+            c2 = (CacheImpl<String, Integer>) cm.createCache("Container1",
+                    "Cache2", cacheModeSet);
+        } catch (CacheExistException cee) {
+            Assert.assertTrue(false);
+        } catch (CacheConfigException cce) {
+            Assert.assertTrue(false);
+        }
+
+        // Make sure correct caches exists
+        Assert.assertTrue(cm.existCache("Container1", "Cache1"));
+        c1 = (CacheImpl<String, Integer>) cm.getCache("Container1", "Cache1");
+        Assert.assertTrue(c1 != null);
+
+        Assert.assertTrue(cm.existCache("Container1", "Cache2"));
+        c2 = (CacheImpl<String, Integer>) cm.getCache("Container1", "Cache2");
+        Assert.assertTrue(c2 != null);
+
+        Assert.assertNull(cm.getCache("Container1", "Cache3"));
+
+        // Get CacheList
+        HashSet<String> cacheList = (HashSet<String>) cm
+                .getCacheList("Container2");
+        Assert.assertEquals(0, cacheList.size());
+
+        cacheList = (HashSet<String>) cm.getCacheList("Container1");
+        Assert.assertEquals(2, cacheList.size());
+        Assert.assertTrue(cacheList.contains("Cache1"));
+        Assert.assertTrue(cacheList.contains("Cache2"));
+
+        // Get CacheProperties
+        Assert.assertNull(cm.getCacheProperties("Container1", ""));
+        Properties p = cm.getCacheProperties("Container1", "Cache1");
+        Assert.assertEquals(3, p.size());
+        Assert.assertNotNull(p
+                .getProperty(IClusterServices.cacheProps.TRANSACTION_PROP
+                        .toString()));
+        Assert.assertNotNull(p
+                .getProperty(IClusterServices.cacheProps.CLUSTERING_PROP
+                        .toString()));
+        Assert.assertNotNull(p
+                .getProperty(IClusterServices.cacheProps.LOCKING_PROP
+                        .toString()));
+
+        // Destroy cache1 and make sure it's gone
+        cm.destroyCache("Container1", "Cache1");
+        cm.destroyCache("Container1", "Cache3");
+        Assert.assertFalse(cm.existCache("Container1", "Cache1"));
+        Assert.assertTrue(cm.existCache("Container1", "Cache2"));
+
+        // Check amIStandBy()
+        boolean standby = cm.amIStandby();
+        Assert.assertFalse(standby);
+
+        // Check addresses, which are all loopback
+        InetAddress activeAddress = cm.getActiveAddress();
+        Assert.assertEquals("/127.0.0.1", activeAddress.toString());
+        InetAddress myAddress = cm.getMyAddress();
+        Assert.assertEquals("/127.0.0.1", myAddress.toString());
+
+        List<InetAddress> cc = cm.getClusteredControllers();
+        Assert.assertEquals(0, cc.size());
+
+        cm.stop();
+    }
+
+}
index dfe331a..96b6819 100644 (file)
@@ -28,6 +28,7 @@ public class FlowEntryInstall {
     private FlowEntry original;
     private ContainerFlow cFlow;
     private FlowEntry install;
+    transient private long requestId; // async request id
     transient private boolean deletePending;
 
     public FlowEntryInstall(FlowEntry original, ContainerFlow cFlow) {
@@ -36,6 +37,7 @@ public class FlowEntryInstall {
         this.install = (cFlow == null) ? original.clone() : original
                 .mergeWith(cFlow);
         deletePending = false;
+        requestId = 0;
     }
 
     @Override
@@ -84,9 +86,17 @@ public class FlowEntryInstall {
         this.deletePending = true;
     }
 
+    public void setRequestId(long rid) {
+        this.requestId = rid;
+    }
+    
+    public long getRequestId() {
+        return requestId;
+    }
+
     @Override
     public String toString() {
-        return "[Install = " + install + " Original: " + original + " cFlow: "
-                + cFlow + "]";
+        return "[Install = " + install + " Original = " + original + " cFlow = "
+                + cFlow + " rid = " + requestId + "]";
     }
 }
index d0efe4a..78917c9 100644 (file)
@@ -73,12 +73,90 @@ public interface IForwardingRulesManager {
      * not valid an error code is returned. If the existing flow is equal to the
      * passed one it will be a no op and success code is returned.
      * 
+     * 
      * @param newone
      *            the new flow entry to install
      * @return the {@code Status} object indicating the result of this action
      */
     public Status modifyOrAddFlowEntry(FlowEntry newone);
 
+    /**
+     * It requests FRM to install the passed Flow Entry through an asynchronous
+     * call. A unique request id is returned to the caller. FRM will request the
+     * SDN protocol plugin to install the flow on the network node. As immediate
+     * result of this asynchronous call, FRM will update its flow database as if
+     * the flow was successfully installed.
+     * 
+     * @param flow
+     *            the flow entry to install
+     * @return the status of this request containing the request id associated
+     *         to this asynchronous request
+     */
+    public Status installFlowEntryAsync(FlowEntry flow);
+
+    /**
+     * It requests FRM to remove the passed Flow Entry through an asynchronous
+     * call. A unique request id is returned to the caller. FRM will request the
+     * SDN protocol plugin to uninstall the flow from the network node. As
+     * immediate result of this asynchronous call, FRM will update its flow
+     * database as if the flow was successfully installed.
+     * 
+     * @param flow
+     *            the flow entry to uninstall
+     * @return the status of this request containing the unique id associated to
+     *         this asynchronous request
+     */
+    public Status uninstallFlowEntryAsync(FlowEntry flow);
+
+    /**
+     * It requests FRM to replace the currently installed Flow Entry with the
+     * new one through an asynchronous call. A unique request id is returned to
+     * the caller. It is up to the SDN protocol plugin to decide how to convey
+     * this message to the network node. It could be a delete + add or a single
+     * modify message depending on the SDN protocol specifications. If the
+     * current flow is equal to the new one it will be a no op.
+     * 
+     * @param current
+     *            the current flow entry to modify
+     * @param newone
+     *            the new flow entry which will replace the current one
+     * @return the status of this request containing the request id associated
+     *         to this asynchronous request
+     */
+    public Status modifyFlowEntryAsync(FlowEntry current, FlowEntry newone);
+
+    /**
+     * It requests the FRM to replace the currently installed Flow Entry with
+     * the new one through an asynchronous call. A unique request id is returned
+     * to the caller. The currently installed entry is derived by the Match
+     * portion of the passed Flow. FRM looks in its database for a previously
+     * installed FlowEntry which Match equals the Match of the passed Flow. If
+     * it finds it, it will request the SDN protocol plugin to replace the
+     * existing flow with the new one on the network node. If it does not find
+     * it, it will request plugin to add the new flow. If the passed entry is
+     * not valid a zero request id is returned. If the existing flow is equal to
+     * the passed one it will be a no op.
+     * 
+     * @param newone
+     *            the new flow entry to install
+     * @return the unique id associated to this request. In case of not
+     *         acceptable request -1 will be returned.
+     */
+    public Status modifyOrAddFlowEntryAsync(FlowEntry newone);
+
+    /**
+     * Requests ForwardingRulesManager to solicit the network node to inform
+     * us about the status of his execution on the asynchronous requests that
+     * were sent to it so far. It is a way for an application to poke the
+     * network node in order to get a feedback asap on the asynchronous
+     * requests generated by the application. It is a non-blocking call
+     * and does not guarantee the node will respond in any given time. 
+     * 
+     * @param node
+     *          The network node to solicit a response
+     */
+    public void solicitStatusResponse(Node node);
+
     /**
      * Check whether the passed flow entry conflicts with the Container flows
      * 
@@ -209,7 +287,7 @@ public interface IForwardingRulesManager {
      * @param name
      *            the flow name
      * @param n
-     *            the netwrok node identifier
+     *            the network node identifier
      * @return the {@code FlowConfig} object
      */
     public FlowConfig getStaticFlow(String name, Node n);
index e2ccdd6..43d1b29 100644 (file)
@@ -26,4 +26,18 @@ public interface IForwardingRulesManagerAware {
      *            otherwise
      */
     public void policyUpdate(String policyName, boolean add);
+
+    /**
+     * Inform listeners that the network node has notified us about a failure in
+     * executing the controller generated asynchronous request identified by the
+     * passed unique id.
+     * 
+     * @param requestId
+     *            the unique id associated with the request which failed to be
+     *            executed on the network node
+     * @param error
+     *            the string describing the error reported by the network node
+     */
+    public void requestFailed(long requestId, String error);
+
 }
index c86363f..fe2cdc4 100644 (file)
@@ -138,9 +138,13 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
      * 
      * @param flowEntry
      *            the original flow entry application requested to add
-     * @return
+     * @param async
+     *            the flag indicating if this is a asynchronous request
+     * @return the status of this request. In case of asynchronous call, it
+     *          will contain the unique id assigned to this request
      */
-    private Status addEntry(FlowEntry flowEntry) {
+    private Status addEntry(FlowEntry flowEntry, boolean async) {
+        
         // Sanity Check
         if (flowEntry == null || flowEntry.getNode() == null) {
             String msg = "Invalid FlowEntry";
@@ -190,14 +194,22 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
 
         // Try to install an entry at the time
         Status error = new Status(null, null);
+        Status succeded = null;
         boolean oneSucceded = false;
-        for (FlowEntryInstall installEntry : toInstallList) {
+        for (FlowEntryInstall installEntry : toInstallSafe) {
 
             // Install and update database
-            Status ret = addEntriesInternal(installEntry);
+            Status ret = addEntriesInternal(installEntry, async);
 
             if (ret.isSuccess()) {
                 oneSucceded = true;
+                /*
+                 * The first successful status response will be returned
+                 * For the asynchronous call, we can discard the container flow
+                 * complication for now and assume we will always deal with
+                 * one flow only per request
+                 */
+                succeded = ret;   
             } else {
                 error = ret;
                 log.warn("Failed to install the entry: {}. The failure is: {}",
@@ -205,7 +217,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
             }
         }
 
-        return (oneSucceded) ? new Status(StatusCode.SUCCESS, null) : error;
+        return (oneSucceded) ? succeded : error;
     }
 
     /**
@@ -251,10 +263,14 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
      * 
      * @param currentFlowEntry
      * @param newFlowEntry
-     * @return Success or error string
+     * @param async
+     *            the flag indicating if this is a asynchronous request
+     * @return the status of this request. In case of asynchronous call, it
+     *          will contain the unique id assigned to this request
      */
     private Status modifyEntry(FlowEntry currentFlowEntry,
-            FlowEntry newFlowEntry) {
+            FlowEntry newFlowEntry, boolean async) {
+
         Status retExt;
 
         // Sanity checks
@@ -329,6 +345,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
          * So, for the above two cases, to simplify, let's decouple the modify
          * in: 1) remove current entries 2) install new entries
          */
+        Status succeeded = null;
         boolean decouple = false;
         if (installedList.size() != toInstallList.size()) {
             log.info("Modify: New flow entry does not satisfy the same "
@@ -354,11 +371,11 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
         if (decouple) {
             // Remove current entries
             for (FlowEntryInstall currEntry : installedList) {
-                this.removeEntryInternal(currEntry);
+                this.removeEntryInternal(currEntry, async);
             }
             // Install new entries
             for (FlowEntryInstall newEntry : toInstallSafe) {
-                this.addEntriesInternal(newEntry);
+                succeeded = this.addEntriesInternal(newEntry, async);
             }
         } else {
             /*
@@ -372,13 +389,13 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
              * fails, we need to stop, restore the already modified entries, and
              * declare failure.
              */
-            Status retModify;
+            Status retModify = null;
             int i = 0;
             int size = toInstallList.size();
             while (i < size) {
                 // Modify and update database
                 retModify = modifyEntryInternal(installedList.get(i),
-                        toInstallList.get(i));
+                        toInstallList.get(i), async);
                 if (retModify.isSuccess()) {
                     i++;
                 } else {
@@ -394,7 +411,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
                 while (j < i) {
                     log.info("Attempting to restore initial entries");
                     retExt = modifyEntryInternal(toInstallList.get(i),
-                            installedList.get(i));
+                            installedList.get(i), async);
                     if (retExt.isSuccess()) {
                         j++;
                     } else {
@@ -408,8 +425,15 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
                     return new Status(StatusCode.INTERNALERROR, msg);
                 }
             }
+            succeeded = retModify;
         }
-        return new Status(StatusCode.SUCCESS, null);
+        /*
+         * The first successful status response will be returned.
+         * For the asynchronous call, we can discard the container flow
+         * complication for now and assume we will always deal with
+         * one flow only per request
+         */
+        return succeeded;
     }
 
     /**
@@ -419,14 +443,22 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
      * 
      * @param currentEntries
      * @param newEntries
-     * @return
+     * @param async
+     *            the flag indicating if this is a asynchronous request
+     * @return the status of this request. In case of asynchronous call, it
+     *          will contain the unique id assigned to this request
      */
     private Status modifyEntryInternal(FlowEntryInstall currentEntries,
-            FlowEntryInstall newEntries) {
+            FlowEntryInstall newEntries, boolean async) {
         // Modify the flow on the network node
-        Status status = programmer.modifyFlow(currentEntries.getNode(),
-                currentEntries.getInstall().getFlow(), newEntries.getInstall()
-                        .getFlow());
+        Status status = (async)? 
+                programmer.modifyFlowAsync(currentEntries.getNode(),
+                        currentEntries.getInstall().getFlow(), newEntries.getInstall()
+                                .getFlow()) :
+                programmer.modifyFlow(currentEntries.getNode(),
+                        currentEntries.getInstall().getFlow(), newEntries.getInstall()
+                                .getFlow());
+
 
         if (!status.isSuccess()) {
             log.warn(
@@ -439,6 +471,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
                 newEntries.getInstall());
 
         // Update DB
+        newEntries.setRequestId(status.getRequestId());
         updateLocalDatabase(currentEntries, false);
         updateLocalDatabase(newEntries, true);
 
@@ -450,9 +483,13 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
      * (entry or node not present), it return successfully
      * 
      * @param flowEntry
-     * @return
+     *          the flow entry to remove
+     * @param async
+     *            the flag indicating if this is a asynchronous request
+     * @return the status of this request. In case of asynchronous call, it
+     *          will contain the unique id assigned to this request
      */
-    private Status removeEntry(FlowEntry flowEntry) {
+    private Status removeEntry(FlowEntry flowEntry, boolean async) {
         Status error = new Status(null, null);
 
         // Sanity Check
@@ -468,6 +505,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
                 flowEntry.clone(), container.getContainerFlows());
 
         Set<FlowEntryInstall> flowsOnNode = nodeFlows.get(flowEntry.getNode());
+        Status succeeded = null;
         boolean atLeastOneRemoved = false;
         for (FlowEntryInstall entry : installedList) {
             if (flowsOnNode == null) {
@@ -481,14 +519,14 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
                 log.debug(logMsg, flowEntry);
                 if (installedList.size() == 1) {
                     // If we had only one entry to remove, we are done
-                    return new Status(StatusCode.SUCCESS, null);
+                    return new Status(StatusCode.SUCCESS);
                 } else {
                     continue;
                 }
             }
 
             // Remove and update DB
-            Status ret = removeEntryInternal(entry);
+            Status ret = removeEntryInternal(entry, async);
 
             if (!ret.isSuccess()) {
                 error = ret;
@@ -499,6 +537,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
                     return error;
                 }
             } else {
+                succeeded = ret;
                 atLeastOneRemoved = true;
             }
         }
@@ -508,8 +547,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
          * of removing the stale entries later, or adjusting the software
          * database if not in sync with hardware
          */
-        return (atLeastOneRemoved) ? new Status(StatusCode.SUCCESS, null)
-                : error;
+        return (atLeastOneRemoved) ? succeeded : error;
     }
 
     /**
@@ -518,16 +556,23 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
      * validity checks are passed
      * 
      * @param entry
-     *            the FlowEntryInstall
-     * @return "Success" or error string
+     *            the flow entry to remove
+     * @param async
+     *            the flag indicating if this is a asynchronous request
+     * @return the status of this request. In case of asynchronous call, it
+     *          will contain the unique id assigned to this request
      */
-    private Status removeEntryInternal(FlowEntryInstall entry) {
+    private Status removeEntryInternal(FlowEntryInstall entry, boolean async) {
         // Mark the entry to be deleted (for CC just in case we fail)
         entry.toBeDeleted();
 
         // Remove from node
-        Status status = programmer.removeFlow(entry.getNode(), entry
-                .getInstall().getFlow());
+        Status status = (async)?
+                programmer.removeFlowAsync(entry.getNode(), entry
+                        .getInstall().getFlow()) :
+                programmer.removeFlow(entry.getNode(), entry
+                        .getInstall().getFlow());
 
         if (!status.isSuccess()) {
             log.warn(
@@ -535,7 +580,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
                     entry.getInstall(), status.getDescription());
             return status;
         }
-        log.info("Removed  {}", entry.getInstall());
+        log.trace("Removed  {}", entry.getInstall());
 
         // Update DB
         updateLocalDatabase(entry, false);
@@ -550,13 +595,20 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
      * whether this flow would conflict or overwrite an existing one.
      * 
      * @param entry
-     *            the FlowEntryInstall
-     * @return "Success" or error string
+     *            the flow entry to install
+     * @param async
+     *            the flag indicating if this is a asynchronous request
+     * @return the status of this request. In case of asynchronous call, it
+     *          will contain the unique id assigned to this request
      */
-    private Status addEntriesInternal(FlowEntryInstall entry) {
+    private Status addEntriesInternal(FlowEntryInstall entry, boolean async) {
         // Install the flow on the network node
-        Status status = programmer.addFlow(entry.getNode(), entry.getInstall()
-                .getFlow());
+        Status status = (async)?
+                programmer.addFlow(entry.getNode(), entry.getInstall()
+                        .getFlow()) :
+                programmer.addFlowAsync(entry.getNode(), entry.getInstall()
+                            .getFlow());
+
 
         if (!status.isSuccess()) {
             log.warn(
@@ -565,9 +617,10 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
             return status;
         }
 
-        log.info("Added    {}", entry.getInstall());
+        log.trace("Added    {}", entry.getInstall());
 
         // Update DB
+        entry.setRequestId(status.getRequestId());
         updateLocalDatabase(entry, true);
 
         return status;
@@ -740,7 +793,20 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
             status = new Status(StatusCode.NOTACCEPTABLE, msg);
             log.warn(logMsg, flowEntry);
         } else {
-            status = addEntry(flowEntry);
+            status = addEntry(flowEntry, false);
+        }
+        return status;
+    }
+
+    @Override
+    public Status installFlowEntryAsync(FlowEntry flowEntry) {
+        Status status;
+        if (inContainerMode) {
+            String msg = "Controller in container mode: Install Refused";
+            status = new Status(StatusCode.NOTACCEPTABLE, msg);
+            log.warn(msg);
+        } else {
+            status = addEntry(flowEntry, true);
         }
         return status;
     }
@@ -754,11 +820,24 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
             status = new Status(StatusCode.NOTACCEPTABLE, msg);
             log.warn(logMsg, entry);
         } else {
-            status = removeEntry(entry);
+            status = removeEntry(entry, false);
         }
         return status;
     }
 
+    @Override
+    public Status uninstallFlowEntryAsync(FlowEntry flowEntry) {
+        Status status;
+        if (inContainerMode) {
+            String msg = "Controller in container mode: Uninstall Refused";
+            status = new Status(StatusCode.NOTACCEPTABLE, msg);
+            log.warn(msg);
+        } else {
+            status = removeEntry(flowEntry, true);
+        }
+        return status;
+    }
+    
     @Override
     public Status modifyFlowEntry(FlowEntry currentFlowEntry,
             FlowEntry newFlowEntry) {
@@ -769,7 +848,20 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
             status = new Status(StatusCode.NOTACCEPTABLE, msg);
             log.warn(logMsg, newFlowEntry);
         } else {
-            status = modifyEntry(currentFlowEntry, newFlowEntry);
+            status = modifyEntry(currentFlowEntry, newFlowEntry, false);
+        }
+        return status;
+    }
+
+    @Override
+    public Status modifyFlowEntryAsync(FlowEntry current, FlowEntry newone) {
+        Status status = null;
+        if (inContainerMode) {
+            String msg = "Controller in container mode: Modify Refused";
+            status = new Status(StatusCode.NOTACCEPTABLE, msg);
+            log.warn(msg);
+        } else {
+            status = modifyEntry(current, newone, true);
         }
         return status;
     }
@@ -795,6 +887,28 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
         }
     }
 
+    @Override
+    public Status modifyOrAddFlowEntryAsync(FlowEntry newone) {
+        /*
+         * Run a loose check on the installed entries to decide whether to go
+         * with a add or modify method. A loose check means only check against
+         * the original flow entry requests and not against the installed flow
+         * entries which are the result of the original entry merged with the
+         * container flow(s) (if any). The modifyFlowEntry method in presence of
+         * conflicts with the Container flows (if any) would revert back to a
+         * delete + add pattern
+         */
+        FlowEntryInstall currentFlowEntries = findMatch(newone, true);
+
+        if (currentFlowEntries != null) {
+            return modifyFlowEntryAsync(currentFlowEntries.getOriginal(),
+                   newone);
+        } else {
+            return installFlowEntry(newone);
+        }
+    }
+
+    
     /**
      * Try to find in the database if a Flow with the same Match and priority of
      * the passed one already exists for the specified network node. Flow,
@@ -858,7 +972,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
             // Remove the old couples. No validity checks to be run, use the
             // internal remove
             for (FlowEntryInstall oldCouple : oldCouples) {
-                this.removeEntryInternal(oldCouple);
+                this.removeEntryInternal(oldCouple, false);
             }
             // Reinstall the original flow entries, via the regular path: new
             // cFlow merge + validations
@@ -951,7 +1065,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
                 for (NodeConnector dstPort : portList) {
                     newFlowEntry.getFlow().addAction(new Output(dstPort));
                 }
-                Status error = modifyEntry(currentFlowEntry, newFlowEntry);
+                Status error = modifyEntry(currentFlowEntry, newFlowEntry, false);
                 if (error.isSuccess()) {
                     log.info("Ports {} added to FlowEntry {}", portList,
                             flowName);
@@ -982,7 +1096,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
                     Action action = new Output(dstPort);
                     newFlowEntry.getFlow().removeAction(action);
                 }
-                Status status = modifyEntry(currentFlowEntry, newFlowEntry);
+                Status status = modifyEntry(currentFlowEntry, newFlowEntry, false);
                 if (status.isSuccess()) {
                     log.info("Ports {} removed from FlowEntry {}", portList,
                             flowName);
@@ -1037,7 +1151,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
         newFlowEntry.getFlow().addAction(new Output(outPort));
 
         // Modify on network node
-        Status status = modifyEntry(currentFlowEntry, newFlowEntry);
+        Status status = modifyEntry(currentFlowEntry, newFlowEntry, false);
 
         if (status.isSuccess()) {
             log.info("Output port replaced with {} for flow {} on node {}",
@@ -1280,7 +1394,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
             // Program hw
             if (config.installInHw()) {
                 FlowEntry entry = config.getFlowEntry();
-                status = this.addEntry(entry);
+                status = this.addEntry(entry, false);
                 if (!status.isSuccess()) {
                     config.setStatus(status.getDescription());
                     if (!restore) {
@@ -1316,7 +1430,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
                 portGroupChanged(pgconfig, existingData, true);
             }
         }
-        return new Status(StatusCode.SUCCESS, null);
+        return new Status(StatusCode.SUCCESS);
     }
 
     private void addStaticFlowsToSwitch(Node node) {
@@ -1328,7 +1442,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
                 if (config.installInHw()
                         && !config.getStatus().equals(
                                 StatusCode.SUCCESS.toString())) {
-                    Status status = this.addEntry(config.getFlowEntry());
+                    Status status = this.addEntry(config.getFlowEntry(), false);
                     config.setStatus(status.getDescription());
                 }
             }
@@ -1395,7 +1509,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
         for (Map.Entry<Integer, FlowConfig> entry : staticFlows.entrySet()) {
             if (entry.getValue().isByNameAndNodeIdEqual(config)) {
                 // Program the network node
-                Status status = this.removeEntry(config.getFlowEntry());
+                Status status = this.removeEntry(config.getFlowEntry(), false);
                 // Update configuration database if programming was successful
                 if (status.isSuccess()) {
                     staticFlows.remove(entry.getKey());
@@ -1425,7 +1539,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
                 }
                 if (!entry.isPortGroupEnabled()) {
                     // Program the network node
-                    status = this.removeEntry(entry.getFlowEntry());
+                    status = this.removeEntry(entry.getFlowEntry(), false);
                 }
                 // Update configuration database if programming was successful
                 if (status.isSuccess()) {
@@ -1492,7 +1606,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
         Status status = new Status(StatusCode.SUCCESS, "Saved in config");
         if (oldFlowConfig.installInHw()) {
             status = this.modifyEntry(oldFlowConfig.getFlowEntry(),
-                    newFlowConfig.getFlowEntry());
+                    newFlowConfig.getFlowEntry(), false);
         }
 
         // Update configuration database if programming was successful
@@ -1529,11 +1643,11 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
             FlowConfig conf = entry.getValue();
             if (conf.isByNameAndNodeIdEqual(config)) {
                 // Program the network node
-                Status status = new Status(StatusCode.SUCCESS, null);
+                Status status = new Status(StatusCode.SUCCESS);
                 if (conf.installInHw()) {
-                    status = this.removeEntry(conf.getFlowEntry());
+                    status = this.removeEntry(conf.getFlowEntry(), false);
                 } else {
-                    status = this.addEntry(conf.getFlowEntry());
+                    status = this.addEntry(conf.getFlowEntry(), false);
                 }
                 if (!status.isSuccess()) {
                     conf.setStatus(status.getDescription());
@@ -1569,10 +1683,10 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
 
         // Now remove the entries
         for (FlowEntry flowEntry : inactiveFlows) {
-            Status status = this.removeEntry(flowEntry);
+            Status status = this.removeEntry(flowEntry, false);
             if (!status.isSuccess()) {
-                log.warn("Failed to remove entry: {}. The failure is: {}"
-                        flowEntry, status.getDescription());
+                log.warn("Failed to remove entry: {}. The failure is: {}",
+                        flowEntry, status.getDescription());
             }
         }
     }
@@ -1586,10 +1700,10 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
         log.info("Reinstalling all inactive flows");
 
         for (FlowEntry flowEntry : this.inactiveFlows) {
-            Status status = this.addEntry(flowEntry);
+            Status status = this.addEntry(flowEntry, false);
             if (!status.isSuccess()) {
-                log.warn("Failed to install entry: {}. The failure is: {}"
-                        flowEntry, status.getDescription());
+                log.warn("Failed to install entry: {}. The failure is: {}",
+                        flowEntry, status.getDescription());
             }
         }
 
@@ -1923,7 +2037,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
     @Override
     public void portGroupChanged(PortGroupConfig config,
             Map<Node, PortGroup> data, boolean add) {
-        log.info("PortGroup Changed for :" + config + " Data: " + portGroupData);
+        log.info("PortGroup Changed for: {} Data: {}", config, portGroupData);
         Map<Node, PortGroup> existingData = portGroupData.get(config);
         if (existingData != null) {
             for (Map.Entry<Node, PortGroup> entry : data.entrySet()) {
@@ -2424,7 +2538,49 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
 
     @Override
     public void flowErrorReported(Node node, long rid, Object err) {
-        log.error("Got error {} for message rid {} from node {}", new Object[] {
-                err, rid, node });
+        log.trace("Got error {} for message rid {} from node {}",
+                new Object[] {err, rid, node });
+        /*
+         *  If this was for a flow install, remove the corresponding entry
+         *  from the software view. If it was a Looking for the rid going through the
+         *  software database. 
+         *  TODO: A more efficient rid <->  FlowEntryInstall mapping will 
+         *  have to be added in future
+         */
+        Set<FlowEntryInstall> entries = nodeFlows.get(node);
+        if (entries != null) {
+            FlowEntryInstall target = null;
+            for (FlowEntryInstall entry : entries) {
+                if (entry.getRequestId() == rid) {
+                    target = entry;
+                    break;
+                }
+            }
+            if (target != null) {
+                // This was a flow install, update database
+                this.updateLocalDatabase(target, false);
+            }
+        }
+        
+        // Notify listeners
+        if (frmAware != null) {
+            synchronized (frmAware) {
+                for (IForwardingRulesManagerAware frma : frmAware) {
+                    try {
+                        frma.requestFailed(rid, err.toString());
+                    } catch (Exception e) {
+                        log.warn("Failed to notify {}", frma);
+                    }
+                }
+            }
+        }
+    }
+    
+    @Override
+    public void solicitStatusResponse(Node node) {
+        if (this.programmer != null) {
+            programmer.sendBarrierMessage(node);
+        }        
     }
+
 }
index d455a0a..6bafee0 100644 (file)
@@ -12,6 +12,7 @@ package org.opendaylight.controller.logging.bridge.internal;
 import org.osgi.service.log.LogEntry;
 import java.util.Enumeration;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.framework.ServiceReference;
@@ -64,6 +65,14 @@ public class Activator implements BundleActivator {
                  */
                 Thread.setDefaultUncaughtExceptionHandler(new org.opendaylight.
                         controller.logging.bridge.internal.UncaughtExceptionHandler());
+                
+                /*
+                 * Install the Shutdown handler. This will intercept SIGTERM signal and
+                 * close the system bundle. This allows for a graceful  closing of OSGI
+                 * framework.
+                 */
+                
+                Runtime.getRuntime().addShutdownHook(new shutdownHandler(context));
             } else {
                 this.log.error("Cannot register the LogListener because "
                         + "cannot retrieve LogReaderService");
@@ -86,4 +95,21 @@ public class Activator implements BundleActivator {
         this.listener = null;
         this.log = null;
     }
+    
+    private class shutdownHandler extends Thread {
+        BundleContext bundlecontext;
+        public shutdownHandler(BundleContext ctxt) {
+                this.bundlecontext = ctxt;
+        }
+        
+        public void run () {
+            try {
+                this.bundlecontext.getBundle(0).stop();
+                log.debug("shutdown handler thread called");
+            } catch (BundleException e) {
+                log.debug("Bundle couldn't be stopped");
+            }
+        }   
+    }
+
 }
index 9ec5b10..bfa6f0b 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
  *
@@ -53,7 +52,8 @@ public class Controller implements IController, CommandProvider {
     private AtomicInteger switchInstanceNumber;
 
     /*
-     * this thread monitors the switchEvents queue for new incoming events from switch
+     * this thread monitors the switchEvents queue for new incoming events from
+     * switch
      */
     private class EventHandler implements Runnable {
         @Override
@@ -64,17 +64,13 @@ public class Controller implements IController, CommandProvider {
                     SwitchEvent ev = switchEvents.take();
                     SwitchEvent.SwitchEventType eType = ev.getEventType();
                     ISwitch sw = ev.getSwitch();
-                    if (eType != SwitchEvent.SwitchEventType.SWITCH_MESSAGE) {
-                        //logger.debug("Received " + ev.toString() + " from " + sw.toString());
-                    }
                     switch (eType) {
                     case SWITCH_ADD:
                         Long sid = sw.getId();
                         ISwitch existingSwitch = switches.get(sid);
                         if (existingSwitch != null) {
-                            logger.info(" Replacing existing "
-                                    + existingSwitch.toString() + " with New "
-                                    + sw.toString());
+                            logger.info("Replacing existing {} with New {}",
+                                    existingSwitch.toString(), sw.toString());
                             disconnectSwitch(existingSwitch);
                         }
                         switches.put(sid, sw);
@@ -97,7 +93,7 @@ public class Controller implements IController, CommandProvider {
                         }
                         break;
                     default:
-                        logger.error("unknow switch event " + eType.ordinal());
+                        logger.error("Unknown switch event {}", eType.ordinal());
                     }
                 } catch (InterruptedException e) {
                     switchEvents.clear();
@@ -111,10 +107,10 @@ public class Controller implements IController, CommandProvider {
     /**
      * Function called by the dependency manager when all the required
      * dependencies are satisfied
-     *
+     * 
      */
     public void init() {
-        logger.debug("OpenFlowCore init");
+        logger.debug("Initializing!");
         this.switches = new ConcurrentHashMap<Long, ISwitch>();
         this.switchEvents = new LinkedBlockingQueue<SwitchEvent>();
         this.messageListeners = new ConcurrentHashMap<OFType, IMessageListener>();
@@ -124,13 +120,12 @@ public class Controller implements IController, CommandProvider {
     }
 
     /**
-     * Function called by dependency manager after "init ()" is called
-     * and after the services provided by the class are registered in
-     * the service registry
-     *
+     * Function called by dependency manager after "init ()" is called and after
+     * the services provided by the class are registered in the service registry
+     * 
      */
     public void start() {
-        logger.debug("OpenFlowCore start() is called");
+        logger.debug("Starting!");
         /*
          * start a thread to handle event coming from the switch
          */
@@ -142,15 +137,15 @@ public class Controller implements IController, CommandProvider {
         try {
             controllerIO.start();
         } catch (IOException ex) {
-            logger.error("Caught exception: " + ex + " during start");
+            logger.error("Caught exception while starting:", ex);
         }
     }
-    
+
     /**
-     * Function called by the dependency manager before the services
-     * exported by the component are unregistered, this will be
-     * followed by a "destroy ()" calls
-     *
+     * Function called by the dependency manager before the services exported by
+     * the component are unregistered, this will be followed by a "destroy ()"
+     * calls
+     * 
      */
     public void stop() {
         for (Iterator<Entry<Long, ISwitch>> it = switches.entrySet().iterator(); it
@@ -161,17 +156,17 @@ public class Controller implements IController, CommandProvider {
         }
         switchEventThread.interrupt();
         try {
-               controllerIO.shutDown();
+            controllerIO.shutDown();
         } catch (IOException ex) {
-               logger.error("Caught exception: " + ex + " during stop");
+            logger.error("Caught exception while stopping:", ex);
         }
     }
 
     /**
-     * Function called by the dependency manager when at least one
-     * dependency become unsatisfied or when the component is shutting
-     * down because for example bundle is being stopped.
-     *
+     * Function called by the dependency manager when at least one dependency
+     * become unsatisfied or when the component is shutting down because for
+     * example bundle is being stopped.
+     * 
      */
     public void destroy() {
     }
@@ -180,18 +175,20 @@ public class Controller implements IController, CommandProvider {
     public void addMessageListener(OFType type, IMessageListener listener) {
         IMessageListener currentListener = this.messageListeners.get(type);
         if (currentListener != null) {
-            logger.warn(type.toString() + " already listened by "
-                    currentListener.toString());
+            logger.warn("{} is already listened by {}", type.toString(),
+                    currentListener.toString());
         }
         this.messageListeners.put(type, listener);
-        logger.debug(type.toString() + " is now listened by "
-                listener.toString());
+        logger.debug("{} is now listened by {}", type.toString(),
+                listener.toString());
     }
 
     @Override
     public void removeMessageListener(OFType type, IMessageListener listener) {
         IMessageListener currentListener = this.messageListeners.get(type);
         if ((currentListener != null) && (currentListener == listener)) {
+            logger.debug("{} listener {} is Removed", type.toString(),
+                    listener.toString());
             this.messageListeners.remove(type);
         }
     }
@@ -199,17 +196,20 @@ public class Controller implements IController, CommandProvider {
     @Override
     public void addSwitchStateListener(ISwitchStateListener listener) {
         if (this.switchStateListener != null) {
-            logger.warn(this.switchStateListener.toString()
-                    + "already listened to switch events");
+            logger.warn("Switch events are already listened by {}",
+                    this.switchStateListener.toString());
         }
         this.switchStateListener = listener;
-        logger.debug(listener.toString() + " now listens to switch events");
+        logger.debug("Switch events are now listened by {}",
+                listener.toString());
     }
 
     @Override
     public void removeSwitchStateListener(ISwitchStateListener listener) {
         if ((this.switchStateListener != null)
                 && (this.switchStateListener == listener)) {
+            logger.debug("SwitchStateListener {} is Removed",
+                    listener.toString());
             this.switchStateListener = null;
         }
     }
@@ -227,7 +227,12 @@ public class Controller implements IController, CommandProvider {
             SwitchHandler switchHandler = new SwitchHandler(this, sc,
                     instanceName);
             switchHandler.start();
-            logger.info(instanceName + " connected: " + sc.toString());
+            if (sc.isConnected()) {
+                logger.info("Switch:{} is connected to the Controller", 
+                        sc.socket().getRemoteSocketAddress()
+                        .toString().split("/")[1]);
+            }
+
         } catch (IOException e) {
             return;
         }
@@ -237,11 +242,8 @@ public class Controller implements IController, CommandProvider {
         if (((SwitchHandler) sw).isOperational()) {
             Long sid = sw.getId();
             if (this.switches.remove(sid, sw)) {
-                logger.warn(sw.toString() + " is disconnected");
+                logger.warn("{} is Disconnected", sw.toString());
                 notifySwitchDeleted(sw);
-            } else {
-                //logger.warn(sw.toString() + " has been replaced by " +
-                //     this.switches.get(sid));
             }
         }
         ((SwitchHandler) sw).stop();
@@ -268,7 +270,7 @@ public class Controller implements IController, CommandProvider {
         }
     }
 
-    public void takeSwtichEventAdd(ISwitch sw) {
+    public void takeSwitchEventAdd(ISwitch sw) {
         SwitchEvent ev = new SwitchEvent(
                 SwitchEvent.SwitchEventType.SWITCH_ADD, sw, null);
         addSwitchEvent(ev);
@@ -317,7 +319,8 @@ public class Controller implements IController, CommandProvider {
         while (iter.hasNext()) {
             Long sid = iter.next();
             Date date = switches.get(sid).getConnectedDate();
-            String switchInstanceName = ((SwitchHandler) switches.get(sid)).getInstanceName();
+            String switchInstanceName = ((SwitchHandler) switches.get(sid))
+                    .getInstanceName();
             s.append(switchInstanceName + "/" + HexString.toHexString(sid)
                     + " connected since " + date.toString() + "\n");
         }
@@ -369,7 +372,7 @@ public class Controller implements IController, CommandProvider {
     @Override
     public String getHelp() {
         StringBuffer help = new StringBuffer();
-        help.append("-- Open Flow Controller --\n");
+        help.append("---Open Flow Controller---\n");
         help.append("\t controllerShowSwitches\n");
         help.append("\t controllerReset\n");
         help.append("\t controllerShowConnConfig\n");
index a4b7584..868e208 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
  *
@@ -40,8 +39,8 @@ public class ControllerIO {
             try {
                 openFlowPort = Short.decode(portString).shortValue();
             } catch (NumberFormatException e) {
-                logger.warn("Invalid port:" + portString + ", use default("
-                        + openFlowPort + ")");
+                logger.warn("Invalid port:{}, use default({})", portString,
+                        openFlowPort);
             }
         }
     }
@@ -72,8 +71,8 @@ public class ControllerIO {
                             SelectionKey skey = selectedKeys.next();
                             selectedKeys.remove();
                             if (skey.isValid() && skey.isAcceptable()) {
-                                 ((Controller) listener).handleNewConnection(selector,
-                                        serverSelectionKey);
+                                ((Controller) listener).handleNewConnection(
+                                        selector, serverSelectionKey);
                             }
                         }
                     } catch (Exception e) {
@@ -83,7 +82,7 @@ public class ControllerIO {
             }
         }, "ControllerI/O Thread");
         controllerIOThread.start();
-        logger.info("Controller is now listening on port " + openFlowPort);
+        logger.info("Controller is now listening on port {}", openFlowPort);
     }
 
     public void shutDown() throws IOException {
index bbf3e91..57098ae 100644 (file)
@@ -356,11 +356,6 @@ public class SwitchHandler implements ISwitch {
         }
         for (OFMessage msg : msgs) {
             logger.trace("Message received: {}", msg.toString());
-            /*
-             * if ((msg.getType() != OFType.ECHO_REQUEST) && (msg.getType() !=
-             * OFType.ECHO_REPLY)) { logger.debug(msg.getType().toString() +
-             * " received from sw " + toString()); }
-             */
             this.lastMsgReceivedTimeStamp = System.currentTimeMillis();
             OFType type = msg.getType();
             switch (type) {
@@ -422,21 +417,14 @@ public class SwitchHandler implements ISwitch {
     }
 
     private void processPortStatusMsg(OFPortStatus msg) {
-        // short portNumber = msg.getDesc().getPortNumber();
         OFPhysicalPort port = msg.getDesc();
         if (msg.getReason() == (byte) OFPortReason.OFPPR_MODIFY.ordinal()) {
             updatePhysicalPort(port);
-            // logger.debug("Port " + portNumber + " on " + toString() +
-            // " modified");
         } else if (msg.getReason() == (byte) OFPortReason.OFPPR_ADD.ordinal()) {
             updatePhysicalPort(port);
-            // logger.debug("Port " + portNumber + " on " + toString() +
-            // " added");
         } else if (msg.getReason() == (byte) OFPortReason.OFPPR_DELETE
                 .ordinal()) {
             deletePhysicalPort(port);
-            // logger.debug("Port " + portNumber + " on " + toString() +
-            // " deleted");
         }
 
     }
@@ -457,8 +445,9 @@ public class SwitchHandler implements ISwitch {
                             reportSwitchStateChange(false);
                         } else {
                             // send a probe to see if the switch is still alive
-                            // logger.debug("Send idle probe (Echo Request) to "
-                            // + switchName());
+                            logger.debug(
+                                    "Send idle probe (Echo Request) to {}",
+                                    toString());
                             probeSent = true;
                             OFMessage echo = factory
                                     .getMessage(OFType.ECHO_REQUEST);
@@ -500,8 +489,7 @@ public class SwitchHandler implements ISwitch {
     private void reportError(Exception e) {
         if (e instanceof AsynchronousCloseException
                 || e instanceof InterruptedException
-                || e instanceof SocketException
-                || e instanceof IOException) {
+                || e instanceof SocketException || e instanceof IOException) {
             logger.debug("Caught exception {}", e.getMessage());
         } else {
             logger.warn("Caught exception ", e);
@@ -512,7 +500,7 @@ public class SwitchHandler implements ISwitch {
 
     private void reportSwitchStateChange(boolean added) {
         if (added) {
-            ((Controller) core).takeSwtichEventAdd(this);
+            ((Controller) core).takeSwitchEventAdd(this);
         } else {
             ((Controller) core).takeSwitchEventDelete(this);
         }
@@ -567,7 +555,7 @@ public class SwitchHandler implements ISwitch {
                                                 .getValue()
                                         | OFPortFeatures.OFPPF_1GB_HD
                                                 .getValue() | OFPortFeatures.OFPPF_10GB_FD
-                                        .getValue()));
+                                            .getValue()));
     }
 
     private void deletePhysicalPort(OFPhysicalPort port) {
@@ -583,11 +571,16 @@ public class SwitchHandler implements ISwitch {
 
     @Override
     public String toString() {
-        return ("["
-                + this.socket.toString()
-                + " SWID "
-                + (isOperational() ? HexString.toHexString(this.sid)
-                        : "unkbown") + "]");
+        try {
+            return ("Switch:"
+                    + socket.socket().getRemoteSocketAddress().toString().split("/")[1]
+                    + " SWID:" + (isOperational() ? HexString
+                    .toHexString(this.sid) : "unknown"));
+        } catch (Exception e) {
+            return (isOperational() ? HexString.toHexString(this.sid)
+                    : "unknown");
+        }
+
     }
 
     @Override
@@ -823,14 +816,14 @@ public class SwitchHandler implements ISwitch {
     }
 
     /**
-     * Sends synchronous Barrier message 
+     * Sends synchronous Barrier message
      */
     @Override
     public Object sendBarrierMessage() {
         OFBarrierRequest barrierMsg = new OFBarrierRequest();
-        return syncSend(barrierMsg);        
+        return syncSend(barrierMsg);
     }
-    
+
     /**
      * This method returns the switch liveness timeout value. If controller did
      * not receive any message from the switch for such a long period,
index 7a09a48..abad0b2 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
  *
@@ -11,19 +10,22 @@ package org.opendaylight.controller.protocol_plugin.openflow.internal;
 
 import java.util.List;
 
+import org.opendaylight.controller.sal.reader.NodeDescription;
 import org.openflow.protocol.statistics.OFDescriptionStatistics;
 import org.openflow.protocol.statistics.OFStatistics;
-
-import org.opendaylight.controller.sal.reader.NodeDescription;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
- * Utility class for converting openflow description statistics
- * into SAL NodeDescription object
- *
- *
- *
+ * Utility class for converting openflow description statistics into SAL
+ * NodeDescription object
+ * 
+ * 
+ * 
  */
 public class DescStatisticsConverter {
+    private static final Logger log = LoggerFactory
+            .getLogger(DescStatisticsConverter.class);
     NodeDescription hwDesc;
     OFDescriptionStatistics ofDesc;
 
@@ -41,6 +43,8 @@ public class DescStatisticsConverter {
             hwDesc.setDescription(ofDesc.getDatapathDescription());
             hwDesc.setSerialNumber(ofDesc.getSerialNumber());
         }
+        log.trace("OFDescriptionStatistics: {}", ofDesc);
+        log.trace("NodeDescription: {}", hwDesc);
         return hwDesc;
     }
 
index 6379b5d..074774a 100644 (file)
@@ -16,29 +16,6 @@ import java.util.List;
 
 import org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension.V6FlowMod;
 import org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension.V6Match;
-import org.openflow.protocol.OFFlowMod;
-import org.openflow.protocol.OFMatch;
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFPacketOut;
-import org.openflow.protocol.OFPort;
-import org.openflow.protocol.OFVendor;
-import org.openflow.protocol.action.OFAction;
-import org.openflow.protocol.action.OFActionDataLayerDestination;
-import org.openflow.protocol.action.OFActionDataLayerSource;
-import org.openflow.protocol.action.OFActionNetworkLayerAddress;
-import org.openflow.protocol.action.OFActionNetworkLayerDestination;
-import org.openflow.protocol.action.OFActionNetworkLayerSource;
-import org.openflow.protocol.action.OFActionNetworkTypeOfService;
-import org.openflow.protocol.action.OFActionOutput;
-import org.openflow.protocol.action.OFActionStripVirtualLan;
-import org.openflow.protocol.action.OFActionTransportLayer;
-import org.openflow.protocol.action.OFActionTransportLayerDestination;
-import org.openflow.protocol.action.OFActionTransportLayerSource;
-import org.openflow.protocol.action.OFActionVirtualLanIdentifier;
-import org.openflow.protocol.action.OFActionVirtualLanPriorityCodePoint;
-import org.openflow.util.U16;
-import org.openflow.util.U32;
-
 import org.opendaylight.controller.sal.action.Action;
 import org.opendaylight.controller.sal.action.ActionType;
 import org.opendaylight.controller.sal.action.Controller;
@@ -67,6 +44,28 @@ import org.opendaylight.controller.sal.match.MatchField;
 import org.opendaylight.controller.sal.match.MatchType;
 import org.opendaylight.controller.sal.utils.NetUtils;
 import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
+import org.openflow.protocol.OFFlowMod;
+import org.openflow.protocol.OFMatch;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFPacketOut;
+import org.openflow.protocol.OFPort;
+import org.openflow.protocol.OFVendor;
+import org.openflow.protocol.action.OFAction;
+import org.openflow.protocol.action.OFActionDataLayerDestination;
+import org.openflow.protocol.action.OFActionDataLayerSource;
+import org.openflow.protocol.action.OFActionNetworkLayerAddress;
+import org.openflow.protocol.action.OFActionNetworkLayerDestination;
+import org.openflow.protocol.action.OFActionNetworkLayerSource;
+import org.openflow.protocol.action.OFActionNetworkTypeOfService;
+import org.openflow.protocol.action.OFActionOutput;
+import org.openflow.protocol.action.OFActionStripVirtualLan;
+import org.openflow.protocol.action.OFActionTransportLayer;
+import org.openflow.protocol.action.OFActionTransportLayerDestination;
+import org.openflow.protocol.action.OFActionTransportLayerSource;
+import org.openflow.protocol.action.OFActionVirtualLanIdentifier;
+import org.openflow.protocol.action.OFActionVirtualLanPriorityCodePoint;
+import org.openflow.util.U16;
+import org.openflow.util.U32;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -75,7 +74,7 @@ import org.slf4j.LoggerFactory;
  */
 public class FlowConverter {
     protected static final Logger logger = LoggerFactory
-    .getLogger(FlowConverter.class);
+            .getLogger(FlowConverter.class);
     private Flow flow; // SAL Flow
     private OFMatch ofMatch; // OF 1.0 match or OF 1.0 + IPv6 extension match
     private List<OFAction> actionsList; // OF 1.0 actions
@@ -256,7 +255,8 @@ public class FlowConverter {
                 ofMatch.setWildcards(U32.t(Long.valueOf(wildcards)));
             }
         }
-
+        logger.trace("SAL Match: {} Openflow Match: {}", flow.getMatch(),
+                ofMatch);
         return ofMatch;
     }
 
@@ -416,6 +416,8 @@ public class FlowConverter {
                 }
             }
         }
+        logger.trace("SAL Actions: {} Openflow Actions: {}", flow.getActions(),
+                actionsList);
         return actionsList;
     }
 
@@ -483,6 +485,9 @@ public class FlowConverter {
                 }
             }
         }
+        logger.trace("Openflow Match: {} Openflow Actions: {}", ofMatch,
+                actionsList);
+        logger.trace("Openflow Mod Message: {}", fm);
         return fm;
     }
 
@@ -684,7 +689,7 @@ public class FlowConverter {
                         try {
                             ip = InetAddress.getByAddress(addr);
                         } catch (UnknownHostException e) {
-                            logger.error("",e);
+                            logger.error("", e);
                         }
                         salAction = new SetNwSrc(ip);
                     } else if (ofAction instanceof OFActionNetworkLayerDestination) {
@@ -695,7 +700,7 @@ public class FlowConverter {
                         try {
                             ip = InetAddress.getByAddress(addr);
                         } catch (UnknownHostException e) {
-                            logger.error("",e);
+                            logger.error("", e);
                         }
                         salAction = new SetNwDst(ip);
                     } else if (ofAction instanceof OFActionNetworkTypeOfService) {
@@ -719,6 +724,9 @@ public class FlowConverter {
             // Create Flow
             flow = new Flow(salMatch, salActionList);
         }
+        logger.trace("Openflow Match: {} Openflow Actions: {}", ofMatch,
+                actionsList);
+        logger.trace("SAL Flow: {}", flow);
         return flow;
     }
 
index 4d3dca1..1d19c8b 100644 (file)
@@ -8,7 +8,6 @@
 
 package org.opendaylight.controller.protocol_plugin.openflow.internal;
 
-import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -24,15 +23,6 @@ import org.opendaylight.controller.protocol_plugin.openflow.IInventoryShimExtern
 import org.opendaylight.controller.protocol_plugin.openflow.core.IController;
 import org.opendaylight.controller.protocol_plugin.openflow.core.IMessageListener;
 import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitch;
-import org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension.V6Error;
-import org.openflow.protocol.OFError;
-import org.openflow.protocol.OFFlowMod;
-import org.openflow.protocol.OFFlowRemoved;
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFPort;
-import org.openflow.protocol.OFType;
-import org.openflow.protocol.action.OFAction;
-
 import org.opendaylight.controller.sal.core.ContainerFlow;
 import org.opendaylight.controller.sal.core.IContainerListener;
 import org.opendaylight.controller.sal.core.Node;
@@ -47,8 +37,15 @@ import org.opendaylight.controller.sal.match.MatchType;
 import org.opendaylight.controller.sal.utils.GlobalConstants;
 import org.opendaylight.controller.sal.utils.HexEncode;
 import org.opendaylight.controller.sal.utils.NodeCreator;
-import org.opendaylight.controller.sal.utils.StatusCode;
 import org.opendaylight.controller.sal.utils.Status;
+import org.opendaylight.controller.sal.utils.StatusCode;
+import org.openflow.protocol.OFError;
+import org.openflow.protocol.OFFlowMod;
+import org.openflow.protocol.OFFlowRemoved;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFPort;
+import org.openflow.protocol.OFType;
+import org.openflow.protocol.action.OFAction;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.FrameworkUtil;
 import org.slf4j.Logger;
@@ -208,22 +205,11 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService,
                 }
                 if (result instanceof Boolean) {
                     return ((Boolean) result == Boolean.TRUE) ? new Status(
-                            StatusCode.SUCCESS, null) : new Status(
+                            StatusCode.SUCCESS, rid) : new Status(
                             StatusCode.TIMEOUT, errorString(null, action,
                                     "Request Timed Out"));
                 } else if (result instanceof OFError) {
                     OFError res = (OFError) result;
-                    if (res.getErrorType() == V6Error.NICIRA_VENDOR_ERRORTYPE) {
-                        V6Error er = new V6Error(res);
-                        byte[] b = res.getError();
-                        ByteBuffer bb = ByteBuffer.allocate(b.length);
-                        bb.put(b);
-                        bb.rewind();
-                        er.readFrom(bb);
-                        return new Status(StatusCode.INTERNALERROR,
-                                errorString("program", action,
-                                        "Vendor Extension Internal Error"));
-                    }
                     return new Status(StatusCode.INTERNALERROR, errorString(
                             "program", action, Utils.getOFErrorString(res)));
                 } else {
@@ -286,7 +272,7 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService,
                         return new Status(StatusCode.TIMEOUT, errorString(null,
                                 action, "Request Timed Out"));
                     } else if (msg2 == null) {
-                        return new Status(StatusCode.SUCCESS, null);
+                        return new Status(StatusCode.SUCCESS, rid);
                     }
                 } else if (result instanceof OFError) {
                     return new Status(StatusCode.INTERNALERROR, errorString(
@@ -315,7 +301,7 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService,
                     }
                     if (result instanceof Boolean) {
                         return ((Boolean) result == Boolean.TRUE) ? new Status(
-                                StatusCode.SUCCESS, null) : new Status(
+                                StatusCode.SUCCESS, rid) : new Status(
                                 StatusCode.TIMEOUT, errorString(null, action,
                                         "Request Timed Out"));
                     } else if (result instanceof OFError) {
@@ -364,7 +350,7 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService,
                 }
                 if (result instanceof Boolean) {
                     return ((Boolean) result == Boolean.TRUE) ? new Status(
-                            StatusCode.SUCCESS, null) : new Status(
+                            StatusCode.SUCCESS, rid) : new Status(
                             StatusCode.TIMEOUT, errorString(null, action,
                                     "Request Timed Out"));
                 } else if (result instanceof OFError) {
@@ -445,7 +431,20 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService,
             xid = errorMsg.getXid();
         }
 
-        long rid = getMessageRid(sw.getId(), xid);
+        Long rid = getMessageRid(sw.getId(), xid);
+        /*
+         * Null or zero requestId indicates that the error message is meant for
+         * a sync message. It will be handled by the sync message worker thread.
+         * Hence we are done here.
+         */
+        if ((rid == null) || (rid == 0)) {
+            return;
+        }
+        
+        /*
+         * Notifies the caller that error has been reported for a previous flow
+         * programming request
+         */
         for (Map.Entry<String, IFlowProgrammerNotifier> containerNotifier : flowProgrammerNotifiers
                 .entrySet()) {
             IFlowProgrammerNotifier notifier = containerNotifier.getValue();
@@ -585,10 +584,14 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService,
      *            The OF message xid
      * @return The Request ID
      */
-    public long getMessageRid(long swid, int xid) {
+    private Long getMessageRid(long swid, Integer xid) {
+        Long rid = null;
+
+        if (xid == null) {
+            return rid;
+        }
+
         Map<Integer, Long> swxid2rid = this.xid2rid.get(swid);
-        long rid = 0;
-        
         if (swxid2rid != null) {
             rid = swxid2rid.get(xid);
         }
index 72482f0..7afe6ce 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
  *
@@ -13,20 +12,24 @@ import java.util.ArrayList;
 import java.util.List;
 
 import org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension.V6StatsReply;
-import org.openflow.protocol.statistics.OFFlowStatisticsReply;
-import org.openflow.protocol.statistics.OFStatistics;
-
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.flowprogrammer.Flow;
 import org.opendaylight.controller.sal.reader.FlowOnNode;
+import org.openflow.protocol.statistics.OFFlowStatisticsReply;
+import org.openflow.protocol.statistics.OFStatistics;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
- * Converts an openflow list of flow statistics in a SAL list of FlowOnNode objects
- *
- *
- *
+ * Converts an openflow list of flow statistics in a SAL list of FlowOnNode
+ * objects
+ * 
+ * 
+ * 
  */
 public class FlowStatisticsConverter {
+    private static final Logger log = LoggerFactory
+            .getLogger(FlowStatisticsConverter.class);
     private List<OFStatistics> ofStatsList;
     private List<FlowOnNode> flowOnNodeList;
 
@@ -34,7 +37,8 @@ public class FlowStatisticsConverter {
         if (statsList == null) {// || statsList.isEmpty()) {
             this.ofStatsList = new ArrayList<OFStatistics>(1); // dummy list
         } else {
-            this.ofStatsList = statsList; //new ArrayList<OFStatistics>(statsList);
+            this.ofStatsList = statsList; // new
+                                          // ArrayList<OFStatistics>(statsList);
         }
         this.flowOnNodeList = null;
     }
@@ -83,6 +87,8 @@ public class FlowStatisticsConverter {
                 flowOnNodeList.add(flowOnNode);
             }
         }
+        log.trace("OFStatistics: {} FlowOnNode: {}", ofStatsList,
+                flowOnNodeList);
         return flowOnNodeList;
     }
 }
index 73dcea5..98a2962 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
  *
@@ -63,9 +62,9 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * It periodically polls the different OF statistics from the OF switches
- * and caches them for quick retrieval for the above layers' modules
- * It also provides an API to directly query the switch about the statistics
+ * It periodically polls the different OF statistics from the OF switches and
+ * caches them for quick retrieval for the above layers' modules It also
+ * provides an API to directly query the switch about the statistics
  */
 public class OFStatisticsManager implements IOFStatisticsManager,
         IInventoryShimExternalListener, CommandProvider {
@@ -94,15 +93,18 @@ public class OFStatisticsManager implements IOFStatisticsManager,
     private Timer statisticsTimer;
     private TimerTask statisticsTimerTask;
     private ConcurrentMap<Long, Boolean> switchSupportsVendorExtStats;
-    private Map<Long, Map<Short, TxRates>> txRates; // Per port sampled (every portStatsPeriod) transmit rate
+    private Map<Long, Map<Short, TxRates>> txRates; // Per port sampled (every
+                                                    // portStatsPeriod) transmit
+                                                    // rate
     private Set<IStatisticsListener> descriptionListeners;
 
     /**
-     * The object containing the latest factoredSamples tx rate samples
-     * for a given switch port
+     * The object containing the latest factoredSamples tx rate samples for a
+     * given switch port
      */
     protected class TxRates {
-        Deque<Long> sampledTxBytes; // contains the latest factoredSamples sampled transmitted bytes
+        Deque<Long> sampledTxBytes; // contains the latest factoredSamples
+                                    // sampled transmitted bytes
 
         public TxRates() {
             sampledTxBytes = new LinkedBlockingDeque<Long>();
@@ -110,8 +112,8 @@ public class OFStatisticsManager implements IOFStatisticsManager,
 
         public void update(Long txBytes) {
             /*
-             * Based on how many samples our average works on,
-             * we might have to remove the oldest sample
+             * Based on how many samples our average works on, we might have to
+             * remove the oldest sample
              */
             if (sampledTxBytes.size() == factoredSamples) {
                 sampledTxBytes.removeLast();
@@ -123,6 +125,7 @@ public class OFStatisticsManager implements IOFStatisticsManager,
 
         /**
          * Returns the average transmit rate in bps
+         * 
          * @return the average transmit rate [bps]
          */
         public long getAverageTxRate() {
@@ -155,10 +158,10 @@ public class OFStatisticsManager implements IOFStatisticsManager,
     /**
      * Function called by the dependency manager when all the required
      * dependencies are satisfied
-     *
+     * 
      */
     void init() {
-       flowStatistics = new ConcurrentHashMap<Long, List<OFStatistics>>();
+        flowStatistics = new ConcurrentHashMap<Long, List<OFStatistics>>();
         descStatistics = new ConcurrentHashMap<Long, List<OFStatistics>>();
         portStatistics = new ConcurrentHashMap<Long, List<OFStatistics>>();
         dummyList = new ArrayList<OFStatistics>(1);
@@ -190,8 +193,8 @@ public class OFStatisticsManager implements IOFStatisticsManager,
                         StatsRequest req = pendingStatsRequests.take();
                         acquireStatistics(req.switchId, req.type);
                     } catch (InterruptedException e) {
-                        log.warn("Flow Statistics Collector thread " +
-                                       "interrupted");
+                        log.warn("Flow Statistics Collector thread "
+                                + "interrupted", e);
                     }
                 }
             }
@@ -206,7 +209,7 @@ public class OFStatisticsManager implements IOFStatisticsManager,
                         long switchId = switchPortStatsUpdated.take();
                         updatePortsTxRate(switchId);
                     } catch (InterruptedException e) {
-                        log.warn("TX Rate Updater thread interrupted");
+                        log.warn("TX Rate Updater thread interrupted", e);
                     }
                 }
             }
@@ -214,19 +217,18 @@ public class OFStatisticsManager implements IOFStatisticsManager,
     }
 
     /**
-     * Function called by the dependency manager when at least one
-     * dependency become unsatisfied or when the component is shutting
-     * down because for example bundle is being stopped.
-     *
+     * Function called by the dependency manager when at least one dependency
+     * become unsatisfied or when the component is shutting down because for
+     * example bundle is being stopped.
+     * 
      */
     void destroy() {
     }
 
     /**
-     * Function called by dependency manager after "init ()" is called
-     * and after the services provided by the class are registered in
-     * the service registry
-     *
+     * Function called by dependency manager after "init ()" is called and after
+     * the services provided by the class are registered in the service registry
+     * 
      */
     void start() {
         // Start managed timers
@@ -243,10 +245,10 @@ public class OFStatisticsManager implements IOFStatisticsManager,
     }
 
     /**
-     * Function called by the dependency manager before the services
-     * exported by the component are unregistered, this will be
-     * followed by a "destroy ()" calls
-     *
+     * Function called by the dependency manager before the services exported by
+     * the component are unregistered, this will be followed by a "destroy ()"
+     * calls
+     * 
      */
     void stop() {
         // Stop managed timers
@@ -254,15 +256,15 @@ public class OFStatisticsManager implements IOFStatisticsManager,
     }
 
     public void setStatisticsListener(IStatisticsListener s) {
-       this.descriptionListeners.add(s);
+        this.descriptionListeners.add(s);
     }
-    
+
     public void unsetStatisticsListener(IStatisticsListener s) {
-       if (s != null) {
-               this.descriptionListeners.remove(s);
-       }
+        if (s != null) {
+            this.descriptionListeners.remove(s);
+        }
     }
-    
+
     private void registerWithOSGIConsole() {
         BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass())
                 .getBundleContext();
@@ -320,10 +322,15 @@ public class OFStatisticsManager implements IOFStatisticsManager,
     }
 
     private void addStatisticsTicks(Long switchId) {
-        switchSupportsVendorExtStats.put(switchId, Boolean.TRUE); // Assume switch supports Vendor extension stats
+        switchSupportsVendorExtStats.put(switchId, Boolean.TRUE); // Assume
+                                                                  // switch
+                                                                  // supports
+                                                                  // Vendor
+                                                                  // extension
+                                                                  // stats
         statisticsTimerTicks.put(switchId, new StatisticsTicks(true));
-        log.info("Added Switch {} to target pool", HexString
-                .toHexString(switchId.longValue()));
+        log.info("Added Switch {} to target pool",
+                HexString.toHexString(switchId.longValue()));
     }
 
     protected static class StatisticsTicks {
@@ -349,7 +356,8 @@ public class OFStatisticsManager implements IOFStatisticsManager,
         }
 
         public boolean decrementFlowTicksIsZero() {
-            // Please ensure no code is inserted between the if check and the flowStatisticsTicks reset
+            // Please ensure no code is inserted between the if check and the
+            // flowStatisticsTicks reset
             if (--flowStatisticsTicks == 0) {
                 flowStatisticsTicks = statisticsTickNumber;
                 return true;
@@ -358,7 +366,8 @@ public class OFStatisticsManager implements IOFStatisticsManager,
         }
 
         public boolean decrementDescTicksIsZero() {
-            // Please ensure no code is inserted between the if check and the descriptionTicks reset
+            // Please ensure no code is inserted between the if check and the
+            // descriptionTicks reset
             if (--descriptionTicks == 0) {
                 descriptionTicks = descriptionTickNumber;
                 return true;
@@ -367,7 +376,8 @@ public class OFStatisticsManager implements IOFStatisticsManager,
         }
 
         public boolean decrementPortTicksIsZero() {
-            // Please ensure no code is inserted between the if check and the descriptionTicks reset
+            // Please ensure no code is inserted between the if check and the
+            // descriptionTicks reset
             if (--portStatisticsTicks == 0) {
                 portStatisticsTicks = portTickNumber;
                 return true;
@@ -382,13 +392,11 @@ public class OFStatisticsManager implements IOFStatisticsManager,
     }
 
     private void printInfoMessage(String type, StatsRequest request) {
-        log
-                .info(
-                        type
-                                + " stats request not inserted for switch: {}. Queue size: {}. Collector state: {}.",
-                        new Object[] { HexString.toHexString(request.switchId),
-                                pendingStatsRequests.size(),
-                                statisticsCollector.getState().toString() });
+        log.info(
+                "{} stats request not inserted for switch: {}. Queue size: {}. Collector state: {}.",
+                new Object[] { type, HexString.toHexString(request.switchId),
+                        pendingStatsRequests.size(),
+                        statisticsCollector.getState().toString() });
     }
 
     protected void decrementTicks() {
@@ -399,9 +407,10 @@ public class OFStatisticsManager implements IOFStatisticsManager,
             Long switchId = entry.getKey();
             if (clock.decrementFlowTicksIsZero() == true) {
                 request = (switchSupportsVendorExtStats.get(switchId) == Boolean.TRUE) ? new StatsRequest(
-                        switchId, OFStatisticsType.VENDOR)
-                        : new StatsRequest(switchId, OFStatisticsType.FLOW);
-                // If a request for this switch is already in the queue, skip to add this new request
+                        switchId, OFStatisticsType.VENDOR) : new StatsRequest(
+                        switchId, OFStatisticsType.FLOW);
+                // If a request for this switch is already in the queue, skip to
+                // add this new request
                 if (!pendingStatsRequests.contains(request)
                         && false == pendingStatsRequests.offer(request)) {
                     printInfoMessage("Flow", request);
@@ -410,7 +419,8 @@ public class OFStatisticsManager implements IOFStatisticsManager,
 
             if (clock.decrementDescTicksIsZero() == true) {
                 request = new StatsRequest(switchId, OFStatisticsType.DESC);
-                // If a request for this switch is already in the queue, skip to add this new request
+                // If a request for this switch is already in the queue, skip to
+                // add this new request
                 if (!pendingStatsRequests.contains(request)
                         && false == pendingStatsRequests.offer(request)) {
                     printInfoMessage("Description", request);
@@ -419,7 +429,8 @@ public class OFStatisticsManager implements IOFStatisticsManager,
 
             if (clock.decrementPortTicksIsZero() == true) {
                 request = new StatsRequest(switchId, OFStatisticsType.PORT);
-                // If a request for this switch is already in the queue, skip to add this new request
+                // If a request for this switch is already in the queue, skip to
+                // add this new request
                 if (!pendingStatsRequests.contains(request)
                         && false == pendingStatsRequests.offer(request)) {
                     printInfoMessage("Port", request);
@@ -429,9 +440,10 @@ public class OFStatisticsManager implements IOFStatisticsManager,
     }
 
     private void removeStatsRequestTasks(Long switchId) {
-        log.info("Cleaning Statistics database for switch "
-                + HexEncode.longToHexString(switchId));
-        // To be safe, let's attempt removal of both VENDOR and FLOW request. It does not hurt
+        log.info("Cleaning Statistics database for switch {}",
+                HexEncode.longToHexString(switchId));
+        // To be safe, let's attempt removal of both VENDOR and FLOW request. It
+        // does not hurt
         pendingStatsRequests.remove(new StatsRequest(switchId,
                 OFStatisticsType.VENDOR));
         pendingStatsRequests.remove(new StatsRequest(switchId,
@@ -449,8 +461,8 @@ public class OFStatisticsManager implements IOFStatisticsManager,
         statisticsTimerTicks.remove(switchId);
         removeStatsRequestTasks(switchId);
         flowStatistics.remove(switchId);
-        log.info("Statistics removed for switch "
-                HexString.toHexString(switchId));
+        log.info("Statistics removed for switch {}",
+                HexString.toHexString(switchId));
     }
 
     private void acquireStatistics(Long switchId, OFStatisticsType statType) {
@@ -465,29 +477,30 @@ public class OFStatisticsManager implements IOFStatisticsManager,
                     || (statType == OFStatisticsType.VENDOR)) {
                 flowStatistics.put(switchId, values);
             } else if (statType == OFStatisticsType.DESC) {
-               // Notify who may be interested in a description change
-                       notifyDescriptionListeners(switchId, values);
-               
+                // Notify who may be interested in a description change
+                notifyDescriptionListeners(switchId, values);
+
                 // Overwrite cache
                 descStatistics.put(switchId, values);
             } else if (statType == OFStatisticsType.PORT) {
                 // Overwrite cache with new port statistics for this switch
                 portStatistics.put(switchId, values);
 
-                // Wake up the thread which maintains the TX byte counters for each port
+                // Wake up the thread which maintains the TX byte counters for
+                // each port
                 switchPortStatsUpdated.offer(switchId);
             }
         }
     }
 
     private void notifyDescriptionListeners(Long switchId,
-                                                               List<OFStatistics> values) {
-               for (IStatisticsListener l : this.descriptionListeners) {
-                       l.descriptionRefreshed(switchId, 
-                                       ((OFDescriptionStatistics)values.get(0)));
-               }
+            List<OFStatistics> values) {
+        for (IStatisticsListener l : this.descriptionListeners) {
+            l.descriptionRefreshed(switchId,
+                    ((OFDescriptionStatistics) values.get(0)));
+        }
     }
-    
+
     /*
      * Generic function to get the statistics form a OF switch
      */
@@ -511,8 +524,8 @@ public class OFStatisticsManager implements IOFStatisticsManager,
                     match.setWildcards(0xffffffff);
                 } else if (!(target instanceof OFMatch)) {
                     // Malformed request
-                    log.warn("Invalid target type for Flow stats request: "
-                            target.getClass());
+                    log.warn("Invalid target type for Flow stats request: {}",
+                            target.getClass());
                     return null;
                 } else {
                     // Specific flow request
@@ -552,8 +565,8 @@ public class OFStatisticsManager implements IOFStatisticsManager,
                     targetPort = (short) OFPort.OFPP_NONE.getValue();
                 } else if (!(target instanceof Short)) {
                     // Malformed request
-                    log.warn("Invalid target type for Port stats request: "
-                            target.getClass());
+                    log.warn("Invalid target type for Port stats request: {}",
+                            target.getClass());
                     return null;
                 } else {
                     // Specific port request
@@ -585,14 +598,13 @@ public class OFStatisticsManager implements IOFStatisticsManager,
                 log.warn("Request Timed Out for ({}) from switch {}", type,
                         HexString.toHexString(switchId));
             } else if (result instanceof OFError) {
-                log.warn("Switch {} failed to handle ({}) stats request: "
-                        + Utils.getOFErrorString((OFError) result), HexString
-                        .toHexString(switchId), type);
+                log.warn("Switch {} failed to handle ({}) stats request: {}",
+                        new Object[] { HexString.toHexString(switchId), type,
+                                Utils.getOFErrorString((OFError) result) });
                 if (this.switchSupportsVendorExtStats.get(switchId) == Boolean.TRUE) {
-                    log
-                            .warn(
-                                    "Switching back to regular Flow stats requests for switch {}",
-                                    HexString.toHexString(switchId));
+                    log.warn(
+                            "Switching back to regular Flow stats requests for switch {}",
+                            HexString.toHexString(switchId));
                     this.switchSupportsVendorExtStats.put(switchId,
                             Boolean.FALSE);
                 }
@@ -608,8 +620,8 @@ public class OFStatisticsManager implements IOFStatisticsManager,
         List<OFStatistics> list = flowStatistics.get(switchId);
 
         /*
-         *  Check on emptiness as interference between add and get is still
-         *  possible on the inner list (the concurrentMap entry's value)
+         * Check on emptiness as interference between add and get is still
+         * possible on the inner list (the concurrentMap entry's value)
          */
         return (list == null || list.isEmpty()) ? this.dummyList
                 : (list.get(0) instanceof OFVendorStatistics) ? this
@@ -621,8 +633,8 @@ public class OFStatisticsManager implements IOFStatisticsManager,
         List<OFStatistics> statsList = flowStatistics.get(switchId);
 
         /*
-         *  Check on emptiness as interference between add and get is still
-         *  possible on the inner list (the concurrentMap entry's value)
+         * Check on emptiness as interference between add and get is still
+         * possible on the inner list (the concurrentMap entry's value)
          */
         if (statsList == null || statsList.isEmpty()) {
             return this.dummyList;
@@ -630,10 +642,10 @@ public class OFStatisticsManager implements IOFStatisticsManager,
 
         if (statsList.get(0) instanceof OFVendorStatistics) {
             /*
-             * Caller could provide regular OF match when we
-             * instead pull the vendor statistics from this node
-             * Caller is not supposed to know whether this switch supports
-             * vendor extensions statistics requests
+             * Caller could provide regular OF match when we instead pull the
+             * vendor statistics from this node Caller is not supposed to know
+             * whether this switch supports vendor extensions statistics
+             * requests
              */
             V6Match targetMatch = (ofMatch instanceof V6Match) ? (V6Match) ofMatch
                     : new V6Match(ofMatch);
@@ -689,19 +701,18 @@ public class OFStatisticsManager implements IOFStatisticsManager,
         ByteBuffer data = ByteBuffer.allocate(length);
         stat.writeTo(data);
         data.rewind();
-        log.trace("getV6ReplyStatistics: Buffer BYTES ARE {}", HexString
-                .toHexString(data.array()));
+        log.trace("getV6ReplyStatistics: Buffer BYTES ARE {}",
+                HexString.toHexString(data.array()));
 
-        int vendor = data.getInt(); //first 4 bytes is vendor id.
+        int vendor = data.getInt(); // first 4 bytes is vendor id.
         if (vendor != V6StatsRequest.NICIRA_VENDOR_ID) {
-            log
-                    .debug("Unexpected vendor id: 0x{}", Integer
-                            .toHexString(vendor));
+            log.warn("Unexpected vendor id: 0x{}", Integer.toHexString(vendor));
             return null;
         } else {
-            //go ahead by 8 bytes which is 8 bytes of 0
-            data.getLong(); //should be all 0's
-            length -= 12; // 4 bytes Nicira Hdr + 8 bytes from above line have been consumed
+            // go ahead by 8 bytes which is 8 bytes of 0
+            data.getLong(); // should be all 0's
+            length -= 12; // 4 bytes Nicira Hdr + 8 bytes from above line have
+                          // been consumed
         }
 
         V6StatsReply v6statsreply;
@@ -727,8 +738,8 @@ public class OFStatisticsManager implements IOFStatisticsManager,
     public List<OFStatistics> queryStatistics(Long switchId,
             OFStatisticsType statType, Object target) {
         /*
-         * Caller does not know and it is not supposed to know whether
-         * this switch supports vendor extension. We adjust the target for him
+         * Caller does not know and it is not supposed to know whether this
+         * switch supports vendor extension. We adjust the target for him
          */
         if (statType == OFStatisticsType.FLOW) {
             if (switchSupportsVendorExtStats.get(switchId) == Boolean.TRUE) {
@@ -782,7 +793,8 @@ public class OFStatisticsManager implements IOFStatisticsManager,
     }
 
     /*
-     * InventoryShim replay for us all the switch addition which happened before we were brought up
+     * InventoryShim replay for us all the switch addition which happened before
+     * we were brought up
      */
     @Override
     public void updateNode(Node node, UpdateType type, Set<Property> props) {
@@ -804,8 +816,9 @@ public class OFStatisticsManager implements IOFStatisticsManager,
     }
 
     /**
-     * Update the cached port rates for this switch with the latest
-     * retrieved port transmit byte count
+     * Update the cached port rates for this switch with the latest retrieved
+     * port transmit byte count
+     * 
      * @param switchId
      */
     private synchronized void updatePortsTxRate(long switchId) {
@@ -861,8 +874,8 @@ public class OFStatisticsManager implements IOFStatisticsManager,
     public String getHelp() {
         StringBuffer help = new StringBuffer();
         help.append("---OF Statistics Manager utilities---\n");
-        help.append("\t ofdumpstatsmgr         - " + 
-                               "Print Internal Stats Mgr db\n");
+        help.append("\t ofdumpstatsmgr         - "
+                + "Print Internal Stats Mgr db\n");
         return help.toString();
     }
 
@@ -909,9 +922,7 @@ public class OFStatisticsManager implements IOFStatisticsManager,
 
     public void _ofdumpstatsmgr(CommandInterpreter ci) {
         ci.println("Global Counter: " + counter);
-        ci
-                .println("Timer Ticks: "
-                        + prettyPrintSwitchMap(statisticsTimerTicks));
+        ci.println("Timer Ticks: " + prettyPrintSwitchMap(statisticsTimerTicks));
         ci.println("PendingStatsQueue: " + pendingStatsRequests);
         ci.println("PendingStatsQueue size: " + pendingStatsRequests.size());
         ci.println("Stats Collector alive: " + statisticsCollector.isAlive());
@@ -973,10 +984,9 @@ public class OFStatisticsManager implements IOFStatisticsManager,
         String averageWindow = ci.nextArgument();
         short seconds = 0;
         if (averageWindow == null) {
-            ci.println("Insert the length in seconds of the median " + 
-                       "window for tx rate");
-            ci.println("Current: " + factoredSamples * portTickNumber
-                            + " secs");
+            ci.println("Insert the length in seconds of the median "
+                    + "window for tx rate");
+            ci.println("Current: " + factoredSamples * portTickNumber + " secs");
             return;
         }
         try {
@@ -984,40 +994,40 @@ public class OFStatisticsManager implements IOFStatisticsManager,
         } catch (NumberFormatException e) {
             ci.println("Invalid period.");
         }
-        OFStatisticsManager.factoredSamples = (short) (seconds/portTickNumber);
+        OFStatisticsManager.factoredSamples = (short) (seconds / portTickNumber);
         ci.println("New: " + factoredSamples * portTickNumber + " secs");
     }
 
     public void _ofstatsmgrintervals(CommandInterpreter ci) {
         String flowStatsInterv = ci.nextArgument();
         String portStatsInterv = ci.nextArgument();
-        
+
         if (flowStatsInterv == null || portStatsInterv == null) {
 
             ci.println("Usage: ostatsmgrintervals <fP> <pP> (in seconds)");
-            ci.println("Current Values: fP=" + statisticsTickNumber +
-                       "s pP=" + portTickNumber + "s");
+            ci.println("Current Values: fP=" + statisticsTickNumber + "s pP="
+                    + portTickNumber + "s");
             return;
         }
         Short fP, pP;
         try {
-               fP = Short.parseShort(flowStatsInterv);
-               pP = Short.parseShort(portStatsInterv);
+            fP = Short.parseShort(flowStatsInterv);
+            pP = Short.parseShort(portStatsInterv);
         } catch (Exception e) {
-               ci.println("Invalid format values: " + e.getMessage());
-               return;
+            ci.println("Invalid format values: " + e.getMessage());
+            return;
         }
 
-        if (pP <= 1 || fP <=1) {
-               ci.println("Invalid values. fP and pP have to be greater than 1.");
-               return;
+        if (pP <= 1 || fP <= 1) {
+            ci.println("Invalid values. fP and pP have to be greater than 1.");
+            return;
         }
-        
+
         statisticsTickNumber = fP;
         portTickNumber = pP;
-        
-        ci.println("New Values: fP=" + statisticsTickNumber +
-                       "s pP=" + portTickNumber + "s");
+
+        ci.println("New Values: fP=" + statisticsTickNumber + "s pP="
+                + portTickNumber + "s");
     }
 
 }
index 61d6730..4107816 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
  *
@@ -9,24 +8,27 @@
 
 package org.opendaylight.controller.protocol_plugin.openflow.internal;
 
-import org.openflow.protocol.OFPort;
-
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
 import org.opendaylight.controller.sal.core.NodeConnector.NodeConnectorIDType;
 import org.opendaylight.controller.sal.utils.NetUtils;
 import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
+import org.openflow.protocol.OFPort;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
- * Abstract class which provides the utilities for converting
- * the Openflow port number to the equivalent NodeConnector and vice versa
- *
- *
- *
+ * Abstract class which provides the utilities for converting the Openflow port
+ * number to the equivalent NodeConnector and vice versa
+ * 
+ * 
+ * 
  */
 public abstract class PortConverter {
-    private static final int maxOFPhysicalPort =
-               NetUtils.getUnsignedShort(OFPort.OFPP_MAX.getValue());
+    private static final Logger log = LoggerFactory
+            .getLogger(PortConverter.class);
+    private static final int maxOFPhysicalPort = NetUtils
+            .getUnsignedShort(OFPort.OFPP_MAX.getValue());
 
     /**
      * Converts the Openflow port number to the equivalent NodeConnector.
@@ -34,7 +36,8 @@ public abstract class PortConverter {
     public static NodeConnector toNodeConnector(short ofPort, Node node) {
         // Restore original OF unsigned 16 bits value for the comparison
         int unsignedOFPort = NetUtils.getUnsignedShort(ofPort);
-
+        log.trace("Openflow port number signed: {} unsigned: {}", ofPort,
+                unsignedOFPort);
         if (unsignedOFPort > maxOFPhysicalPort) {
             if (ofPort == OFPort.OFPP_LOCAL.getValue()) {
                 return NodeConnectorCreator.createNodeConnector(
@@ -57,13 +60,12 @@ public abstract class PortConverter {
      * Converts the NodeConnector to the equivalent Openflow port number
      */
     public static short toOFPort(NodeConnector salPort) {
+        log.trace("SAL Port", salPort);
         if (salPort.getType().equals(NodeConnectorIDType.SWSTACK)) {
             return OFPort.OFPP_LOCAL.getValue();
-        } else if (salPort.getType().equals(
-                NodeConnectorIDType.HWPATH)) {
+        } else if (salPort.getType().equals(NodeConnectorIDType.HWPATH)) {
             return OFPort.OFPP_NORMAL.getValue();
-        } else if (salPort.getType().equals(
-                NodeConnectorIDType.CONTROLLER)) {
+        } else if (salPort.getType().equals(NodeConnectorIDType.CONTROLLER)) {
             return OFPort.OFPP_CONTROLLER.getValue();
         }
         return (Short) salPort.getID();
index 2b4df3f..3fbf68f 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
  *
@@ -12,21 +11,24 @@ package org.opendaylight.controller.protocol_plugin.openflow.internal;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.openflow.protocol.statistics.OFPortStatisticsReply;
-import org.openflow.protocol.statistics.OFStatistics;
-
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
 import org.opendaylight.controller.sal.utils.NodeCreator;
+import org.openflow.protocol.statistics.OFPortStatisticsReply;
+import org.openflow.protocol.statistics.OFStatistics;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Converts an openflow list of port statistics in a SAL list of
  * NodeConnectorStatistics objects
- *
- *
- *
+ * 
+ * 
+ * 
  */
 public class PortStatisticsConverter {
+    private static final Logger log = LoggerFactory
+            .getLogger(PortStatisticsConverter.class);
     private long switchId;
     private List<OFStatistics> ofStatsList;
     private List<NodeConnectorStatistics> ncStatsList;
@@ -63,13 +65,13 @@ public class PortStatisticsConverter {
                         .getReceiveFrameErrors());
                 NCStat.setReceiveOverRunErrorCount(ofPortStat
                         .getReceiveOverrunErrors());
-                NCStat
-                        .setReceiveCRCErrorCount(ofPortStat
-                                .getReceiveCRCErrors());
+                NCStat.setReceiveCRCErrorCount(ofPortStat.getReceiveCRCErrors());
                 NCStat.setCollisionCount(ofPortStat.getCollisions());
                 this.ncStatsList.add(NCStat);
             }
         }
+        log.trace("OFStatistics: {} NodeConnectorStatistics: {}", ofStatsList,
+                ncStatsList);
         return this.ncStatsList;
     }
 
index 77a39e9..f1ce03a 100644 (file)
@@ -9,6 +9,9 @@
 
 package org.opendaylight.controller.protocol_plugin.openflow.internal;
 
+import java.nio.ByteBuffer;
+
+import org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension.V6Error;
 import org.openflow.protocol.OFError;
 import org.openflow.protocol.OFError.OFBadActionCode;
 import org.openflow.protocol.OFError.OFBadRequestCode;
@@ -20,6 +23,18 @@ import org.openflow.protocol.OFError.OFQueueOpFailedCode;
 
 public abstract class Utils {
     public static String getOFErrorString(OFError error) {
+        // Handle VENDOR extension errors here
+        if (error.getErrorType() == V6Error.NICIRA_VENDOR_ERRORTYPE) {
+            V6Error er = new V6Error(error);
+            byte[] b = error.getError();
+            ByteBuffer bb = ByteBuffer.allocate(b.length);
+            bb.put(b);
+            bb.rewind();
+            er.readFrom(bb);
+            return er.toString();
+        }
+        
+        // Handle OF1.0 errors here
         OFErrorType et = OFErrorType.values()[0xffff & error.getErrorType()];
         String errorStr = "Error : " + et.toString();
         switch (et) {
index 5cdf9d8..dbd7eaf 100644 (file)
@@ -20,7 +20,10 @@ public interface IFlowProgrammerService {
      * Synchronously add a flow to the network node
      * 
      * @param node
+     *            The target network node
      * @param flow
+     *            The flow to install
+     * @return The status of this request
      */
     Status addFlow(Node node, Flow flow);
 
@@ -28,7 +31,12 @@ public interface IFlowProgrammerService {
      * Synchronously modify existing flow on the switch
      * 
      * @param node
-     * @param flow
+     *            The target network node
+     * @param oldFlow
+     *            The existing flow to modify
+     * @param newFlow
+     *            The new flow to install
+     * @return The status of this request
      */
     Status modifyFlow(Node node, Flow oldFlow, Flow newFlow);
 
@@ -36,7 +44,10 @@ public interface IFlowProgrammerService {
      * Synchronously remove the flow from the network node
      * 
      * @param node
+     *            The target network node
      * @param flow
+     *            The flow to remove
+     * @return The status of this request
      */
     Status removeFlow(Node node, Flow flow);
 
@@ -44,7 +55,10 @@ public interface IFlowProgrammerService {
      * Asynchronously add a flow to the network node
      * 
      * @param node
+     *            The target network node
      * @param flow
+     *            The flow to install
+     * @return The status of this request containing the unique request id
      */
     Status addFlowAsync(Node node, Flow flow);
 
@@ -52,7 +66,12 @@ public interface IFlowProgrammerService {
      * Asynchronously modify existing flow on the switch
      * 
      * @param node
-     * @param flow
+     *            The target network node
+     * @param oldFlow
+     *            The existing flow to modify
+     * @param newFlow
+     *            The new flow to install
+     * @return The status of this request containing the unique request id
      */
     Status modifyFlowAsync(Node node, Flow oldFlow, Flow newFlow);
 
@@ -60,7 +79,10 @@ public interface IFlowProgrammerService {
      * Asynchronously remove the flow from the network node
      * 
      * @param node
+     *            The target network node
      * @param flow
+     *            The flow to remove
+     * @return The status of this request containing the unique request id
      */
     Status removeFlowAsync(Node node, Flow flow);
 
@@ -68,13 +90,23 @@ public interface IFlowProgrammerService {
      * Remove all flows present on the network node
      * 
      * @param node
+     *            The target network node
+     * @return The status of this request containing the unique request id
      */
     Status removeAllFlows(Node node);
 
     /**
-     * Send synchronous Barrier message 
+     * Send synchronous Barrier message
+     * 
+     * Solicit the network node to report whether all the requests sent so far
+     * are completed. When this call is done, caller knows that all past flow
+     * operations requested to the node in asynchronous fashion were satisfied
+     * by the network node and that in case of any failure, a message was sent
+     * to the controller.
      * 
      * @param node
+     *            The network node to solicit
+     * @return The status of this request containing the unique request id
      */
     Status sendBarrierMessage(Node node);
 }
index 503e08e..2fbb3e5 100644 (file)
@@ -14,8 +14,9 @@ package org.opendaylight.controller.sal.utils;
  * a string which describes a failure reason (if any) in human readable form.
  */
 public class Status {
-    StatusCode code;
-    String description;
+    private StatusCode code;
+    private String description;
+    private long requestId;
 
     /**
      * Generates an instance of the Status class. This is used as return code
@@ -34,6 +35,7 @@ public class Status {
         this.code = (errorCode != null) ? errorCode : StatusCode.UNDEFINED;
         this.description = (description != null) ? description : this.code
                 .toString();
+        this.requestId = 0;
     }
 
     /**
@@ -49,6 +51,27 @@ public class Status {
         this.code = (errorCode != null) ? errorCode : StatusCode.UNDEFINED;
         this.description = (description != null) ? description : this.code
                 .toString();
+        this.requestId = 0;
+    }
+
+    /**
+     * Generates an instance of the Status class to be used in case of
+     * asynchronous call. It is supposed to be created by the underlying
+     * infrastructure only when it was successful in allocating the asynchronous
+     * request id, hence caller should expect StatusCode to be successful.
+     * 
+     * @param errorCode
+     *            The status code. If passed as null, code will be stored as
+     *            {@code StatusCode.UNDEFINED}
+     * @param requestId
+     *            The request id set by underlying infrastructure for this
+     *            request
+     */
+    public Status(StatusCode errorCode, long requestId) {
+        this.code = (errorCode != null) ? errorCode : StatusCode.UNDEFINED;
+        this.description = (description != null) ? description : this.code
+                .toString();
+        this.requestId = requestId;
     }
 
     /**
@@ -78,9 +101,20 @@ public class Status {
         return code == StatusCode.SUCCESS;
     }
 
+    /**
+     * Return the request id assigned by underlying infrastructure in case of
+     * asynchronous request. In case of synchronous requests, the returned id
+     * is expected to be 0
+     * 
+     * @return The request id assigned for this asynchronous request
+     */
+    public long getRequestId() {
+        return requestId;
+    }
+
     @Override
     public String toString() {
-        return code + ": " + description;
+        return code + ": " + description + " (" + requestId + ")";
     }
 
     @Override
index 1c63e4e..0abebf8 100644 (file)
@@ -28,8 +28,8 @@ import org.opendaylight.controller.sal.action.PopVlan;
 import org.opendaylight.controller.sal.action.SetNwDst;
 import org.opendaylight.controller.sal.core.ConstructionException;
 import org.opendaylight.controller.sal.core.Node;
-import org.opendaylight.controller.sal.core.NodeConnector;
 import org.opendaylight.controller.sal.core.Node.NodeIDType;
+import org.opendaylight.controller.sal.core.NodeConnector;
 import org.opendaylight.controller.sal.flowprogrammer.Flow;
 import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerListener;
 import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerService;
@@ -37,11 +37,11 @@ import org.opendaylight.controller.sal.flowprogrammer.IPluginInFlowProgrammerSer
 import org.opendaylight.controller.sal.flowprogrammer.IPluginOutFlowProgrammerService;
 import org.opendaylight.controller.sal.match.Match;
 import org.opendaylight.controller.sal.match.MatchType;
-import org.opendaylight.controller.sal.utils.StatusCode;
 import org.opendaylight.controller.sal.utils.EtherTypes;
 import org.opendaylight.controller.sal.utils.IPProtocols;
 import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
 import org.opendaylight.controller.sal.utils.Status;
+import org.opendaylight.controller.sal.utils.StatusCode;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.FrameworkUtil;
 import org.slf4j.Logger;
index add138e..ce0543d 100644 (file)
                        <groupId>org.mockito</groupId>\r
                        <artifactId>mockito-all</artifactId>\r
                        <version>1.8.4</version>\r
-               </dependency>\r
+               </dependency>
+        <dependency>\r
+          <groupId>com.google.guava</groupId>\r
+          <artifactId>guava</artifactId>\r
+          <version>14.0.1</version>\r
+        </dependency>\r
+\r
        </dependencies>\r
        <build>\r
                <plugins>\r
index 1ef6242..e15184d 100644 (file)
@@ -16,7 +16,7 @@ string : STRING (PLUS STRING)*;
 
 identifier_stmt : IDENTIFIER string? stmtend;
                   
-stmtend : (SEMICOLON identifier_stmt?) | (LEFT_BRACE identifier_stmt? RIGHT_BRACE);
+stmtend : (SEMICOLON) | (LEFT_BRACE identifier_stmt? RIGHT_BRACE);
 deviate_replace_stmt : DEVIATE_KEYWORD string /* REPLACE_KEYWORD */ (SEMICOLON | (LEFT_BRACE (identifier_stmt |type_stmt | units_stmt | default_stmt | config_stmt | mandatory_stmt | min_elements_stmt | max_elements_stmt )* RIGHT_BRACE));
 deviate_delete_stmt : DEVIATE_KEYWORD string /* DELETE_KEYWORD */ (SEMICOLON | (LEFT_BRACE (identifier_stmt |units_stmt | must_stmt | unique_stmt | default_stmt )* RIGHT_BRACE));
 deviate_add_stmt : DEVIATE_KEYWORD string /*ADD_KEYWORD*/ (SEMICOLON | (LEFT_BRACE (identifier_stmt |units_stmt | must_stmt | unique_stmt | default_stmt | config_stmt | mandatory_stmt  | min_elements_stmt  | max_elements_stmt )* RIGHT_BRACE));
@@ -78,7 +78,7 @@ require_instance_stmt : REQUIRE_INSTANCE_KEYWORD require_instance_arg stmtend;
 path_stmt : PATH_KEYWORD string stmtend;
 leafref_specification : path_stmt;
 enum_stmt : ENUM_KEYWORD string (SEMICOLON | (LEFT_BRACE  (identifier_stmt |value_stmt | status_stmt | description_stmt | reference_stmt )* RIGHT_BRACE));
-enum_specification : enum_stmt (identifier_stmt | enum_stmt )+;
+enum_specification : enum_stmt (identifier_stmt | enum_stmt )*;
 default_stmt : DEFAULT_KEYWORD string stmtend;
 pattern_stmt : PATTERN_KEYWORD string (SEMICOLON | (LEFT_BRACE  (identifier_stmt |error_message_stmt | error_app_tag_stmt | description_stmt | reference_stmt )* RIGHT_BRACE));
 length_stmt : LENGTH_KEYWORD string (SEMICOLON | (LEFT_BRACE  (identifier_stmt |error_message_stmt | error_app_tag_stmt | description_stmt | reference_stmt )* RIGHT_BRACE));
index 906afd9..979d892 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.controller.yang.model.parser.builder.impl;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
@@ -24,6 +25,7 @@ public class IdentitySchemaNodeBuilder implements SchemaNodeBuilder {
     private final IdentitySchemaNodeImpl instance;
     private IdentitySchemaNodeBuilder baseIdentity;
     private String baseIdentityName;
+    private final List<UnknownSchemaNodeBuilder> addedUnknownNodes = new ArrayList<UnknownSchemaNodeBuilder>();
 
     IdentitySchemaNodeBuilder(final QName qname) {
         this.qname = qname;
@@ -38,6 +40,14 @@ public class IdentitySchemaNodeBuilder implements SchemaNodeBuilder {
             final IdentitySchemaNode base = baseIdentity.build();
             instance.setBaseIdentity(base);
         }
+
+        // UNKNOWN NODES
+        final List<UnknownSchemaNode> unknownNodes = new ArrayList<UnknownSchemaNode>();
+        for (UnknownSchemaNodeBuilder b : addedUnknownNodes) {
+            unknownNodes.add(b.build());
+        }
+        instance.setUnknownSchemaNodes(unknownNodes);
+
         return instance;
     }
 
@@ -73,10 +83,13 @@ public class IdentitySchemaNodeBuilder implements SchemaNodeBuilder {
         }
     }
 
+    public List<UnknownSchemaNodeBuilder> getUnknownNodes() {
+        return addedUnknownNodes;
+    }
+
     @Override
-    public void addUnknownSchemaNode(final UnknownSchemaNodeBuilder unknownNode) {
-        throw new IllegalStateException(
-                "Can not add schema node to identity statement");
+    public void addUnknownSchemaNode(UnknownSchemaNodeBuilder unknownNode) {
+        addedUnknownNodes.add(unknownNode);
     }
 
     public String getBaseIdentityName() {
@@ -98,6 +111,7 @@ public class IdentitySchemaNodeBuilder implements SchemaNodeBuilder {
         private String reference;
         private Status status = Status.CURRENT;
         private SchemaPath path;
+        private List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
 
         private IdentitySchemaNodeImpl(final QName qname) {
             this.qname = qname;
@@ -157,7 +171,14 @@ public class IdentitySchemaNodeBuilder implements SchemaNodeBuilder {
 
         @Override
         public List<UnknownSchemaNode> getUnknownSchemaNodes() {
-            return Collections.emptyList();
+            return unknownNodes;
+        }
+
+        private void setUnknownSchemaNodes(
+                List<UnknownSchemaNode> unknownSchemaNodes) {
+            if (unknownSchemaNodes != null) {
+                this.unknownNodes = unknownSchemaNodes;
+            }
         }
 
         @Override
index 996ba6e..e309172 100644 (file)
@@ -514,7 +514,7 @@ public class ModuleBuilder implements Builder {
         List<String> pathToCase = new ArrayList<String>(parentPath);
         ChoiceCaseBuilder builder = new ChoiceCaseBuilder(caseName);
 
-        final ChoiceBuilder parent = (ChoiceBuilder) moduleNodes
+        final ChildNodeBuilder parent = (ChildNodeBuilder) moduleNodes
                 .get(pathToCase);
         if (parent != null) {
             if (parent instanceof AugmentationSchemaBuilder) {
@@ -524,7 +524,6 @@ public class ModuleBuilder implements Builder {
         }
 
         pathToCase.add(caseName.getLocalName());
-        addedChilds.put(pathToCase, builder);
         moduleNodes.put(pathToCase, builder);
 
         return builder;
@@ -591,11 +590,12 @@ public class ModuleBuilder implements Builder {
     }
 
     public void addIdentityrefType(String baseString, List<String> parentPath) {
+        List<String> pathToIdentityref = new ArrayList<String>(parentPath);
         TypeAwareBuilder parent = (TypeAwareBuilder) moduleNodes
-                .get(parentPath);
+                .get(pathToIdentityref);
         IdentityrefTypeBuilder identityref = new IdentityrefTypeBuilder(baseString);
         parent.setType(identityref);
-        dirtyNodes.put(parentPath, parent);
+        dirtyNodes.put(pathToIdentityref, parent);
     }
 
     public DeviationBuilder addDeviation(String targetPath,
@@ -608,8 +608,11 @@ public class ModuleBuilder implements Builder {
         return builder;
     }
 
-    public IdentitySchemaNodeBuilder addIdentity(QName qname) {
+    public IdentitySchemaNodeBuilder addIdentity(QName qname, List<String> parentPath) {
+        List<String> pathToIdentity = new ArrayList<String>(parentPath);
         IdentitySchemaNodeBuilder builder = new IdentitySchemaNodeBuilder(qname);
+        pathToIdentity.add(qname.getLocalName());
+        moduleNodes.put(pathToIdentity, builder);
         addedIdentities.add(builder);
         return builder;
     }
index e2ebea7..b10798b 100644 (file)
@@ -78,6 +78,7 @@ import org.opendaylight.controller.yang.model.parser.util.YangParseException;
 import org.opendaylight.controller.yang.model.util.ExtendedType;
 import org.opendaylight.controller.yang.model.util.IdentityrefType;
 import org.opendaylight.controller.yang.model.util.UnknownType;
+import org.opendaylight.controller.yang.model.validator.YangModelBasicValidator;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -161,19 +162,8 @@ public class YangModelParserImpl implements YangModelParser {
         final List<ParseTree> trees = parseStreams(yangFiles);
         final ModuleBuilder[] builders = new ModuleBuilder[trees.size()];
 
-        // validation
-        // if validation fails with any file, do not continue and throw
-        // exception
-        for (int i = 0; i < trees.size(); i++) {
-            try {
-                final YangModelValidationListener yangModelParser = new YangModelValidationListener();
-                walker.walk(yangModelParser, trees.get(i));
-            } catch (IllegalStateException e) {
-                // wrap exception to add information about which file failed
-                throw new YangValidationException(
-                        "Yang validation failed for file" + yangFiles[i], e);
-            }
-        }
+        // validate yang
+        new YangModelBasicValidator(walker).validate(trees);
 
         YangModelParserListenerImpl yangModelParser = null;
         for (int i = 0; i < trees.size(); i++) {
@@ -727,7 +717,6 @@ public class YangModelParserImpl implements YangModelParser {
 
                 final QName currentQName = currentParent.getQName();
                 final QName lastAugmentPathElement = path.get(path.size() - 1);
-
                 if (currentQName.getLocalName().equals(
                         lastAugmentPathElement.getLocalName())) {
                     fillAugmentTarget(augmentBuilder,
@@ -902,7 +891,6 @@ public class YangModelParserImpl implements YangModelParser {
                 }
             }
         }
-
     }
 
     /**
@@ -997,7 +985,7 @@ public class YangModelParserImpl implements YangModelParser {
         if(baseString.contains(":")) {
             String[] splittedBase = baseString.split(":");
             if(splittedBase.length > 2) {
-                throw new YangParseException("Failed to parse identity base: "+ baseString);
+                throw new YangParseException("Failed to parse identityref base: "+ baseString);
             }
             String prefix = splittedBase[0];
             String name = splittedBase[1];
@@ -1029,7 +1017,7 @@ public class YangModelParserImpl implements YangModelParser {
         if (prefix.equals(module.getPrefix())) {
             dependentModule = module;
         } else {
-            final ModuleImport dependentModuleImport = getModuleImport(module,
+            final ModuleImport dependentModuleImport = ParserUtils.getModuleImport(module,
                     prefix);
             if (dependentModuleImport == null) {
                 throw new YangParseException("No import found with prefix '"
@@ -1065,26 +1053,6 @@ public class YangModelParserImpl implements YangModelParser {
         return dependentModule;
     }
 
-    /**
-     * Get module import referenced by given prefix.
-     *
-     * @param builder
-     *            module to search
-     * @param prefix
-     *            prefix associated with import
-     * @return ModuleImport based on given prefix
-     */
-    private ModuleImport getModuleImport(final ModuleBuilder builder,
-            final String prefix) {
-        ModuleImport moduleImport = null;
-        for (ModuleImport mi : builder.getModuleImports()) {
-            if (mi.getPrefix().equals(prefix)) {
-                moduleImport = mi;
-                break;
-            }
-        }
-        return moduleImport;
-    }
 
     private static class SchemaContextImpl implements SchemaContext {
         private final Set<Module> modules;
index 76eafaa..bc5f77b 100644 (file)
@@ -78,8 +78,8 @@ import org.opendaylight.controller.yang.model.util.YangTypesConverter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-final class YangModelParserListenerImpl extends YangParserBaseListener {
-
+public final class YangModelParserListenerImpl extends YangParserBaseListener {\r
+\r
     private static final Logger logger = LoggerFactory
             .getLogger(YangModelParserListenerImpl.class);
 
@@ -90,7 +90,7 @@ final class YangModelParserListenerImpl extends YangParserBaseListener {
     private String yangModelPrefix;
     private Date revision = new Date(0L);
 
-    final static DateFormat simpleDateFormat = new SimpleDateFormat(
+    public final static DateFormat simpleDateFormat = new SimpleDateFormat(\r
             "yyyy-MM-dd");
     private final Stack<String> actualPath = new Stack<String>();
 
@@ -325,7 +325,7 @@ final class YangModelParserListenerImpl extends YangParserBaseListener {
         if (YangTypesConverter.isBaseYangType(typeName)) {
             if (typeBody == null) {
                 // if there are no constraints, just grab default base yang type
-                type = YangTypesConverter.javaTypeForBaseYangType(typeName);
+                type = YangTypesConverter.javaTypeForBaseYangType(actualPath, namespace, revision, typeName);
                 moduleBuilder.setType(type, actualPath);
             } else {
                 if ("union".equals(typeName)) {
@@ -770,7 +770,7 @@ final class YangModelParserListenerImpl extends YangParserBaseListener {
         final QName identityQName = new QName(namespace, revision,
                 yangModelPrefix, identityName);
         IdentitySchemaNodeBuilder builder = moduleBuilder
-                .addIdentity(identityQName);
+                .addIdentity(identityQName, actualPath);
         updatePath(identityName);
 
         builder.setPath(createActualSchemaPath(actualPath, namespace, revision,
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/impl/YangModelValidationListener.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/impl/YangModelValidationListener.java
deleted file mode 100644 (file)
index 68887a1..0000000
+++ /dev/null
@@ -1,414 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.yang.model.parser.impl;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.text.DateFormat;
-import java.text.ParseException;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.regex.Pattern;
-
-import org.antlr.v4.runtime.tree.ParseTree;
-import org.opendaylight.controller.antlrv4.code.gen.YangParser;
-import org.opendaylight.controller.antlrv4.code.gen.YangParser.Belongs_to_stmtContext;
-import org.opendaylight.controller.antlrv4.code.gen.YangParser.Import_stmtContext;
-import org.opendaylight.controller.antlrv4.code.gen.YangParser.Include_stmtContext;
-import org.opendaylight.controller.antlrv4.code.gen.YangParser.Module_header_stmtsContext;
-import org.opendaylight.controller.antlrv4.code.gen.YangParser.Namespace_stmtContext;
-import org.opendaylight.controller.antlrv4.code.gen.YangParser.Prefix_stmtContext;
-import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_date_stmtContext;
-import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_stmtContext;
-import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_stmtsContext;
-import org.opendaylight.controller.antlrv4.code.gen.YangParser.Submodule_header_stmtsContext;
-import org.opendaylight.controller.antlrv4.code.gen.YangParser.Submodule_stmtContext;
-import org.opendaylight.controller.antlrv4.code.gen.YangParser.Yang_version_stmtContext;
-import org.opendaylight.controller.antlrv4.code.gen.YangParserBaseListener;
-import org.opendaylight.controller.yang.model.parser.util.YangModelBuilderUtil;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Validation listener that validates yang statements according to RFC-6020.
- * This validator expects only one module or submodule per file.
- */
-
-/*
- * TODO is this assumption(module per file) correct ? if so, should a check be
- * performed ?
- * 
- * TODO break into smaller classes e.g. class for header statements, body
- * statements...
- */
-final class YangModelValidationListener extends YangParserBaseListener {
-
-    private static final Logger logger = LoggerFactory
-            .getLogger(YangModelValidationListener.class);
-
-    private final Set<String> uniquePrefixes;
-    private final Set<String> uniqueImports;
-    private final Set<String> uniqueIncludes;
-
-    public YangModelValidationListener() {
-        super();
-        uniquePrefixes = new HashSet<String>();
-        uniqueImports = new HashSet<String>();
-        uniqueIncludes = new HashSet<String>();
-    }
-
-    /**
-     * Rules:
-     * <ol>
-     * <li>Identifier contains only permitted characters</li>
-     * <li>One revision statements present</li>
-     * <li>One header statements present</li>
-     * </ol>
-     */
-    @Override
-    public void enterModule_stmt(YangParser.Module_stmtContext ctx) {
-        String moduleName = getName(ctx);
-
-        checkIdentifier(moduleName, "Module");
-
-        checkPresentChildOfType(ctx, Revision_stmtsContext.class,
-                f("Missing revision statements in module:%s", moduleName), true);
-
-        checkPresentChildOfType(ctx, Module_header_stmtsContext.class,
-                f("Missing header statements in module:%s", moduleName), true);
-    }
-
-    /**
-     * Rules:
-     * <ol>
-     * <li>Identifier contains only permitted characters</li>
-     * <li>One revision statements present</li>
-     * <li>One header statements present</li>
-     * </ol>
-     */
-    @Override
-    public void enterSubmodule_stmt(Submodule_stmtContext ctx) {
-        String submoduleName = getName(ctx);
-
-        checkIdentifier(submoduleName, "Submodule");
-
-        checkPresentChildOfType(
-                ctx,
-                Revision_stmtsContext.class,
-                f("Missing revision statements in submodule:%s", submoduleName),
-                true);
-
-        checkPresentChildOfType(ctx, Submodule_header_stmtsContext.class,
-                f("Missing header statements in submodule:%s", submoduleName),
-                true);
-    }
-
-    /**
-     * Rules:
-     * <ol>
-     * <li>One Belongs-to statement present</li>
-     * </ol>
-     */
-    @Override
-    public void enterSubmodule_header_stmts(Submodule_header_stmtsContext ctx) {
-        String submoduleName = getRootParentName(ctx);
-
-        checkPresentChildOfType(
-                ctx,
-                Belongs_to_stmtContext.class,
-                f("Missing belongs-to statement in submodule:%s", submoduleName),
-                true);
-
-        // check Yang version present, if not issue warning
-        checkYangVersion(ctx, submoduleName);
-    }
-
-    /**
-     * Rules:
-     * <ol>
-     * <li>Identifier contains only permitted characters</li>
-     * <li>One Prefix statement child</li>
-     * </ol>
-     */
-    @Override
-    public void enterBelongs_to_stmt(Belongs_to_stmtContext ctx) {
-        String belongToName = getName(ctx);
-        String rootParentName = getRootParentName(ctx);
-
-        checkIdentifier(belongToName,
-                f("In (sub)module:%s , Belongs-to statement", rootParentName));
-
-        checkPresentChildOfType(
-                ctx,
-                Prefix_stmtContext.class,
-                f("Missing prefix statement in belongs-to:%s, in (sub)module:%s",
-                        belongToName, rootParentName), true);
-    }
-
-    /**
-     * Rules:
-     * <ol>
-     * <li>At least one Revision statement present</li>
-     * </ol>
-     */
-    @Override
-    public void enterRevision_stmts(Revision_stmtsContext ctx) {
-        String rootParentName = getRootParentName(ctx);
-
-        checkPresentChildOfType(
-                ctx,
-                Revision_stmtContext.class,
-                f("Missing at least one revision statement in (sub)module:%s",
-                        rootParentName), false);
-    }
-
-    /**
-     * Rules:
-     * <ol>
-     * <li>One Namespace statement present</li>
-     * </ol>
-     */
-    @Override
-    public void enterModule_header_stmts(Module_header_stmtsContext ctx) {
-        String moduleName = getRootParentName(ctx);
-
-        checkPresentChildOfType(ctx, Namespace_stmtContext.class,
-                f("Missing namespace statement in module:%s", moduleName), true);
-
-        // check Yang version present, if not issue warning
-        checkYangVersion(ctx, moduleName);
-    }
-
-    /**
-     * Rules:
-     * <ol>
-     * <li>Namespace string can be parsed as URI</li>
-     * </ol>
-     */
-    @Override
-    public void enterNamespace_stmt(Namespace_stmtContext ctx) {
-        String namespaceName = getName(ctx);
-        String rootParentName = getRootParentName(ctx);
-
-        try {
-            new URI(namespaceName);
-        } catch (URISyntaxException e) {
-            throw new YangValidationException(f(
-                    "Namespace:%s in module:%s cannot be parsed as URI",
-                    namespaceName, rootParentName));
-        }
-    }
-
-    /**
-     * Rules:
-     * <ol>
-     * <li>Identifier contains only permitted characters</li>
-     * <li>Every import(identified by identifier) within a module/submodule is
-     * present only once</li>
-     * <li>One prefix statement child</li>
-     * <li>One revision-date statement child</li>
-     * </ol>
-     */
-    @Override
-    public void enterImport_stmt(Import_stmtContext ctx) {
-        String importName = getName(ctx);
-        String rootParentName = getRootParentName(ctx);
-
-        checkIdentifier(importName,
-                f("In (sub)module:%s , Import statement", rootParentName));
-
-        if (uniqueImports.contains(importName))
-            throw new YangValidationException(f(
-                    "Module:%s imported twice in (sub)module:%s", importName,
-                    rootParentName));
-        uniqueImports.add(importName);
-
-        checkPresentChildOfType(
-                ctx,
-                Prefix_stmtContext.class,
-                f("Missing prefix statement in import:%s, in (sub)module:%s",
-                        importName, rootParentName), true);
-        //checkPresentChildOfType(
-        //        ctx,
-        //        Revision_date_stmtContext.class,
-        //        f("Missing revision-date statement in import:%s, in (sub)module:%s",
-        //                importName, rootParentName), true);
-    }
-
-    /**
-     * Rules:
-     * <ol>
-     * <li>Date is in valid format</li>
-     * </ol>
-     */
-    @Override
-    public void enterRevision_date_stmt(Revision_date_stmtContext ctx) {
-        String rootParentName = getRootParentName(ctx);
-        String exceptionMessage = f(
-                "Invalid date format for revision-date:%s in import/include statement:%s, in (sub)module:%s , expected date format is:%s",
-                getName(ctx), getRootParentName(ctx), rootParentName,
-                YangModelParserListenerImpl.simpleDateFormat.format(new Date()));
-
-        validateDateFormat(getName(ctx),
-                YangModelParserListenerImpl.simpleDateFormat, exceptionMessage);
-    }
-
-    /**
-     * Rules:
-     * <ol>
-     * <li>Identifier contains only permitted characters</li>
-     * <li>Every include(identified by identifier) within a module/submodule is
-     * present only once</li>
-     * <li>One Revision-date statement child</li>
-     * </ol>
-     */
-    @Override
-    public void enterInclude_stmt(Include_stmtContext ctx) {
-        String includeName = getName(ctx);
-        String rootParentName = getRootParentName(ctx);
-
-        checkIdentifier(includeName,
-                f("In (sub)module:%s , Include statement", rootParentName));
-
-        if (uniqueIncludes.contains(includeName))
-            throw new YangValidationException(f(
-                    "Submodule:%s included twice in (sub)module:%s",
-                    includeName, rootParentName));
-        uniqueIncludes.add(includeName);
-
-        checkPresentChildOfType(
-                ctx,
-                Revision_date_stmtContext.class,
-                f("Missing revision-date statement in include:%s, in (sub)module:%s",
-                        includeName, rootParentName), true);
-    }
-
-    static final String SUPPORTED_YANG_VERSION = "1";
-
-    /**
-     * Rules:
-     * <ol>
-     * <li>Yang-version is specified as 1</li>
-     * </ol>
-     */
-    @Override
-    public void enterYang_version_stmt(YangParser.Yang_version_stmtContext ctx) {
-        String version = getName(ctx);
-        String rootParentName = getRootParentName(ctx);
-        if (!version.equals(SUPPORTED_YANG_VERSION)) {
-            throw new YangValidationException(
-                    f("Unsupported yang version:%s, in (sub)module:%s, supported version:%s",
-                            version, rootParentName, SUPPORTED_YANG_VERSION));
-        }
-    }
-
-    /**
-     * Rules:
-     * <ol>
-     * <li>Date is in valid format</li>
-     * </ol>
-     */
-    @Override
-    public void enterRevision_stmt(YangParser.Revision_stmtContext ctx) {
-        String parentName = getRootParentName(ctx);
-        String exceptionMessage = f(
-                "Invalid date format for revision:%s in (sub)module:%s, expected date format is:%s",
-                getName(ctx), parentName,
-                YangModelParserListenerImpl.simpleDateFormat.format(new Date()));
-
-        validateDateFormat(getName(ctx),
-                YangModelParserListenerImpl.simpleDateFormat, exceptionMessage);
-    }
-
-    /**
-     * Rules:
-     * <ol>
-     * <li>Identifier contains only permitted characters</li>
-     * <li>Every prefix(identified by identifier) within a module/submodule is
-     * presented only once</li>
-     * </ol>
-     */
-    @Override
-    public void enterPrefix_stmt(Prefix_stmtContext ctx) {
-        String name = getName(ctx);
-        checkIdentifier(
-                name,
-                f("In module or import statement:%s , Prefix",
-                        getRootParentName(ctx)));
-
-        if (uniquePrefixes.contains(name))
-            throw new YangValidationException(f(
-                    "Not a unique prefix:%s, in (sub)module:%s", name,
-                    getRootParentName(ctx)));
-        uniquePrefixes.add(name);
-    }
-
-    private String getRootParentName(ParseTree ctx) {
-        ParseTree root = ctx;
-        while (root.getParent() != null) {
-            root = root.getParent();
-        }
-        return getName(root);
-    }
-
-    private static String getName(ParseTree child) {
-        return YangModelBuilderUtil.stringFromNode(child);
-    }
-
-    private static String f(String base, Object... args) {
-        return String.format(base, args);
-    }
-
-    private static void checkYangVersion(ParseTree ctx, String moduleName) {
-        if (!checkPresentChildOfType(ctx, Yang_version_stmtContext.class, true))
-            logger.warn(f(
-                    "Yang version statement not present in module:%s, Validating as yang version:%s",
-                    moduleName, SUPPORTED_YANG_VERSION));
-    }
-
-    private static void validateDateFormat(String string, DateFormat format,
-            String message) {
-        try {
-            format.parse(string);
-        } catch (ParseException e) {
-            throw new YangValidationException(message);
-        }
-    }
-
-    private static Pattern identifierPattern = Pattern
-            .compile("[a-zA-Z_][a-zA-Z0-9_.-]*");
-
-    static void checkIdentifier(String name, String messagePrefix) {
-        if (!identifierPattern.matcher(name).matches())
-            throw new YangValidationException(f(
-                    "%s identifier:%s is not in required format:%s",
-                    messagePrefix, name, identifierPattern.toString()));
-    }
-
-    private static void checkPresentChildOfType(ParseTree ctx,
-            Class<?> expectedChildType, String message, boolean atMostOne) {
-        if (!checkPresentChildOfType(ctx, expectedChildType, atMostOne))
-            throw new YangValidationException(message);
-    }
-
-    private static boolean checkPresentChildOfType(ParseTree ctx,
-            Class<?> expectedChildType, boolean atMostOne) {
-
-        int count = 0;
-
-        for (int i = 0; i < ctx.getChildCount(); i++) {
-            ParseTree child = ctx.getChild(i);
-            if (expectedChildType.isInstance(child))
-                count++;
-        }
-
-        return atMostOne ? count == 1 ? true : false : count != 0 ? true
-                : false;
-    }
-}
index f533b8e..e7775ce 100644 (file)
@@ -11,6 +11,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.ModuleImport;
 import org.opendaylight.controller.yang.model.api.MustDefinition;
 import org.opendaylight.controller.yang.model.api.SchemaPath;
 import org.opendaylight.controller.yang.model.api.TypeDefinition;
@@ -27,6 +28,7 @@ import org.opendaylight.controller.yang.model.parser.builder.impl.ContainerSchem
 import org.opendaylight.controller.yang.model.parser.builder.impl.LeafListSchemaNodeBuilder;
 import org.opendaylight.controller.yang.model.parser.builder.impl.LeafSchemaNodeBuilder;
 import org.opendaylight.controller.yang.model.parser.builder.impl.ListSchemaNodeBuilder;
+import org.opendaylight.controller.yang.model.parser.builder.impl.ModuleBuilder;
 import org.opendaylight.controller.yang.model.parser.builder.impl.UnknownSchemaNodeBuilder;
 
 public final class ParserUtils {
@@ -34,6 +36,32 @@ public final class ParserUtils {
     private ParserUtils() {
     }
 
+    /**
+     * Get module import referenced by given prefix.
+     *
+     * @param builder
+     *            module to search
+     * @param prefix
+     *            prefix associated with import
+     * @return ModuleImport based on given prefix
+     */
+    public static ModuleImport getModuleImport(final ModuleBuilder builder,
+            final String prefix) {
+        ModuleImport moduleImport = null;
+        for (ModuleImport mi : builder.getModuleImports()) {
+            if (mi.getPrefix().equals(prefix)) {
+                moduleImport = mi;
+                break;
+            }
+        }
+        return moduleImport;
+    }
+
+    /**
+     * Parse uses path.
+     * @param usesPath as String
+     * @return SchemaPath from given String
+     */
     public static SchemaPath parseUsesPath(final String usesPath) {
         final boolean absolute = usesPath.startsWith("/");
         final String[] splittedPath = usesPath.split("/");
index 8b33702..94b790f 100644 (file)
@@ -88,13 +88,21 @@ import org.opendaylight.controller.yang.model.parser.util.RefineHolder.Refine;
 import org.opendaylight.controller.yang.model.util.BaseConstraints;
 import org.opendaylight.controller.yang.model.util.BinaryType;
 import org.opendaylight.controller.yang.model.util.BitsType;
+import org.opendaylight.controller.yang.model.util.Decimal64;
 import org.opendaylight.controller.yang.model.util.EnumerationType;
 import org.opendaylight.controller.yang.model.util.InstanceIdentifier;
+import org.opendaylight.controller.yang.model.util.Int16;
+import org.opendaylight.controller.yang.model.util.Int32;
+import org.opendaylight.controller.yang.model.util.Int64;
+import org.opendaylight.controller.yang.model.util.Int8;
 import org.opendaylight.controller.yang.model.util.Leafref;
 import org.opendaylight.controller.yang.model.util.RevisionAwareXPathImpl;
 import org.opendaylight.controller.yang.model.util.StringType;
+import org.opendaylight.controller.yang.model.util.Uint16;
+import org.opendaylight.controller.yang.model.util.Uint32;
+import org.opendaylight.controller.yang.model.util.Uint64;
+import org.opendaylight.controller.yang.model.util.Uint8;
 import org.opendaylight.controller.yang.model.util.UnknownType;
-import org.opendaylight.controller.yang.model.util.YangTypesConverter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -982,19 +990,32 @@ public final class YangModelBuilderUtil {
                 typeBody, actualPath, namespace, revision, prefix);
 
         if ("decimal64".equals(typeName)) {
-            type = YangTypesConverter.javaTypeForBaseYangDecimal64Type(
-                    rangeStatements, fractionDigits);
+            type = new Decimal64(actualPath, namespace, revision, fractionDigits);
         } else if (typeName.startsWith("int")) {
-            type = YangTypesConverter.javaTypeForBaseYangSignedIntegerType(
-                    typeName, rangeStatements);
+            if (typeName.equals("int8")) {
+                type = new Int8(actualPath, namespace, revision, rangeStatements, null, null);
+            } else if (typeName.equals("int16")) {
+                type = new Int16(actualPath, namespace, revision, rangeStatements, null, null);
+            } else if (typeName.equals("int32")) {
+                type = new Int32(actualPath, namespace, revision, rangeStatements, null, null);
+            } else if (typeName.equals("int64")) {
+                type = new Int64(actualPath, namespace, revision, rangeStatements, null, null);
+            }
         } else if (typeName.startsWith("uint")) {
-            type = YangTypesConverter.javaTypeForBaseYangUnsignedIntegerType(
-                    typeName, rangeStatements);
+            if (typeName.equals("uint8")) {
+                type = new Uint8(actualPath, namespace, revision, rangeStatements, null, null);
+            } else if (typeName.equals("uint16")) {
+                type = new Uint16(actualPath, namespace, revision, rangeStatements, null, null);
+            } else if (typeName.equals("uint32")) {
+                type = new Uint32(actualPath, namespace, revision, rangeStatements, null, null);
+            } else if (typeName.equals("uint64")) {
+                type = new Uint64(actualPath, namespace, revision, rangeStatements, null, null);
+            }
         } else if ("enumeration".equals(typeName)) {
             type = new EnumerationType(actualPath, namespace, revision,
                     enumConstants);
         } else if ("string".equals(typeName)) {
-            type = new StringType(lengthStatements, patternStatements);
+            type = new StringType(actualPath, namespace, revision, lengthStatements, patternStatements);
         } else if ("bits".equals(typeName)) {
             type = new BitsType(getBits(typeBody, actualPath, namespace,
                     revision, prefix));
@@ -5,13 +5,13 @@
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
-package org.opendaylight.controller.yang.model.parser.impl;
+package org.opendaylight.controller.yang.model.parser.util;
 
 /**
  * Unchecked exception thrown if yang definition is not valid according to
- * {@link YangModelValidationListener}
+ * {@link YangModelBasicValidationListener}
  */
-public class YangValidationException extends RuntimeException {
+public final class YangValidationException extends RuntimeException {
 
     private static final long serialVersionUID = 7414330400390825381L;
 
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/validator/BasicValidations.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/validator/BasicValidations.java
new file mode 100644 (file)
index 0000000..f9e3fc2
--- /dev/null
@@ -0,0 +1,303 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/eplv10.html
+ */
+package org.opendaylight.controller.yang.model.validator;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Yang_version_stmtContext;
+import org.opendaylight.controller.yang.model.parser.impl.YangModelParserListenerImpl;
+import org.opendaylight.controller.yang.model.parser.util.YangValidationException;
+
+import com.google.common.collect.Sets;
+
+/**
+ * Reusable checks of basic constraints on yang statements
+ */
+final class BasicValidations {
+
+    static final String SUPPORTED_YANG_VERSION = "1";
+
+    static void checkNotPresentBoth(ParseTree parent,
+            Class<? extends ParseTree> childType1,
+            Class<? extends ParseTree> childType2) {
+        if (BasicValidations.checkPresentChildOfTypeSafe(parent, childType1,
+                true)
+                && BasicValidations.checkPresentChildOfTypeSafe(parent,
+                        childType2, false))
+            ValidationUtil
+                    .ex(ValidationUtil
+                            .f("(In (sub)module:%s) Both %s and %s statement present in %s:%s",
+                                    ValidationUtil.getRootParentName(parent),
+                                    ValidationUtil
+                                            .getSimpleStatementName(childType1),
+                                    ValidationUtil
+                                            .getSimpleStatementName(childType2),
+                                    ValidationUtil
+                                            .getSimpleStatementName(parent
+                                                    .getClass()),
+                                    ValidationUtil.getName(parent)));
+    }
+
+    static void checkOnlyPermittedValues(ParseTree ctx,
+            Set<String> permittedValues) {
+        String mandatory = ValidationUtil.getName(ctx);
+        String rootParentName = ValidationUtil.getRootParentName(ctx);
+
+        if (!permittedValues.contains(mandatory))
+            ValidationUtil
+                    .ex(ValidationUtil
+                            .f("(In (sub)module:%s) %s:%s, illegal value for %s statement, only permitted:%s",
+                                    rootParentName, ValidationUtil
+                                            .getSimpleStatementName(ctx
+                                                    .getClass()), mandatory,
+                                    ValidationUtil.getSimpleStatementName(ctx
+                                            .getClass()), permittedValues));
+    }
+
+    static void checkUniquenessInNamespace(ParseTree stmt, Set<String> uniques) {
+        String name = ValidationUtil.getName(stmt);
+        String rootParentName = ValidationUtil.getRootParentName(stmt);
+
+        if (uniques.contains(name))
+            ValidationUtil.ex(ValidationUtil.f(
+                    "(In (sub)module:%s) %s:%s not unique in (sub)module",
+                    rootParentName,
+                    ValidationUtil.getSimpleStatementName(stmt.getClass()),
+                    name));
+        uniques.add(name);
+    }
+
+    /**
+     * Check if only one module or submodule is present in session(one yang
+     * file)
+     */
+    static void checkOnlyOneModulePresent(String moduleName, String globalId) {
+        if (globalId != null)
+            ValidationUtil.ex(ValidationUtil
+                    .f("Multiple (sub)modules per file"));
+    }
+
+    static void checkPresentYangVersion(ParseTree ctx, String moduleName) {
+        if (!checkPresentChildOfTypeSafe(ctx, Yang_version_stmtContext.class,
+                true))
+            ValidationUtil
+                    .ex(ValidationUtil
+                            .f("Yang version statement not present in module:%s, Validating as yang version:%s",
+                                    moduleName, SUPPORTED_YANG_VERSION));
+    }
+
+    static void checkDateFormat(ParseTree stmt, DateFormat format) {
+        try {
+            format.parse(ValidationUtil.getName(stmt));
+        } catch (ParseException e) {
+            String exceptionMessage = ValidationUtil
+                    .f("(In (sub)module:%s) %s:%s, invalid date format expected date format is:%s",
+                            ValidationUtil.getRootParentName(stmt),
+                            ValidationUtil.getSimpleStatementName(stmt
+                                    .getClass()), ValidationUtil.getName(stmt),
+                            YangModelParserListenerImpl.simpleDateFormat
+                                    .format(new Date()));
+            ValidationUtil.ex(exceptionMessage);
+        }
+    }
+
+    static Pattern identifierPattern = Pattern
+            .compile("[a-zA-Z_][a-zA-Z0-9_.-]*");
+
+    static void checkIdentifier(ParseTree statement) {
+        checkIdentifierInternal(statement, ValidationUtil.getName(statement));
+    }
+
+    static void checkIdentifierInternal(ParseTree statement, String name) {
+        if (!identifierPattern.matcher(name).matches()) {
+
+            String message = ValidationUtil
+                    .f("%s statement identifier:%s is not in required format:%s",
+                            ValidationUtil.getSimpleStatementName(statement
+                                    .getClass()), name, identifierPattern
+                                    .toString());
+            String parent = ValidationUtil.getRootParentName(statement);
+            message = parent.equals(name) ? message : ValidationUtil.f(
+                    "(In (sub)module:%s) %s", parent, message);
+
+            ValidationUtil.ex(message);
+        }
+    }
+
+    static Pattern prefixedIdentifierPattern = Pattern.compile("(.+):(.+)");
+
+    static void checkPrefixedIdentifier(ParseTree statement) {
+        checkPrefixedIdentifierInternal(statement,
+                ValidationUtil.getName(statement));
+    }
+
+    private static void checkPrefixedIdentifierInternal(ParseTree statement,
+            String id) {
+        Matcher matcher = prefixedIdentifierPattern.matcher(id);
+
+        if (matcher.matches()) {
+            try {
+                // check prefix
+                checkIdentifierInternal(statement, matcher.group(1));
+                // check ID
+                checkIdentifierInternal(statement, matcher.group(2));
+            } catch (YangValidationException e) {
+                ValidationUtil.ex(ValidationUtil.f(
+                        "Prefixed id:%s not in required format, details:%s",
+                        id, e.getMessage()));
+            }
+        } else
+            checkIdentifierInternal(statement, id);
+    }
+
+    static void checkSchemaNodeIdentifier(ParseTree statement) {
+        String id = ValidationUtil.getName(statement);
+
+        try {
+            for (String oneOfId : id.split("/")) {
+                if (oneOfId.isEmpty())
+                    continue;
+                checkPrefixedIdentifierInternal(statement, oneOfId);
+            }
+        } catch (YangValidationException e) {
+            ValidationUtil.ex(ValidationUtil.f(
+                    "Schema node id:%s not in required format, details:%s", id,
+                    e.getMessage()));
+        }
+    }
+
+    private static interface MessageProvider {
+        String getMessage();
+    }
+
+    static void checkPresentChildOfTypeInternal(ParseTree parent,
+            Set<Class<? extends ParseTree>> expectedChildType,
+            MessageProvider message, boolean atMostOne) {
+        if (!checkPresentChildOfTypeSafe(parent, expectedChildType, atMostOne)) {
+            String str = atMostOne ? "(Expected exactly one statement) "
+                    + message.getMessage() : message.getMessage();
+            ValidationUtil.ex(str);
+        }
+    }
+
+    static void checkPresentChildOfType(final ParseTree parent,
+            final Class<? extends ParseTree> expectedChildType,
+            boolean atMostOne) {
+
+        // Construct message in checkPresentChildOfTypeInternal only if
+        // validaiton fails, not in advance
+        MessageProvider message = new MessageProvider() {
+
+            @Override
+            public String getMessage() {
+                String message = ValidationUtil
+                        .f("Missing %s statement in %s:%s", ValidationUtil
+                                .getSimpleStatementName(expectedChildType),
+                                ValidationUtil.getSimpleStatementName(parent
+                                        .getClass()), ValidationUtil
+                                        .getName(parent));
+
+                String root = ValidationUtil.getRootParentName(parent);
+                message = parent.equals(ValidationUtil
+                        .getRootParentName(parent)) ? message : ValidationUtil
+                        .f("(In (sub)module:%s) %s", root, message);
+                return message;
+            }
+        };
+
+        Set<Class<? extends ParseTree>> expectedChildTypeSet = Sets
+                .newHashSet();
+        expectedChildTypeSet.add(expectedChildType);
+
+        checkPresentChildOfTypeInternal(parent, expectedChildTypeSet, message,
+                atMostOne);
+    }
+
+    static void checkPresentChildOfTypes(final ParseTree parent,
+            final Set<Class<? extends ParseTree>> expectedChildTypes,
+            boolean atMostOne) {
+
+        // Construct message in checkPresentChildOfTypeInternal only if
+        // validaiton fails, not in advance
+        MessageProvider message = new MessageProvider() {
+
+            @Override
+            public String getMessage() {
+                StringBuilder childTypes = new StringBuilder();
+                String orStr = " OR ";
+                for (Class<? extends ParseTree> type : expectedChildTypes) {
+                    childTypes.append(ValidationUtil
+                            .getSimpleStatementName(type));
+                    childTypes.append(orStr);
+                }
+
+                String message = ValidationUtil
+                        .f("Missing %s statement in %s:%s", childTypes
+                                .toString(), ValidationUtil
+                                .getSimpleStatementName(parent.getClass()),
+                                ValidationUtil.getName(parent));
+
+                String root = ValidationUtil.getRootParentName(parent);
+                message = parent.equals(ValidationUtil
+                        .getRootParentName(parent)) ? message : ValidationUtil
+                        .f("(In (sub)module:%s) %s", root, message);
+
+                return message;
+            }
+        };
+
+        checkPresentChildOfTypeInternal(parent, expectedChildTypes, message,
+                atMostOne);
+    }
+
+    static boolean checkPresentChildOfTypeSafe(ParseTree parent,
+            Set<Class<? extends ParseTree>> expectedChildType, boolean atMostOne) {
+
+        int foundChildrenOfType = ValidationUtil.countPresentChildrenOfType(
+                parent, expectedChildType);
+
+        return atMostOne ? foundChildrenOfType == 1 ? true : false
+                : foundChildrenOfType != 0 ? true : false;
+    }
+
+    static boolean checkPresentChildOfTypeSafe(ParseTree parent,
+            Class<? extends ParseTree> expectedChildType, boolean atMostOne) {
+
+        int foundChildrenOfType = ValidationUtil.countPresentChildrenOfType(
+                parent, expectedChildType);
+
+        return atMostOne ? foundChildrenOfType == 1 ? true : false
+                : foundChildrenOfType != 0 ? true : false;
+    }
+
+    static List<String> getAndCheckUniqueKeys(ParseTree ctx) {
+        String key = ValidationUtil.getName(ctx);
+        ParseTree parent = ctx.getParent();
+        String rootParentName = ValidationUtil.getRootParentName(ctx);
+
+        List<String> keyList = ValidationUtil.listKeysFromId(key);
+        Set<String> duplicates = ValidationUtil.getDuplicates(keyList);
+
+        if (duplicates.size() != 0)
+            ValidationUtil.ex(ValidationUtil.f(
+                    "(In (sub)module:%s) %s:%s, %s:%s contains duplicates:%s",
+                    rootParentName,
+                    ValidationUtil.getSimpleStatementName(parent.getClass()),
+                    ValidationUtil.getName(parent),
+                    ValidationUtil.getSimpleStatementName(ctx.getClass()), key,
+                    duplicates));
+        return keyList;
+    }
+}
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/validator/ValidationUtil.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/validator/ValidationUtil.java
new file mode 100644 (file)
index 0000000..31c4b8a
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/eplv10.html
+ */
+package org.opendaylight.controller.yang.model.validator;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Module_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Submodule_stmtContext;
+import org.opendaylight.controller.yang.model.parser.util.YangModelBuilderUtil;
+import org.opendaylight.controller.yang.model.parser.util.YangValidationException;
+
+/**
+ * Validation utilities
+ */
+final class ValidationUtil {
+
+    static void ex(String message) {
+        throw new YangValidationException(message);
+    }
+
+    static Set<String> getDuplicates(Collection<String> keyList) {
+        Set<String> all = new HashSet<String>();
+        Set<String> duplicates = new HashSet<String>();
+
+        for (String key : keyList) {
+            if (!all.add(key))
+                duplicates.add(key);
+        }
+        return duplicates;
+    }
+
+    static List<String> listKeysFromId(String keys) {
+        return Arrays.asList(keys.split(" "));
+    }
+
+    static String getRootParentName(ParseTree ctx) {
+        ParseTree root = getRootParent(ctx);
+        return ValidationUtil.getName(root);
+    }
+
+    private static ParseTree getRootParent(ParseTree ctx) {
+        ParseTree root = ctx;
+        while (root.getParent() != null) {
+            if (root.getClass().equals(Module_stmtContext.class)
+                    || root.getClass().equals(Submodule_stmtContext.class))
+                break;
+            root = root.getParent();
+        }
+        return root;
+    }
+
+    static String getName(ParseTree child) {
+        return YangModelBuilderUtil.stringFromNode(child);
+    }
+
+    static String f(String base, Object... args) {
+        return String.format(base, args);
+    }
+
+    /**
+     * Get simple name from statement class e.g. Module from Module_stmt_context
+     */
+    static String getSimpleStatementName(
+            Class<? extends ParseTree> typeOfStatement) {
+
+        String className = typeOfStatement.getSimpleName();
+        int lastIndexOf = className.indexOf('$');
+        className = lastIndexOf == -1 ? className : className
+                .substring(lastIndexOf + 1);
+        int indexOfStmt = className.indexOf("_stmt");
+        int index = indexOfStmt == -1 ? className.indexOf("_arg") : indexOfStmt;
+        return className.substring(0, index).replace('_', '-');
+    }
+
+    static int countPresentChildrenOfType(ParseTree parent,
+            Set<Class<? extends ParseTree>> expectedChildTypes) {
+        int foundChildrenOfType = 0;
+
+        for (Class<? extends ParseTree> type : expectedChildTypes) {
+            foundChildrenOfType += countPresentChildrenOfType(parent, type);
+        }
+        return foundChildrenOfType;
+    }
+
+    static int countPresentChildrenOfType(ParseTree parent,
+            Class<? extends ParseTree> expectedChildType) {
+        int foundChildrenOfType = 0;
+
+        for (int i = 0; i < parent.getChildCount(); i++) {
+            ParseTree child = parent.getChild(i);
+            if (expectedChildType.isInstance(child))
+                foundChildrenOfType++;
+        }
+        return foundChildrenOfType;
+    }
+
+}
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/validator/YangModelBasicValidationListener.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/validator/YangModelBasicValidationListener.java
new file mode 100644 (file)
index 0000000..37e2a21
--- /dev/null
@@ -0,0 +1,672 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.yang.model.validator;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Set;
+
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Anyxml_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Argument_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Augment_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Base_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Belongs_to_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Case_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Choice_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Config_argContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Container_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Default_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Deviate_add_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Deviation_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Extension_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Feature_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Grouping_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Identity_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.If_feature_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Import_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Include_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Key_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Leaf_list_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Leaf_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.List_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Mandatory_argContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Mandatory_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Module_header_stmtsContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Module_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Namespace_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Notification_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Ordered_by_argContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Prefix_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Refine_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_date_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Rpc_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Status_argContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Submodule_header_stmtsContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Submodule_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Type_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Typedef_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Unique_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Uses_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Yin_element_argContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParserBaseListener;
+import org.opendaylight.controller.yang.model.parser.impl.YangModelParserListenerImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Sets;
+
+/**
+ * Validation listener that validates yang statements according to RFC-6020.
+ * This validator expects only one module or submodule per file and performs
+ * only basic validation where context from all yang models is not present.
+ */
+final class YangModelBasicValidationListener extends YangParserBaseListener {
+
+    private static final Logger logger = LoggerFactory
+            .getLogger(YangModelBasicValidationListener.class);
+
+    private final Set<String> uniquePrefixes;
+    private final Set<String> uniqueImports;
+    private final Set<String> uniqueIncludes;
+
+    private String globalModuleId;
+
+    YangModelBasicValidationListener() {
+        super();
+        uniquePrefixes = Sets.newHashSet();
+        uniqueImports = Sets.newHashSet();
+        uniqueIncludes = Sets.newHashSet();
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * <li>Header statements present(mandatory prefix and namespace statements
+     * are in header)</li>
+     * <li>Only one module or submodule per file</li>
+     * </ol>
+     */
+    @Override
+    public void enterModule_stmt(Module_stmtContext ctx) {
+
+        BasicValidations.checkIdentifier(ctx);
+
+        BasicValidations.checkPresentChildOfType(ctx,
+                Module_header_stmtsContext.class, true);
+
+        String moduleName = ValidationUtil.getName(ctx);
+        BasicValidations.checkOnlyOneModulePresent(moduleName, globalModuleId);
+        globalModuleId = moduleName;
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * <li>Header statements present(mandatory belongs-to statement is in
+     * header)</li>
+     * <li>Only one module or submodule per file</li>
+     * </ol>
+     */
+    @Override
+    public void enterSubmodule_stmt(Submodule_stmtContext ctx) {
+
+        BasicValidations.checkIdentifier(ctx);
+
+        BasicValidations.checkPresentChildOfType(ctx,
+                Submodule_header_stmtsContext.class, true);
+
+        String submoduleName = ValidationUtil.getName(ctx);
+        BasicValidations.checkOnlyOneModulePresent(submoduleName,
+                globalModuleId);
+        globalModuleId = submoduleName;
+
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>One Belongs-to statement present</li>
+     * </ol>
+     */
+    @Override
+    public void enterSubmodule_header_stmts(Submodule_header_stmtsContext ctx) {
+        BasicValidations.checkPresentChildOfType(ctx,
+                Belongs_to_stmtContext.class, true);
+
+        // check Yang version present, if not log
+        try {
+            BasicValidations.checkPresentYangVersion(ctx,
+                    ValidationUtil.getRootParentName(ctx));
+        } catch (Exception e) {
+            logger.debug(e.getMessage());
+        }
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>One Namespace statement present</li>
+     * <li>One Prefix statement present</li>
+     * </ol>
+     */
+    @Override
+    public void enterModule_header_stmts(Module_header_stmtsContext ctx) {
+        String moduleName = ValidationUtil.getRootParentName(ctx);
+
+        BasicValidations.checkPresentChildOfType(ctx,
+                Namespace_stmtContext.class, true);
+        BasicValidations.checkPresentChildOfType(ctx, Prefix_stmtContext.class,
+                true);
+
+        // check Yang version present, if not log
+        try {
+            BasicValidations.checkPresentYangVersion(ctx, moduleName);
+        } catch (Exception e) {
+            logger.debug(e.getMessage());
+        }
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Date is in valid format</li>
+     * </ol>
+     */
+    @Override
+    public void enterRevision_stmt(Revision_stmtContext ctx) {
+        BasicValidations.checkDateFormat(ctx,
+                YangModelParserListenerImpl.simpleDateFormat);
+
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * <li>One Prefix statement child</li>
+     * </ol>
+     */
+    @Override
+    public void enterBelongs_to_stmt(Belongs_to_stmtContext ctx) {
+        BasicValidations.checkIdentifier(ctx);
+
+        BasicValidations.checkPresentChildOfType(ctx, Prefix_stmtContext.class,
+                true);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Namespace string can be parsed as URI</li>
+     * </ol>
+     */
+    @Override
+    public void enterNamespace_stmt(Namespace_stmtContext ctx) {
+        String namespaceName = ValidationUtil.getName(ctx);
+        String rootParentName = ValidationUtil.getRootParentName(ctx);
+
+        try {
+            new URI(namespaceName);
+        } catch (URISyntaxException e) {
+            ValidationUtil.ex(ValidationUtil.f(
+                    "(In module:%s) Namespace:%s cannot be parsed as URI",
+                    rootParentName, namespaceName));
+        }
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * <li>Every import(identified by identifier) within a module/submodule is
+     * present only once</li>
+     * <li>One prefix statement child</li>
+     * </ol>
+     */
+    @Override
+    public void enterImport_stmt(Import_stmtContext ctx) {
+
+        BasicValidations.checkIdentifier(ctx);
+
+        BasicValidations.checkUniquenessInNamespace(ctx, uniqueImports);
+
+        BasicValidations.checkPresentChildOfType(ctx, Prefix_stmtContext.class,
+                true);
+
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Date is in valid format</li>
+     * </ol>
+     */
+    @Override
+    public void enterRevision_date_stmt(Revision_date_stmtContext ctx) {
+        BasicValidations.checkDateFormat(ctx,
+                YangModelParserListenerImpl.simpleDateFormat);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * <li>Every include(identified by identifier) within a module/submodule is
+     * present only once</li>
+     * </ol>
+     */
+    @Override
+    public void enterInclude_stmt(Include_stmtContext ctx) {
+
+        BasicValidations.checkIdentifier(ctx);
+
+        BasicValidations.checkUniquenessInNamespace(ctx, uniqueIncludes);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Yang-version is specified as 1</li>
+     * </ol>
+     */
+    @Override
+    public void enterYang_version_stmt(YangParser.Yang_version_stmtContext ctx) {
+        String version = ValidationUtil.getName(ctx);
+        String rootParentName = ValidationUtil.getRootParentName(ctx);
+        if (!version.equals(BasicValidations.SUPPORTED_YANG_VERSION)) {
+            ValidationUtil
+                    .ex(ValidationUtil
+                            .f("(In (sub)module:%s) Unsupported yang version:%s, supported version:%s",
+                                    rootParentName, version,
+                                    BasicValidations.SUPPORTED_YANG_VERSION));
+        }
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * <li>Every prefix(identified by identifier) within a module/submodule is
+     * presented only once</li>
+     * </ol>
+     */
+    @Override
+    public void enterPrefix_stmt(Prefix_stmtContext ctx) {
+
+        BasicValidations.checkIdentifier(ctx);
+
+        BasicValidations.checkUniquenessInNamespace(ctx, uniquePrefixes);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * <li>One type statement child</li>
+     * </ol>
+     */
+    @Override
+    public void enterTypedef_stmt(Typedef_stmtContext ctx) {
+
+        BasicValidations.checkIdentifier(ctx);
+
+        BasicValidations.checkPresentChildOfType(ctx, Type_stmtContext.class,
+                true);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>(Prefix):Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterType_stmt(Type_stmtContext ctx) {
+        BasicValidations.checkPrefixedIdentifier(ctx);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterContainer_stmt(Container_stmtContext ctx) {
+        BasicValidations.checkIdentifier(ctx);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * <li>One type statement child</li>
+     * <li>Default statement must not be present if mandatory statement is</li>
+     * </ol>
+     */
+    @Override
+    public void enterLeaf_stmt(Leaf_stmtContext ctx) {
+        BasicValidations.checkIdentifier(ctx);
+
+        BasicValidations.checkPresentChildOfType(ctx, Type_stmtContext.class,
+                true);
+
+        BasicValidations.checkNotPresentBoth(ctx, Mandatory_stmtContext.class,
+                Default_stmtContext.class);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * <li>One type statement child</li>
+     * </ol>
+     */
+    @Override
+    public void enterLeaf_list_stmt(Leaf_list_stmtContext ctx) {
+
+        BasicValidations.checkIdentifier(ctx);
+
+        BasicValidations.checkPresentChildOfType(ctx, Type_stmtContext.class,
+                true);
+    }
+
+    private static final Set<String> permittedOrderByArgs = Sets.newHashSet(
+            "system", "user");
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Value must be one of: system, user</li>
+     * </ol>
+     */
+    @Override
+    public void enterOrdered_by_arg(Ordered_by_argContext ctx) {
+        BasicValidations.checkOnlyPermittedValues(ctx, permittedOrderByArgs);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterList_stmt(List_stmtContext ctx) {
+        BasicValidations.checkIdentifier(ctx);
+        // TODO check: "if config==true then key must be present" could be
+        // performed
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>No duplicate keys</li>
+     * </ol>
+     */
+    @Override
+    public void enterKey_stmt(Key_stmtContext ctx) {
+        BasicValidations.getAndCheckUniqueKeys(ctx);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <liNo duplicate uniques</li>
+     * </ol>
+     */
+    @Override
+    public void enterUnique_stmt(Unique_stmtContext ctx) {
+        BasicValidations.getAndCheckUniqueKeys(ctx);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * <li>Default statement must not be present if mandatory statement is</li>
+     * </ol>
+     */
+    @Override
+    public void enterChoice_stmt(Choice_stmtContext ctx) {
+        BasicValidations.checkIdentifier(ctx);
+
+        BasicValidations.checkNotPresentBoth(ctx, Mandatory_stmtContext.class,
+                Default_stmtContext.class);
+
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterCase_stmt(Case_stmtContext ctx) {
+        BasicValidations.checkIdentifier(ctx);
+    }
+
+    private static final Set<String> permittedBooleanArgs = Sets.newHashSet(
+            "true", "false");
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Value must be one of: true, false</li>
+     * </ol>
+     */
+    @Override
+    public void enterMandatory_arg(Mandatory_argContext ctx) {
+        BasicValidations.checkOnlyPermittedValues(ctx, permittedBooleanArgs);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterAnyxml_stmt(Anyxml_stmtContext ctx) {
+        BasicValidations.checkIdentifier(ctx);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterGrouping_stmt(Grouping_stmtContext ctx) {
+        BasicValidations.checkIdentifier(ctx);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>(Prefix):Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterUses_stmt(Uses_stmtContext ctx) {
+        BasicValidations.checkPrefixedIdentifier(ctx);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterRefine_stmt(Refine_stmtContext ctx) {
+        BasicValidations.checkIdentifier(ctx);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterRpc_stmt(Rpc_stmtContext ctx) {
+        BasicValidations.checkIdentifier(ctx);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterNotification_stmt(Notification_stmtContext ctx) {
+        BasicValidations.checkIdentifier(ctx);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Schema Node Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterAugment_stmt(Augment_stmtContext ctx) {
+        BasicValidations.checkSchemaNodeIdentifier(ctx);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterIdentity_stmt(Identity_stmtContext ctx) {
+        BasicValidations.checkIdentifier(ctx);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>(Prefix):Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterBase_stmt(Base_stmtContext ctx) {
+        BasicValidations.checkPrefixedIdentifier(ctx);
+
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Value must be one of: true, false</li>
+     * </ol>
+     */
+    @Override
+    public void enterYin_element_arg(Yin_element_argContext ctx) {
+        BasicValidations.checkOnlyPermittedValues(ctx, permittedBooleanArgs);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterExtension_stmt(Extension_stmtContext ctx) {
+        BasicValidations.checkIdentifier(ctx);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterArgument_stmt(Argument_stmtContext ctx) {
+        BasicValidations.checkIdentifier(ctx);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterFeature_stmt(Feature_stmtContext ctx) {
+        BasicValidations.checkIdentifier(ctx);
+
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>(Prefix):Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterIf_feature_stmt(If_feature_stmtContext ctx) {
+        BasicValidations.checkPrefixedIdentifier(ctx);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Schema Node Identifier is in required format</li>
+     * <li>At least one deviate-* statement child</li>
+     * </ol>
+     */
+    @Override
+    public void enterDeviation_stmt(Deviation_stmtContext ctx) {
+        BasicValidations.checkSchemaNodeIdentifier(ctx);
+
+        Set<Class<? extends ParseTree>> types = Sets.newHashSet();
+        types.add(Deviate_add_stmtContext.class);
+        types.add(Deviate_add_stmtContext.class);
+        BasicValidations.checkPresentChildOfTypes(ctx, types, false);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Value must be one of: true, false</li>
+     * </ol>
+     */
+    @Override
+    public void enterConfig_arg(Config_argContext ctx) {
+        BasicValidations.checkOnlyPermittedValues(ctx, permittedBooleanArgs);
+    }
+
+    private static final Set<String> permittedStatusArgs = Sets.newHashSet(
+            "current", "deprecated", "obsolete");
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Value must be one of: "current", "deprecated", "obsolete"</li>
+     * </ol>
+     */
+    @Override
+    public void enterStatus_arg(Status_argContext ctx) {
+        BasicValidations.checkOnlyPermittedValues(ctx, permittedStatusArgs);
+    }
+
+}
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/validator/YangModelBasicValidator.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/validator/YangModelBasicValidator.java
new file mode 100644 (file)
index 0000000..dc80dba
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.yang.model.validator;
+
+import java.util.List;
+
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.antlr.v4.runtime.tree.ParseTreeWalker;
+import org.opendaylight.controller.yang.model.parser.util.YangValidationException;
+
+/**
+ * Exposed basic yang validation.
+ *
+ * Every file is validated using {@link YangModelBasicValidationListener}.
+ */
+public final class YangModelBasicValidator {
+
+    private final ParseTreeWalker walker;
+
+    public YangModelBasicValidator(ParseTreeWalker walker) {
+        this.walker = walker;
+    }
+
+    public YangModelBasicValidator() {
+        this.walker = new ParseTreeWalker();
+    }
+
+    public void validate(List<ParseTree> trees) {
+        for (int i = 0; i < trees.size(); i++) {
+            try {
+                final YangModelBasicValidationListener yangModelParser = new YangModelBasicValidationListener();
+                walker.walk(yangModelParser, trees.get(i));
+            } catch (YangValidationException e) {
+                // wrap exception to add information about which file failed
+                throw new YangValidationException(
+                        "Yang validation failed for file" + e);
+            }
+        }
+    }
+
+}
index de8f7a4..736efe7 100644 (file)
@@ -189,10 +189,10 @@ public class YangModelParserTest {
 
         LeafSchemaNode ifIndex = (LeafSchemaNode) ifEntry
                 .getDataChildByName("ifIndex");
-        assertEquals(new Uint32(), ifIndex.getType());
+        assertTrue(ifIndex.getType() instanceof Uint32);
         LeafSchemaNode ifMtu = (LeafSchemaNode) ifEntry
                 .getDataChildByName("ifMtu");
-        assertEquals(new Int32(), ifMtu.getType());
+        assertTrue(ifMtu.getType() instanceof Int32);
     }
 
     @Test
@@ -677,11 +677,4 @@ public class YangModelParserTest {
         assertNotNull(output.getDataChildByName("data"));
     }
 
-    @Test
-    public void test() {
-        Module testModule = TestUtils.findModule(modules, "types4");
-
-        boolean flag = false;
-    }
-
 }
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/impl/YangModelValidationListenerTest_Module.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/impl/YangModelValidationListenerTest_Module.java
deleted file mode 100644 (file)
index 76715e8..0000000
+++ /dev/null
@@ -1,315 +0,0 @@
-package org.opendaylight.controller.yang.model.parser.impl;
-
-import static org.hamcrest.core.Is.*;
-import static org.junit.Assert.*;
-import static org.junit.matchers.JUnitMatchers.*;
-import static org.mockito.Mockito.*;
-
-import java.util.Date;
-
-import org.antlr.v4.runtime.tree.ParseTree;
-import org.junit.Before;
-import org.junit.Test;
-import org.opendaylight.controller.antlrv4.code.gen.YangParser.Import_stmtContext;
-import org.opendaylight.controller.antlrv4.code.gen.YangParser.Include_stmtContext;
-import org.opendaylight.controller.antlrv4.code.gen.YangParser.Module_header_stmtsContext;
-import org.opendaylight.controller.antlrv4.code.gen.YangParser.Module_stmtContext;
-import org.opendaylight.controller.antlrv4.code.gen.YangParser.Namespace_stmtContext;
-import org.opendaylight.controller.antlrv4.code.gen.YangParser.Prefix_stmtContext;
-import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_date_stmtContext;
-import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_stmtContext;
-import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_stmtsContext;
-import org.opendaylight.controller.antlrv4.code.gen.YangParser.StringContext;
-import org.opendaylight.controller.antlrv4.code.gen.YangParser.Yang_version_stmtContext;
-
-public class YangModelValidationListenerTest_Module {
-
-    private YangModelValidationListener valid;
-    private Module_stmtContext ctx;
-
-    @Before
-    public void setUp() {
-        valid = new YangModelValidationListener();
-    }
-
-    @Test(expected = YangValidationException.class)
-    public void testRevisionInvalidDateFormat() {
-        Revision_stmtContext mockedRev = mockModuleWithRevision(2, "badFormat");
-
-        try {
-            valid.enterRevision_stmt(mockedRev);
-        } catch (YangValidationException e) {
-            assertThat(
-                    e.getMessage(),
-                    containsString("Invalid date format for revision:badFormat in (sub)module:module1, expected date format is:"));
-            throw e;
-        }
-    }
-
-    private Revision_stmtContext mockModuleWithRevision(int moduleChildren,
-            String date) {
-        Revision_stmtContext mockedRev = mock(Revision_stmtContext.class);
-        doReturn(1).when(mockedRev).getChildCount();
-        mockName(mockedRev, date);
-
-        Revision_stmtsContext revs = mockRevisionsParent(2, mockedRev);
-
-        mockModuleParent(moduleChildren, revs, "module1");
-        return mockedRev;
-    }
-
-    @Test
-    public void testRevisionValidDateFormat() {
-        Revision_stmtContext mockedRev = mockModuleWithRevision(2,
-                getFormattedDate());
-
-        valid.enterRevision_stmt(mockedRev);
-    }
-
-    private String getFormattedDate() {
-        return YangModelParserListenerImpl.simpleDateFormat.format(new Date());
-    }
-
-    @Test(expected = YangValidationException.class)
-    public void testNoRevision() {
-
-        Module_stmtContext ctx = mock(Module_stmtContext.class);
-        doReturn(1).when(ctx).getChildCount();
-        mockName(ctx, "module1");
-
-        try {
-            valid.enterModule_stmt(ctx);
-        } catch (YangValidationException e) {
-            assertThat(
-                    e.getMessage(),
-                    containsString("Missing revision statements in module:module1"));
-            throw e;
-        }
-    }
-
-    @Test(expected = YangValidationException.class)
-    public void testNoHeaderStmts() {
-        mockModuleWithRevision(2, "1999-4-5");
-
-        try {
-            valid.enterModule_stmt(ctx);
-        } catch (YangValidationException e) {
-            assertThat(
-                    e.getMessage(),
-                    containsString("Missing header statements in module:module1"));
-            throw e;
-        }
-    }
-
-    @Test(expected = YangValidationException.class)
-    public void testNoNamespace() {
-        Module_header_stmtsContext header = mock(Module_header_stmtsContext.class);
-        mockModuleParent(2, header, "module1");
-
-        try {
-            valid.enterModule_header_stmts(header);
-        } catch (YangValidationException e) {
-            assertThat(
-                    e.getMessage(),
-                    containsString("Missing namespace statement in module:module1"));
-            throw e;
-        }
-    }
-
-    @Test
-    public void testPrefixes() {
-        Prefix_stmtContext pref = mock(Prefix_stmtContext.class);
-        doReturn(1).when(pref).getChildCount();
-        mockName(pref, "unique1");
-        mockModuleParent(2, pref, "module1");
-        valid.enterPrefix_stmt(pref);
-
-        pref = mock(Prefix_stmtContext.class);
-        doReturn(1).when(pref).getChildCount();
-        mockName(pref, "unique1");
-        mockModuleParent(2, pref, "module1");
-
-        try {
-            valid.enterPrefix_stmt(pref);
-        } catch (Exception e) {
-            return;
-        }
-
-        fail("Validation Exception should have occured");
-    }
-
-    @Test
-    public void testNamespace() {
-        Namespace_stmtContext namespace = mock(Namespace_stmtContext.class);
-        doReturn(1).when(namespace).getChildCount();
-        mockName(namespace, "http://test.parsing.uri.com");
-        mockModuleParent(2, namespace, "module1");
-        valid.enterNamespace_stmt(namespace);
-
-        namespace = mock(Namespace_stmtContext.class);
-        doReturn(1).when(namespace).getChildCount();
-        mockName(namespace, "invalid uri");
-        mockModuleParent(2, namespace, "module1");
-        try {
-            valid.enterNamespace_stmt(namespace);
-        } catch (YangValidationException e) {
-            assertThat(
-                    e.getMessage(),
-                    containsString("Namespace:invalid uri in module:module1 cannot be parsed as URI"));
-            return;
-        }
-
-        fail("Validation Exception should have occured");
-    }
-
-    @Test
-    public void testImports() {
-        Import_stmtContext impor = mockImport("unique1", "p1");
-        mockModuleParent(2, impor, "module1");
-        valid.enterImport_stmt(impor);
-
-        impor = mockImport("unique1", "p2");
-        mockModuleParent(2, impor, "module1");
-        mockName(impor, "unique1");
-
-        try {
-            valid.enterImport_stmt(impor);
-        } catch (YangValidationException e) {
-            assertThat(
-                    e.getMessage(),
-                    containsString("Module:unique1 imported twice in (sub)module:module1"));
-            return;
-        }
-
-        fail("Validation Exception should have occured");
-    }
-
-    @Test
-    public void testIncludes() {
-        Include_stmtContext impor = mockInclude("unique1");
-        mockModuleParent(2, impor, "module1");
-        valid.enterInclude_stmt(impor);
-
-        impor = mockInclude("unique1");
-        mockModuleParent(2, impor, "module1");
-        mockName(impor, "unique1");
-
-        try {
-            valid.enterInclude_stmt(impor);
-        } catch (YangValidationException e) {
-            assertThat(
-                    e.getMessage(),
-                    containsString("Submodule:unique1 included twice in (sub)module:module1"));
-            return;
-        }
-
-        fail("Validation Exception should have occured");
-    }
-
-    private Import_stmtContext mockImport(String name, String prefixName) {
-        Import_stmtContext impor = mock(Import_stmtContext.class);
-        doReturn(3).when(impor).getChildCount();
-        Prefix_stmtContext prefix = mock(Prefix_stmtContext.class);
-        mockName(prefix, prefixName);
-        doReturn(prefix).when(impor).getChild(1);
-        Revision_date_stmtContext revDate = mock(Revision_date_stmtContext.class);
-        mockName(revDate, getFormattedDate());
-        doReturn(revDate).when(impor).getChild(2);
-        mockName(impor, name);
-        return impor;
-    }
-
-    private Include_stmtContext mockInclude(String name) {
-        Include_stmtContext impor = mock(Include_stmtContext.class);
-        doReturn(2).when(impor).getChildCount();
-        Revision_date_stmtContext revDate = mock(Revision_date_stmtContext.class);
-        mockName(revDate, getFormattedDate());
-        doReturn(revDate).when(impor).getChild(1);
-        mockName(impor, name);
-        return impor;
-    }
-
-    @Test(expected = YangValidationException.class)
-    public void testInvalidYangVersion() {
-
-        Yang_version_stmtContext yangVersion = mock(Yang_version_stmtContext.class);
-        doReturn(1).when(yangVersion).getChildCount();
-        mockName(yangVersion, "55Unsup");
-
-        mockModuleParent(2, yangVersion, "module1");
-
-        try {
-            valid.enterYang_version_stmt(yangVersion);
-        } catch (YangValidationException e) {
-            assertThat(
-                    e.getMessage(),
-                    containsString("Unsupported yang version:55Unsup, in (sub)module:module1, supported version:"
-                            + YangModelValidationListener.SUPPORTED_YANG_VERSION));
-            throw e;
-        }
-    }
-
-    private void mockModuleParent(int moduleChildren, ParseTree child,
-            String moduleName) {
-        ctx = mock(Module_stmtContext.class);
-        doReturn(moduleChildren).when(ctx).getChildCount();
-        mockName(ctx, moduleName);
-        doReturn(child).when(ctx).getChild(1);
-        doReturn(ctx).when(child).getParent();
-    }
-
-    static Revision_stmtsContext mockRevisionsParent(int moduleChildren,
-            Revision_stmtContext mockedRev) {
-        Revision_stmtsContext revs = mock(Revision_stmtsContext.class);
-        doReturn(moduleChildren).when(revs).getChildCount();
-        doReturn(mockedRev).when(revs).getChild(1);
-        doReturn(revs).when(mockedRev).getParent();
-        return revs;
-    }
-
-    @Test
-    public void testValidYangVersion() {
-
-        Yang_version_stmtContext ctx = mock(Yang_version_stmtContext.class);
-        doReturn(1).when(ctx).getChildCount();
-        mockName(ctx, "1");
-
-        valid.enterYang_version_stmt(ctx);
-    }
-
-    @Test
-    public void testIdentifierMatching() {
-        YangModelValidationListener.checkIdentifier("_ok98-.87.-.8...88-asdAD",
-                null);
-        YangModelValidationListener.checkIdentifier("AA.bcd", null);
-        YangModelValidationListener.checkIdentifier("a", null);
-
-        int thrown = 0;
-
-        try {
-            YangModelValidationListener.checkIdentifier("9aa", null);
-        } catch (YangValidationException e) {
-            thrown++;
-        }
-        try {
-            YangModelValidationListener.checkIdentifier("-", null);
-        } catch (YangValidationException e) {
-            thrown++;
-        }
-        try {
-            YangModelValidationListener.checkIdentifier(".", null);
-        } catch (YangValidationException e) {
-            thrown++;
-        }
-
-        assertThat(thrown, is(3));
-    }
-
-    static void mockName(ParseTree mockedRev, String name) {
-        StringContext nameCtx = mock(StringContext.class);
-        ParseTree internalName = mock(ParseTree.class);
-        doReturn(name).when(internalName).getText();
-        doReturn(internalName).when(nameCtx).getChild(0);
-        doReturn(nameCtx).when(mockedRev).getChild(0);
-    }
-}
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/impl/YangModelValidationListenerTest_SubModule.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/impl/YangModelValidationListenerTest_SubModule.java
deleted file mode 100644 (file)
index 056e869..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-package org.opendaylight.controller.yang.model.parser.impl;
-
-import static org.junit.Assert.*;
-import static org.junit.matchers.JUnitMatchers.*;
-import static org.mockito.Mockito.*;
-
-import org.antlr.v4.runtime.tree.ParseTree;
-import org.junit.Before;
-import org.junit.Test;
-import org.opendaylight.controller.antlrv4.code.gen.YangParser.Belongs_to_stmtContext;
-import org.opendaylight.controller.antlrv4.code.gen.YangParser.Prefix_stmtContext;
-import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_stmtContext;
-import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_stmtsContext;
-import org.opendaylight.controller.antlrv4.code.gen.YangParser.Submodule_header_stmtsContext;
-import org.opendaylight.controller.antlrv4.code.gen.YangParser.Submodule_stmtContext;
-
-public class YangModelValidationListenerTest_SubModule {
-
-    private YangModelValidationListener valid;
-    private Submodule_stmtContext ctx;
-
-    @Before
-    public void setUp() {
-        valid = new YangModelValidationListener();
-    }
-
-    @Test(expected = YangValidationException.class)
-    public void testNoRevision() {
-
-        Submodule_stmtContext ctx = mock(Submodule_stmtContext.class);
-        doReturn(1).when(ctx).getChildCount();
-        YangModelValidationListenerTest_Module.mockName(ctx, "submodule1");
-
-        try {
-            valid.enterSubmodule_stmt(ctx);
-        } catch (YangValidationException e) {
-            assertThat(
-                    e.getMessage(),
-                    containsString("Missing revision statements in submodule:submodule1"));
-            throw e;
-        }
-    }
-
-    @Test(expected = YangValidationException.class)
-    public void testNoHeaderStmts() {
-        mockSubmoduleWithRevision(2, "1999-4-5", "submodule");
-
-        try {
-            valid.enterSubmodule_stmt(ctx);
-        } catch (YangValidationException e) {
-            assertThat(
-                    e.getMessage(),
-                    containsString("Missing header statements in submodule:submodule"));
-            throw e;
-        }
-    }
-
-    @Test(expected = YangValidationException.class)
-    public void testNoBelongsTo() {
-        Submodule_header_stmtsContext header = mock(Submodule_header_stmtsContext.class);
-        mockSubmoduleParent(2, header, "submodule");
-
-        try {
-            valid.enterSubmodule_header_stmts(header);
-        } catch (YangValidationException e) {
-            assertThat(
-                    e.getMessage(),
-                    containsString("Missing belongs-to statement in submodule:submodule"));
-            throw e;
-        }
-    }
-
-    @Test(expected = YangValidationException.class)
-    public void testBelongsToNoPrefix() {
-        Belongs_to_stmtContext belongsTo = mock(Belongs_to_stmtContext.class);
-        doReturn(1).when(belongsTo).getChildCount();
-        YangModelValidationListenerTest_Module.mockName(belongsTo,
-                "supermodule");
-
-        mockSubmoduleParent(2, belongsTo, "submodule");
-
-        try {
-            valid.enterBelongs_to_stmt(belongsTo);
-        } catch (YangValidationException e) {
-            assertThat(
-                    e.getMessage(),
-                    containsString("Missing prefix statement in belongs-to:supermodule, in (sub)module:submodule"));
-            throw e;
-        }
-    }
-
-    @Test
-    public void testBelongsTo() {
-        Belongs_to_stmtContext belongsTo = mock(Belongs_to_stmtContext.class);
-        doReturn(2).when(belongsTo).getChildCount();
-        YangModelValidationListenerTest_Module.mockName(belongsTo,
-                "supermodule");
-
-        Prefix_stmtContext prefix = mock(Prefix_stmtContext.class);
-        doReturn(prefix).when(belongsTo).getChild(1);
-        doReturn(belongsTo).when(prefix).getParent();
-
-        mockSubmoduleParent(2, belongsTo, "submodule");
-        valid.enterBelongs_to_stmt(belongsTo);
-
-    }
-
-    private Revision_stmtContext mockSubmoduleWithRevision(int moduleChildren,
-            String date, String nameOfSubmodule) {
-        Revision_stmtContext mockedRev = mock(Revision_stmtContext.class);
-        doReturn(1).when(mockedRev).getChildCount();
-        YangModelValidationListenerTest_Module.mockName(mockedRev, date);
-
-        Revision_stmtsContext revs = YangModelValidationListenerTest_Module
-                .mockRevisionsParent(2, mockedRev);
-
-        mockSubmoduleParent(moduleChildren, revs, nameOfSubmodule);
-        return mockedRev;
-    }
-
-    private void mockSubmoduleParent(int moduleChildren, ParseTree child,
-            String moduleName) {
-        ctx = mock(Submodule_stmtContext.class);
-        doReturn(moduleChildren).when(ctx).getChildCount();
-        YangModelValidationListenerTest_Module.mockName(ctx, moduleName);
-        doReturn(child).when(ctx).getChild(1);
-        doReturn(ctx).when(child).getParent();
-    }
-}
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/validator/YangModelValidationListTest.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/validator/YangModelValidationListTest.java
new file mode 100644 (file)
index 0000000..4e05f48
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.yang.model.validator;
+
+import static org.junit.Assert.*;
+import static org.junit.matchers.JUnitMatchers.*;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Default_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Key_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Leaf_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.List_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Mandatory_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Ordered_by_argContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Type_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Unique_stmtContext;
+import org.opendaylight.controller.yang.model.parser.util.YangValidationException;
+
+public class YangModelValidationListTest {
+
+    private YangModelBasicValidationListener valid;
+
+    @Before
+    public void setUp() {
+        valid = new YangModelBasicValidationListener();
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testKeyValidationDuplicates() {
+
+        List_stmtContext list = YangModelValidationTest.mockStatement(
+                List_stmtContext.class, "list");
+        Key_stmtContext key = YangModelValidationTest.mockStatement(
+                Key_stmtContext.class, "leaf1 leaf2 leaf1 leaf1");
+        YangModelValidationTest.addChild(list, key);
+
+        try {
+            valid.enterKey_stmt(key);
+        } catch (YangValidationException e) {
+            assertThat(e.getMessage(),
+                    containsString("contains duplicates:[leaf1]"));
+            throw e;
+        }
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testUniqueValidationDuplicates() {
+        List_stmtContext list = YangModelValidationTest.mockStatement(
+                List_stmtContext.class, "list");
+        Unique_stmtContext unique = YangModelValidationTest.mockStatement(
+                Unique_stmtContext.class, "leaf1/a leaf2/n leaf1/a leaf1");
+        YangModelValidationTest.addChild(list, unique);
+
+        try {
+            valid.enterUnique_stmt(unique);
+        } catch (YangValidationException e) {
+            assertThat(e.getMessage(),
+                    containsString("contains duplicates:[leaf1/a]"));
+            throw e;
+        }
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testOrderBy() {
+        Ordered_by_argContext ctx = YangModelValidationTest.mockStatement(
+                Ordered_by_argContext.class, "unknown");
+
+        try {
+            valid.enterOrdered_by_arg(ctx);
+        } catch (YangValidationException e) {
+            assertThat(
+                    e.getMessage(),
+                    containsString("Ordered-by:unknown, illegal value for Ordered-by statement, only permitted:"));
+            throw e;
+        }
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testLeaf() {
+        Leaf_stmtContext ctx = YangModelValidationTest.mockStatement(
+                Leaf_stmtContext.class, "leaf1");
+        Default_stmtContext def = YangModelValidationTest.mockStatement(
+                Default_stmtContext.class, "default");
+        YangModelValidationTest.addChild(ctx, def);
+        Type_stmtContext typ = YangModelValidationTest.mockStatement(
+                Type_stmtContext.class, "type");
+        YangModelValidationTest.addChild(ctx, def);
+        YangModelValidationTest.addChild(ctx, typ);
+
+        Mandatory_stmtContext mand = YangModelValidationTest.mockStatement(
+                Mandatory_stmtContext.class, null);
+        YangModelValidationTest.addChild(ctx, mand);
+
+        try {
+            valid.enterLeaf_stmt(ctx);
+        } catch (YangValidationException e) {
+            assertThat(
+                    e.getMessage(),
+                    containsString("Both Mandatory and Default statement present"));
+            throw e;
+        }
+    }
+
+}
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/validator/YangModelValidationModuleTest.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/validator/YangModelValidationModuleTest.java
new file mode 100644 (file)
index 0000000..2bdd3e5
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.yang.model.validator;
+
+import static org.junit.Assert.*;
+import static org.junit.matchers.JUnitMatchers.*;
+import static org.mockito.Mockito.*;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Module_header_stmtsContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Module_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Namespace_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_stmtsContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Yang_version_stmtContext;
+import org.opendaylight.controller.yang.model.parser.util.YangValidationException;
+
+public class YangModelValidationModuleTest {
+
+    private YangModelBasicValidationListener valid;
+
+    @Before
+    public void setUp() {
+        valid = new YangModelBasicValidationListener();
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testRevisionInvalidDateFormat() {
+        Revision_stmtContext mockedRev = mockModuleWithRevision("badFormat",
+                "module1");
+
+        try {
+            valid.enterRevision_stmt(mockedRev);
+        } catch (YangValidationException e) {
+            assertThat(
+                    e.getMessage(),
+                    containsString("Revision:badFormat, invalid date format expected date format is:"));
+            throw e;
+        }
+    }
+
+    @Test
+    public void testRevisionValidDateFormat() {
+        Revision_stmtContext mockedRev = mockModuleWithRevision(
+                YangModelValidationTest.getFormattedDate(), "module1");
+
+        valid.enterRevision_stmt(mockedRev);
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testNoHeaderStmts() {
+        Revision_stmtContext rev = mockModuleWithRevision("1999-4-5", "module1");
+
+        try {
+            valid.enterModule_stmt((Module_stmtContext) rev.getParent()
+                    .getParent());
+        } catch (YangValidationException e) {
+            assertThat(
+                    e.getMessage(),
+                    containsString("Missing Module-header statement in Module:module1"));
+            throw e;
+        }
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testMultipleModulesPerSession() {
+        Module_stmtContext module1 = (Module_stmtContext) mockModuleWithRevision(
+                "1999-09-10", "m1").getParent().getParent();
+        YangModelValidationTest.addChild(module1, YangModelValidationTest
+                .mockStatement(Namespace_stmtContext.class, ""));
+
+        Module_stmtContext module2 = (Module_stmtContext) mockModuleWithRevision(
+                "1999-09-10", "m2").getParent().getParent();
+        YangModelValidationTest.addChild(module1, YangModelValidationTest
+                .mockStatement(Namespace_stmtContext.class, ""));
+        valid.enterModule_stmt(module1);
+
+        try {
+            valid.enterModule_stmt(module2);
+        } catch (YangValidationException e) {
+            assertThat(e.getMessage(),
+                    containsString("Multiple (sub)modules per file"));
+            throw e;
+        }
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testNoNamespace() {
+        Module_header_stmtsContext header = YangModelValidationTest
+                .mockStatement(Module_header_stmtsContext.class, null);
+        Module_stmtContext mod = YangModelValidationTest.mockStatement(
+                Module_stmtContext.class, "module1");
+        YangModelValidationTest.addChild(mod, header);
+
+        try {
+            valid.enterModule_header_stmts(header);
+        } catch (YangValidationException e) {
+            assertThat(
+                    e.getMessage(),
+                    containsString("Missing Namespace statement in Module-header:"));
+            throw e;
+        }
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testNoPrefix() {
+        Module_header_stmtsContext header = YangModelValidationTest
+                .mockStatement(Module_header_stmtsContext.class, null);
+        Namespace_stmtContext nmspc = YangModelValidationTest.mockStatement(
+                Namespace_stmtContext.class, "http://test");
+        Module_stmtContext mod = YangModelValidationTest.mockStatement(
+                Module_stmtContext.class, "module1");
+        YangModelValidationTest.addChild(mod, header);
+        YangModelValidationTest.addChild(header, nmspc);
+
+        try {
+            valid.enterModule_header_stmts(header);
+        } catch (YangValidationException e) {
+            assertThat(
+                    e.getMessage(),
+                    containsString("Missing Prefix statement in Module-header:"));
+            throw e;
+        }
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testInvalidYangVersion() {
+
+        Yang_version_stmtContext yangVersion = YangModelValidationTest
+                .mockStatement(Yang_version_stmtContext.class, "55Unsup");
+
+        Module_stmtContext mod = YangModelValidationTest.mockStatement(
+                Module_stmtContext.class, "module1");
+        YangModelValidationTest.addChild(mod, yangVersion);
+
+        try {
+            valid.enterYang_version_stmt(yangVersion);
+        } catch (YangValidationException e) {
+            assertThat(
+                    e.getMessage(),
+                    containsString("Unsupported yang version:55Unsup, supported version:"
+                            + BasicValidations.SUPPORTED_YANG_VERSION));
+            throw e;
+        }
+    }
+
+    @Test
+    public void testValidYangVersion() {
+
+        Yang_version_stmtContext ctx = mock(Yang_version_stmtContext.class);
+        doReturn(1).when(ctx).getChildCount();
+        YangModelValidationTest.mockName(ctx, "1");
+
+        valid.enterYang_version_stmt(ctx);
+    }
+
+    private static Revision_stmtContext mockModuleWithRevision(String date,
+            String moduleName) {
+        Revision_stmtContext mockedRev = YangModelValidationTest.mockStatement(
+                Revision_stmtContext.class, date);
+        Revision_stmtsContext revs = YangModelValidationTest.mockStatement(
+                Revision_stmtsContext.class, null);
+        Module_stmtContext mod = YangModelValidationTest.mockStatement(
+                Module_stmtContext.class, moduleName);
+
+        YangModelValidationTest.addChild(revs, mockedRev);
+        YangModelValidationTest.addChild(mod, revs);
+        return mockedRev;
+    }
+}
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/validator/YangModelValidationSubModuleTest.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/validator/YangModelValidationSubModuleTest.java
new file mode 100644 (file)
index 0000000..fe4f0a2
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.yang.model.validator;
+
+import static org.junit.Assert.*;
+import static org.junit.matchers.JUnitMatchers.*;
+import static org.mockito.Mockito.*;
+
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Belongs_to_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Submodule_header_stmtsContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Submodule_stmtContext;
+import org.opendaylight.controller.yang.model.parser.util.YangValidationException;
+
+public class YangModelValidationSubModuleTest {
+
+    private YangModelBasicValidationListener valid;
+
+    @Before
+    public void setUp() {
+        valid = new YangModelBasicValidationListener();
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testNoRevision() {
+
+        Submodule_stmtContext ctx = YangModelValidationTest.mockStatement(
+                Submodule_stmtContext.class, "submodule1");
+
+        try {
+            valid.enterSubmodule_stmt(ctx);
+        } catch (YangValidationException e) {
+            assertThat(
+                    e.getMessage(),
+                    containsString("Missing Submodule-header statement in Submodule:submodule"));
+            throw e;
+        }
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testNoBelongsTo() {
+        Submodule_header_stmtsContext header = mock(Submodule_header_stmtsContext.class);
+        mockSubmoduleParent(header, "submodule");
+
+        try {
+            valid.enterSubmodule_header_stmts(header);
+        } catch (YangValidationException e) {
+            assertThat(
+                    e.getMessage(),
+                    containsString("Missing Belongs-to statement in Submodule-header:"));
+            throw e;
+        }
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testBelongsToNoPrefix() {
+        Belongs_to_stmtContext belongsTo = YangModelValidationTest
+                .mockStatement(Belongs_to_stmtContext.class, "supermodule");
+
+        mockSubmoduleParent(belongsTo, "submodule");
+
+        try {
+            valid.enterBelongs_to_stmt(belongsTo);
+        } catch (YangValidationException e) {
+            assertThat(
+                    e.getMessage(),
+                    containsString("Missing Prefix statement in Belongs-to:supermodule"));
+            throw e;
+        }
+    }
+
+    private Submodule_stmtContext mockSubmoduleParent(ParseTree child,
+            String moduleName) {
+        Submodule_stmtContext ctx = YangModelValidationTest.mockStatement(
+                Submodule_stmtContext.class, moduleName);
+        YangModelValidationTest.addChild(ctx, child);
+        return ctx;
+    }
+}
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/validator/YangModelValidationTest.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/validator/YangModelValidationTest.java
new file mode 100644 (file)
index 0000000..ffcadf6
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.yang.model.validator;
+
+import static org.hamcrest.core.Is.*;
+import static org.junit.Assert.*;
+import static org.junit.matchers.JUnitMatchers.*;
+import static org.mockito.Mockito.*;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Augment_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Deviate_add_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Deviate_delete_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Deviation_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Import_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Include_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Module_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Namespace_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Prefix_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_date_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Status_argContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.StringContext;
+import org.opendaylight.controller.yang.model.parser.impl.YangModelParserListenerImpl;
+import org.opendaylight.controller.yang.model.parser.util.YangValidationException;
+
+import com.google.common.collect.Sets;
+
+public class YangModelValidationTest {
+
+    private YangModelBasicValidationListener valid;
+
+    @Before
+    public void setUp() {
+
+        valid = new YangModelBasicValidationListener();
+    }
+
+    @Test
+    public void testPrefixes() {
+        Prefix_stmtContext pref = mockStatement(Prefix_stmtContext.class,
+                "unique1");
+        Module_stmtContext module = mockStatement(Module_stmtContext.class,
+                "module1");
+        addChild(module, pref);
+
+        valid.enterPrefix_stmt(pref);
+
+        pref = mockStatement(Prefix_stmtContext.class, "unique1");
+        module = mockStatement(Module_stmtContext.class, "module1");
+        addChild(module, pref);
+
+        try {
+            valid.enterPrefix_stmt(pref);
+        } catch (Exception e) {
+            return;
+        }
+
+        fail("Validation Exception should have occured");
+    }
+
+    @Test
+    public void testNamespace() {
+
+        Namespace_stmtContext namespace = mockStatement(
+                Namespace_stmtContext.class, "http://test.parsing.uri.com");
+        Module_stmtContext module = mockStatement(Module_stmtContext.class,
+                "module1");
+        addChild(module, namespace);
+
+        valid.enterNamespace_stmt(namespace);
+
+        namespace = mockStatement(Namespace_stmtContext.class, "invalid uri");
+        module = mockStatement(Module_stmtContext.class, "module1");
+        addChild(module, namespace);
+
+        try {
+            valid.enterNamespace_stmt(namespace);
+        } catch (YangValidationException e) {
+            assertThat(
+                    e.getMessage(),
+                    containsString("Namespace:invalid uri cannot be parsed as URI"));
+            return;
+        }
+
+        fail("Validation Exception should have occured");
+    }
+
+    @Test
+    public void testImports() {
+        Import_stmtContext impor = mockImport("unique1", "p1");
+        Module_stmtContext mod = mockStatement(Module_stmtContext.class,
+                "module1");
+        addChild(mod, impor);
+
+        valid.enterImport_stmt(impor);
+
+        impor = mockImport("unique1", "p2");
+        mod = mockStatement(Module_stmtContext.class, "module1");
+        addChild(mod, impor);
+
+        try {
+            valid.enterImport_stmt(impor);
+        } catch (YangValidationException e) {
+            assertThat(e.getMessage(),
+                    containsString("Import:unique1 not unique"));
+            return;
+        }
+
+        fail("Validation Exception should have occured");
+    }
+
+    @Test
+    public void testIncludes() {
+        Include_stmtContext incl = mockInclude("unique1");
+        Module_stmtContext mod = mockStatement(Module_stmtContext.class,
+                "module1");
+        addChild(mod, incl);
+        valid.enterInclude_stmt(incl);
+
+        incl = mockInclude("unique1");
+        mod = mockStatement(Module_stmtContext.class, "module1");
+        addChild(mod, incl);
+
+        try {
+            valid.enterInclude_stmt(incl);
+        } catch (YangValidationException e) {
+            assertThat(e.getMessage(),
+                    containsString("Include:unique1 not unique in (sub)module"));
+            return;
+        }
+
+        fail("Validation Exception should have occured");
+    }
+
+    @Test
+    public void testIdentifierMatching() {
+        List<String> ids = new ArrayList<String>();
+        // valid
+        ids.add("_ok98-.87.-.8...88-asdAD");
+        ids.add("AA.bcd");
+        ids.add("a");
+        // invalid
+        ids.add("9aa");
+        ids.add("-");
+        ids.add(".");
+
+        int thrown = 0;
+        for (String id : ids) {
+            try {
+                BasicValidations.checkIdentifierInternal(
+                        mock(Module_stmtContext.class), id);
+            } catch (YangValidationException e) {
+                thrown++;
+            }
+        }
+
+        assertThat(thrown, is(3));
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testAugument() {
+        Augment_stmtContext augument = mockStatement(Augment_stmtContext.class,
+                "/a:*abc/a:augument1");
+        Module_stmtContext mod1 = mockStatement(Module_stmtContext.class,
+                "mod1");
+        addChild(mod1, augument);
+
+        try {
+            valid.enterAugment_stmt(augument);
+        } catch (YangValidationException e) {
+            assertThat(
+                    e.getMessage(),
+                    containsString("Schema node id:/a:*abc/a:augument1 not in required format, details:Prefixed id:a:*abc not in required format"));
+            throw e;
+        }
+    }
+
+    @Test
+    public void testDeviate() {
+        Deviation_stmtContext ctx = mockStatement(Deviation_stmtContext.class,
+                "deviations");
+        Deviate_add_stmtContext add = mockStatement(
+                Deviate_add_stmtContext.class, "add");
+        Deviate_delete_stmtContext del = mockStatement(
+                Deviate_delete_stmtContext.class, "delete");
+
+        addChild(ctx, add);
+        addChild(ctx, del);
+
+        valid.enterDeviation_stmt(ctx);
+
+        HashSet<Class<? extends ParseTree>> types = Sets.newHashSet();
+        types.add(Deviate_add_stmtContext.class);
+        types.add(Deviate_delete_stmtContext.class);
+
+        int count = ValidationUtil.countPresentChildrenOfType(ctx, types);
+        assertThat(count, is(2));
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testStatus() throws Exception {
+        Status_argContext status = mockStatement(Status_argContext.class,
+                "unknown");
+        try {
+            valid.enterStatus_arg(status);
+        } catch (YangValidationException e) {
+            assertThat(
+                    e.getMessage(),
+                    containsString("illegal value for Status statement, only permitted:"));
+            throw e;
+        }
+    }
+
+    private Import_stmtContext mockImport(String name, String prefixName) {
+        Import_stmtContext impor = mockStatement(Import_stmtContext.class, name);
+
+        Prefix_stmtContext prefix = mockStatement(Prefix_stmtContext.class,
+                prefixName);
+        Revision_date_stmtContext revDate = mockStatement(
+                Revision_date_stmtContext.class, getFormattedDate());
+
+        addChild(impor, prefix);
+        addChild(impor, revDate);
+        return impor;
+    }
+
+    static String getFormattedDate() {
+        return YangModelParserListenerImpl.simpleDateFormat.format(new Date());
+    }
+
+    private Include_stmtContext mockInclude(String name) {
+        Include_stmtContext incl = mockStatement(Include_stmtContext.class,
+                name);
+
+        Revision_date_stmtContext revDate = mockStatement(
+                Revision_date_stmtContext.class, getFormattedDate());
+
+        addChild(incl, revDate);
+        return incl;
+    }
+
+    static void mockName(ParseTree stmt, String name) {
+        StringContext nameCtx = mock(StringContext.class);
+        ParseTree internalName = mock(ParseTree.class);
+        doReturn(1).when(stmt).getChildCount();
+        doReturn(name).when(internalName).getText();
+        doReturn(internalName).when(nameCtx).getChild(0);
+        doReturn(nameCtx).when(stmt).getChild(0);
+    }
+
+    static <T extends ParseTree> T mockStatement(Class<T> stmtType, String name) {
+        T stmt = stmtType.cast(mock(stmtType));
+
+        doReturn(0).when(stmt).getChildCount();
+
+        if (name != null)
+            mockName(stmt, name);
+        return stmt;
+    }
+
+    static void addChild(ParseTree parent, ParseTree child) {
+        int childCount = parent.getChildCount() + 1;
+        doReturn(childCount).when(parent).getChildCount();
+        doReturn(child).when(parent).getChild(childCount - 1);
+        doReturn(parent).when(child).getParent();
+    }
+
+}
index 366df63..3907cc1 100644 (file)
@@ -7,8 +7,10 @@
  */
 package org.opendaylight.controller.yang.model.util;
 
+import java.net.URI;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Date;
 import java.util.List;
 
 import org.opendaylight.controller.yang.common.QName;
@@ -23,7 +25,7 @@ import org.opendaylight.controller.yang.model.api.type.RangeConstraint;
  * interface which represents SIGNED Integer values defined in Yang language. <br>
  * The integer built-in types in Yang are int8, int16, int32, int64. They
  * represent signed integers of different sizes:
- * 
+ *
  * <ul>
  * <li>int8 - represents integer values between -128 and 127, inclusively.</li>
  * <li>int16 - represents integer values between -32768 and 32767, inclusively.</li>
@@ -32,7 +34,7 @@ import org.opendaylight.controller.yang.model.api.type.RangeConstraint;
  * <li>int64 - represents integer values between -9223372036854775808 and
  * 9223372036854775807, inclusively.</li>
  * </ul>
- * 
+ *
  */
 public abstract class AbstractSignedInteger implements IntegerTypeDefinition {
 
@@ -51,17 +53,20 @@ public abstract class AbstractSignedInteger implements IntegerTypeDefinition {
      * @param maxRange
      * @param units
      */
-    public AbstractSignedInteger(final QName name, final String description,
-            final Number minRange, final Number maxRange, final String units) {
+    public AbstractSignedInteger(final List<String> actualPath,
+            final URI namespace, final Date revision, final QName name,
+            final String description, final Number minRange,
+            final Number maxRange, final String units) {
         this.name = name;
         this.description = description;
-        this.path = BaseTypes.schemaPath(name);
+        this.path = BaseTypes.schemaPath(actualPath, namespace, revision);
         this.units = units;
         this.rangeStatements = new ArrayList<RangeConstraint>();
         final String rangeDescription = "Integer values between " + minRange
                 + " and " + maxRange + ", inclusively.";
         this.rangeStatements.add(BaseConstraints.rangeConstraint(minRange,
-                maxRange, rangeDescription, "https://tools.ietf.org/html/rfc6020#section-9.2.4"));
+                maxRange, rangeDescription,
+                "https://tools.ietf.org/html/rfc6020#section-9.2.4"));
     }
 
     /**
@@ -70,11 +75,13 @@ public abstract class AbstractSignedInteger implements IntegerTypeDefinition {
      * @param rangeStatements
      * @param units
      */
-    public AbstractSignedInteger(final QName name, final String description,
+    public AbstractSignedInteger(final List<String> actualPath,
+            final URI namespace, final Date revision, final QName name,
+            final String description,
             final List<RangeConstraint> rangeStatements, final String units) {
         this.name = name;
         this.description = description;
-        this.path = BaseTypes.schemaPath(name);
+        this.path = BaseTypes.schemaPath(actualPath, namespace, revision);
         this.units = units;
         this.rangeStatements = rangeStatements;
     }
index c444ce9..7604851 100644 (file)
@@ -1,10 +1,12 @@
 /**
- * 
+ *
  */
 package org.opendaylight.controller.yang.model.util;
 
+import java.net.URI;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Date;
 import java.util.List;
 
 import org.opendaylight.controller.yang.common.QName;
@@ -17,16 +19,16 @@ import org.opendaylight.controller.yang.model.api.type.UnsignedIntegerTypeDefini
 /**
  * The Abstract Integer class defines implementation of IntegerTypeDefinition
  * interface which represents UNSIGNED Integer values defined in Yang language. <br>
- * The integer built-in types in Yang are uint8,  uint16, uint32, and uint64. They
- * represent unsigned integers of different sizes:
- * 
+ * The integer built-in types in Yang are uint8, uint16, uint32, and uint64.
+ * They represent unsigned integers of different sizes:
+ *
  * <ul>
  * <li>uint8 - represents integer values between 0 and 255, inclusively.</li>
  * <li>uint16 - represents integer values between 0 and 65535, inclusively.</li>
- * <li>uint32 - represents integer values between 0 and 4294967295,
     inclusively.</li>
+ * <li>uint32 - represents integer values between 0 and 4294967295, inclusively.
</li>
  * <li>uint64 - represents integer values between 0 and 18446744073709551615,
     inclusively.</li>
* inclusively.</li>
  * </ul>
  *
  */
@@ -39,7 +41,7 @@ public abstract class AbstractUnsignedInteger implements
 
     private final String units;
     private final List<RangeConstraint> rangeStatements;
-    
+
     /**
      * @param name
      * @param description
@@ -47,17 +49,20 @@ public abstract class AbstractUnsignedInteger implements
      * @param maxRange
      * @param units
      */
-    public AbstractUnsignedInteger(final QName name, final String description,
-            final Number minRange, final Number maxRange, final String units) {
+    public AbstractUnsignedInteger(final List<String> actualPath,
+            final URI namespace, final Date revision, final QName name,
+            final String description, final Number minRange,
+            final Number maxRange, final String units) {
         this.name = name;
         this.description = description;
-        this.path = BaseTypes.schemaPath(name);
+        this.path = BaseTypes.schemaPath(actualPath, namespace, revision);
         this.units = units;
         this.rangeStatements = new ArrayList<RangeConstraint>();
         final String rangeDescription = "Integer values between " + minRange
                 + " and " + maxRange + ", inclusively.";
         this.rangeStatements.add(BaseConstraints.rangeConstraint(minRange,
-                maxRange, rangeDescription, "https://tools.ietf.org/html/rfc6020#section-9.2.4"));
+                maxRange, rangeDescription,
+                "https://tools.ietf.org/html/rfc6020#section-9.2.4"));
     }
 
     /**
@@ -66,15 +71,17 @@ public abstract class AbstractUnsignedInteger implements
      * @param rangeStatements
      * @param units
      */
-    public AbstractUnsignedInteger(final QName name, final String description,
+    public AbstractUnsignedInteger(final List<String> actualPath,
+            final URI namespace, final Date revision, final QName name,
+            final String description,
             final List<RangeConstraint> rangeStatements, final String units) {
         this.name = name;
         this.description = description;
-        this.path = BaseTypes.schemaPath(name);
+        this.path = BaseTypes.schemaPath(actualPath, namespace, revision);
         this.units = units;
         this.rangeStatements = rangeStatements;
     }
-    
+
     @Override
     public String getUnits() {
         return units;
index a1073c6..158865a 100644 (file)
@@ -8,8 +8,10 @@
 package org.opendaylight.controller.yang.model.util;
 
 import java.math.BigDecimal;
+import java.net.URI;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Date;
 import java.util.List;
 
 import org.opendaylight.controller.yang.common.QName;
@@ -21,8 +23,8 @@ import org.opendaylight.controller.yang.model.api.type.RangeConstraint;
 
 /**
  * The <code>default</code> implementation of Decimal Type Definition interface.
- * 
- * 
+ *
+ *
  * @see DecimalTypeDefinition
  */
 public class Decimal64 implements DecimalTypeDefinition {
@@ -52,14 +54,15 @@ public class Decimal64 implements DecimalTypeDefinition {
      * inclusively as defined interface {@link DecimalTypeDefinition} <br>
      * If the fraction digits are not defined inner the definition boundaries
      * the constructor will throw {@link IllegalArgumentException}
-     * 
+     *
      * @param fractionDigits
      *            integer between 1 and 18 inclusively
-     * 
+     *
      * @see DecimalTypeDefinition
      * @exception IllegalArgumentException
      */
-    public Decimal64(final Integer fractionDigits) {
+    public Decimal64(final List<String> actualPath, final URI namespace,
+            final Date revision, final Integer fractionDigits) {
         super();
         if (!((fractionDigits.intValue() > 1) && (fractionDigits.intValue() <= 18))) {
             throw new IllegalArgumentException(
@@ -67,12 +70,12 @@ public class Decimal64 implements DecimalTypeDefinition {
         }
         this.fractionDigits = fractionDigits;
         rangeStatements = defaultRangeStatements();
-        this.path = BaseTypes.schemaPath(name);
+        this.path = BaseTypes.schemaPath(actualPath, namespace, revision);
     }
 
     /**
      * Decimal64 Type Constructor. <br>
-     * 
+     *
      * If parameter <code>Range Statements</code> is <code>null</code> or
      * defined as <code>empty List</code> the constructor automatically assigns
      * the boundaries as min and max value defined for Decimal64 in <a
@@ -83,14 +86,15 @@ public class Decimal64 implements DecimalTypeDefinition {
      * inclusively as defined interface {@link DecimalTypeDefinition} <br>
      * If the fraction digits are not defined inner the definition boundaries
      * the constructor will throw {@link IllegalArgumentException}
-     * 
+     *
      * @param rangeStatements
      *            Range Constraint Statements
      * @param fractionDigits
      *            integer between 1 and 18 inclusively
      * @exception IllegalArgumentException
      */
-    public Decimal64(final List<RangeConstraint> rangeStatements,
+    public Decimal64(final List<String> actualPath, final URI namespace,
+            final Date revision, final List<RangeConstraint> rangeStatements,
             Integer fractionDigits) {
         super();
         if (!((fractionDigits.intValue() > 1) && (fractionDigits.intValue() <= 18))) {
@@ -103,7 +107,7 @@ public class Decimal64 implements DecimalTypeDefinition {
             this.rangeStatements = Collections.unmodifiableList(rangeStatements);
         }
         this.fractionDigits = fractionDigits;
-        this.path = BaseTypes.schemaPath(name);
+        this.path = BaseTypes.schemaPath(actualPath, namespace, revision);
     }
 
     /**
@@ -118,7 +122,7 @@ public class Decimal64 implements DecimalTypeDefinition {
      * inclusively as defined interface {@link DecimalTypeDefinition} <br>
      * If the fraction digits are not defined inner the definition boundaries
      * the constructor will throw {@link IllegalArgumentException}
-     * 
+     *
      * @param units
      *            units associated with the type
      * @param defaultValue
@@ -127,10 +131,11 @@ public class Decimal64 implements DecimalTypeDefinition {
      *            Range Constraint Statements
      * @param fractionDigits
      *            integer between 1 and 18 inclusively
-     * 
+     *
      * @exception IllegalArgumentException
      */
-    public Decimal64(final String units, final BigDecimal defaultValue,
+    public Decimal64(final List<String> actualPath, final URI namespace,
+            final Date revision, final String units, final BigDecimal defaultValue,
             final List<RangeConstraint> rangeStatements,
             final Integer fractionDigits) {
         super();
@@ -141,7 +146,7 @@ public class Decimal64 implements DecimalTypeDefinition {
 
         if (rangeStatements == null || rangeStatements.isEmpty()) {