Merge "Bug 383 - exception raised if key part of URI is incorrect"
authorTony Tkacik <ttkacik@cisco.com>
Mon, 3 Mar 2014 10:41:25 +0000 (10:41 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Mon, 3 Mar 2014 10:41:25 +0000 (10:41 +0000)
77 files changed:
opendaylight/commons/opendaylight/pom.xml
opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/02-toaster-sample.xml [new file with mode: 0644]
opendaylight/forwardingrulesmanager/api/src/main/java/org/opendaylight/controller/forwardingrulesmanager/FlowConfig.java
opendaylight/forwardingrulesmanager/api/src/test/java/org/opendaylight/controller/forwardingrulesmanager/frmTest.java
opendaylight/forwardingrulesmanager/implementation/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManager.java
opendaylight/forwardingrulesmanager/integrationtest/pom.xml
opendaylight/hosttracker/integrationtest/pom.xml
opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/FlowServiceAdapter.java
opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/FlowStatisticsAdapter.java
opendaylight/md-sal/model/pom.xml
opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RoutingTable.java
opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/Activator.java
opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImpl.java
opendaylight/md-sal/remoterpc-routingtable/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImplTest.java
opendaylight/md-sal/sal-binding-broker/pom.xml
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java
opendaylight/md-sal/sal-binding-config/pom.xml
opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/Futures.java
opendaylight/md-sal/sal-dom-api/pom.xml
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RoutedRpcDefaultImplementation.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcProvisionRegistry.java
opendaylight/md-sal/sal-dom-broker/pom.xml
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.xtend
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/MountPointImpl.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareRpcBroker.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/RpcProvisionRegistryProxy.java
opendaylight/md-sal/sal-netconf-connector/pom.xml
opendaylight/md-sal/sal-remote/pom.xml
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/config/yang/md/sal/remote/rpc/ZeroMQServerModule.java
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/ClientImpl.java
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/RemoteRpcClient.java
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/RemoteRpcProvider.java
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/RoutingTableProvider.java
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/ServerImpl.java
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/dto/RouteIdentifierImpl.java
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/yang/odl-sal-dom-rpc-remote-cfg.yang
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/ClientImplTest.java
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/MockRoutingTable.java
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/RemoteRpcProviderTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/RouteIdentifierImplTest.java [deleted file]
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/ServerImplTest.java
opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-nb/pom.xml
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend
opendaylight/md-sal/samples/pom.xml
opendaylight/md-sal/samples/toaster-consumer/pom.xml
opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/config/yang/config/toaster_consumer/impl/ToasterConsumerModule.java [new file with mode: 0644]
opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/config/yang/config/toaster_consumer/impl/ToasterConsumerModuleFactory.java [new file with mode: 0644]
opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/sample/toaster/provider/impl/ToastConsumerImpl.java
opendaylight/md-sal/samples/toaster-consumer/src/main/yang/toaster-consumer-impl.yang [new file with mode: 0644]
opendaylight/md-sal/samples/toaster-consumer/src/main/yang/toaster-consumer.yang [new file with mode: 0644]
opendaylight/md-sal/samples/toaster-it/pom.xml
opendaylight/md-sal/samples/toaster-it/src/test/java/org/opendaylight/controller/sample/toaster/it/ToasterTest.java
opendaylight/md-sal/samples/toaster-it/src/test/resources/controller.xml [new file with mode: 0644]
opendaylight/md-sal/samples/toaster-it/src/test/resources/logback.xml
opendaylight/md-sal/samples/toaster-provider/pom.xml
opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/config/yang/config/toaster_provider/impl/ToasterProviderModule.java [new file with mode: 0644]
opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/config/yang/config/toaster_provider/impl/ToasterProviderModuleFactory.java [new file with mode: 0644]
opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/OpendaylightToaster.java
opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/ToasterActivator.java [deleted file]
opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/ToasterProvider.java [deleted file]
opendaylight/md-sal/samples/toaster-provider/src/main/yang/toaster-provider-impl.yang [new file with mode: 0644]
opendaylight/md-sal/samples/toaster-provider/src/main/yang/toaster-provider.yang [new file with mode: 0644]
opendaylight/md-sal/samples/toaster/pom.xml
opendaylight/netconf/config-persister-impl/pom.xml
opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/MessageHeaderTest.java
opendaylight/netconf/netconf-util/pom.xml
opendaylight/northbound/flowprogrammer/src/main/java/org/opendaylight/controller/flowprogrammer/northbound/FlowProgrammerNorthbound.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/Activator.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Path.java
opendaylight/statisticsmanager/integrationtest/pom.xml
opendaylight/switchmanager/integrationtest/pom.xml
opendaylight/topologymanager/integrationtest/pom.xml
third-party/com.siemens.ct.exi/pom.xml [deleted file]

index acda40035f425d24c829957ff40e65bf038393bb..77c807b0ed936fa27361274591aeb749e034f141 100644 (file)
         <artifactId>maven-surefire-plugin</artifactId>
         <version>${surefire.version}</version>
         <configuration>
+          <argLine>${testvm.argLine}</argLine>
           <systemProperties>
             <property>
               <name>logback.configurationFile</name>
           <artifactId>maven-release-plugin</artifactId>
           <version>${releaseplugin.version}</version>
         </plugin>
+        <plugin>
+            <groupId>org.jacoco</groupId>
+            <artifactId>jacoco-maven-plugin</artifactId>
+            <version>${jacoco.version}</version>
+        </plugin>
+        <plugin>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-maven-plugin</artifactId>
+            <version>${yangtools.version}</version>
+        </plugin>
+
         <!-- Ignore/Execute plugin execution -->
         <plugin>
           <groupId>org.eclipse.m2e</groupId>
diff --git a/opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/02-toaster-sample.xml b/opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/02-toaster-sample.xml
new file mode 100644 (file)
index 0000000..c481485
--- /dev/null
@@ -0,0 +1,73 @@
+<snapshot>
+    <configuration>
+        <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+            <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+                <module>
+                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider:impl">
+                        prefix:toaster-provider-impl
+                    </type>
+                    <name>toaster-provider-impl</name>
+
+                    <rpc-registry>
+                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
+                        <name>binding-rpc-broker</name>
+                    </rpc-registry>
+
+                    <notification-service>
+                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
+                            binding:binding-notification-service
+                        </type>
+                        <name>binding-notification-broker</name>
+                    </notification-service>
+                </module>
+
+                <module>
+                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer:impl">
+                        prefix:toaster-consumer-impl
+                    </type>
+                    <name>toaster-consumer-impl</name>
+
+                    <rpc-registry>
+                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
+                        <name>binding-rpc-broker</name>
+                    </rpc-registry>
+
+                    <notification-service>
+                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
+                            binding:binding-notification-service
+                        </type>
+                        <name>binding-notification-broker</name>
+                    </notification-service>
+                </module>
+            </modules>
+
+            <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+                <service>
+                    <type xmlns:toaster="urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider">toaster:toaster-provider</type>
+                    <instance>
+                        <name>toaster-provider</name>
+                        <provider>/modules/module[type='toaster-provider-impl'][name='toaster-provider-impl']</provider>
+                    </instance>
+                </service>
+                <service>
+                    <type xmlns:toaster="urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer">toaster:toaster-consumer</type>
+                    <instance>
+                        <name>toaster-consumer</name>
+                        <provider>/modules/module[type='toaster-consumer-impl'][name='toaster-consumer-impl']</provider>
+                    </instance>
+                </service>
+            </services>
+        </data>
+
+    </configuration>
+
+    <required-capabilities>
+        <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&amp;revision=2013-10-28</capability>
+        <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer?module=toaster-consumer&amp;revision=2014-01-31</capability>
+        <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer:impl?module=toaster-consumer-impl&amp;revision=2014-01-31</capability>
+        <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider?module=toaster-provider&amp;revision=2014-01-31</capability>
+        <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider:impl?module=toaster-provider-impl&amp;revision=2014-01-31</capability>
+    </required-capabilities>
+
+</snapshot>
+
index c56eb60a6b47d7f4093e56ade0a4d0b1d3262583..3ad08ca207b4a49a125274969f1f07f14d43990e 100644 (file)
@@ -8,6 +8,19 @@
 
 package org.opendaylight.controller.forwardingrulesmanager;
 
+import java.io.Serializable;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
 import org.opendaylight.controller.configuration.ConfigurationObject;
 import org.opendaylight.controller.sal.action.Action;
 import org.opendaylight.controller.sal.action.ActionType;
@@ -30,38 +43,19 @@ import org.opendaylight.controller.sal.action.SetTpSrc;
 import org.opendaylight.controller.sal.action.SetVlanId;
 import org.opendaylight.controller.sal.action.SetVlanPcp;
 import org.opendaylight.controller.sal.action.SwPath;
-import org.opendaylight.controller.sal.core.ContainerFlow;
-import org.opendaylight.controller.sal.core.IContainer;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
 import org.opendaylight.controller.sal.flowprogrammer.Flow;
 import org.opendaylight.controller.sal.match.Match;
 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.IPProtocols;
 import org.opendaylight.controller.sal.utils.NetUtils;
-import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
-import org.opendaylight.controller.sal.utils.ServiceHelper;
 import org.opendaylight.controller.sal.utils.Status;
 import org.opendaylight.controller.sal.utils.StatusCode;
-import org.opendaylight.controller.switchmanager.ISwitchManager;
-import org.opendaylight.controller.switchmanager.Switch;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlRootElement;
-import java.io.Serializable;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
 /**
  * Configuration Java Object which represents a flow configuration information
  * for Forwarding Rules Manager.
@@ -608,15 +602,6 @@ public class FlowConfig extends ConfigurationObject implements Serializable {
         return true;
     }
 
-    public boolean isPortValid(Switch sw, String port) {
-        if (sw == null) {
-            log.debug("switch info is not available. Skip checking if port is part of a switch or not.");
-            return true;
-        }
-        NodeConnector nc = NodeConnectorCreator.createNodeConnector(port, sw.getNode());
-        return sw.getNodeConnectors().contains(nc);
-    }
-
     public boolean isVlanIdValid(String vlanId) {
         int vlan = Integer.decode(vlanId);
         return ((vlan >= 0) && (vlan < 4096));
@@ -647,45 +632,11 @@ public class FlowConfig extends ConfigurationObject implements Serializable {
         return (proto != null);
     }
 
-    private Status conflictWithContainerFlow(IContainer container) {
-        // Return true if it's default container
-        if (container.getName().equals(GlobalConstants.DEFAULT.toString())) {
-            return new Status(StatusCode.SUCCESS);
-        }
-
-        // No container flow = no conflict
-        List<ContainerFlow> cFlowList = container.getContainerFlows();
-        if (((cFlowList == null)) || cFlowList.isEmpty()) {
-            return new Status(StatusCode.SUCCESS);
-        }
-
-        // Check against each container's flow
-        Flow flow = this.getFlow();
-
-        // Configuration is rejected if it conflicts with _all_ the container
-        // flows
-        for (ContainerFlow cFlow : cFlowList) {
-            if (cFlow.allowsFlow(flow)) {
-                log.trace("Config is congruent with at least one container flow");
-                return new Status(StatusCode.SUCCESS);
-            }
-        }
-        String msg = "Flow Config conflicts with all existing container flows";
-        log.trace(msg);
-
-        return new Status(StatusCode.BADREQUEST, msg);
-    }
-
-    public Status validate(IContainer container) {
+    public Status validate() {
         EtherIPType etype = EtherIPType.ANY;
         EtherIPType ipsrctype = EtherIPType.ANY;
         EtherIPType ipdsttype = EtherIPType.ANY;
 
-        String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container.getName();
-        ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName,
-                this);
-
-        Switch sw = null;
         try {
             // Flow name cannot be internal flow signature
             if (!isValidResourceName(name) || isInternalFlow()) {
@@ -696,20 +647,6 @@ public class FlowConfig extends ConfigurationObject implements Serializable {
                 return new Status(StatusCode.BADREQUEST, "Node is null");
             }
 
-            if (switchManager != null) {
-                for (Switch device : switchManager.getNetworkDevices()) {
-                    if (device.getNode().equals(node)) {
-                        sw = device;
-                        break;
-                    }
-                }
-                if (sw == null) {
-                    return new Status(StatusCode.BADREQUEST, String.format("Node %s not found", node));
-                }
-            } else {
-                log.debug("switchmanager is not set yet");
-            }
-
             if (priority != null) {
                 if (Integer.decode(priority) < 0 || (Integer.decode(priority) > 65535)) {
                     return new Status(StatusCode.BADREQUEST, String.format("priority %s is not in the range 0 - 65535",
@@ -722,14 +659,8 @@ public class FlowConfig extends ConfigurationObject implements Serializable {
                 Long.decode(cookie);
             }
 
-            if (ingressPort != null) {
-                if (!isPortValid(sw, ingressPort)) {
-                    String msg = String.format("Ingress port %s is not valid for the Switch", ingressPort);
-                    if (!containerName.equals(GlobalConstants.DEFAULT.toString())) {
-                        msg += " in Container " + containerName;
-                    }
-                    return new Status(StatusCode.BADREQUEST, msg);
-                }
+            if (ingressPort != null && ingressPort.isEmpty()) {
+                return new Status(StatusCode.BADREQUEST, "Invalid ingress port");
             }
 
             if ((vlanId != null) && !isVlanIdValid(vlanId)) {
@@ -832,48 +763,6 @@ public class FlowConfig extends ConfigurationObject implements Serializable {
                 return new Status(StatusCode.BADREQUEST, "Actions value is null or empty");
             }
             for (String actiongrp : actions) {
-                // check output ports
-                sstr = Pattern.compile("OUTPUT=(.*)").matcher(actiongrp);
-                if (sstr.matches()) {
-                    for (String t : sstr.group(1).split(",")) {
-                        if (t != null) {
-                            if (!isPortValid(sw, t)) {
-                                String msg = String.format("Output port %s is not valid for this switch", t);
-                                if (!containerName.equals(GlobalConstants.DEFAULT.toString())) {
-                                    msg += " in Container " + containerName;
-                                }
-                                return new Status(StatusCode.BADREQUEST, msg);
-                            }
-                        }
-                    }
-                    continue;
-                }
-                // check enqueue
-                sstr = Pattern.compile("ENQUEUE=(.*)").matcher(actiongrp);
-                if (sstr.matches()) {
-                    for (String t : sstr.group(1).split(",")) {
-                        if (t != null) {
-                            String port = t.split(":")[0];
-                            if (!isPortValid(sw, port)) {
-                                String msg = String.format("Output port %d is not valid for this switch", port);
-                                if (!containerName.equals(GlobalConstants.DEFAULT.toString())) {
-                                    msg += " in Container " + containerName;
-                                }
-                                return new Status(StatusCode.BADREQUEST, msg);
-                            }
-                        }
-                    }
-                    continue;
-                }
-                // Check src IP
-                sstr = Pattern.compile(ActionType.FLOOD.toString()).matcher(actiongrp);
-                if (sstr.matches()) {
-                    if (!containerName.equals(GlobalConstants.DEFAULT.toString())) {
-                        return new Status(StatusCode.BADREQUEST, String.format(
-                                "flood is not allowed in container %s", containerName));
-                    }
-                    continue;
-                }
                 // Check src IP
                 sstr = Pattern.compile(ActionType.SET_NW_SRC.toString() + "=(.*)").matcher(actiongrp);
                 if (sstr.matches()) {
@@ -965,11 +854,6 @@ public class FlowConfig extends ConfigurationObject implements Serializable {
                     continue;
                 }
             }
-            // Check against the container flow
-            Status status;
-            if (!containerName.equals(GlobalConstants.DEFAULT.toString()) && !(status = conflictWithContainerFlow(container)).isSuccess()) {
-                return status;
-            }
         } catch (NumberFormatException e) {
             return new Status(StatusCode.BADREQUEST, String.format("Invalid number format %s", e.getMessage()));
         }
index 48e1f07716ec267ddb52340e3ea21ef64ac8cebd..685ccdb7c44ea78931de795bb21547c1bd116b36 100644 (file)
@@ -257,7 +257,7 @@ public class frmTest {
         FlowConfig flowConfig = new FlowConfig();
         Assert.assertFalse(flowConfig.isInternalFlow());
         flowConfig.setName("__Internal__");
-        Status status = flowConfig.validate(null);
+        Status status = flowConfig.validate();
         Assert.assertFalse(status.isSuccess());
         Assert.assertTrue(status.getDescription().contains("name"));
         Assert.assertTrue(flowConfig.isInternalFlow());
@@ -509,228 +509,228 @@ public class frmTest {
     @Test
     public void testValid() throws UnknownHostException {
         FlowConfig fc2 = createSampleFlowConfig();
-        Assert.assertTrue(fc2.validate(null).isSuccess());
+        Assert.assertTrue(fc2.validate().isSuccess());
 
         FlowConfig fc = new FlowConfig();
-        Status status = fc.validate(null);
+        Status status = fc.validate();
         Assert.assertFalse(status.isSuccess());
         Assert.assertTrue(status.getDescription().contains("Invalid name"));
 
         fc.setName("Config");
-        status = fc.validate(null);
+        status = fc.validate();
         Assert.assertFalse(status.isSuccess());
         Assert.assertTrue(status.getDescription().contains("Node is null"));
 
         fc.setNode(Node.fromString(Node.NodeIDType.OPENFLOW, "1"));
-        Assert.assertFalse(fc.validate(null).isSuccess());
+        Assert.assertFalse(fc.validate().isSuccess());
         List<String> actions = new ArrayList<String>();
         fc.setActions(actions);
-        Assert.assertFalse(fc.validate(null).isSuccess());
+        Assert.assertFalse(fc.validate().isSuccess());
         actions.add("OUTPUT=2");
         fc.setActions(actions);
-        Assert.assertTrue(fc.validate(null).isSuccess());
+        Assert.assertTrue(fc.validate().isSuccess());
 
         fc.setPriority("-1");
-        status = fc.validate(null);
+        status = fc.validate();
         Assert.assertFalse(status.isSuccess());
         Assert.assertTrue(status.getDescription().contains("is not in the range 0 - 65535"));
 
         fc.setPriority("100000");
-        status = fc.validate(null);
+        status = fc.validate();
         Assert.assertFalse(status.isSuccess());
         Assert.assertTrue(status.getDescription().contains("is not in the range 0 - 65535"));
 
         fc.setPriority("2000");
-        Assert.assertTrue(fc.validate(null).isSuccess());
+        Assert.assertTrue(fc.validate().isSuccess());
 
         fc.setCookie("100");
-        Assert.assertTrue(fc.validate(null).isSuccess());
+        Assert.assertTrue(fc.validate().isSuccess());
 
         fc.setIngressPort("100");
-        Assert.assertTrue(fc.validate(null).isSuccess());
+        Assert.assertTrue(fc.validate().isSuccess());
 
         fc.setVlanId(("-1"));
-        status = fc.validate(null);
+        status = fc.validate();
         Assert.assertFalse(status.isSuccess());
         Assert.assertTrue(status.getDescription().contains("is not in the range 0 - 4095"));
 
         fc.setVlanId("5000");
-        status = fc.validate(null);
+        status = fc.validate();
         Assert.assertFalse(status.isSuccess());
         Assert.assertTrue(status.getDescription().contains("is not in the range 0 - 4095"));
 
         fc.setVlanId("100");
-        Assert.assertTrue(fc.validate(null).isSuccess());
+        Assert.assertTrue(fc.validate().isSuccess());
 
         fc.setVlanPriority("-1");
-        status = fc.validate(null);
+        status = fc.validate();
         Assert.assertFalse(status.isSuccess());
         Assert.assertTrue(status.getDescription().contains("is not in the range 0 - 7"));
 
         fc.setVlanPriority("9");
-        status = fc.validate(null);
+        status = fc.validate();
         Assert.assertFalse(status.isSuccess());
         Assert.assertTrue(status.getDescription().contains("is not in the range 0 - 7"));
 
         fc.setVlanPriority("5");
-        Assert.assertTrue(fc.validate(null).isSuccess());
+        Assert.assertTrue(fc.validate().isSuccess());
 
         fc.setEtherType("-1");
-        status = fc.validate(null);
+        status = fc.validate();
         Assert.assertFalse(status.isSuccess());
         Assert.assertTrue(status.getDescription().contains("Ethernet type"));
 
         fc.setEtherType("0xfffff");
-        status = fc.validate(null);
+        status = fc.validate();
         Assert.assertFalse(status.isSuccess());
         Assert.assertTrue(status.getDescription().contains("Ethernet type"));
 
         fc.setEtherType("0x800");
-        Assert.assertTrue(fc.validate(null).isSuccess());
+        Assert.assertTrue(fc.validate().isSuccess());
 
         fc.setTosBits("-1");
-        status = fc.validate(null);
+        status = fc.validate();
         Assert.assertFalse(status.isSuccess());
         Assert.assertTrue(status.getDescription().contains("IP ToS bits"));
 
         fc.setTosBits("65");
-        status = fc.validate(null);
+        status = fc.validate();
         Assert.assertFalse(status.isSuccess());
         Assert.assertTrue(status.getDescription().contains("IP ToS bits"));
 
         fc.setTosBits("60");
-        Assert.assertTrue(fc.validate(null).isSuccess());
+        Assert.assertTrue(fc.validate().isSuccess());
 
         fc.setSrcPort("-1");
-        status = fc.validate(null);
+        status = fc.validate();
         Assert.assertFalse(status.isSuccess());
         Assert.assertTrue(status.getDescription().contains("Transport source port"));
 
         fc.setSrcPort("0xfffff");
-        status = fc.validate(null);
+        status = fc.validate();
         Assert.assertFalse(status.isSuccess());
         Assert.assertTrue(status.getDescription().contains("Transport source port"));
 
         fc.setSrcPort("0");
-        Assert.assertTrue(fc.validate(null).isSuccess());
+        Assert.assertTrue(fc.validate().isSuccess());
 
         fc.setSrcPort("0x00ff");
-        Assert.assertTrue(fc.validate(null).isSuccess());
+        Assert.assertTrue(fc.validate().isSuccess());
 
         fc.setSrcPort("0xffff");
-        Assert.assertTrue(fc.validate(null).isSuccess());
+        Assert.assertTrue(fc.validate().isSuccess());
 
         fc.setDstPort("-1");
-        status = fc.validate(null);
+        status = fc.validate();
         Assert.assertFalse(status.isSuccess());
         Assert.assertTrue(status.getDescription().contains("Transport destination port"));
 
         fc.setDstPort("0xfffff");
-        status = fc.validate(null);
+        status = fc.validate();
         Assert.assertFalse(status.isSuccess());
         Assert.assertTrue(status.getDescription().contains("Transport destination port"));
 
         fc.setDstPort("0");
-        Assert.assertTrue(fc.validate(null).isSuccess());
+        Assert.assertTrue(fc.validate().isSuccess());
 
         fc.setDstPort("0x00ff");
-        Assert.assertTrue(fc.validate(null).isSuccess());
+        Assert.assertTrue(fc.validate().isSuccess());
 
         fc.setDstPort("0xffff");
-        Assert.assertTrue(fc.validate(null).isSuccess());
+        Assert.assertTrue(fc.validate().isSuccess());
 
         fc.setSrcMac("abc");
-        status = fc.validate(null);
+        status = fc.validate();
         Assert.assertFalse(status.isSuccess());
         Assert.assertTrue(status.getDescription().contains("Ethernet source address"));
 
         fc.setSrcMac("00:A0:C9:14:C8:29");
-        Assert.assertTrue(fc.validate(null).isSuccess());
+        Assert.assertTrue(fc.validate().isSuccess());
 
         fc.setDstMac("abc");
-        status = fc.validate(null);
+        status = fc.validate();
         Assert.assertFalse(status.isSuccess());
         Assert.assertTrue(status.getDescription().contains("Ethernet destination address"));
 
         fc.setDstMac("00:A0:C9:22:AB:11");
-        Assert.assertTrue(fc.validate(null).isSuccess());
+        Assert.assertTrue(fc.validate().isSuccess());
 
         fc.setSrcIp("-1");
-        status = fc.validate(null);
+        status = fc.validate();
         Assert.assertFalse(status.isSuccess());
         Assert.assertTrue(status.getDescription().contains("IP source address"));
 
         fc.setSrcIp("2001:420:281:1004:407a:57f4:4d15:c355");
-        status = fc.validate(null);
+        status = fc.validate();
         Assert.assertFalse(status.isSuccess());
         Assert.assertTrue(status.getDescription().contains("Type mismatch between Ethernet & Src IP"));
 
         fc.setEtherType("0x86dd");
-        Assert.assertTrue(fc.validate(null).isSuccess());
+        Assert.assertTrue(fc.validate().isSuccess());
 
         fc.setSrcIp("1.1.1.1");
-        status = fc.validate(null);
+        status = fc.validate();
         Assert.assertFalse(status.isSuccess());
         Assert.assertTrue(status.getDescription().contains("Type mismatch between Ethernet & Src IP"));
 
         fc.setEtherType("0x800");
-        Assert.assertTrue(fc.validate(null).isSuccess());
+        Assert.assertTrue(fc.validate().isSuccess());
 
         fc.setDstIp("-1");
-        status = fc.validate(null);
+        status = fc.validate();
         Assert.assertFalse(status.isSuccess());
         Assert.assertTrue(status.getDescription().contains("IP destination address"));
 
         fc.setDstIp("2001:420:281:1004:407a:57f4:4d15:c355");
-        status = fc.validate(null);
+        status = fc.validate();
         Assert.assertFalse(status.isSuccess());
         Assert.assertTrue(status.getDescription().contains("Type mismatch between Ethernet & Dst IP"));
 
         fc.setEtherType("0x86dd");
         fc.setSrcIp("2001:420:281:1004:407a:57f4:4d15:c355");
-        Assert.assertTrue(fc.validate(null).isSuccess());
+        Assert.assertTrue(fc.validate().isSuccess());
 
         fc.setDstIp("2.2.2.2");
-        status = fc.validate(null);
+        status = fc.validate();
         Assert.assertFalse(status.isSuccess());
         Assert.assertTrue(status.getDescription().contains("Type mismatch between Ethernet & Dst IP"));
 
         fc.setEtherType("0x800");
         fc.setSrcIp("1.1.1.1");
-        Assert.assertTrue(fc.validate(null).isSuccess());
+        Assert.assertTrue(fc.validate().isSuccess());
 
         fc.setEtherType(null);
         fc.setSrcIp("2001:420:281:1004:407a:57f4:4d15:c355");
-        status = fc.validate(null);
+        status = fc.validate();
         Assert.assertFalse(status.isSuccess());
         Assert.assertTrue(status.getDescription().contains("IP Src Dest Type mismatch"));
 
         fc.setSrcIp("1.1.1.1");
         fc.setIdleTimeout("-1");
-        status = fc.validate(null);
+        status = fc.validate();
         Assert.assertFalse(status.isSuccess());
         Assert.assertTrue(status.getDescription().contains("Idle Timeout value"));
 
         fc.setIdleTimeout("0xfffff");
-        status = fc.validate(null);
+        status = fc.validate();
         Assert.assertFalse(status.isSuccess());
         Assert.assertTrue(status.getDescription().contains("Idle Timeout value"));
 
         fc.setIdleTimeout("10");
-        Assert.assertTrue(fc.validate(null).isSuccess());
+        Assert.assertTrue(fc.validate().isSuccess());
 
         fc.setHardTimeout("-1");
-        status = fc.validate(null);
+        status = fc.validate();
         Assert.assertFalse(status.isSuccess());
         Assert.assertTrue(status.getDescription().contains("Hard Timeout value"));
 
         fc.setHardTimeout("0xfffff");
-        status = fc.validate(null);
+        status = fc.validate();
         Assert.assertFalse(status.isSuccess());
         Assert.assertTrue(status.getDescription().contains("Hard Timeout value"));
 
         fc.setHardTimeout("10");
-        Assert.assertTrue(fc.validate(null).isSuccess());
+        Assert.assertTrue(fc.validate().isSuccess());
 
     }
 
index b94103fb1c7c9233bb417e93cc74d42bbef498e7..614c39e0608fe1a7d384b854588d143c0ad5761e 100644 (file)
@@ -50,6 +50,9 @@ import org.opendaylight.controller.forwardingrulesmanager.PortGroupProvider;
 import org.opendaylight.controller.forwardingrulesmanager.implementation.data.FlowEntryDistributionOrder;
 import org.opendaylight.controller.sal.action.Action;
 import org.opendaylight.controller.sal.action.ActionType;
+import org.opendaylight.controller.sal.action.Enqueue;
+import org.opendaylight.controller.sal.action.Flood;
+import org.opendaylight.controller.sal.action.FloodAll;
 import org.opendaylight.controller.sal.action.Output;
 import org.opendaylight.controller.sal.connection.ConnectionLocality;
 import org.opendaylight.controller.sal.core.Config;
@@ -243,6 +246,57 @@ public class ForwardingRulesManager implements
         return null;
     }
 
+    /**
+     * Checks if the FlowEntry targets are valid for this container
+     *
+     * @param flowEntry
+     *            The flow entry to test
+     * @return a Status object representing the result of the validation
+     */
+    private Status validateEntry(FlowEntry flowEntry) {
+        // Node presence check
+        Node node = flowEntry.getNode();
+        if (!switchManager.getNodes().contains(node)) {
+            return new Status(StatusCode.BADREQUEST, String.format("Node %s is not present in this container", node));
+        }
+
+        // Ports and actions validation check
+        Flow flow = flowEntry.getFlow();
+        Match match = flow.getMatch();
+        if (match.isPresent(MatchType.IN_PORT)) {
+            NodeConnector inputPort = (NodeConnector)match.getField(MatchType.IN_PORT).getValue();
+            if (!switchManager.getNodeConnectors(node).contains(inputPort)) {
+                String msg = String.format("Ingress port %s is not present on this container", inputPort);
+                return new Status(StatusCode.BADREQUEST, msg);
+            }
+        }
+        for (Action action : flow.getActions()) {
+            if (action instanceof Flood && !GlobalConstants.DEFAULT.toString().equals(getContainerName())) {
+                return new Status(StatusCode.BADREQUEST, String.format("Flood is only allowed in default container"));
+            }
+            if (action instanceof FloodAll && !GlobalConstants.DEFAULT.toString().equals(getContainerName())) {
+                return new Status(StatusCode.BADREQUEST, String.format("FloodAll is only allowed in default container"));
+            }
+            if (action instanceof Output) {
+                Output out = (Output)action;
+                NodeConnector outputPort = out.getPort();
+                if (!switchManager.getNodeConnectors(node).contains(outputPort)) {
+                    String msg = String.format("Output port %s is not present on this container", outputPort);
+                    return new Status(StatusCode.BADREQUEST, msg);
+                }
+            }
+            if (action instanceof Enqueue) {
+                Enqueue out = (Enqueue)action;
+                NodeConnector outputPort = out.getPort();
+                if (!switchManager.getNodeConnectors(node).contains(outputPort)) {
+                    String msg = String.format("Enqueue port %s is not present on this container", outputPort);
+                    return new Status(StatusCode.BADREQUEST, msg);
+                }
+            }
+        }
+        return new Status(StatusCode.SUCCESS);
+    }
+
     /**
      * Adds a flow entry onto the network node It runs various validity checks
      * and derive the final container flows merged entries that will be
@@ -264,6 +318,15 @@ public class ForwardingRulesManager implements
             return new Status(StatusCode.NOTACCEPTABLE, INVALID_FLOW_ENTRY);
         }
 
+        // Operational check: input, output and queue ports presence check and
+        // action validation for this container
+        Status status = validateEntry(flowEntry);
+        if (!status.isSuccess()) {
+            String msg = String.format("%s: %s", INVALID_FLOW_ENTRY, status.getDescription());
+            log.warn("{}: {}", msg, flowEntry);
+            return new Status(StatusCode.NOTACCEPTABLE, msg);
+        }
+
         /*
          * Redundant Check: Check if the request is a redundant one from the
          * same application the flowEntry is equal to an existing one. Given we
@@ -422,6 +485,15 @@ public class ForwardingRulesManager implements
             return new Status(StatusCode.SUCCESS, msg);
         }
 
+        // Operational check: input, output and queue ports presence check and
+        // action validation for this container
+        Status status = validateEntry(newFlowEntry);
+        if (!status.isSuccess()) {
+            String msg = String.format("Modify: %s: %s", INVALID_FLOW_ENTRY, status.getDescription());
+            log.warn("{}: {}", msg, newFlowEntry);
+            return new Status(StatusCode.NOTACCEPTABLE, msg);
+        }
+
         /*
          * Conflict Check: Verify the new entry would not conflict with an
          * existing one. This is a loose check on the previous original flow
@@ -1121,7 +1193,10 @@ public class ForwardingRulesManager implements
             List<FlowEntryInstall> list = new ArrayList<FlowEntryInstall>(groupFlows.get(groupName));
             toBeRemoved = list.size();
             for (FlowEntryInstall entry : list) {
-                Status status = this.removeEntry(entry.getOriginal(), false);
+                // since this is the entry that was stored in groupFlows
+                // it is already validated and merged
+                // so can call removeEntryInternal directly
+                Status status = this.removeEntryInternal(entry, false);
                 if (status.isSuccess()) {
                     toBeRemoved -= 1;
                 } else {
@@ -1516,7 +1591,7 @@ public class ForwardingRulesManager implements
     @Override
     public Status addStaticFlow(FlowConfig config) {
         // Configuration object validation
-        Status status = config.validate(container);
+        Status status = config.validate();
         if (!status.isSuccess()) {
             log.warn("Invalid Configuration for flow {}. The failure is {}", config, status.getDescription());
             String error = "Invalid Configuration (" + status.getDescription() + ")";
@@ -1680,6 +1755,7 @@ public class ForwardingRulesManager implements
                     config.setStatus(StatusCode.SUCCESS.toString());
                     break;
                 default:
+                    break;
                 }
             }
         }
@@ -1775,7 +1851,7 @@ public class ForwardingRulesManager implements
         }
 
         // Validity Check
-        Status status = newFlowConfig.validate(container);
+        Status status = newFlowConfig.validate();
         if (!status.isSuccess()) {
             String msg = "Invalid Configuration (" + status.getDescription() + ")";
             newFlowConfig.setStatus(msg);
@@ -1855,7 +1931,7 @@ public class ForwardingRulesManager implements
             }
         }
         if (target != null) {
-            Status status = target.validate(container);
+            Status status = target.validate();
             if (!status.isSuccess()) {
                 log.warn(status.getDescription());
                 return status;
@@ -2757,6 +2833,7 @@ public class ForwardingRulesManager implements
             this.reinstallAllFlowEntries();
             break;
         default:
+            break;
         }
 
         // Update our configuration DB
index 7ac45f47b6f94a26e5a1f6404b713afb1304ae56..3cc857098cd4814fa5513e76e3de28130200c731 100644 (file)
     <sonar.jacoco.itReportPath>../implementation/target/jacoco-it.exec</sonar.jacoco.itReportPath>
   </properties>
   <build>
-    <pluginManagement>
-      <plugins>
-        <plugin>
-          <groupId>org.jacoco</groupId>
-          <artifactId>jacoco-maven-plugin</artifactId>
-          <version>0.5.3.201107060350</version>
-        </plugin>
-      </plugins>
-    </pluginManagement>
     <plugins>
       <plugin>
         <groupId>org.jacoco</groupId>
         <artifactId>jacoco-maven-plugin</artifactId>
-        <version>${jacoco.version}</version>
         <configuration>
           <destFile>../implementation/target/jacoco-it.exec</destFile>
           <includes>org.opendaylight.controller.*</includes>
index 17f43057d7b3e36945671679ca44dbbbf07e5cb0..e4e779001202dd383ba235f71728f391dea3f640 100644 (file)
   </properties>
 
   <build>
-    <pluginManagement>
-      <plugins>
-        <plugin>
-          <groupId>org.jacoco</groupId>
-          <artifactId>jacoco-maven-plugin</artifactId>
-          <version>0.5.3.201107060350</version>
-        </plugin>
-      </plugins>
-    </pluginManagement>
     <plugins>
       <plugin>
         <groupId>org.jacoco</groupId>
         <artifactId>jacoco-maven-plugin</artifactId>
-        <version>${jacoco.version}</version>
         <configuration>
           <destFile>../implementation/target/jacoco-it.exec</destFile>
           <includes>org.opendaylight.controller.*</includes>
index 84508ca03e99475b7a95fcc0a0e676082e227f04..01d75acfe6332b3e6574683ad49736efdf58655f 100644 (file)
@@ -8,10 +8,8 @@
 package org.opendaylight.controller.sal.compatibility.adsal;
 
 import java.math.BigInteger;
-import java.util.concurrent.Future;
 
 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
-import org.opendaylight.controller.sal.common.util.Futures;
 import org.opendaylight.controller.sal.common.util.Rpcs;
 import org.opendaylight.controller.sal.compatibility.InventoryMapping;
 import org.opendaylight.controller.sal.compatibility.ToSalConversionsUtils;
@@ -37,6 +35,9 @@ import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
 public class FlowServiceAdapter implements SalFlowService, IFlowProgrammerListener {
 
     private static final Logger LOG = LoggerFactory.getLogger(FlowServiceAdapter.class);
@@ -59,7 +60,7 @@ public class FlowServiceAdapter implements SalFlowService, IFlowProgrammerListen
     }
 
     @Override
-    public Future<RpcResult<AddFlowOutput>> addFlow(AddFlowInput input) {
+    public ListenableFuture<RpcResult<AddFlowOutput>> addFlow(AddFlowInput input) {
 
         Flow flow = ToSalConversionsUtils.toFlow(input, null);
         @SuppressWarnings("unchecked")
@@ -73,7 +74,7 @@ public class FlowServiceAdapter implements SalFlowService, IFlowProgrammerListen
     }
 
     @Override
-    public Future<RpcResult<RemoveFlowOutput>> removeFlow(RemoveFlowInput input) {
+    public ListenableFuture<RpcResult<RemoveFlowOutput>> removeFlow(RemoveFlowInput input) {
 
         Flow flow = ToSalConversionsUtils.toFlow(input, null);
         @SuppressWarnings("unchecked")
@@ -88,7 +89,7 @@ public class FlowServiceAdapter implements SalFlowService, IFlowProgrammerListen
     }
 
     @Override
-    public Future<RpcResult<UpdateFlowOutput>> updateFlow(UpdateFlowInput input) {
+    public ListenableFuture<RpcResult<UpdateFlowOutput>> updateFlow(UpdateFlowInput input) {
         @SuppressWarnings("unchecked")
         org.opendaylight.controller.sal.core.Node node = InventoryMapping.toAdNode((InstanceIdentifier<Node>) input
                 .getNode().getValue());
index 4bc23fe33b0b9a7c1709d5440700f7b56d28c0ed..c5cbecabedae35c96eb1fd0cad2ae5059253d074 100644 (file)
@@ -13,7 +13,6 @@ import java.util.List;
 import java.util.concurrent.Future;
 
 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
-import org.opendaylight.controller.sal.common.util.Futures;
 import org.opendaylight.controller.sal.common.util.Rpcs;
 import org.opendaylight.controller.sal.compatibility.FromSalConversionsUtils;
 import org.opendaylight.controller.sal.compatibility.InventoryMapping;
@@ -64,6 +63,9 @@ import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
 public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService, IReadServiceListener{
 
     private static final Logger LOG = LoggerFactory.getLogger(FlowStatisticsAdapter.class);
@@ -73,7 +75,7 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService,
     @Override
     public Future<RpcResult<GetAggregateFlowStatisticsFromFlowTableForAllFlowsOutput>> getAggregateFlowStatisticsFromFlowTableForAllFlows(
             GetAggregateFlowStatisticsFromFlowTableForAllFlowsInput input) {
-        //TODO: No supported API exist in AD-SAL, it can either be implemented by fetching all the stats of the flows and 
+        //TODO: No supported API exist in AD-SAL, it can either be implemented by fetching all the stats of the flows and
         // generating aggregate flow statistics out of those individual flow stats.
         return null;
     }
@@ -81,13 +83,13 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService,
     @Override
     public Future<RpcResult<GetAggregateFlowStatisticsFromFlowTableForGivenMatchOutput>> getAggregateFlowStatisticsFromFlowTableForGivenMatch(
             GetAggregateFlowStatisticsFromFlowTableForGivenMatchInput input) {
-        //TODO: No supported API exist in AD-SAL, it can either be implemented by fetching all the stats of the flows and 
+        //TODO: No supported API exist in AD-SAL, it can either be implemented by fetching all the stats of the flows and
         // generating aggregate flow statistics out of those individual flow stats.
         return null;
     }
 
     @Override
-    public Future<RpcResult<GetAllFlowStatisticsFromFlowTableOutput>> getAllFlowStatisticsFromFlowTable(
+    public ListenableFuture<RpcResult<GetAllFlowStatisticsFromFlowTableOutput>> getAllFlowStatisticsFromFlowTable(
             GetAllFlowStatisticsFromFlowTableInput input) {
         GetAllFlowStatisticsFromFlowTableOutput rpcResultType = null;
         boolean rpcResultBool = false;
@@ -99,7 +101,7 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService,
             GetAllFlowStatisticsFromFlowTableOutputBuilder builder = new GetAllFlowStatisticsFromFlowTableOutputBuilder();
             builder.setTransactionId(new TransactionId(new BigInteger("0")));
             rpcResultType = builder.setFlowAndStatisticsMapList(flowsStatistics).build();
-            
+
             rpcResultBool = true;
         } catch (ConstructionException e) {
             LOG.error(e.getMessage());
@@ -112,9 +114,9 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService,
      * Essentially this API will return the same result as getAllFlowStatisticsFromFlowTable
      */
     @Override
-    public Future<RpcResult<GetAllFlowsStatisticsFromAllFlowTablesOutput>> getAllFlowsStatisticsFromAllFlowTables(
+    public ListenableFuture<RpcResult<GetAllFlowsStatisticsFromAllFlowTablesOutput>> getAllFlowsStatisticsFromAllFlowTables(
             GetAllFlowsStatisticsFromAllFlowTablesInput input) {
-        
+
         GetAllFlowsStatisticsFromAllFlowTablesOutput rpcResultType = null;
         boolean rpcResultBool = false;
 
@@ -125,7 +127,7 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService,
             GetAllFlowsStatisticsFromAllFlowTablesOutputBuilder builder = new GetAllFlowsStatisticsFromAllFlowTablesOutputBuilder();
             builder.setTransactionId(new TransactionId(new BigInteger("0")));
             rpcResultType = builder.setFlowAndStatisticsMapList(flowsStatistics).build();
-            
+
             rpcResultBool = true;
         } catch (ConstructionException e) {
             LOG.error(e.getMessage());
@@ -135,7 +137,7 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService,
     }
 
     @Override
-    public Future<RpcResult<GetFlowStatisticsFromFlowTableOutput>> getFlowStatisticsFromFlowTable(
+    public ListenableFuture<RpcResult<GetFlowStatisticsFromFlowTableOutput>> getFlowStatisticsFromFlowTable(
             GetFlowStatisticsFromFlowTableInput input) {
         GetFlowStatisticsFromFlowTableOutput rpcResultType = null;
         boolean rpcResultBool = false;
@@ -170,7 +172,7 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService,
     public void nodeConnectorStatisticsUpdated(Node node, List<NodeConnectorStatistics> ncStatsList) {
         NodeConnectorStatisticsUpdateBuilder nodeConnectorStatisticsUpdateBuilder = new NodeConnectorStatisticsUpdateBuilder();
         List<NodeConnectorStatisticsAndPortNumberMap> nodeConnectorStatistics = toOdNodeConnectorStatistics(ncStatsList);
-        
+
         nodeConnectorStatisticsUpdateBuilder.setNodeConnectorStatisticsAndPortNumberMap(nodeConnectorStatistics);
         nodeConnectorStatisticsUpdateBuilder.setMoreReplies(false);
         nodeConnectorStatisticsUpdateBuilder.setTransactionId(null);
@@ -180,9 +182,9 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService,
 
     @Override
     public void nodeTableStatisticsUpdated(Node node, List<NodeTableStatistics> tableStatsList) {
-        
-        FlowTableStatisticsUpdateBuilder flowTableStatisticsUpdateBuilder = new FlowTableStatisticsUpdateBuilder();  
-        
+
+        FlowTableStatisticsUpdateBuilder flowTableStatisticsUpdateBuilder = new FlowTableStatisticsUpdateBuilder();
+
         List<FlowTableAndStatisticsMap>  flowTableStatistics = toOdFlowTableStatistics(tableStatsList);
         flowTableStatisticsUpdateBuilder.setFlowTableAndStatisticsMap(flowTableStatistics);
         flowTableStatisticsUpdateBuilder.setMoreReplies(false);
@@ -194,7 +196,7 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService,
         @Override
     public void descriptionStatisticsUpdated(Node node, NodeDescription nodeDescription) {
             // TODO which *StatisticsUpdated interface should be used?
-        
+
     }
 
     private List<FlowAndStatisticsMapList> toOdFlowsStatistics(List<FlowOnNode> flowsOnNode) {
@@ -234,7 +236,7 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService,
     }
 
     private List<FlowTableAndStatisticsMap> toOdFlowTableStatistics(List<NodeTableStatistics> tableStatsList) {
-        
+
         List<FlowTableAndStatisticsMap> flowTableStatsMap = new ArrayList<FlowTableAndStatisticsMap>();
         for (NodeTableStatistics nodeTableStatistics : tableStatsList) {
             FlowTableAndStatisticsMapBuilder flowTableAndStatisticsMapBuilder = new FlowTableAndStatisticsMapBuilder();
@@ -245,7 +247,7 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService,
             flowTableAndStatisticsMapBuilder.setTableId(new TableId((short)nodeTableStatistics.getNodeTable().getID()));
             flowTableStatsMap.add(flowTableAndStatisticsMapBuilder.build());
         }
-        
+
         return flowTableStatsMap;
     }
 
@@ -254,7 +256,7 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService,
         List<NodeConnectorStatisticsAndPortNumberMap> nodeConnectorStatisticsList = new ArrayList<NodeConnectorStatisticsAndPortNumberMap>();
         for(NodeConnectorStatistics ofNodeConnectorStatistics : ncStatsList){
             NodeConnectorStatisticsAndPortNumberMapBuilder nodeConnectorStatisticsAndPortNumberMapBuilder = new NodeConnectorStatisticsAndPortNumberMapBuilder();
-            
+
             nodeConnectorStatisticsAndPortNumberMapBuilder.setBytes(extractBytes(ofNodeConnectorStatistics));
             nodeConnectorStatisticsAndPortNumberMapBuilder.setCollisionCount(toBI(ofNodeConnectorStatistics.getCollisionCount()));
             nodeConnectorStatisticsAndPortNumberMapBuilder.setDuration(null);
@@ -268,7 +270,7 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService,
             nodeConnectorStatisticsAndPortNumberMapBuilder.setTransmitErrors(toBI(ofNodeConnectorStatistics.getTransmitErrorCount()));
             nodeConnectorStatisticsList.add(nodeConnectorStatisticsAndPortNumberMapBuilder.build());
         }
-        
+
         return nodeConnectorStatisticsList;
     }
 
index 5092995eb05cb174121f17799008ce248ee58c33..1ea0a3e132c65bc25d33dd0adfb542502954807a 100644 (file)
@@ -47,7 +47,6 @@
             <plugin>
                 <groupId>org.opendaylight.yangtools</groupId>
                 <artifactId>yang-maven-plugin</artifactId>
-                <version>${yangtools.version}</version>
                 <executions>
                     <execution>
                         <goals>
index 2da031e54008cb68c5cf23cddc84b4cd50742da1..e5e314cd877d74ab7e52d505a80cf4e1ea059d44 100644 (file)
@@ -7,25 +7,33 @@
  */
 package org.opendaylight.controller.sal.connector.remoterpc.api;
 
-import java.util.Map;
 import java.util.Set;
 
 public interface RoutingTable<I,R> {
 
-
-
   /**
-   * Adds a network address for the route. If address for route
-   * exists, appends the address to the list
+   * Adds a network address for the route. If the route already exists,
+   * it throws <code>DuplicateRouteException</code>.
+   * This method would be used when registering a global service.
+   *
    *
    * @param routeId route identifier
    * @param route network address
-   * @throws RoutingTableException for any logical exception
+   * @throws DuplicateRouteException
+   * @throws RoutingTableException
+   */
+  public void addGlobalRoute(I routeId, R route) throws  RoutingTableException, SystemException;
+
+  /**
+   * Remove the route.
+   * This method would be used when registering a global service.
+   * @param routeId
+   * @throws RoutingTableException
    * @throws SystemException
    */
-  public void addRoute(I routeId, R route) throws  RoutingTableException,SystemException;
+  public void removeGlobalRoute(I routeId) throws RoutingTableException, SystemException;
 
-    /**
+  /**
    * Adds a network address for the route. If the route already exists,
    * it throws <code>DuplicateRouteException</code>.
    * This method would be used when registering a global service.
@@ -36,9 +44,18 @@ public interface RoutingTable<I,R> {
    * @throws DuplicateRouteException
    * @throws RoutingTableException
    */
-  public void addGlobalRoute(I routeId, R route) throws  RoutingTableException, SystemException;
-
+  public R getGlobalRoute(I routeId) throws  RoutingTableException, SystemException;
 
+  /**
+   * Adds a network address for the route. If address for route
+   * exists, appends the address to the list
+   *
+   * @param routeId route identifier
+   * @param route network address
+   * @throws RoutingTableException for any logical exception
+   * @throws SystemException
+   */
+  public void addRoute(I routeId, R route) throws RoutingTableException,SystemException;
 
 
   /**
@@ -47,17 +64,28 @@ public interface RoutingTable<I,R> {
    * @param routeId
    * @param route
    */
-  public void removeRoute(I routeId, R route);
+  public void removeRoute(I routeId, R route) throws RoutingTableException,SystemException;
 
+  /**
+   * Adds address for a set of route identifiers. If address for route
+   * exists, appends the address to the set.
+   *
+   * @param routeIds a set of routeIds
+   * @param route network address
+   * @throws RoutingTableException for any logical exception
+   * @throws SystemException
+   */
+  public void addRoutes(Set<I> routeIds, R route) throws  RoutingTableException,SystemException;
 
-    /**
-     * Remove the route.
-     * This method would be used when registering a global service.
-     * @param routeId
-     * @throws RoutingTableException
-     * @throws SystemException
-     */
-    public void removeGlobalRoute(I routeId) throws RoutingTableException, SystemException;
+  /**
+   * Removes address for a set of route identifiers.
+   *
+   * @param routeIds a set of routeIds
+   * @param route network address
+   * @throws RoutingTableException for any logical exception
+   * @throws SystemException
+   */
+  public void removeRoutes(Set<I> routeIds, R route) throws  RoutingTableException,SystemException;
 
   /**
    * Returns a set of network addresses associated with this route
@@ -66,29 +94,14 @@ public interface RoutingTable<I,R> {
    */
   public Set<R> getRoutes(I routeId);
 
-  /**
-   * Returns all network addresses stored in the table
-   * @return
-   */
-  public Set<Map.Entry> getAllRoutes();
 
   /**
-   * Returns only one address from the list of network addresses
-   * associated with the route. The algorithm to determine that
-   * one address is upto the implementer
+   * Returns the last inserted address from the list of network addresses
+   * associated with the route.
    * @param routeId
    * @return
    */
-  public R getARoute(I routeId);
-
-    /**
-     *
-     * This will be removed after listeners
-     * have made change on their end to use whiteboard pattern
-     * @deprecated
-     */
-
-  public void registerRouteChangeListener(RouteChangeListener listener);
+  public R getLastAddedRoute(I routeId);
 
   public class DuplicateRouteException extends RoutingTableException {
       public DuplicateRouteException(String message) {
index 6e2d280a89f5158358c3d6757c7c1e4e2f72e64e..a826a3c1d7bfcc3bac9c43cd2ae43345bff1b21d 100644 (file)
@@ -67,7 +67,8 @@ public class Activator extends ComponentActivatorAbstractBase {
         if (imp.equals(RoutingTableImpl.class)) {
             Dictionary<String, Set<String>> props = new Hashtable<String, Set<String>>();
             Set<String> propSet = new HashSet<String>();
-            propSet.add(RoutingTableImpl.ROUTING_TABLE_GLOBAL_CACHE);
+            propSet.add(RoutingTableImpl.GLOBALRPC_CACHE);
+            propSet.add(RoutingTableImpl.RPC_CACHE);
             props.put(CACHE_UPDATE_AWARE_REGISTRY_KEY, propSet);
 
             c.setInterface(new String[] { RoutingTable.class.getName(),ICacheUpdateAware.class.getName()  }, props);
index 40c4c6b43625d9c99eecb786a1556762cbdc0085..d6b42faccf60f8351f849cdd350f02819bec0674 100644 (file)
@@ -8,15 +8,11 @@
 
 package org.opendaylight.controller.sal.connector.remoterpc.impl;
 
+import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableSet;
 import org.apache.felix.dm.Component;
-import org.opendaylight.controller.clustering.services.CacheConfigException;
-import org.opendaylight.controller.clustering.services.CacheExistException;
-import org.opendaylight.controller.clustering.services.CacheListenerAddException;
-import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
-import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
-import org.opendaylight.controller.clustering.services.IClusterServices;
-import org.opendaylight.controller.sal.connector.remoterpc.api.RouteChangeListener;
+import org.opendaylight.controller.clustering.services.*;
 import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
 import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableException;
 import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException;
@@ -27,309 +23,415 @@ import javax.transaction.HeuristicMixedException;
 import javax.transaction.HeuristicRollbackException;
 import javax.transaction.NotSupportedException;
 import javax.transaction.RollbackException;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 import java.util.concurrent.ConcurrentMap;
 
-/**
- * @author: syedbahm
- */
 public class RoutingTableImpl<I, R> implements RoutingTable<I, R>, ICacheUpdateAware<I, R> {
-    public static final String ROUTING_TABLE_GLOBAL_CACHE = "routing_table_global_cache";
 
-    private Logger log = LoggerFactory.getLogger(RoutingTableImpl.class);
+  private Logger log = LoggerFactory.getLogger(RoutingTableImpl.class);
 
-    private IClusterGlobalServices clusterGlobalServices = null;
-    private RoutingTableImpl routingTableInstance = null;
-    private ConcurrentMap routingTableCache = null;
-    private Set<RouteChangeListener> routeChangeListeners = Collections
-            .synchronizedSet(new HashSet<RouteChangeListener>());
+  private IClusterGlobalServices clusterGlobalServices = null;
 
-    public RoutingTableImpl() {
-    }
+  private ConcurrentMap<I,R> globalRpcCache = null;
+  private ConcurrentMap<I, LinkedHashSet<R>> rpcCache = null;  //need routes to ordered by insert-order
 
-    @Override
-    public void addRoute(I routeId, R route) throws RoutingTableException {
-        throw new UnsupportedOperationException(" Not implemented yet!");
-    }
+  public static final String GLOBALRPC_CACHE = "remoterpc_routingtable.globalrpc_cache";
+  public static final String RPC_CACHE = "remoterpc_routingtable.rpc_cache";
 
-    @Override
-    public void addGlobalRoute(I routeId, R route) throws RoutingTableException, SystemException {
-        Preconditions.checkNotNull(routeId, "addGlobalRoute: routeId cannot be null!");
-        Preconditions.checkNotNull(route, "addGlobalRoute: route cannot be null!");
-        try {
-
-            Set<R> existingRoute = null;
-            // ok does the global route is already registered ?
-            if ((existingRoute = getRoutes(routeId)) == null) {
-
-                if (log.isDebugEnabled()) {
-                    log.debug("addGlobalRoute: adding  a new route with id" + routeId + " and value = "
-                            + route);
-                }
-                // lets start a transaction
-                clusterGlobalServices.tbegin();
-
-                routingTableCache.put(routeId, route);
-                clusterGlobalServices.tcommit();
-            } else {
-                throw new DuplicateRouteException(" There is already existing route " + existingRoute);
-            }
-
-        } catch (NotSupportedException|HeuristicRollbackException|RollbackException|HeuristicMixedException e) {
-            throw new RoutingTableException("Transaction error - while trying to create route id="
-                    + routeId + "with route" + route, e);
-        } catch (javax.transaction.SystemException e) {
-            throw new SystemException("System error occurred - while trying to create with value", e);
-        }
+  public RoutingTableImpl() {
+  }
 
-    }
+  @Override
+  public R getGlobalRoute(I routeId) throws RoutingTableException, SystemException {
+    Preconditions.checkNotNull(routeId, "getGlobalRoute: routeId cannot be null!");
+    return globalRpcCache.get(routeId);
+  }
 
-    @Override
-    public void removeRoute(I routeId, R route) {
-        throw new UnsupportedOperationException("Not implemented yet!");
+  @Override
+  public void addGlobalRoute(I routeId, R route) throws RoutingTableException, SystemException {
+    Preconditions.checkNotNull(routeId, "addGlobalRoute: routeId cannot be null!");
+    Preconditions.checkNotNull(route, "addGlobalRoute: route cannot be null!");
+    try {
+
+      log.debug("addGlobalRoute: adding  a new route with id[{}] and value [{}]", routeId, route);
+      clusterGlobalServices.tbegin();
+      if (globalRpcCache.putIfAbsent(routeId, route) != null) {
+        throw new DuplicateRouteException(" There is already existing route " + routeId);
+      }
+      clusterGlobalServices.tcommit();
+
+    } catch (NotSupportedException | HeuristicRollbackException | RollbackException | HeuristicMixedException e) {
+      throw new RoutingTableException("Transaction error - while trying to create route id="
+          + routeId + "with route" + route, e);
+    } catch (javax.transaction.SystemException e) {
+      throw new SystemException("System error occurred - while trying to create with value", e);
     }
 
-    @Override
-    public void removeGlobalRoute(I routeId) throws RoutingTableException, SystemException {
-        Preconditions.checkNotNull(routeId, "removeGlobalRoute: routeId cannot be null!");
-        try {
-            if (log.isDebugEnabled()) {
-                log.debug("removeGlobalRoute: removing  a new route with id" + routeId);
-            }
-            // lets start a transaction
-            clusterGlobalServices.tbegin();
-
-            routingTableCache.remove(routeId);
-            clusterGlobalServices.tcommit();
-
-        } catch (NotSupportedException|HeuristicRollbackException|RollbackException|HeuristicMixedException e) {
-            throw new RoutingTableException("Transaction error - while trying to remove route id="
-                    + routeId, e);
-        } catch (javax.transaction.SystemException e) {
-            throw new SystemException("System error occurred - while trying to remove with value", e);
-        }
+  }
+
+  @Override
+  public void removeGlobalRoute(I routeId) throws RoutingTableException, SystemException {
+    Preconditions.checkNotNull(routeId, "removeGlobalRoute: routeId cannot be null!");
+    try {
+      log.debug("removeGlobalRoute: removing  a new route with id [{}]", routeId);
+
+      clusterGlobalServices.tbegin();
+      globalRpcCache.remove(routeId);
+      clusterGlobalServices.tcommit();
+
+    } catch (NotSupportedException | HeuristicRollbackException | RollbackException | HeuristicMixedException e) {
+      throw new RoutingTableException("Transaction error - while trying to remove route id="
+          + routeId, e);
+    } catch (javax.transaction.SystemException e) {
+      throw new SystemException("System error occurred - while trying to remove with value", e);
     }
+  }
+
 
-    @Override
-    public Set<R> getRoutes(I routeId) {
+  @Override
+  public Set<R> getRoutes(I routeId) {
+    Preconditions.checkNotNull(routeId, "getRoutes: routeId cannot be null!");
+    Set<R> routes = rpcCache.get(routeId);
 
-        // Note: currently works for global routes only wherein there is just single
-        // route
-        Preconditions.checkNotNull(routeId, "getARoute: routeId cannot be null!");
-        R route = (R)routingTableCache.get(routeId);
-        Set<R>routes = null;
-        if(route !=null){
-           routes = new HashSet<R>();
-           routes.add(route);
-        }
+    if (routes == null) return Collections.emptySet();
+
+    return ImmutableSet.copyOf(routes);
+  }
 
-        return routes;
-    }
+
+
+  public R getLastAddedRoute(I routeId) {
+
+    Set<R> routes = getRoutes(routeId);
+
+    if (routes.isEmpty()) return null;
+
+    R route = null;
+    Iterator<R> iter = routes.iterator();
+    while (iter.hasNext())
+      route = iter.next();
+
+    return route;
+  }
 
   @Override
-  public Set<Map.Entry> getAllRoutes() {
-    return routingTableCache.entrySet();
+  public void addRoute(I routeId, R route)  throws RoutingTableException, SystemException {
+    Preconditions.checkNotNull(routeId, "addRoute: routeId cannot be null");
+    Preconditions.checkNotNull(route, "addRoute: route cannot be null");
+
+    try{
+      clusterGlobalServices.tbegin();
+      log.debug("addRoute: adding a route with k/v [{}/{}]", routeId, route);
+      threadSafeAdd(routeId, route);
+      clusterGlobalServices.tcommit();
+
+    } catch (NotSupportedException | HeuristicRollbackException | RollbackException | HeuristicMixedException e) {
+      throw new RoutingTableException("Transaction error - while trying to remove route id="
+          + routeId, e);
+    } catch (javax.transaction.SystemException e) {
+      throw new SystemException("System error occurred - while trying to remove with value", e);
+    }
   }
 
   @Override
-    public R getARoute(I routeId) {
-        throw new UnsupportedOperationException("Not implemented yet!");
+  public void addRoutes(Set<I> routeIds, R route) throws RoutingTableException, SystemException {
+    Preconditions.checkNotNull(routeIds, "addRoutes: routeIds must not be null");
+    for (I routeId : routeIds){
+      addRoute(routeId, route);
     }
+  }
 
-    /**
-     * @deprecated doesn't do anything will be removed once listeners used
-     *             whiteboard pattern Registers listener for sending any change
-     *             notification
-     * @param listener
-     */
-    @Override
-    public void registerRouteChangeListener(RouteChangeListener listener) {
+  @Override
+  public void removeRoute(I routeId, R route) throws RoutingTableException, SystemException {
+    Preconditions.checkNotNull(routeId, "removeRoute: routeId cannot be null!");
+    Preconditions.checkNotNull(route, "removeRoute: route cannot be null!");
 
-    }
+    LinkedHashSet<R> routes = rpcCache.get(routeId);
+    if (routes == null) return;
 
-    public void setRouteChangeListener(RouteChangeListener rcl) {
-        if(rcl != null){
-            routeChangeListeners.add(rcl);
-        }else{
-            log.warn("setRouteChangeListener called with null listener");
-        }
-    }
+    try {
+      log.debug("removeRoute: removing  a new route with k/v [{}/{}]", routeId, route);
 
-    public void unSetRouteChangeListener(RouteChangeListener rcl) {
-        if(rcl != null){
-         routeChangeListeners.remove(rcl);
-        }else{
-            log.warn("unSetRouteChangeListener called with null listener");
-        }
+      clusterGlobalServices.tbegin();
+      threadSafeRemove(routeId, route);
+      clusterGlobalServices.tcommit();
+
+    } catch (NotSupportedException | HeuristicRollbackException | RollbackException | HeuristicMixedException e) {
+      throw new RoutingTableException("Transaction error - while trying to remove route id="
+          + routeId, e);
+    } catch (javax.transaction.SystemException e) {
+      throw new SystemException("System error occurred - while trying to remove with value", e);
     }
+  }
 
-    /**
-     * Returning the set of route change listeners for Unit testing Note: the
-     * package scope is default
-     *
-     * @return List of registered RouteChangeListener<I,R> listeners
-     */
-    Set<RouteChangeListener> getRegisteredRouteChangeListeners() {
-        return routeChangeListeners;
+  @Override
+  public void removeRoutes(Set<I> routeIds, R route) throws RoutingTableException, SystemException {
+    Preconditions.checkNotNull(routeIds, "removeRoutes: routeIds must not be null");
+    for (I routeId : routeIds){
+      removeRoute(routeId, route);
     }
+  }
 
-    public void setClusterGlobalServices(IClusterGlobalServices clusterGlobalServices) {
-        this.clusterGlobalServices = clusterGlobalServices;
+  /**
+   * This method guarantees that no 2 thread over write each other's changes.
+   * Just so that we dont end up in infinite loop, it tries for 100 times then throw
+   */
+  private void threadSafeAdd(I routeId, R route) {
+
+    for (int i=0;i<100;i++){
+
+      LinkedHashSet<R> updatedRoutes = new LinkedHashSet<>();
+      updatedRoutes.add(route);
+      LinkedHashSet<R> oldRoutes = rpcCache.putIfAbsent(routeId, updatedRoutes);
+      if (oldRoutes == null) return;
+
+      updatedRoutes = new LinkedHashSet<>(oldRoutes);
+      updatedRoutes.add(route);
+
+      if (rpcCache.replace(routeId, oldRoutes, updatedRoutes)) return;
     }
+    //the method did not already return means it failed to add route in 10 attempts
+    throw new IllegalStateException("Failed to add route [" + routeId + "]");
+  }
+
+  /**
+   * This method guarantees that no 2 thread over write each other's changes.
+   * Just so that we dont end up in infinite loop, it tries for 10 times then throw
+   */
+  private void threadSafeRemove(I routeId, R route) {
+    LinkedHashSet<R> updatedRoutes = null;
+    for (int i=0;i<10;i++){
+      LinkedHashSet<R> oldRoutes = rpcCache.get(routeId);
+
+      // if route to be deleted is the only entry in the set then remove routeId from the cache
+      if ((oldRoutes.size() == 1) && oldRoutes.contains(route)){
+        rpcCache.remove(routeId);
+        return;
+      }
+
+      // if there are multiple routes for this routeId, remove the route to be deleted only from the set.
+      updatedRoutes = new LinkedHashSet<>(oldRoutes);
+      updatedRoutes.remove(route);
+      if (rpcCache.replace(routeId, oldRoutes, updatedRoutes)) return;
 
-    public void unsetClusterGlobalServices(IClusterGlobalServices clusterGlobalServices) {
-        if((clusterGlobalServices != null ) &&  (this.clusterGlobalServices.equals(clusterGlobalServices))){
-            this.clusterGlobalServices = null;
-        }
     }
+    //the method did not already return means it failed to remove route in 10 attempts
+    throw new IllegalStateException("Failed to remove route [" + routeId + "]");
+  }
+
 
-    /**
-     * Creates the Routing Table clustered global services cache
-     *
-     * @throws CacheExistException
-     *           -- cluster global services exception when cache exist
-     * @throws CacheConfigException
-     *           -- cluster global services exception during cache config
-     * @throws CacheListenerAddException
-     *           -- cluster global services exception during adding of listener
-     */
-
-    void createRoutingTableCache() throws CacheExistException, CacheConfigException,
-            CacheListenerAddException {
-        // TBD: HOW DO WE DECIDE ON PROPERTIES OF THE CACHE i.e. what duration it
-        // should be caching?
-
-        // let us check here if the cache already exists -- if so don't create
-        if (!clusterGlobalServices.existCache(ROUTING_TABLE_GLOBAL_CACHE)) {
-
-            if (log.isDebugEnabled()) {
-                log.debug("createRoutingTableCache: creating a new routing table cache "
-                        + ROUTING_TABLE_GLOBAL_CACHE);
-            }
-            routingTableCache = clusterGlobalServices.createCache(ROUTING_TABLE_GLOBAL_CACHE,
-                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
-        } else {
-            if (log.isDebugEnabled()) {
-                log.debug("createRoutingTableCache: found existing routing table cache "
-                        + ROUTING_TABLE_GLOBAL_CACHE);
-            }
-            routingTableCache = clusterGlobalServices.getCache(ROUTING_TABLE_GLOBAL_CACHE);
-        }
+//    /**
+//     * @deprecated doesn't do anything will be removed once listeners used
+//     *             whiteboard pattern Registers listener for sending any change
+//     *             notification
+//     * @param listener
+//     */
+//    @Override
+//    public void registerRouteChangeListener(RouteChangeListener listener) {
+//
+//    }
+
+//    public void setRouteChangeListener(RouteChangeListener rcl) {
+//        if(rcl != null){
+//            routeChangeListeners.add(rcl);
+//        }else{
+//            log.warn("setRouteChangeListener called with null listener");
+//        }
+//    }
+//
+//    public void unSetRouteChangeListener(RouteChangeListener rcl) {
+//        if(rcl != null){
+//         routeChangeListeners.remove(rcl);
+//        }else{
+//            log.warn("unSetRouteChangeListener called with null listener");
+//        }
+//    }
+
+  /**
+   * Returning the set of route change listeners for Unit testing Note: the
+   * package scope is default
+   *
+   * @return List of registered RouteChangeListener<I,R> listeners
+   */
+//    Set<RouteChangeListener> getRegisteredRouteChangeListeners() {
+//        return routeChangeListeners;
+//    }
+  public void setClusterGlobalServices(IClusterGlobalServices clusterGlobalServices) {
+    this.clusterGlobalServices = clusterGlobalServices;
+  }
+
+  public void unsetClusterGlobalServices(IClusterGlobalServices clusterGlobalServices) {
+    if ((clusterGlobalServices != null) && (this.clusterGlobalServices.equals(clusterGlobalServices))) {
+      this.clusterGlobalServices = null;
+    }
+  }
 
+  /**
+   * Finds OR Creates clustered cache for Global RPCs
+   *
+   * @throws CacheExistException       -- cluster global services exception when cache exist
+   * @throws CacheConfigException      -- cluster global services exception during cache config
+   * @throws CacheListenerAddException -- cluster global services exception during adding of listener
+   */
+
+  void findOrCreateGlobalRpcCache() throws CacheExistException, CacheConfigException,
+      CacheListenerAddException {
+    // TBD: HOW DO WE DECIDE ON PROPERTIES OF THE CACHE i.e. what duration it
+    // should be caching?
+
+    // let us check here if the cache already exists -- if so don't create
+    if (!clusterGlobalServices.existCache(GLOBALRPC_CACHE)) {
+
+      globalRpcCache = (ConcurrentMap<I,R>) clusterGlobalServices.createCache(GLOBALRPC_CACHE,
+          EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
+      log.debug("Cache created [{}] ", GLOBALRPC_CACHE);
+
+    } else {
+      globalRpcCache = (ConcurrentMap<I,R>) clusterGlobalServices.getCache(GLOBALRPC_CACHE);
+      log.debug("Cache exists [{}] ", GLOBALRPC_CACHE);
     }
+  }
 
-    /**
-     * Function called by the dependency manager when all the required
-     * dependencies are satisfied
-     *
-     */
-    void init(Component c) {
-        try {
-
-            createRoutingTableCache();
-        } catch (CacheExistException e) {
-            throw new IllegalStateException("could not construct routing table cache");
-        } catch (CacheConfigException e) {
-            throw new IllegalStateException("could not construct routing table cache");
-        } catch (CacheListenerAddException e) {
-            throw new IllegalStateException("could not construct routing table cache");
-        }
+  /**
+   * Finds OR Creates clustered cache for Routed RPCs
+   *
+   * @throws CacheExistException       -- cluster global services exception when cache exist
+   * @throws CacheConfigException      -- cluster global services exception during cache config
+   * @throws CacheListenerAddException -- cluster global services exception during adding of listener
+   */
+
+  void findOrCreateRpcCache() throws CacheExistException, CacheConfigException,
+      CacheListenerAddException {
+    // TBD: HOW DO WE DECIDE ON PROPERTIES OF THE CACHE i.e. what duration it
+    // should be caching?
+
+    if (clusterGlobalServices.existCache(RPC_CACHE)){
+      rpcCache = (ConcurrentMap<I,LinkedHashSet<R>>) clusterGlobalServices.getCache(RPC_CACHE);
+      log.debug("Cache exists [{}] ", RPC_CACHE);
+      return;
     }
 
-    /**
-     * Get routing table method is useful for unit testing <note>It has package
-     * scope</note>
-     */
-    ConcurrentMap getRoutingTableCache() {
-        return this.routingTableCache;
+    //cache doesnt exist, create one
+    rpcCache = (ConcurrentMap<I,LinkedHashSet<R>>) clusterGlobalServices.createCache(RPC_CACHE,
+          EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
+    log.debug("Cache created [{}] ", RPC_CACHE);
+  }
+
+
+  /**
+   * Function called by the dependency manager when all the required
+   * dependencies are satisfied
+   */
+  void init(Component c) {
+    try {
+
+      findOrCreateGlobalRpcCache();
+      findOrCreateRpcCache();
+
+    } catch (CacheExistException|CacheConfigException|CacheListenerAddException e) {
+      throw new IllegalStateException("could not construct routing table cache");
     }
+  }
+
+  /**
+   * Useful for unit testing <note>It has package
+   * scope</note>
+   */
+  ConcurrentMap getGlobalRpcCache() {
+    return this.globalRpcCache;
+  }
+
+  /**
+   * Useful for unit testing <note>It has package
+   * scope</note>
+   */
+  ConcurrentMap getRpcCache() {
+    return this.rpcCache;
+  }
 
-    /**
-     * This is used from integration test NP rest API to check out the result of the
-     * cache population
-     * <Note> For testing purpose only-- use it wisely</Note>
-     * @return
-     */
-    public String dumpRoutingTableCache(){
-       Set<Map.Entry<I, R>> cacheEntrySet = this.routingTableCache.entrySet();
-       StringBuilder sb = new StringBuilder();
-       for(Map.Entry<I,R> entry:cacheEntrySet){
-           sb.append("Key:").append(entry.getKey()).append("---->Value:")
-                   .append((entry.getValue() != null)?entry.getValue():"null")
-                   .append("\n");
-       }
-       return sb.toString();
+  /**
+   * This is used from integration test NP rest API to check out the result of the
+   * cache population
+   * <Note> For testing purpose only-- use it wisely</Note>
+   *
+   * @return
+   */
+  public String dumpGlobalRpcCache() {
+    Set<Map.Entry<I, R>> cacheEntrySet = this.globalRpcCache.entrySet();
+    StringBuilder sb = new StringBuilder();
+    for (Map.Entry<I, R> entry : cacheEntrySet) {
+      sb.append("Key:").append(entry.getKey()).append("---->Value:")
+          .append((entry.getValue() != null) ? entry.getValue() : "null")
+          .append("\n");
     }
+    return sb.toString();
+  }
 
-    /**
-     * Invoked when a new entry is available in the cache, the key is only
-     * provided, the value will come as an entryUpdate invocation
-     *
-     * @param key
-     *          Key for the entry just created
-     * @param cacheName
-     *          name of the cache for which update has been received
-     * @param originLocal
-     *          true if the event is generated from this node
-     */
-    @Override
-    public void entryCreated(I key, String cacheName, boolean originLocal) {
-        // TBD: do we require this.
-        if (log.isDebugEnabled()) {
-            log.debug("RoutingTableUpdates: entryCreated  routeId = " + key + " cacheName=" + cacheName);
-        }
+  public String dumpRpcCache() {
+    Set<Map.Entry<I, LinkedHashSet<R>>> cacheEntrySet = this.rpcCache.entrySet();
+    StringBuilder sb = new StringBuilder();
+    for (Map.Entry<I, LinkedHashSet<R>> entry : cacheEntrySet) {
+      sb.append("Key:").append(entry.getKey()).append("---->Value:")
+          .append((entry.getValue() != null) ? entry.getValue() : "null")
+          .append("\n");
     }
+    return sb.toString();
+  }
+  /**
+   * Invoked when a new entry is available in the cache, the key is only
+   * provided, the value will come as an entryUpdate invocation
+   *
+   * @param key         Key for the entry just created
+   * @param cacheName   name of the cache for which update has been received
+   * @param originLocal true if the event is generated from this node
+   */
+  @Override
+  public void entryCreated(I key, String cacheName, boolean originLocal) {
+    // TBD: do we require this.
+    if (log.isDebugEnabled()) {
+      log.debug("RoutingTableUpdates: entryCreated  routeId = " + key + " cacheName=" + cacheName);
+    }
+  }
 
-    /**
-     * Called anytime a given entry is updated
-     *
-     * @param key
-     *          Key for the entry modified
-     * @param new_value
-     *          the new value the key will have
-     * @param cacheName
-     *          name of the cache for which update has been received
-     * @param originLocal
-     *          true if the event is generated from this node
-     */
-    @Override
-    public void entryUpdated(I key, R new_value, String cacheName, boolean originLocal) {
-        if (log.isDebugEnabled()) {
-            log.debug("RoutingTableUpdates: entryUpdated  routeId = " + key + ",value = " + new_value
-                    + " ,cacheName=" + cacheName + " originLocal="+originLocal);
-        }
-        if (!originLocal) {
-            for (RouteChangeListener rcl : routeChangeListeners) {
-                rcl.onRouteUpdated(key, new_value);
-            }
-        }
+  /**
+   * Called anytime a given entry is updated
+   *
+   * @param key         Key for the entry modified
+   * @param new_value   the new value the key will have
+   * @param cacheName   name of the cache for which update has been received
+   * @param originLocal true if the event is generated from this node
+   */
+  @Override
+  public void entryUpdated(I key, R new_value, String cacheName, boolean originLocal) {
+    if (log.isDebugEnabled()) {
+      log.debug("RoutingTableUpdates: entryUpdated  routeId = " + key + ",value = " + new_value
+          + " ,cacheName=" + cacheName + " originLocal=" + originLocal);
     }
+//        if (!originLocal) {
+//            for (RouteChangeListener rcl : routeChangeListeners) {
+//                rcl.onRouteUpdated(key, new_value);
+//            }
+//        }
+  }
 
-    /**
-     * Called anytime a given key is removed from the ConcurrentHashMap we are
-     * listening to.
-     *
-     * @param key
-     *          Key of the entry removed
-     * @param cacheName
-     *          name of the cache for which update has been received
-     * @param originLocal
-     *          true if the event is generated from this node
-     */
-    @Override
-    public void entryDeleted(I key, String cacheName, boolean originLocal) {
-        if (log.isDebugEnabled()) {
-            log.debug("RoutingTableUpdates: entryUpdated  routeId = " + key + " local = " + originLocal
-                    + " cacheName=" + cacheName + " originLocal="+originLocal);
-        }
-        if (!originLocal) {
-            for (RouteChangeListener rcl : routeChangeListeners) {
-                rcl.onRouteDeleted(key);
-            }
-        }
+  /**
+   * Called anytime a given key is removed from the ConcurrentHashMap we are
+   * listening to.
+   *
+   * @param key         Key of the entry removed
+   * @param cacheName   name of the cache for which update has been received
+   * @param originLocal true if the event is generated from this node
+   */
+  @Override
+  public void entryDeleted(I key, String cacheName, boolean originLocal) {
+    if (log.isDebugEnabled()) {
+      log.debug("RoutingTableUpdates: entryUpdated  routeId = " + key + " local = " + originLocal
+          + " cacheName=" + cacheName + " originLocal=" + originLocal);
     }
+//        if (!originLocal) {
+//            for (RouteChangeListener rcl : routeChangeListeners) {
+//                rcl.onRouteDeleted(key);
+//            }
+//        }
+  }
 }
\ No newline at end of file
index 50460d4e5ec897892a9a507a1b48244098887c86..0987df595689176b2d734da6c048ef00a909b2b0 100644 (file)
@@ -10,196 +10,321 @@ package org.opendaylight.controller.sal.connector.remoterpc.impl;
 
 import junit.framework.Assert;
 import org.apache.felix.dm.Component;
+import org.junit.After;
+import org.junit.Before;
 import org.junit.Test;
 import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
 import org.opendaylight.controller.clustering.services.IClusterServices;
 import org.opendaylight.controller.sal.connector.api.RpcRouter;
-import org.opendaylight.controller.sal.connector.remoterpc.api.RouteChangeListener;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableException;
+import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 
 import java.net.URI;
 import java.util.EnumSet;
 import java.util.HashSet;
-import java.util.Iterator;
+import java.util.LinkedHashSet;
 import java.util.Set;
-import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.*;
 
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.*;
 
-/**
- * @author: syedbahm
- */
 public class RoutingTableImplTest {
 
-    private IClusterGlobalServices ics =  mock(IClusterGlobalServices.class);
-    private RoutingTableImpl rti = new RoutingTableImpl();
+  private final URI namespace = URI.create("http://cisco.com/example");
+  private final QName QNAME = new QName(namespace, "global");
 
-    private final URI namespace = URI.create("http://cisco.com/example");
-    private final QName QNAME = new QName(namespace,"global");
+  private IClusterGlobalServices clusterService;
+  private RoutingTableImpl<RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier>, String> routingTable;
+  ConcurrentMap mockGlobalRpcCache;
+  ConcurrentMap mockRpcCache;
 
-    ConcurrentMap concurrentMapMock = mock(ConcurrentMap.class);
+  @Before
+  public void setUp() throws Exception{
+    clusterService = mock(IClusterGlobalServices.class);
+    routingTable = new RoutingTableImpl<RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier>, String>();
+    mockGlobalRpcCache = new ConcurrentHashMap<>();
+    mockRpcCache = new ConcurrentHashMap<>();
+    createRoutingTableCache();
+  }
 
+  @After
+  public void tearDown(){
+    reset(clusterService);
+    mockGlobalRpcCache = null;
+    mockRpcCache = null;
+  }
 
-    @Test
-    public void testAddGlobalRoute() throws Exception {
-        ConcurrentMap concurrentMap = createRoutingTableCache();
+  @Test
+  public void addGlobalRoute_ValidArguments_ShouldAdd() throws Exception {
 
-        Assert.assertNotNull(concurrentMap);
-        RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeIdentifier =  mock(RpcRouter.RouteIdentifier.class);
-        InstanceIdentifier identifier = mock(InstanceIdentifier.class);
-        when(routeIdentifier.getType()).thenReturn(QNAME);
-        when(routeIdentifier.getRoute()).thenReturn(identifier);
+    Assert.assertNotNull(mockGlobalRpcCache);
+    RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeIdentifier = getRouteIdentifier();
 
-        rti.addGlobalRoute(routeIdentifier, "172.27.12.1:5000");
+    final String expectedRoute = "172.27.12.1:5000";
+    routingTable.addGlobalRoute(routeIdentifier, expectedRoute);
 
-        Set<String> globalService = new HashSet<String>();
-        globalService.add("172.27.12.1:5000");
+    ConcurrentMap latestCache = routingTable.getGlobalRpcCache();
+    Assert.assertEquals(mockGlobalRpcCache, latestCache);
+    Assert.assertEquals(expectedRoute, latestCache.get(routeIdentifier));
+  }
 
-        when(concurrentMap.get(routeIdentifier)).thenReturn(globalService);
-        ConcurrentMap latestCache = rti.getRoutingTableCache();
+  @Test (expected = RoutingTable.DuplicateRouteException.class)
+  public void addGlobalRoute_DuplicateRoute_ShouldThrow() throws Exception{
 
-        Assert.assertEquals(concurrentMap,latestCache);
+    Assert.assertNotNull(mockGlobalRpcCache);
 
-        Set<String> servicesGlobal = (Set<String>)latestCache.get(routeIdentifier);
-        Assert.assertEquals(servicesGlobal.size(),1);
+    RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeIdentifier = getRouteIdentifier();
+    routingTable.addGlobalRoute(routeIdentifier, new String());
+    routingTable.addGlobalRoute(routeIdentifier, new String());
+  }
 
-        Assert.assertEquals(servicesGlobal.iterator().next(),"172.27.12.1:5000");
+  @Test
+  public void getGlobalRoute_ExistingRouteId_ShouldReturnRoute() throws Exception {
 
-    }
+    Assert.assertNotNull(mockGlobalRpcCache);
+    RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeIdentifier = getRouteIdentifier();
+    String expectedRoute = "172.27.12.1:5000";
 
-    @Test
-    public void testGetRoutes() throws Exception {
-        ConcurrentMap concurrentMap = createRoutingTableCache();
+    routingTable.addGlobalRoute(routeIdentifier, expectedRoute);
 
-        Assert.assertNotNull(concurrentMap);
-        RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeIdentifier =  mock(RpcRouter.RouteIdentifier.class);
-        InstanceIdentifier identifier = mock(InstanceIdentifier.class);
-        when(routeIdentifier.getContext()).thenReturn(QNAME);
-        when(routeIdentifier.getRoute()).thenReturn(identifier);
+    String actualRoute = (String) routingTable.getGlobalRoute(routeIdentifier);
+    Assert.assertEquals(expectedRoute, actualRoute);
+  }
 
-        rti.addGlobalRoute(routeIdentifier, "172.27.12.1:5000");
+  @Test
+  public void getGlobalRoute_NonExistentRouteId_ShouldReturnNull() throws Exception {
 
-        String globalService =   "172.27.12.1:5000";
+    Assert.assertNotNull(mockGlobalRpcCache);
+    RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeIdentifier = getRouteIdentifier();
 
-        when(concurrentMap.get(routeIdentifier)).thenReturn(globalService);
-        ConcurrentMap latestCache = rti.getRoutingTableCache();
+    String actualRoute = (String) routingTable.getGlobalRoute(routeIdentifier);
+    Assert.assertNull(actualRoute);
+  }
 
-        Assert.assertEquals(concurrentMap,latestCache);
+  @Test
+  public void removeGlobalRoute_ExistingRouteId_ShouldRemove() throws Exception {
 
-        Set<String> servicesGlobal =  rti.getRoutes(routeIdentifier);
+    Assert.assertNotNull(mockGlobalRpcCache);
+    RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeIdentifier = getRouteIdentifier();
 
+    ConcurrentMap cache = routingTable.getGlobalRpcCache();
+    Assert.assertTrue(cache.size() == 0);
+    routingTable.addGlobalRoute(routeIdentifier, "172.27.12.1:5000");
+    Assert.assertTrue(cache.size() == 1);
 
-        Assert.assertEquals(servicesGlobal.size(),1);
-        Iterator<String> iterator = servicesGlobal.iterator();
-        while(iterator.hasNext()){
-        Assert.assertEquals(iterator.next(),"172.27.12.1:5000");
-        }
+    routingTable.removeGlobalRoute(routeIdentifier);
+    Assert.assertTrue(cache.size() == 0);
 
+  }
 
-    }
-    @Test
-    public void testRegisterRouteChangeListener() throws Exception {
-        Assert.assertEquals(rti.getRegisteredRouteChangeListeners().size(),0);
-        rti.registerRouteChangeListener(new RouteChangeListenerImpl());
+  @Test
+  public void removeGlobalRoute_NonExistentRouteId_ShouldDoNothing() throws Exception {
 
-        Assert.assertEquals(rti.getRegisteredRouteChangeListeners().size(),0); //old should not work
-        //what about the new approach - using whiteboard pattern
-        rti.setRouteChangeListener(new RouteChangeListenerImpl());
+    Assert.assertNotNull(mockGlobalRpcCache);
+    RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeIdentifier = getRouteIdentifier();
 
-        Assert.assertEquals(rti.getRegisteredRouteChangeListeners().size(),1); //should not work
+    ConcurrentMap cache = routingTable.getGlobalRpcCache();
+    Assert.assertTrue(cache.size() == 0);
 
+    routingTable.removeGlobalRoute(routeIdentifier);
+    Assert.assertTrue(cache.size() == 0);
 
-    }
-    @Test
-    public void testRemoveGlobalRoute()throws Exception {
+  }
 
-        ConcurrentMap concurrentMap = createRoutingTableCache();
+  @Test
+  public void addRoute_ForNewRouteId_ShouldAddRoute() throws Exception {
+    Assert.assertTrue(mockRpcCache.size() == 0);
 
-        Assert.assertNotNull(concurrentMap);
-        RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeIdentifier =  mock(RpcRouter.RouteIdentifier.class);
-        InstanceIdentifier identifier = mock(InstanceIdentifier.class);
-        when(routeIdentifier.getContext()).thenReturn(QNAME);
-        when(routeIdentifier.getRoute()).thenReturn(identifier);
+    RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeId = getRouteIdentifier();
 
-        rti.addGlobalRoute(routeIdentifier, "172.27.12.1:5000");
+    routingTable.addRoute(routeId, new String());
+    Assert.assertTrue(mockRpcCache.size() == 1);
 
-        String globalService =   "172.27.12.1:5000";
+    Set<String> routes = routingTable.getRoutes(routeId);
+    Assert.assertEquals(1, routes.size());
+  }
 
-        when(concurrentMap.get(routeIdentifier)).thenReturn(globalService);
-        ConcurrentMap latestCache = rti.getRoutingTableCache();
+  @Test
+  public void addRoute_ForExistingRouteId_ShouldAppendRoute() throws Exception {
 
-        Assert.assertEquals(concurrentMap,latestCache);
+    Assert.assertTrue(mockRpcCache.size() == 0);
 
-        Set<String> servicesGlobal =  rti.getRoutes(routeIdentifier);
+    RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeId = getRouteIdentifier();
 
+    String route_1 = "10.0.0.1:5955";
+    String route_2 = "10.0.0.2:5955";
 
-        Assert.assertEquals(servicesGlobal.size(),1);
+    routingTable.addRoute(routeId, route_1);
+    routingTable.addRoute(routeId, route_2);
 
-        Assert.assertEquals(servicesGlobal.iterator().next(),"172.27.12.1:5000");
+    Assert.assertTrue(mockRpcCache.size() == 1);
 
-        rti.removeGlobalRoute(routeIdentifier);
+    Set<String> routes = routingTable.getRoutes(routeId);
+    Assert.assertEquals(2, routes.size());
+    Assert.assertTrue(routes.contains(route_1));
+    Assert.assertTrue(routes.contains(route_2));
+  }
 
-        Assert.assertNotNull(rti.getRoutes(routeIdentifier));
+  @Test
+  public void addRoute_UsingMultipleThreads_ShouldNotOverwrite(){
+    ExecutorService threadPool = Executors.newCachedThreadPool();
 
+    int numOfRoutesToAdd = 100;
+    String routePrefix_1   = "10.0.0.1:555";
+    RpcRouter.RouteIdentifier routeId = getRouteIdentifier();
+    threadPool.submit(addRoutes(numOfRoutesToAdd, routePrefix_1, routeId));
+    String routePrefix_2   = "10.0.0.1:556";
+    threadPool.submit(addRoutes(numOfRoutesToAdd, routePrefix_2, routeId));
 
+    // wait for all tasks to complete; timeout in 10 sec
+    threadPool.shutdown();
+    try {
+      threadPool.awaitTermination(10, TimeUnit.SECONDS); //
+    } catch (InterruptedException e) {
+      e.printStackTrace();
     }
 
-    private ConcurrentMap createRoutingTableCache() throws Exception {
+    Assert.assertEquals(2*numOfRoutesToAdd, routingTable.getRoutes(routeId).size());
+  }
 
-        //here init
-        Component c = mock(Component.class);
+  @Test(expected = NullPointerException.class)
+  public void addRoute_NullRouteId_shouldThrowNpe() throws Exception {
 
-        when(ics.existCache(
-                RoutingTableImpl.ROUTING_TABLE_GLOBAL_CACHE)).thenReturn(false);
+    routingTable.addRoute(null, new String());
+  }
 
-        when(ics.createCache(RoutingTableImpl.ROUTING_TABLE_GLOBAL_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(concurrentMapMock);
-         rti.setClusterGlobalServices(this.ics);
-        rti.init(c);
+  @Test(expected = NullPointerException.class)
+  public void addRoute_NullRoute_shouldThrowNpe() throws Exception{
 
-        Assert.assertEquals(concurrentMapMock,rti.getRoutingTableCache() );
-        return concurrentMapMock;
+    routingTable.addRoute(getRouteIdentifier(), null);
+  }
 
-    }
+  @Test (expected = UnsupportedOperationException.class)
+  public void getRoutes_Call_ShouldReturnImmutableCopy() throws Exception{
+    Assert.assertNotNull(routingTable);
+    RpcRouter.RouteIdentifier routeId = getRouteIdentifier();
+    routingTable.addRoute(routeId, new String());
 
+    Set<String> routes = routingTable.getRoutes(routeId); //returns Immutable Set
 
-    @Test
-    public void testCreateRoutingTableCacheReturnExistingCache() throws Exception {
-        ConcurrentMap concurrentMap = createRoutingTableCache();
+    routes.add(new String()); //can not be modified; should throw
+  }
 
-        //OK here we should try creating again the cache but this time it should return the existing one
-        when(ics.existCache(
-                RoutingTableImpl.ROUTING_TABLE_GLOBAL_CACHE)).thenReturn(true);
+  @Test
+  public void getRoutes_With2RoutesFor1RouteId_ShouldReturnASetWithSize2() throws Exception{
+    Assert.assertNotNull(routingTable);
+    RpcRouter.RouteIdentifier routeId = getRouteIdentifier();
+    routingTable.addRoute(routeId, "10.0.0.1:5555");
+    routingTable.addRoute(routeId, "10.0.0.2:5555");
 
-        when(ics.getCache(
-                RoutingTableImpl.ROUTING_TABLE_GLOBAL_CACHE)).thenReturn(concurrentMap);
+    Set<String> routes = routingTable.getRoutes(routeId); //returns Immutable Set
 
+    Assert.assertEquals(2, routes.size());
+  }
 
-        //here init
-        Component c = mock(Component.class);
+  @Test
+  public void getLastAddedRoute_WhenMultipleRoutesExists_ShouldReturnLatestRoute()
+    throws Exception {
 
-        rti.init(c);
+    Assert.assertNotNull(routingTable);
+    RpcRouter.RouteIdentifier routeId = getRouteIdentifier();
+    String route_1 = "10.0.0.1:5555";
+    String route_2 = "10.0.0.2:5555";
+    routingTable.addRoute(routeId, route_1);
+    routingTable.addRoute(routeId, route_2);
 
-        Assert.assertEquals(concurrentMap,rti.getRoutingTableCache());
+    Assert.assertEquals(route_2, routingTable.getLastAddedRoute(routeId));
+  }
 
+  @Test
+  public void removeRoute_WhenMultipleRoutesExist_RemovesGivenRoute() throws Exception{
+    Assert.assertNotNull(routingTable);
+    RpcRouter.RouteIdentifier routeId = getRouteIdentifier();
+    String route_1 = "10.0.0.1:5555";
+    String route_2 = "10.0.0.2:5555";
 
+    routingTable.addRoute(routeId, route_1);
+    routingTable.addRoute(routeId, route_2);
 
+    Assert.assertEquals(2, routingTable.getRoutes(routeId).size());
 
+    routingTable.removeRoute(routeId, route_1);
+    Assert.assertEquals(1, routingTable.getRoutes(routeId).size());
 
-    }
+  }
 
-    private class RouteChangeListenerImpl<I,R> implements RouteChangeListener<I,R>{
+  @Test
+  public void removeRoute_WhenOnlyOneRouteExists_RemovesRouteId() throws Exception{
+    Assert.assertNotNull(routingTable);
+    RpcRouter.RouteIdentifier routeId = getRouteIdentifier();
+    String route_1 = "10.0.0.1:5555";
 
-        @Override
-        public void onRouteUpdated(I key, R new_value) {
-            //To change body of implemented methods use File | Settings | File Templates.
-        }
+    routingTable.addRoute(routeId, route_1);
+    Assert.assertEquals(1, routingTable.getRoutes(routeId).size());
 
-        @Override
-        public void onRouteDeleted(I key) {
-            //To change body of implemented methods use File | Settings | File Templates.
-        }
-    }
+    routingTable.removeRoute(routeId, route_1);
+    ConcurrentMap cache = routingTable.getRpcCache();
+    Assert.assertFalse(cache.containsKey(routeId));
+
+  }
 
+  /*
+   * Private helper methods
+   */
+  private void createRoutingTableCache() throws Exception {
+
+    //here init
+    Component c = mock(Component.class);
+
+    when(clusterService.existCache(
+        RoutingTableImpl.GLOBALRPC_CACHE)).thenReturn(false);
+
+    when(clusterService.createCache(RoutingTableImpl.GLOBALRPC_CACHE,
+        EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).
+        thenReturn(mockGlobalRpcCache);
+
+    when(clusterService.existCache(
+        RoutingTableImpl.RPC_CACHE)).thenReturn(false);
+
+    when(clusterService.createCache(RoutingTableImpl.RPC_CACHE,
+        EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).
+        thenReturn(mockRpcCache);
+
+    doNothing().when(clusterService).tbegin();
+    doNothing().when(clusterService).tcommit();
+
+    routingTable.setClusterGlobalServices(this.clusterService);
+    routingTable.init(c);
+
+    Assert.assertEquals(mockGlobalRpcCache, routingTable.getGlobalRpcCache());
+    Assert.assertEquals(mockRpcCache, routingTable.getRpcCache());
+  }
+
+  private RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> getRouteIdentifier(){
+    RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeIdentifier = mock(RpcRouter.RouteIdentifier.class);
+    InstanceIdentifier identifier = mock(InstanceIdentifier.class);
+    when(routeIdentifier.getType()).thenReturn(QNAME);
+    when(routeIdentifier.getRoute()).thenReturn(identifier);
+
+    return routeIdentifier;
+  }
+
+  private Runnable addRoutes(final int numRoutes, final String routePrefix, final RpcRouter.RouteIdentifier routeId){
+    return new Runnable() {
+      @Override
+      public void run() {
+        for (int i=0;i<numRoutes;i++){
+          String route = routePrefix + i;
+          try {
+            routingTable.addRoute(routeId, route);
+          } catch (Exception e) {
+            e.printStackTrace();
+          }
+        }
+      }
+    };
+  }
 }
index 4c8ca42be44c9afcb1b7ed3a2470125f70bb2ba3..ad4a1ee200501ceaa5d5647a5f507afbd19e61e2 100644 (file)
@@ -19,7 +19,6 @@
             <plugin>
                 <groupId>org.opendaylight.yangtools</groupId>
                 <artifactId>yang-maven-plugin</artifactId>
-                <version>${yangtools.version}</version>
                 <executions>
                     <execution>
                         <goals>
index e48ebbc0577f1b6101a772284ba9e07b3e6580cf..e6e935c920b613c577d4b9f890092a22c13cb49d 100644 (file)
@@ -202,6 +202,16 @@ public class BindingIndependentConnector implements //
             DataModification<InstanceIdentifier<? extends DataObject>, DataObject> source) {
         DataModificationTransaction target = biDataService.beginTransaction();
         LOG.debug("Created DOM Transaction {} for {},", target.getIdentifier(),source.getIdentifier());
+        for (InstanceIdentifier<? extends DataObject> entry : source.getRemovedConfigurationData()) {
+            org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry);
+            target.removeConfigurationData(biEntry);
+            LOG.debug("Delete of Binding Configuration Data {} is translated to {}",entry,biEntry);
+        }
+        for (InstanceIdentifier<? extends DataObject> entry : source.getRemovedOperationalData()) {
+            org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry);
+            target.removeOperationalData(biEntry);
+            LOG.debug("Delete of Binding Operational Data {} is translated to {}",entry,biEntry);
+        }
         for (Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : source.getUpdatedConfigurationData()
                 .entrySet()) {
             Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> biEntry = mappingService
@@ -216,16 +226,7 @@ public class BindingIndependentConnector implements //
             target.putOperationalData(biEntry.getKey(), biEntry.getValue());
             LOG.debug("Update of Binding Operational Data {} is translated to {}",entry,biEntry);
         }
-        for (InstanceIdentifier<? extends DataObject> entry : source.getRemovedConfigurationData()) {
-            org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry);
-            target.removeConfigurationData(biEntry);
-            LOG.debug("Delete of Binding Configuration Data {} is translated to {}",entry,biEntry);
-        }
-        for (InstanceIdentifier<? extends DataObject> entry : source.getRemovedOperationalData()) {
-            org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry);
-            target.removeOperationalData(biEntry);
-            LOG.debug("Delete of Binding Operational Data {} is translated to {}",entry,biEntry);
-        }
+
         return target;
     }
 
@@ -233,6 +234,24 @@ public class BindingIndependentConnector implements //
             DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> source) {
         org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction target = baDataService
                 .beginTransaction();
+        for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedConfigurationData()) {
+            try {
+
+                InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
+                target.removeConfigurationData(baEntry);
+            } catch (DeserializationException e) {
+                LOG.error("Ommiting from BA transaction: {}.", entry, e);
+            }
+        }
+        for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedOperationalData()) {
+            try {
+
+                InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
+                target.removeOperationalData(baEntry);
+            } catch (DeserializationException e) {
+                LOG.error("Ommiting from BA transaction: {}.", entry, e);
+            }
+        }
         for (Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> entry : source
                 .getUpdatedConfigurationData().entrySet()) {
             try {
@@ -254,24 +273,6 @@ public class BindingIndependentConnector implements //
                 LOG.error("Ommiting from BA transaction: {}.", entry.getKey(), e);
             }
         }
-        for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedConfigurationData()) {
-            try {
-
-                InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
-                target.removeConfigurationData(baEntry);
-            } catch (DeserializationException e) {
-                LOG.error("Ommiting from BA transaction: {}.", entry, e);
-            }
-        }
-        for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedOperationalData()) {
-            try {
-
-                InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
-                target.removeOperationalData(baEntry);
-            } catch (DeserializationException e) {
-                LOG.error("Ommiting from BA transaction: {}.", entry, e);
-            }
-        }
         return target;
     }
 
index ccb3ac6757a6fd4b35e26df3cbcf27b723c91c0e..a58df8435b8f85d5b54f718cae4f4ff27d088af7 100644 (file)
@@ -24,7 +24,6 @@
             <plugin>
                 <groupId>org.opendaylight.yangtools</groupId>
                 <artifactId>yang-maven-plugin</artifactId>
-                <version>${yangtools.version}</version>
                 <executions>
                     <execution>
                         <goals>
index 42b00ba03d113dbcf0eb67958f068d5370491792..3384e8fb20037d0e9da1e020bf9ae2e744cc24a8 100644 (file)
@@ -12,6 +12,10 @@ import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
+/**
+ * @deprecated Use {@link com.google.common.util.concurrent.Futures} instead.
+ */
+@Deprecated
 public class Futures {
 
     private Futures() {
index f57a8e31bc5f94af0ed8784ba2aa7c587a00bb4b..9eadce3ed7cb0d35885f3239637ee0478b150002 100644 (file)
@@ -22,7 +22,6 @@
             <plugin>
                 <groupId>org.opendaylight.yangtools</groupId>
                 <artifactId>yang-maven-plugin</artifactId>
-                <version>${yangtools.version}</version>
                 <executions>
                     <execution>
                         <goals>
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RoutedRpcDefaultImplementation.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RoutedRpcDefaultImplementation.java
new file mode 100644 (file)
index 0000000..c8eb7fd
--- /dev/null
@@ -0,0 +1,12 @@
+package org.opendaylight.controller.sal.core.api;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+
+public interface RoutedRpcDefaultImplementation {
+
+  public RpcResult<CompositeNode> invokeRpc(QName rpc, InstanceIdentifier identifier, CompositeNode input);
+
+}
index 8a9d1678657c6b3555ba23d4a3c536cae5d3d30d..f43dcd6b43565692136eda0eecac5354b29681ac 100644 (file)
@@ -42,4 +42,13 @@ public interface RpcProvisionRegistry extends RpcImplementation, BrokerService,
     ListenerRegistration<RpcRegistrationListener> addRpcRegistrationListener(RpcRegistrationListener listener);
 
     RoutedRpcRegistration addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation);
+
+  /**
+   * Sets this RoutedRpc Implementation as a delegate rpc provider and will be asked to invoke rpc if the
+   * current provider can't service the rpc request
+   *
+   * @param defaultImplementation
+   *              Provider's implementation of RPC functionality
+   */
+    public void setRoutedRpcDefaultDelegate(RoutedRpcDefaultImplementation defaultImplementation);
 }
index cdcaacbb8284da9dbb3092467957bc77471f371e..225281e7a400fa3aefb3c0d38c85b08c48b77daa 100644 (file)
@@ -63,7 +63,6 @@
             <plugin>
                 <groupId>org.opendaylight.yangtools</groupId>
                 <artifactId>yang-maven-plugin</artifactId>
-                <version>${yangtools.version}</version>
                 <executions>
                     <execution>
                         <goals>
index 1159d5650e6599a72db0af912909244d17cf612b..6b5f5acb1945a872d48b925da58283e314014af4 100644 (file)
@@ -50,7 +50,7 @@ class BrokerConfigActivator implements AutoCloseable {
         broker.setRouter(new SchemaAwareRpcBroker("/", SchemaContextProviders.fromSchemaService(schemaService)));
 
         dataService = new DataBrokerImpl();
-        dataService.setExecutor(broker.getExecutor());
+        //dataService.setExecutor(broker.getExecutor());
 
         dataReg = context.registerService(DataBrokerService, dataService, emptyProperties);
         dataProviderReg = context.registerService(DataProviderService, dataService, emptyProperties);
index 3bbdab2c0722d656aba74035186faa4bc0d843aa..64de8683d1d1a8a5c3854aa5f55e6b907852c448 100644 (file)
@@ -14,21 +14,22 @@ import java.util.concurrent.Callable
 import java.util.concurrent.ExecutorService
 import java.util.concurrent.Executors
 import java.util.concurrent.Future
-import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener
 import org.opendaylight.controller.sal.core.api.Broker
 import org.opendaylight.controller.sal.core.api.Consumer
 import org.opendaylight.controller.sal.core.api.Provider
-import org.opendaylight.controller.sal.core.api.RpcImplementation
-import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry
-import org.opendaylight.controller.sal.core.api.RpcRegistrationListener
-import org.opendaylight.controller.sal.core.api.RpcRoutingContext
-import org.opendaylight.controller.sal.dom.broker.spi.RpcRouter
 import org.opendaylight.yangtools.yang.common.QName
 import org.opendaylight.yangtools.yang.common.RpcResult
 import org.opendaylight.yangtools.yang.data.api.CompositeNode
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
 import org.osgi.framework.BundleContext
 import org.slf4j.LoggerFactory
+import org.opendaylight.controller.sal.dom.broker.spi.RpcRouter
+import org.opendaylight.controller.sal.core.api.RpcRegistrationListener
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry
+import org.opendaylight.controller.sal.core.api.RpcImplementation
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener
+import org.opendaylight.controller.sal.core.api.RpcRoutingContext
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
+import org.opendaylight.controller.sal.core.api.RoutedRpcDefaultImplementation
 
 public class BrokerImpl implements Broker, RpcProvisionRegistry, AutoCloseable {
     private static val log = LoggerFactory.getLogger(BrokerImpl);
@@ -122,7 +123,11 @@ public class BrokerImpl implements Broker, RpcProvisionRegistry, AutoCloseable {
     override addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation) {
         router.addRoutedRpcImplementation(rpcType,implementation);
     }
-    
+
+    override setRoutedRpcDefaultDelegate(RoutedRpcDefaultImplementation defaultImplementation) {
+        router.setRoutedRpcDefaultDelegate(defaultImplementation);
+    }
+
     override addRpcRegistrationListener(RpcRegistrationListener listener) {
         return router.addRpcRegistrationListener(listener);
     }
index a8bdddb5108d3ab0242024b7c3db4df3a1d1694a..5d93f4ee4d162b22a35c610d4f79b35e7cf66fb6 100644 (file)
@@ -19,6 +19,7 @@ import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener
 import org.opendaylight.controller.sal.common.DataStoreIdentifier;
 import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration;
 import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration;
+import org.opendaylight.controller.sal.core.api.RoutedRpcDefaultImplementation;
 import org.opendaylight.controller.sal.core.api.RpcImplementation;
 import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
 import org.opendaylight.controller.sal.core.api.RpcRoutingContext;
@@ -104,6 +105,11 @@ public class MountPointImpl implements MountProvisionInstance, SchemaContextProv
     }
 
     @Override
+    public void setRoutedRpcDefaultDelegate(RoutedRpcDefaultImplementation defaultImplementation) {
+      rpcs.setRoutedRpcDefaultDelegate(defaultImplementation);
+    }
+
+  @Override
     public RpcRegistration addRpcImplementation(QName rpcType, RpcImplementation implementation)
             throws IllegalArgumentException {
         return rpcs.addRpcImplementation(rpcType, implementation);
index f380c273732c5fb174c51a07cc2f554b21f394c0..d8315568bee86ea07ee00b86feddcb0801faaa8e 100644 (file)
@@ -9,19 +9,14 @@ package org.opendaylight.controller.sal.dom.broker.impl;
 
 import static com.google.common.base.Preconditions.checkState;
 
-import java.io.Console;
 import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
-import java.util.Set;
 import java.util.concurrent.Future;
 
-import javax.activation.UnsupportedDataTypeException;
-
 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 import org.opendaylight.controller.md.sal.common.api.data.DataModification;
 import org.opendaylight.controller.md.sal.common.api.data.DataReader;
@@ -34,11 +29,9 @@ import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.InstanceIdentifierBuilder;
 import org.opendaylight.yangtools.yang.data.api.Node;
 import org.opendaylight.yangtools.yang.data.api.SimpleNode;
 import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
-import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition;
 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
@@ -47,7 +40,6 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
 import com.google.common.collect.FluentIterable;
 import com.google.common.collect.ImmutableSet;
@@ -180,18 +172,25 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator<DataS
     private NormalizedDataModification prepareMergedTransaction(
             DataModification<InstanceIdentifier, CompositeNode> original) {
         NormalizedDataModification normalized = new NormalizedDataModification(original);
-        for (Entry<InstanceIdentifier, CompositeNode> entry : original.getUpdatedConfigurationData().entrySet()) {
-            normalized.putDeepConfigurationData(entry.getKey(), entry.getValue());
-        }
-        for (Entry<InstanceIdentifier, CompositeNode> entry : original.getUpdatedOperationalData().entrySet()) {
-            normalized.putDeepOperationalData(entry.getKey(), entry.getValue());
-        }
+        LOG.trace("Transaction: {} Removed Configuration {}, Removed Operational {}", original.getIdentifier(),
+                original.getRemovedConfigurationData(), original.getRemovedConfigurationData());
+        LOG.trace("Transaction: {} Created Configuration {}, Created Operational {}", original.getIdentifier(),
+                original.getCreatedConfigurationData().entrySet(), original.getCreatedOperationalData().entrySet());
+        LOG.trace("Transaction: {} Updated Configuration {}, Updated Operational {}", original.getIdentifier(),
+                original.getUpdatedConfigurationData().entrySet(), original.getUpdatedOperationalData().entrySet());
+
         for (InstanceIdentifier entry : original.getRemovedConfigurationData()) {
             normalized.deepRemoveConfigurationData(entry);
         }
         for (InstanceIdentifier entry : original.getRemovedOperationalData()) {
             normalized.deepRemoveOperationalData(entry);
         }
+        for (Entry<InstanceIdentifier, CompositeNode> entry : original.getUpdatedConfigurationData().entrySet()) {
+            normalized.putDeepConfigurationData(entry.getKey(), entry.getValue());
+        }
+        for (Entry<InstanceIdentifier, CompositeNode> entry : original.getUpdatedOperationalData().entrySet()) {
+            normalized.putDeepOperationalData(entry.getKey(), entry.getValue());
+        }
         return normalized;
     }
 
@@ -359,7 +358,7 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator<DataS
         public void putDeepConfigurationData(InstanceIdentifier entryKey, CompositeNode entryData) {
             this.putCompositeNodeData(entryKey, entryData, CONFIGURATIONAL_DATA_STORE_MARKER);
         }
-        
+
         public void putDeepOperationalData(InstanceIdentifier entryKey, CompositeNode entryData) {
             this.putCompositeNodeData(entryKey, entryData, OPERATIONAL_DATA_STORE_MARKER);
         }
@@ -401,18 +400,20 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator<DataS
                     this.putOperationalData(entryKey, entryData);
                     break;
 
-                default :
+                default:
                     LOG.error(dataStoreIdentifier + " is NOT valid DataStore switch marker");
                     throw new RuntimeException(dataStoreIdentifier + " is NOT valid DataStore switch marker");
                 }
             }
         }
 
-        private void putCompositeNodeData(InstanceIdentifier entryKey, CompositeNode entryData, String dataStoreIdentifier) {
+        private void putCompositeNodeData(InstanceIdentifier entryKey, CompositeNode entryData,
+                String dataStoreIdentifier) {
             this.putData(entryKey, entryData, dataStoreIdentifier);
-            
+
             for (Node<?> child : entryData.getChildren()) {
-                InstanceIdentifier subEntryId = InstanceIdentifier.builder(entryKey).node(child.getNodeType()).toInstance();
+                InstanceIdentifier subEntryId = InstanceIdentifier.builder(entryKey).node(child.getNodeType())
+                        .toInstance();
                 if (child instanceof CompositeNode) {
                     DataSchemaNode subSchema = schemaNodeFor(subEntryId);
                     CompositeNode compNode = (CompositeNode) child;
@@ -420,12 +421,13 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator<DataS
 
                     if (subSchema instanceof ListSchemaNode) {
                         ListSchemaNode listSubSchema = (ListSchemaNode) subSchema;
-                        Map<QName, Object> mapOfSubValues = this.getValuesFromListSchema(listSubSchema, (CompositeNode) child);
+                        Map<QName, Object> mapOfSubValues = this.getValuesFromListSchema(listSubSchema,
+                                (CompositeNode) child);
                         if (mapOfSubValues != null) {
-                            instanceId = InstanceIdentifier.builder(entryKey).nodeWithKey(listSubSchema.getQName(), mapOfSubValues).toInstance();
+                            instanceId = InstanceIdentifier.builder(entryKey)
+                                    .nodeWithKey(listSubSchema.getQName(), mapOfSubValues).toInstance();
                         }
-                    } 
-                    else if (subSchema instanceof ContainerSchemaNode) {
+                    } else if (subSchema instanceof ContainerSchemaNode) {
                         ContainerSchemaNode containerSchema = (ContainerSchemaNode) subSchema;
                         instanceId = InstanceIdentifier.builder(entryKey).node(subSchema.getQName()).toInstance();
                     }
@@ -436,13 +438,13 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator<DataS
             }
         }
 
-        private Map<QName, Object> getValuesFromListSchema (ListSchemaNode listSchema, CompositeNode entryData) {
+        private Map<QName, Object> getValuesFromListSchema(ListSchemaNode listSchema, CompositeNode entryData) {
             List<QName> keyDef = listSchema.getKeyDefinition();
-            if (keyDef != null && ! keyDef.isEmpty()) {
+            if (keyDef != null && !keyDef.isEmpty()) {
                 Map<QName, Object> map = new HashMap<QName, Object>();
                 for (QName key : keyDef) {
                     List<Node<?>> data = entryData.get(key);
-                    if (data != null && ! data.isEmpty()) {
+                    if (data != null && !data.isEmpty()) {
                         for (Node<?> nodeData : data) {
                             if (nodeData instanceof SimpleNode<?>) {
                                 map.put(key, data.get(0).getValue());
index 28d5ae914fc686a8cd41032755b77db529f9a85b..22319abb17df7d1dec301105a59c50fad2cb1164 100644 (file)
@@ -19,6 +19,7 @@ import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener
 import org.opendaylight.controller.md.sal.common.impl.routing.RoutingUtils;
 import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration;
 import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration;
+import org.opendaylight.controller.sal.core.api.RoutedRpcDefaultImplementation;
 import org.opendaylight.controller.sal.core.api.RpcImplementation;
 import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
 import org.opendaylight.controller.sal.core.api.RpcRoutingContext;
@@ -44,7 +45,7 @@ import org.slf4j.LoggerFactory;
 import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableSet;
 
-public class SchemaAwareRpcBroker implements RpcRouter, Identifiable<String> {
+public class SchemaAwareRpcBroker implements RpcRouter, Identifiable<String>, RoutedRpcDefaultImplementation {
 
     private static final Logger LOG = LoggerFactory.getLogger(SchemaAwareRpcBroker.class);
 
@@ -58,6 +59,7 @@ public class SchemaAwareRpcBroker implements RpcRouter, Identifiable<String> {
     private final ConcurrentMap<QName, RpcImplementation> implementations = new ConcurrentHashMap<>();
     private RpcImplementation defaultImplementation;
     private SchemaContextProvider schemaProvider;
+    private RoutedRpcDefaultImplementation defaultDelegate;
 
     public SchemaAwareRpcBroker(String identifier, SchemaContextProvider schemaProvider) {
         super();
@@ -81,7 +83,16 @@ public class SchemaAwareRpcBroker implements RpcRouter, Identifiable<String> {
         this.schemaProvider = schemaProvider;
     }
 
+  public RoutedRpcDefaultImplementation getRoutedRpcDefaultDelegate() {
+    return defaultDelegate;
+  }
+
     @Override
+  public void setRoutedRpcDefaultDelegate(RoutedRpcDefaultImplementation defaultDelegate) {
+    this.defaultDelegate = defaultDelegate;
+  }
+
+  @Override
     public RoutedRpcRegistration addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation) {
         checkArgument(rpcType != null, "RPC Type should not be null");
         checkArgument(implementation != null, "RPC Implementatoin should not be null");
@@ -221,6 +232,12 @@ public class SchemaAwareRpcBroker implements RpcRouter, Identifiable<String> {
         return ret;
     }
 
+    @Override
+    public RpcResult<CompositeNode> invokeRpc(QName rpc, InstanceIdentifier identifier, CompositeNode input) {
+      checkState(defaultDelegate != null);
+      return defaultDelegate.invokeRpc(rpc, identifier, input);
+    }
+
     private static abstract class RoutingStrategy implements Identifiable<QName> {
 
         private final QName identifier;
@@ -304,6 +321,7 @@ public class SchemaAwareRpcBroker implements RpcRouter, Identifiable<String> {
             SimpleNode<?> routeContainer = inputContainer.getFirstSimpleByName(strategy.getLeaf());
             checkArgument(routeContainer != null, "Leaf %s must be set with value", strategy.getLeaf());
             Object route = routeContainer.getValue();
+            checkArgument(route instanceof InstanceIdentifier);
             RpcImplementation potential = null;
             if (route != null) {
                 RoutedRpcRegImpl potentialReg = implementations.get(route);
@@ -312,7 +330,7 @@ public class SchemaAwareRpcBroker implements RpcRouter, Identifiable<String> {
                 }
             }
             if (potential == null) {
-                potential = defaultDelegate;
+                return router.invokeRpc(rpc, (InstanceIdentifier) route, input);
             }
             checkState(potential != null, "No implementation is available for rpc:%s path:%s", rpc, route);
             return potential.invokeRpc(rpc, input);
index e218a957826f110bd36d3acb3fe059fc69b5092a..40842c004a2779ede0d231b2fef122920bc4ebc9 100644 (file)
@@ -9,11 +9,7 @@
 package org.opendaylight.controller.sal.dom.broker.osgi;
 
 import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
-import org.opendaylight.controller.sal.core.api.Broker;
-import org.opendaylight.controller.sal.core.api.RpcImplementation;
-import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
-import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
-import org.opendaylight.controller.sal.core.api.RpcRoutingContext;
+import org.opendaylight.controller.sal.core.api.*;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.RpcResult;
@@ -45,7 +41,12 @@ public class RpcProvisionRegistryProxy extends AbstractBrokerServiceProxy<RpcPro
         return getDelegate().addRoutedRpcImplementation(rpcType, implementation);
     }
 
-    @Override
+  @Override
+  public void setRoutedRpcDefaultDelegate(RoutedRpcDefaultImplementation defaultImplementation) {
+    getDelegate().setRoutedRpcDefaultDelegate(defaultImplementation);
+  }
+
+  @Override
     public <L extends RouteChangeListener<RpcRoutingContext, InstanceIdentifier>> ListenerRegistration<L> registerRouteChangeListener(L listener) {
         return getDelegate().registerRouteChangeListener(listener);
     }
index c196095726314d2cd30cd6f90553c36aed30a660..33cd94d6a8ca6dccce75868190893a376f3608cb 100644 (file)
@@ -44,7 +44,6 @@
         <dependency>
             <groupId>org.opendaylight.controller</groupId>
             <artifactId>sal-broker-impl</artifactId>
-            <version>1.1-SNAPSHOT</version>
             <scope>test</scope>
             <type>jar</type>
         </dependency>
             <plugin>
                 <groupId>org.opendaylight.yangtools</groupId>
                 <artifactId>yang-maven-plugin</artifactId>
-                <version>${yangtools.version}</version>
                 <executions>
                     <execution>
                         <goals>
index d4f5d43e5ed0ee077782122b124797a811bb8e42..090c56f67dd0c431f8df2b24ae4e123c5b35190c 100644 (file)
@@ -17,7 +17,6 @@
         <dependency>
             <groupId>org.opendaylight.controller</groupId>
             <artifactId>sal-binding-api</artifactId>
-            <version>1.1-SNAPSHOT</version>
         </dependency>
     </dependencies>
     <build>
@@ -30,7 +29,6 @@
             <plugin>
                 <groupId>org.opendaylight.yangtools</groupId>
                 <artifactId>yang-maven-plugin</artifactId>
-                <version>${yangtools.version}</version>
                 <executions>
                     <execution>
                         <id>sal-remote</id>
index 95bb62f93b331257413f2273bcba32ce22fdc7e9..d874381ab374eb2d32a10e09bf959dc810080c0d 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.controller.config.yang.md.sal.remote.rpc;
 
 import org.opendaylight.controller.sal.connector.remoterpc.*;
 import org.opendaylight.controller.sal.core.api.Broker;
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
 import org.osgi.framework.BundleContext;
 
 /**
@@ -46,17 +47,18 @@ public final class ZeroMQServerModule extends org.opendaylight.controller.config
         
         ClientImpl clientImpl = new ClientImpl();
 
-        RoutingTableProvider provider = new RoutingTableProvider(bundleContext,serverImpl);
+    RoutingTableProvider provider = new RoutingTableProvider(bundleContext);//,serverImpl);
 
-        RemoteRpcProvider facade = new RemoteRpcProvider(serverImpl, clientImpl);
-        
-        facade.setRoutingTableProvider(provider );
-        
-        broker.registerProvider(facade, bundleContext);
-        return facade;
-    }
 
-    public void setBundleContext(BundleContext bundleContext) {
-        this.bundleContext = bundleContext;
-    }
+    facade.setRoutingTableProvider(provider );
+    facade.setContext(bundleContext);
+    facade.setRpcProvisionRegistry((RpcProvisionRegistry) broker);
+
+    broker.registerProvider(facade, bundleContext);
+    return facade;
+  }
+
+  public void setBundleContext(BundleContext bundleContext) {
+    this.bundleContext = bundleContext;
+  }
 }
index 291fe0b8e73a5a52e65f1d6e9be4fcca31290a50..30e11c0806731c24ab151dd7cf585408916fd233 100644 (file)
@@ -12,6 +12,8 @@ import org.opendaylight.controller.sal.common.util.RpcErrors;
 import org.opendaylight.controller.sal.common.util.Rpcs;
 import org.opendaylight.controller.sal.connector.api.RpcRouter;
 import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableException;
+import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException;
 import org.opendaylight.controller.sal.connector.remoterpc.dto.Message;
 import org.opendaylight.controller.sal.connector.remoterpc.dto.RouteIdentifierImpl;
 import org.opendaylight.controller.sal.connector.remoterpc.util.XmlUtils;
@@ -20,14 +22,13 @@ import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.RpcError;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.zeromq.ZMQ;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
-import java.util.Set;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.FutureTask;
@@ -66,12 +67,6 @@ public class ClientImpl implements RemoteRpcClient {
     this.routingTableProvider = routingTableProvider;
   }
 
- @Override
-  public Set<QName> getSupportedRpcs(){
-    //TODO: Find the entries from routing table
-    return Collections.emptySet();
-  }
-
   @Override
   public void start() {/*NOOPS*/}
 
@@ -97,14 +92,40 @@ public class ClientImpl implements RemoteRpcClient {
    * @param input payload for the remote service
    * @return
    */
-  @Override
   public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input) {
+    RouteIdentifierImpl routeId = new RouteIdentifierImpl();
+    routeId.setType(rpc);
+
+    String address = lookupRemoteAddressForGlobalRpc(routeId);
+    return sendMessage(input, routeId, address);
+  }
+
+  /**
+   * Finds remote server that can execute this routed rpc and sends a message to it
+   * requesting execution.
+   * The call blocks until a response from remote server is received. Its upto
+   * the client of this API to implement a timeout functionality.
+   *
+   * @param rpc
+   *          rpc to be called
+   * @param identifier
+   *          instance identifier on which rpc is to be executed
+   * @param input
+   *          payload
+   * @return
+   */
+  public RpcResult<CompositeNode> invokeRpc(QName rpc, InstanceIdentifier identifier, CompositeNode input) {
 
     RouteIdentifierImpl routeId = new RouteIdentifierImpl();
     routeId.setType(rpc);
+    routeId.setRoute(identifier);
+
+    String address = lookupRemoteAddressForRpc(routeId);
 
-    String address = lookupRemoteAddress(routeId);
+    return sendMessage(input, routeId, address);
+  }
 
+  private RpcResult<CompositeNode> sendMessage(CompositeNode input, RouteIdentifierImpl routeId, String address) {
     Message request = new Message.MessageBuilder()
         .type(Message.MessageType.REQUEST)
         .sender(Context.getInstance().getLocalUri())
@@ -128,7 +149,6 @@ public class ClientImpl implements RemoteRpcClient {
       collectErrors(e, errors);
       return Rpcs.getRpcResult(false, null, errors);
     }
-
   }
 
   /**
@@ -136,19 +156,36 @@ public class ClientImpl implements RemoteRpcClient {
    * @param  routeId route identifier
    * @return         remote network address
    */
-  private String lookupRemoteAddress(RpcRouter.RouteIdentifier routeId){
+  private String lookupRemoteAddressForGlobalRpc(RpcRouter.RouteIdentifier routeId){
     checkNotNull(routeId, "route must not be null");
 
-    Optional<RoutingTable<String, String>> routingTable = routingTableProvider.getRoutingTable();
+    Optional<RoutingTable<RpcRouter.RouteIdentifier, String>> routingTable = routingTableProvider.getRoutingTable();
     checkNotNull(routingTable.isPresent(), "Routing table is null");
 
-    Set<String> addresses = routingTable.get().getRoutes(routeId.toString());
-    checkNotNull(addresses, "Address not found for route [%s]", routeId);
-    checkState(addresses.size() == 1,
-        "Multiple remote addresses found for route [%s], \nonly 1 expected", routeId); //its a global service.
+    String address = null;
+    try {
+      address = routingTable.get().getGlobalRoute(routeId);
+    } catch (RoutingTableException|SystemException e) {
+      _logger.error("Exception caught while looking up remote address " + e);
+    }
+    checkState(address != null, "Address not found for route [%s]", routeId);
+
+    return address;
+  }
+
+  /**
+   * Find address for the given route identifier in routing table
+   * @param  routeId route identifier
+   * @return         remote network address
+   */
+  private String lookupRemoteAddressForRpc(RpcRouter.RouteIdentifier routeId){
+    checkNotNull(routeId, "route must not be null");
+
+    Optional<RoutingTable<RpcRouter.RouteIdentifier, String>> routingTable = routingTableProvider.getRoutingTable();
+    checkNotNull(routingTable.isPresent(), "Routing table is null");
 
-    String address = addresses.iterator().next();
-    checkNotNull(address, "Address not found for route [%s]", routeId);
+    String address = routingTable.get().getLastAddedRoute(routeId);
+    checkState(address != null, "Address not found for route [%s]", routeId);
 
     return address;
   }
index 1f78a6771a0b6deb1f4d208db11ecb2275a04a73..a564a0ad045a533818135b2921c173e684a603b1 100644 (file)
@@ -9,9 +9,9 @@
 package org.opendaylight.controller.sal.connector.remoterpc;
 
 import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.controller.sal.core.api.RoutedRpcDefaultImplementation;
 
-public interface RemoteRpcClient extends RpcImplementation,AutoCloseable{
-
+public interface RemoteRpcClient extends AutoCloseable{
 
     void setRoutingTableProvider(RoutingTableProvider provider);
     
index bf205fc38d54a57ebc2ac351a3436f1d0215dbd9..639e31ddc3ec0e8380b5108efbe8f4afa92ec513 100644 (file)
 
 package org.opendaylight.controller.sal.connector.remoterpc;
 
+import com.google.common.base.Optional;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChange;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
+import org.opendaylight.controller.sal.connector.api.RpcRouter;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableException;
+import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.RouteIdentifierImpl;
 import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
 import org.opendaylight.controller.sal.core.api.Provider;
+import org.opendaylight.controller.sal.core.api.RoutedRpcDefaultImplementation;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
+import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
+import org.opendaylight.controller.sal.core.api.RpcRoutingContext;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.util.tracker.ServiceTracker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
 
-public class RemoteRpcProvider implements 
-    RemoteRpcServer,
-    RemoteRpcClient,
+import static com.google.common.base.Preconditions.checkNotNull;
+
+public class RemoteRpcProvider implements
+    RpcImplementation,
+    RoutedRpcDefaultImplementation,
+    AutoCloseable,
     Provider {
 
-    private final ServerImpl server;
-    private final ClientImpl client;
-    private RoutingTableProvider provider;
+  private Logger _logger = LoggerFactory.getLogger(RemoteRpcProvider.class);
 
-    @Override
-    public void setRoutingTableProvider(RoutingTableProvider provider) {
-        this.provider = provider;
-        server.setRoutingTableProvider(provider);
-        client.setRoutingTableProvider(provider);
+  private final ServerImpl server;
+  private final ClientImpl client;
+  private RoutingTableProvider routingTableProvider;
+  private final RpcListener listener = new RpcListener();
+  private final RoutedRpcListener routeChangeListener = new RoutedRpcListener();
+  private ProviderSession brokerSession;
+  private RpcProvisionRegistry rpcProvisionRegistry;
+  private BundleContext context;
+  private ServiceTracker clusterTracker;
+
+  public RemoteRpcProvider(ServerImpl server, ClientImpl client) {
+    this.server = server;
+    this.client = client;
+  }
+
+  public void setRoutingTableProvider(RoutingTableProvider provider) {
+    this.routingTableProvider = provider;
+    client.setRoutingTableProvider(provider);
+  }
+
+  public void setContext(BundleContext context){
+    this.context = context;
+  }
+
+  public void setRpcProvisionRegistry(RpcProvisionRegistry rpcProvisionRegistry){
+    this.rpcProvisionRegistry = rpcProvisionRegistry;
+  }
+
+  @Override
+  public void onSessionInitiated(ProviderSession session) {
+    brokerSession = session;
+    server.setBrokerSession(session);
+    start();
+  }
+
+  @Override
+  public Set<QName> getSupportedRpcs() {
+    //TODO: Ask Tony if we need to get this from routing table
+    return Collections.emptySet();
+  }
+
+  @Override
+  public Collection<ProviderFunctionality> getProviderFunctionality() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input) {
+    return client.invokeRpc(rpc, input);
+  }
+
+  @Override
+  public RpcResult<CompositeNode> invokeRpc(QName rpc, InstanceIdentifier identifier, CompositeNode input) {
+    return client.invokeRpc(rpc, identifier, input);
+  }
+
+  public void start() {
+    server.start();
+    client.start();
+    brokerSession.addRpcRegistrationListener(listener);
+    rpcProvisionRegistry.setRoutedRpcDefaultDelegate(this);
+    rpcProvisionRegistry.registerRouteChangeListener(routeChangeListener);
+
+    announceSupportedRpcs();
+    announceSupportedRoutedRpcs();
+  }
+
+  @Override
+  public void close() throws Exception {
+    unregisterSupportedRpcs();
+    unregisterSupportedRoutedRpcs();
+    server.close();
+    client.close();
+  }
+
+  public void stop() {
+    server.stop();
+    client.stop();
+  }
+
+  /**
+   * Add all the locally registered RPCs in the clustered routing table
+   */
+  private void announceSupportedRpcs(){
+    Set<QName> currentlySupported = brokerSession.getSupportedRpcs();
+    for (QName rpc : currentlySupported) {
+      listener.onRpcImplementationAdded(rpc);
     }
-    
-    @Override
-    public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input) {
-        return client.invokeRpc(rpc, input);
+  }
+
+  /**
+   * Add all the locally registered Routed RPCs in the clustered routing table
+   */
+  private void announceSupportedRoutedRpcs(){
+
+    //TODO: announce all routed RPCs as well
+
+  }
+
+  /**
+   * Un-Register all the supported RPCs from clustered routing table
+   */
+  private void unregisterSupportedRpcs(){
+    Set<QName> currentlySupported = brokerSession.getSupportedRpcs();
+    //TODO: remove all routed RPCs as well
+    for (QName rpc : currentlySupported) {
+      listener.onRpcImplementationRemoved(rpc);
     }
-    
+  }
+
+  /**
+   * Un-Register all the locally supported Routed RPCs from clustered routing table
+   */
+  private void unregisterSupportedRoutedRpcs(){
+
+    //TODO: remove all routed RPCs as well
+
+  }
+
+  private RoutingTable<RpcRouter.RouteIdentifier, String> getRoutingTable(){
+    Optional<RoutingTable<RpcRouter.RouteIdentifier, String>> routingTable =
+        routingTableProvider.getRoutingTable();
+
+    checkNotNull(routingTable.isPresent(), "Routing table is null");
+
+    return routingTable.get();
+  }
+
+  /**
+   * Listener for rpc registrations in broker
+   */
+  private class RpcListener implements RpcRegistrationListener {
+
     @Override
-    public Set<QName> getSupportedRpcs() {
-        return client.getSupportedRpcs();
-    }
-    
-    
-    public RemoteRpcProvider(ServerImpl server, ClientImpl client) {
-        this.server = server;
-        this.client = client;
-    }
-    
-    public void setBrokerSession(ProviderSession session) {
-        server.setBrokerSession(session);
-    }
-//    public void setServerPool(ExecutorService serverPool) {
-//        server.setServerPool(serverPool);
-//    }
-    public void start() {
-        //when listener was being invoked and addRPCImplementation was being
-        //called the client was null.
-        server.setClient(client);
-        server.start();
-        client.start();
+    public void onRpcImplementationAdded(QName rpc) {
+
+      _logger.debug("Adding registration for [{}]", rpc);
+      RouteIdentifierImpl routeId = new RouteIdentifierImpl();
+      routeId.setType(rpc);
 
+      RoutingTable<RpcRouter.RouteIdentifier, String> routingTable = getRoutingTable();
 
+      try {
+        routingTable.addGlobalRoute(routeId, server.getServerAddress());
+        _logger.debug("Route added [{}-{}]", routeId, server.getServerAddress());
+
+      } catch (RoutingTableException | SystemException e) {
+        //TODO: This can be thrown when route already exists in the table. Broker
+        //needs to handle this.
+        _logger.error("Unhandled exception while adding global route to routing table [{}]", e);
+
+      }
     }
 
-    
     @Override
-    public Collection<ProviderFunctionality> getProviderFunctionality() {
-        // TODO Auto-generated method stub
-        return null;
+    public void onRpcImplementationRemoved(QName rpc) {
+
+      _logger.debug("Removing registration for [{}]", rpc);
+      RouteIdentifierImpl routeId = new RouteIdentifierImpl();
+      routeId.setType(rpc);
+
+      RoutingTable<RpcRouter.RouteIdentifier, String> routingTable = getRoutingTable();
+
+      try {
+        routingTable.removeGlobalRoute(routeId);
+      } catch (RoutingTableException | SystemException e) {
+        _logger.error("Route delete failed {}", e);
+      }
     }
-    
-    
+  }
+
+  /**
+   * Listener for Routed Rpc registrations in broker
+   */
+  private class RoutedRpcListener
+      implements RouteChangeListener<RpcRoutingContext, InstanceIdentifier> {
+
+    /**
+     *
+     * @param routeChange
+     */
     @Override
-    public void onSessionInitiated(ProviderSession session) {
-        server.setBrokerSession(session);
-        start();
+    public void onRouteChange(RouteChange<RpcRoutingContext, InstanceIdentifier> routeChange) {
+      Map<RpcRoutingContext, Set<InstanceIdentifier>> announcements = routeChange.getAnnouncements();
+      announce(getRouteIdentifiers(announcements));
+
+      Map<RpcRoutingContext, Set<InstanceIdentifier>> removals = routeChange.getRemovals();
+      remove(getRouteIdentifiers(removals));
+    }
+
+    /**
+     *
+     * @param announcements
+     */
+    private void announce(Set<RpcRouter.RouteIdentifier> announcements) {
+      _logger.debug("Announcing [{}]", announcements);
+      RoutingTable<RpcRouter.RouteIdentifier, String> routingTable = getRoutingTable();
+      try {
+        routingTable.addRoutes(announcements, server.getServerAddress());
+      } catch (RoutingTableException | SystemException e) {
+        _logger.error("Route announcement failed {}", e);
+      }
     }
-    
-    
-    public void close() throws Exception {
-        server.close();
-        client.close();
+
+    /**
+     *
+     * @param removals
+     */
+    private void remove(Set<RpcRouter.RouteIdentifier> removals){
+      _logger.debug("Removing [{}]", removals);
+      RoutingTable<RpcRouter.RouteIdentifier, String> routingTable = getRoutingTable();
+      try {
+        routingTable.removeRoutes(removals, server.getServerAddress());
+      } catch (RoutingTableException | SystemException e) {
+        _logger.error("Route removal failed {}", e);
+      }
     }
 
-    @Override
-    public void stop() {
-        server.stop();
-        client.stop();
+    /**
+     *
+     * @param changes
+     * @return
+     */
+    private Set<RpcRouter.RouteIdentifier> getRouteIdentifiers(Map<RpcRoutingContext, Set<InstanceIdentifier>> changes) {
+      RouteIdentifierImpl routeId = null;
+      Set<RpcRouter.RouteIdentifier> routeIdSet = new HashSet<RpcRouter.RouteIdentifier>();
+
+      for (RpcRoutingContext context : changes.keySet()){
+        routeId = new RouteIdentifierImpl();
+        routeId.setType(context.getRpc());
+        routeId.setContext(context.getContext());
+
+        for (InstanceIdentifier instanceId : changes.get(context)){
+          routeId.setRoute(instanceId);
+          routeIdSet.add(routeId);
+        }
+      }
+      return routeIdSet;
     }
+
+
+
+  }
+
 }
index f62c26e0fdaad757112f4e80e860dcd97a464552..71bab288e6ce3c38c555a036cf3a6b05c35af4de 100644 (file)
@@ -9,8 +9,10 @@
 package org.opendaylight.controller.sal.connector.remoterpc;
 
 import com.google.common.base.Optional;
+import org.opendaylight.controller.sal.connector.api.RpcRouter;
 import org.opendaylight.controller.sal.connector.remoterpc.api.RouteChangeListener;
 import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.RouteIdentifierImpl;
 import org.opendaylight.controller.sal.connector.remoterpc.impl.RoutingTableImpl;
 import org.osgi.framework.BundleContext;
 import org.osgi.util.tracker.ServiceTracker;
@@ -22,26 +24,26 @@ public class RoutingTableProvider implements AutoCloseable {
 
     private RoutingTableImpl routingTableImpl = null;
 
-    final private RouteChangeListener routeChangeListener;
+    //final private RouteChangeListener routeChangeListener;
     
     
-    public RoutingTableProvider(BundleContext ctx,RouteChangeListener rcl) {
+    public RoutingTableProvider(BundleContext ctx){//,RouteChangeListener rcl) {
         @SuppressWarnings("rawtypes")
         ServiceTracker<RoutingTable, RoutingTable> rawTracker = new ServiceTracker<>(ctx, RoutingTable.class, null);
         tracker = rawTracker;
         tracker.open();
 
-        routeChangeListener = rcl;
+        //routeChangeListener = rcl;
     }
     
-    public Optional<RoutingTable<String, String>> getRoutingTable() {
+    public Optional<RoutingTable<RpcRouter.RouteIdentifier, String>> getRoutingTable() {
         @SuppressWarnings("unchecked")
-        RoutingTable<String,String> tracked = tracker.getService();
+        RoutingTable<RpcRouter.RouteIdentifier,String> tracked = tracker.getService();
 
         if(tracked instanceof RoutingTableImpl){
             if(routingTableImpl != tracked){
              routingTableImpl= (RoutingTableImpl)tracked;
-             routingTableImpl.setRouteChangeListener(routeChangeListener);
+             //routingTableImpl.setRouteChangeListener(routeChangeListener);
             }
         }
 
index 5c14dd0c453ce8365e528506d743699edf418f3a..722ca0687904f2c7f2e5c42572fc2d16c762936b 100644 (file)
@@ -18,6 +18,7 @@ import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableExcep
 import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException;
 import org.opendaylight.controller.sal.connector.remoterpc.dto.RouteIdentifierImpl;
 import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
 import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
 import org.opendaylight.controller.sal.core.api.RpcRoutingContext;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -43,10 +44,9 @@ import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
 
 /**
- * ZeroMq based implementation of RpcRouter. It implements RouteChangeListener of RoutingTable
- * so that it gets route change notifications from routing table.
+ * ZeroMq based implementation of RpcRouter.
  */
-public class ServerImpl implements RemoteRpcServer, RouteChangeListener<String, String> {
+public class ServerImpl implements RemoteRpcServer {
 
   private Logger _logger = LoggerFactory.getLogger(ServerImpl.class);
 
@@ -57,8 +57,6 @@ public class ServerImpl implements RemoteRpcServer, RouteChangeListener<String,
   private ProviderSession brokerSession;
   private ZMQ.Context context;
 
-  private final RpcListener listener = new RpcListener();
-
   private final String HANDLER_INPROC_ADDRESS = "inproc://rpc-request-handler";
   private final int HANDLER_WORKER_COUNT = 2;
   private final int HWM = 200;//high water mark on sockets
@@ -67,10 +65,6 @@ public class ServerImpl implements RemoteRpcServer, RouteChangeListener<String,
   private String serverAddress;
   private int port;
 
-  private ClientImpl client;
-
-  private  RoutingTableProvider routingTableProvider;
-
   public static enum State {
     STARTING, STARTED, STOPPED;
   }
@@ -79,22 +73,6 @@ public class ServerImpl implements RemoteRpcServer, RouteChangeListener<String,
     this.port = port;
   }
 
-  public RoutingTableProvider getRoutingTableProvider() {
-    return routingTableProvider;
-  }
-
-  public void setRoutingTableProvider(RoutingTableProvider routingTableProvider) {
-    this.routingTableProvider = routingTableProvider;
-  }
-
-  public ClientImpl getClient(){
-    return this.client;
-  }
-
-  public void setClient(ClientImpl client) {
-    this.client = client;
-  }
-
   public State getStatus() {
     return this.status;
   }
@@ -157,11 +135,6 @@ public class ServerImpl implements RemoteRpcServer, RouteChangeListener<String,
     remoteServices = new HashSet<QName>();//
     serverPool = Executors.newSingleThreadExecutor();//main server thread
     serverPool.execute(receive()); // Start listening rpc requests
-    brokerSession.addRpcRegistrationListener(listener);
-
-    announceLocalRpcs();
-
-    registerRemoteRpcs();
 
     status = State.STARTED;
     _logger.info("Remote RPC Server started [{}]", getServerAddress());
@@ -179,8 +152,6 @@ public class ServerImpl implements RemoteRpcServer, RouteChangeListener<String,
 
     if (State.STOPPED == this.getStatus()) return; //do nothing
 
-    unregisterLocalRpcs();
-
     if (serverPool != null)
       serverPool.shutdown();
 
@@ -192,7 +163,7 @@ public class ServerImpl implements RemoteRpcServer, RouteChangeListener<String,
 
   /**
    * Closes ZMQ Context. It tries to gracefully terminate the context. If
-   * termination takes more than a second, its forcefully shutdown.
+   * termination takes more than 5 seconds, its forcefully shutdown.
    */
   private void closeZmqContext() {
     ExecutorService exec = Executors.newSingleThreadExecutor();
@@ -269,81 +240,6 @@ public class ServerImpl implements RemoteRpcServer, RouteChangeListener<String,
     };
   }
 
-  /**
-   * Register the remote RPCs from the routing table into broker
-   */
-  private void registerRemoteRpcs(){
-    Optional<RoutingTable<String, String>> routingTableOptional = routingTableProvider.getRoutingTable();
-
-    Preconditions.checkState(routingTableOptional.isPresent(), "Routing table is absent");
-
-    Set<Map.Entry> remoteRoutes =
-            routingTableProvider.getRoutingTable().get().getAllRoutes();
-
-    //filter out all entries that contains local address
-    //we dont want to register local RPCs as remote
-    Predicate<Map.Entry> notLocalAddressFilter = new Predicate<Map.Entry>(){
-      public boolean apply(Map.Entry remoteRoute){
-        return !getServerAddress().equalsIgnoreCase((String)remoteRoute.getValue());
-      }
-    };
-
-    //filter the entries created by current node
-    Set<Map.Entry> filteredRemoteRoutes = Sets.filter(remoteRoutes, notLocalAddressFilter);
-
-    for (Map.Entry route : filteredRemoteRoutes){
-      onRouteUpdated((String) route.getKey(), "");//value is not needed by broker
-    }
-  }
-
-  /**
-   * Un-Register the local RPCs from the routing table
-   */
-  private void unregisterLocalRpcs(){
-    Set<QName> currentlySupported = brokerSession.getSupportedRpcs();
-    for (QName rpc : currentlySupported) {
-      listener.onRpcImplementationRemoved(rpc);
-    }
-  }
-
-  /**
-   * Publish all the locally registered RPCs in the routing table
-   */
-  private void announceLocalRpcs(){
-    Set<QName> currentlySupported = brokerSession.getSupportedRpcs();
-    for (QName rpc : currentlySupported) {
-      listener.onRpcImplementationAdded(rpc);
-    }
-  }
-
-  /**
-   * @param key
-   * @param value
-   */
-  @Override
-  public void onRouteUpdated(String key, String value) {
-    RouteIdentifierImpl rId = new RouteIdentifierImpl();
-    try {
-      _logger.debug("Updating key/value {}-{}", key, value);
-      brokerSession.addRpcImplementation(
-          (QName) rId.fromString(key).getType(), client);
-
-      //TODO: Check with Tony for routed rpc
-      //brokerSession.addRoutedRpcImplementation((QName) rId.fromString(key).getRoute(), client);
-    } catch (Exception e) {
-      _logger.info("Route update failed {}", e);
-    }
-  }
-
-  /**
-   * @param key
-   */
-  @Override
-  public void onRouteDeleted(String key) {
-    //TODO: Broker session needs to be updated to support this
-    throw new UnsupportedOperationException();
-  }
-
   /**
    * Finds IPv4 address of the local VM
    * TODO: This method is non-deterministic. There may be more than one IPv4 address. Cant say which
@@ -381,74 +277,4 @@ public class ServerImpl implements RemoteRpcServer, RouteChangeListener<String,
     return null;
   }
 
-  /**
-   * Listener for rpc registrations
-   */
-  private class RpcListener implements RpcRegistrationListener {
-
-    @Override
-    public void onRpcImplementationAdded(QName name) {
-
-      //if the service name exists in the set, this notice
-      //has bounced back from the broker. It should be ignored
-      if (remoteServices.contains(name))
-        return;
-
-      _logger.debug("Adding registration for [{}]", name);
-      RouteIdentifierImpl routeId = new RouteIdentifierImpl();
-      routeId.setType(name);
-
-      RoutingTable<String, String> routingTable = getRoutingTable();
-
-      try {
-        routingTable.addGlobalRoute(routeId.toString(), getServerAddress());
-        _logger.debug("Route added [{}-{}]", name, getServerAddress());
-
-      } catch (RoutingTableException | SystemException e) {
-        //TODO: This can be thrown when route already exists in the table. Broker
-        //needs to handle this.
-        _logger.error("Unhandled exception while adding global route to routing table [{}]", e);
-
-      }
-    }
-
-    @Override
-    public void onRpcImplementationRemoved(QName name) {
-
-      _logger.debug("Removing registration for [{}]", name);
-      RouteIdentifierImpl routeId = new RouteIdentifierImpl();
-      routeId.setType(name);
-
-      RoutingTable<String, String> routingTable = getRoutingTable();
-
-      try {
-        routingTable.removeGlobalRoute(routeId.toString());
-      } catch (RoutingTableException | SystemException e) {
-        _logger.error("Route delete failed {}", e);
-      }
-    }
-
-    private RoutingTable<String, String> getRoutingTable(){
-      Optional<RoutingTable<String, String>> routingTable =
-          routingTableProvider.getRoutingTable();
-
-      checkNotNull(routingTable.isPresent(), "Routing table is null");
-
-      return routingTable.get();
-    }
-  }
-
-  /*
-   * Listener for Route changes in broker. Broker notifies this listener in the event
-   * of any change (add/delete). Listener then updates the routing table.
-   */
-  private class BrokerRouteChangeListener
-      implements org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener<RpcRoutingContext, InstanceIdentifier>{
-
-    @Override
-    public void onRouteChange(RouteChange<RpcRoutingContext, InstanceIdentifier> routeChange) {
-
-    }
-  }
-
 }
index 06107a8773a6213f79df91c3a2bd637e085647ff..ec6a1a94b6ecfe2a4d58504f332145ccd5c53184 100644 (file)
@@ -18,8 +18,6 @@ import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 
 public class RouteIdentifierImpl implements RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier>,Serializable {
 
-  transient ObjectMapper mapper = new ObjectMapper();
-
   private QName context;
   private QName type;
   private InstanceIdentifier route;
@@ -50,38 +48,4 @@ public class RouteIdentifierImpl implements RpcRouter.RouteIdentifier<QName, QNa
   public void setRoute(InstanceIdentifier route) {
     this.route = route;
   }
-
-  @Override
-  public String toString() {
-    try {
-      return mapper.writeValueAsString(this);
-    } catch (Throwable e) {
-      //do nothing
-    }
-
-    return super.toString();
-  }
-
-  public RpcRouter.RouteIdentifier fromString(String input)
-      throws Exception {
-
-    JsonNode root = mapper.readTree(input);
-    this.context  = parseQName(root.get("context"));
-    this.type     = parseQName(root.get("type"));
-
-    return this;
-  }
-
-  private QName parseQName(JsonNode node){
-    if (node == null) return null;
-
-    String namespace = (node.get("namespace") != null) ?
-                       node.get("namespace").asText()  : "";
-
-    String localName = (node.get("localName") != null) ?
-                       node.get("localName").asText() : "";
-
-    URI uri = URI.create(namespace);
-    return new QName(uri, localName);
-  }
 }
index d20efe50c154a054e46eb83aaf1b4c3d2520393c..beeb936c97200517fc911276e56a483e182c1b5f 100644 (file)
@@ -26,8 +26,6 @@ module odl-sal-dom-rpc-remote-cfg {
 
     identity remote-zeromq-rpc-server {
         base config:module-type;
-        config:provided-service remote-rpc-server;
-        config:provided-service remote-rpc-client;
         config:java-name-prefix ZeroMQServer;
     }
 
index f63584b7fc4531b11466e1a84f07cbf14b46eae7..c0aae2dfb56590a39ac1e90a5a413b29c2a87cdb 100644 (file)
@@ -13,6 +13,7 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.opendaylight.controller.sal.common.util.Rpcs;
+import org.opendaylight.controller.sal.connector.api.RpcRouter;
 import org.opendaylight.controller.sal.connector.remoterpc.api.RouteChangeListener;
 import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
 import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableException;
@@ -43,8 +44,8 @@ public class ClientImplTest {
 
     //mock routing table
     routingTableProvider = mock(RoutingTableProvider.class);
-    RoutingTable<String, String> mockRoutingTable = new MockRoutingTable<String, String>();
-    Optional<RoutingTable<String, String>> optionalRoutingTable = Optional.fromNullable(mockRoutingTable);
+    RoutingTable<RpcRouter.RouteIdentifier, String> mockRoutingTable = new MockRoutingTable<String, String>();
+    Optional<RoutingTable<RpcRouter.RouteIdentifier, String>> optionalRoutingTable = Optional.fromNullable(mockRoutingTable);
     when(routingTableProvider.getRoutingTable()).thenReturn(optionalRoutingTable);
 
     //mock ClientRequestHandler
@@ -81,7 +82,7 @@ public class ClientImplTest {
 
   }
 
-  @Test
+  //@Test
   public void invokeRpc_NormalCall_ShouldReturnSuccess() throws Exception {
 
     when(mockHandler.handle(any(Message.class))).
@@ -94,7 +95,7 @@ public class ClientImplTest {
     Assert.assertNull(result.getResult());
   }
 
-  @Test
+  //@Test
   public void invokeRpc_HandlerThrowsException_ShouldReturnError() throws Exception {
 
     when(mockHandler.handle(any(Message.class))).
index 9c74be93bd7d28e22222cffb8273c2ae5b2505f7..0fe0155bb6a90e48a24e3ce7d3ecaaee37f956f8 100644 (file)
@@ -38,11 +38,26 @@ public class MockRoutingTable<K, V> implements RoutingTable {
 
   }
 
+  @Override
+  public void addRoutes(Set set, Object o) throws RoutingTableException, SystemException {
+    //To change body of implemented methods use File | Settings | File Templates.
+  }
+
+  @Override
+  public void removeRoutes(Set set, Object o) throws RoutingTableException, SystemException {
+    //To change body of implemented methods use File | Settings | File Templates.
+  }
+
   @Override
   public void removeGlobalRoute(Object o) throws RoutingTableException, SystemException {
 
   }
 
+  @Override
+  public Object getGlobalRoute(Object o) throws RoutingTableException, SystemException {
+    return null;  //To change body of implemented methods use File | Settings | File Templates.
+  }
+
   @Override
   public Set getRoutes(Object o) {
     Set<String> routes = new HashSet<String>();
@@ -51,17 +66,17 @@ public class MockRoutingTable<K, V> implements RoutingTable {
   }
 
   @Override
-  public Set<Map.Entry> getAllRoutes() {
-    return Collections.emptySet();
+  public Object getLastAddedRoute(Object o) {
+    return null;  //To change body of implemented methods use File | Settings | File Templates.
   }
 
-  @Override
-  public Object getARoute(Object o) {
-    return null;
-  }
+//  @Override
+//  public Set<Map.Entry> getAllRoutes() {
+//    return Collections.emptySet();
+//  }
 
-  @Override
-  public void registerRouteChangeListener(RouteChangeListener routeChangeListener) {
-
-  }
+//  @Override
+//  public Object getARoute(Object o) {
+//    return null;
+//  }
 }
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/RemoteRpcProviderTest.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/RemoteRpcProviderTest.java
new file mode 100644 (file)
index 0000000..06360aa
--- /dev/null
@@ -0,0 +1,62 @@
+package org.opendaylight.controller.sal.connector.remoterpc;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class RemoteRpcProviderTest {
+  @Before
+  public void setUp() throws Exception {
+
+  }
+
+  @After
+  public void tearDown() throws Exception {
+
+  }
+
+  @Test
+  public void testSetRoutingTableProvider() throws Exception {
+
+  }
+
+  @Test
+  public void testOnSessionInitiated() throws Exception {
+
+  }
+
+  @Test
+  public void testGetSupportedRpcs() throws Exception {
+
+  }
+
+  @Test
+  public void testGetProviderFunctionality() throws Exception {
+
+  }
+
+  @Test
+  public void testInvokeRpc() throws Exception {
+
+  }
+
+  @Test
+  public void testInvokeRoutedRpc() throws Exception {
+
+  }
+
+  @Test
+  public void testStart() throws Exception {
+
+  }
+
+  @Test
+  public void testClose() throws Exception {
+
+  }
+
+  @Test
+  public void testStop() throws Exception {
+
+  }
+}
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/RouteIdentifierImplTest.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/RouteIdentifierImplTest.java
deleted file mode 100644 (file)
index 468d782..0000000
+++ /dev/null
@@ -1,62 +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.sal.connector.remoterpc;
-
-import java.net.URI;
-
-import com.fasterxml.jackson.core.JsonParseException;
-import org.junit.Assert;
-import org.junit.Test;
-import org.opendaylight.controller.sal.connector.api.RpcRouter;
-import org.opendaylight.controller.sal.connector.remoterpc.dto.RouteIdentifierImpl;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class RouteIdentifierImplTest {
-
-  Logger _logger = LoggerFactory.getLogger(RouteIdentifierImplTest.class);
-
-  private final URI namespace = URI.create("http://cisco.com/example");
-  private final QName QNAME = new QName(namespace, "heartbeat");
-
-  @Test
-  public void testToString() throws Exception {
-    RouteIdentifierImpl rId = new RouteIdentifierImpl();
-    rId.setType(QNAME);
-
-    _logger.debug(rId.toString());
-
-    Assert.assertTrue(true);
-
-  }
-
-  @Test
-  public void testFromString() throws Exception {
-    RouteIdentifierImpl rId = new RouteIdentifierImpl();
-    rId.setType(QNAME);
-
-    String s = rId.toString();
-    _logger.debug("serialized route: {}", s);
-
-    RpcRouter.RouteIdentifier ref = new RouteIdentifierImpl().fromString(s);
-    _logger.debug("deserialized route: {}", ref);
-
-    Assert.assertTrue(true);
-  }
-
-  @Test(expected = JsonParseException.class)
-  public void testFromInvalidString() throws Exception {
-    String invalidInput = "aklhdgadfa;;;;;;;]]]]=]ag" ;
-    RouteIdentifierImpl rId = new RouteIdentifierImpl();
-    rId.fromString(invalidInput);
-
-    _logger.debug("" + rId);
-    Assert.assertTrue(true);
-  }
-}
index 1b282f6ab5e5ead6d903c387cea22d015afba297..886ff426c7948d4a95d778d0f5717da1f0aa582e 100644 (file)
@@ -11,6 +11,7 @@ package org.opendaylight.controller.sal.connector.remoterpc;
 import com.google.common.base.Optional;
 import junit.framework.Assert;
 import org.junit.*;
+import org.opendaylight.controller.sal.connector.api.RpcRouter;
 import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
 import org.opendaylight.controller.sal.connector.remoterpc.utils.MessagingUtil;
 import org.opendaylight.controller.sal.core.api.Broker;
@@ -66,10 +67,9 @@ public class ServerImplTest {
 
     server = new ServerImpl(port);
     server.setBrokerSession(brokerSession);
-    server.setRoutingTableProvider(routingTableProvider);
 
-    RoutingTable<String, String> mockRoutingTable = new MockRoutingTable<String, String>();
-    Optional<RoutingTable<String, String>> optionalRoutingTable = Optional.fromNullable(mockRoutingTable);
+    RoutingTable<RpcRouter.RouteIdentifier, String> mockRoutingTable = new MockRoutingTable<String, String>();
+    Optional<RoutingTable<RpcRouter.RouteIdentifier, String>> optionalRoutingTable = Optional.fromNullable(mockRoutingTable);
     when(routingTableProvider.getRoutingTable()).thenReturn(optionalRoutingTable);
 
     when(brokerSession.addRpcRegistrationListener(listener)).thenReturn(null);
@@ -94,11 +94,6 @@ public class ServerImplTest {
     Assert.assertEquals(ServerImpl.State.STOPPED, server.getStatus());
   }
 
-  @Test
-  public void getRoutingTableProvider_Call_ShouldReturnRoutingTable() throws Exception {
-    Assert.assertNotNull(server.getRoutingTableProvider());
-  }
-
   @Test
   public void getBrokerSession_Call_ShouldReturnBrokerSession() throws Exception {
     Optional<Broker.ProviderSession> mayBeBroker = server.getBrokerSession();
index dc2fdbf9a05382d19307d6cccb20c918c6c1aafc..a6bbe31684008c00722482b6e4eb2078d60fa4d4 100644 (file)
             </Export-Package>
             <Import-Package>
               com.sun.jersey.spi.container.servlet,
-              org.codehaus.jackson.annotate,
+              !org.codehaus.jackson.annotate,
               javax.ws.rs,
               javax.ws.rs.core,
               javax.xml.bind,
               javax.xml.bind.annotation,
               org.slf4j,
               org.apache.catalina.filters,
-              org.codehaus.jackson.jaxrs,
+              !org.codehaus.jackson.jaxrs,
               org.opendaylight.controller.sample.zeromq.provider,
               org.opendaylight.controller.sample.zeromq.consumer,
               org.opendaylight.controller.sal.utils,
index f6c39bf8c5a3ac70d75b8490f01aa2c5dfe73bc7..0683c45ebc82b7997a02cdbbceb90658a391fe5b 100644 (file)
@@ -94,14 +94,14 @@ public interface RestconfService {
     @Consumes({Draft02.MediaTypes.OPERATION+JSON, Draft02.MediaTypes.OPERATION+XML,
                Draft02.MediaTypes.DATA+JSON, Draft02.MediaTypes.DATA+XML,
                MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
-    public StructuredData invokeRpc(@PathParam("identifier") String identifier, CompositeNode payload);
+    public StructuredData invokeRpc(@Encoded @PathParam("identifier") String identifier, CompositeNode payload);
     
     @POST
     @Path("/operations/{identifier:.+}")
     @Produces({Draft02.MediaTypes.OPERATION+JSON, Draft02.MediaTypes.OPERATION+XML,
                Draft02.MediaTypes.DATA+JSON, Draft02.MediaTypes.DATA+XML,
                MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
-    public StructuredData invokeRpc(@PathParam("identifier") String identifier, @DefaultValue("") String noPayload);
+    public StructuredData invokeRpc(@Encoded @PathParam("identifier") String identifier, @DefaultValue("") String noPayload);
     
     @GET
     @Path("/config/{identifier:.+}")
index 66e5cbf910fa159fcabb76a02326de23b069737d..837d7ae5b7d147b59aa762b1fda4a32de0b86175 100644 (file)
@@ -43,14 +43,14 @@ import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
 import org.opendaylight.yangtools.yang.model.api.Module
 import org.opendaylight.yangtools.yang.model.api.RpcDefinition
 import org.opendaylight.yangtools.yang.model.api.SchemaContext
-import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener
+import org.opendaylight.yangtools.yang.model.api.SchemaContextListener
 import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition
 import org.slf4j.LoggerFactory
 
 import static com.google.common.base.Preconditions.*
 import static javax.ws.rs.core.Response.Status.*
 
-class ControllerContext implements SchemaServiceListener {
+class ControllerContext implements SchemaContextListener {
     val static LOG = LoggerFactory.getLogger(ControllerContext)
     val static ControllerContext INSTANCE = new ControllerContext
     val static NULL_VALUE = "null"
@@ -356,7 +356,6 @@ class ControllerContext implements SchemaServiceListener {
 
     private def toUriString(Object object) {
         if(object === null) return "";
-//        return object.toString.replace("/",URI_SLASH_PLACEHOLDER)
         return URLEncoder.encode(object.toString,URI_ENCODING_CHAR_SET)        
     }
     
@@ -626,6 +625,13 @@ class ControllerContext implements SchemaServiceListener {
             decodedPathArgs.add(URLDecoder.decode(pathArg, URI_ENCODING_CHAR_SET))
         }
         return decodedPathArgs
+    }
+
+    def urlPathArgDecode(String pathArg) {
+        if (pathArg !== null) {
+            return URLDecoder.decode(pathArg, URI_ENCODING_CHAR_SET)
+        }
+        return null
     }    
 
 }
index cfbce736fb70041ad2ee03eb26fdbc47d4c86797..e09dc7ac017d143c65f45564beeb1783ed97a8be 100644 (file)
@@ -230,10 +230,7 @@ class RestconfImpl implements RestconfService {
     }
 
     override invokeRpc(String identifier, CompositeNode payload) {
-        val rpc = identifier.rpcDefinition
-        if (rpc === null) {
-            throw new ResponseException(NOT_FOUND, "RPC does not exist.");
-        }
+        val rpc = resolveIdentifierInInvokeRpc(identifier)
         if (rpc.QName.namespace.toString == SAL_REMOTE_NAMESPACE && rpc.QName.localName == SAL_REMOTE_RPC_SUBSRCIBE) {
             val value = normalizeNode(payload, rpc.input, null)
             val pathNode = value?.getFirstSimpleByName(QName.create(rpc.QName, "path"))
@@ -267,7 +264,22 @@ class RestconfImpl implements RestconfService {
         if (!noPayload.nullOrEmpty) {
             throw new ResponseException(UNSUPPORTED_MEDIA_TYPE, "Content-Type contains unsupported Media Type.");
         }
-        return callRpc(identifier.rpcDefinition, null)
+        val rpc = resolveIdentifierInInvokeRpc(identifier)
+        return callRpc(rpc, null)
+    }
+
+    def resolveIdentifierInInvokeRpc(String identifier) {
+        if (identifier.indexOf("/") === -1) {
+            val identifierDecoded = identifier.urlPathArgDecode
+            val rpc = identifierDecoded.rpcDefinition
+            if (rpc !== null) {
+                return rpc
+            }
+            throw new ResponseException(NOT_FOUND, "RPC does not exist.");
+        }
+        val slashErrorMsg  = String.format("Identifier %n%s%ncan't contain slash character (/). +
+            If slash is part of identifier name then use %2F placeholder.",identifier)
+        throw new ResponseException(NOT_FOUND, slashErrorMsg);
     }
 
     private def StructuredData callRpc(RpcDefinition rpc, CompositeNode payload) {
index a332ef77b6591233d3b818f608490c9d963b9ded..54810266a799bc028afd6eeb93eee16730845d30 100644 (file)
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
@@ -18,7 +19,7 @@
                <module>toaster</module>
                <module>toaster-consumer</module>
                <module>toaster-provider</module>
-       </modules>
+  </modules>
 
     <profiles>
       <profile>
           <activeByDefault>false</activeByDefault>
         </activation>
         <modules>
-          <!--module>toaster-it</module -->
+          <module>toaster-it</module>
         </modules>
       </profile>
     </profiles>
 
        <groupId>org.opendaylight.controller.samples</groupId>
-</project>
+</project>
\ No newline at end of file
index 40e99ec28b74920996b962d99964ee9e8bff98dd..07a7d41ee7734849e0eed91c3c9bce09001fb36f 100644 (file)
       <tag>HEAD</tag>
   </scm>
 
+    <properties>
+        <sal-binding-api.version>1.1-SNAPSHOT</sal-binding-api.version>
+        <jmxGeneratorPath>${project.build.directory}/generated-sources/config</jmxGeneratorPath>
+
+    </properties>
+
        <build>
                <plugins>
                        <plugin>
                                <artifactId>maven-bundle-plugin</artifactId>
                                <configuration>
                                        <instructions>
-                                               <Export-Package>org.opendaylight.controller.sample.toaster.provider.api</Export-Package>
-                                               <Private-Package>org.opendaylight.controller.sample.toaster.provider.impl</Private-Package>
-                                               <Bundle-Activator>org.opendaylight.controller.sample.toaster.provider.impl.ToastConsumerImpl</Bundle-Activator>
+                                               <Export-Package>
+                            org.opendaylight.controller.sample.toaster.provider.api,
+                            org.opendaylight.controller.config.yang.toaster-consumer,
+                        </Export-Package>
+                        <Import-Package>*</Import-Package>
                                        </instructions>
                                </configuration>
                        </plugin>
+            <plugin>
+                <groupId>org.opendaylight.yangtools</groupId>
+                <artifactId>yang-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>config</id>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>
+                                        org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+                                    </codeGeneratorClass>
+                                    <outputBaseDir>${jmxGeneratorPath}</outputBaseDir>
+                                    <additionalConfiguration>
+                                        <namespaceToPackage1>
+                                            urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang
+                                        </namespaceToPackage1>
+                                    </additionalConfiguration>
+                                </generator>
+                            </codeGenerators>
+                            <inspectDependencies>true</inspectDependencies>
+                        </configuration>
+                    </execution>
+                </executions>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.controller</groupId>
+                        <artifactId>yang-jmx-generator-plugin</artifactId>
+                        <version>${config.version}</version>
+                    </dependency>
+                </dependencies>
+            </plugin>
+
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <version>1.8</version>
+                <executions>
+                    <execution>
+                        <id>add-source</id>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>add-source</goal>
+                        </goals>
+                        <configuration>
+                            <sources>
+                                <source>${jmxGeneratorPath}</source>
+                            </sources>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
                </plugins>
        </build>
 
                        <groupId>org.opendaylight.controller</groupId>
                        <artifactId>sal-binding-api</artifactId>
                </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>config-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-config</artifactId>
+        </dependency>
        </dependencies>
 </project>
diff --git a/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/config/yang/config/toaster_consumer/impl/ToasterConsumerModule.java b/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/config/yang/config/toaster_consumer/impl/ToasterConsumerModule.java
new file mode 100644 (file)
index 0000000..c006a34
--- /dev/null
@@ -0,0 +1,68 @@
+/**
+* Generated file
+
+* Generated from: yang module name: toaster-consumer-impl  yang module local name: toaster-consumer-impl
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Wed Feb 05 11:31:30 CET 2014
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.controller.config.yang.config.toaster_consumer.impl;
+
+import org.opendaylight.controller.sal.binding.api.NotificationListener;
+import org.opendaylight.controller.sample.toaster.provider.api.ToastConsumer;
+import org.opendaylight.controller.sample.toaster.provider.impl.ToastConsumerImpl;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastDone;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastType;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService;
+import org.opendaylight.yangtools.concepts.Registration;
+
+/**
+*
+*/
+public final class ToasterConsumerModule extends org.opendaylight.controller.config.yang.config.toaster_consumer.impl.AbstractToasterConsumerModule
+ {
+
+    public ToasterConsumerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public ToasterConsumerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
+            ToasterConsumerModule oldModule, java.lang.AutoCloseable oldInstance) {
+
+        super(identifier, dependencyResolver, oldModule, oldInstance);
+    }
+
+    @Override
+    protected void customValidation(){
+        // No need to validate dependencies, since all dependencies have mandatory true flag in yang
+        // config-subsystem will perform the validation
+    }
+
+    @Override
+    public java.lang.AutoCloseable createInstance() {
+        ToasterService toasterService = getRpcRegistryDependency().getRpcService(ToasterService.class);
+
+        final ToastConsumerImpl consumer = new ToastConsumerImpl(toasterService);
+        final Registration<NotificationListener<ToastDone>> notificationRegistration = getNotificationServiceDependency()
+                .registerNotificationListener(ToastDone.class, consumer);
+
+        final ToasterConsumerRuntimeRegistration runtimeRegistration = getRootRuntimeBeanRegistratorWrapper().register(consumer);
+
+        final class AutoCloseableToastConsumer implements AutoCloseable, ToastConsumer {
+
+            @Override
+            public void close() throws Exception {
+                runtimeRegistration.close();
+                notificationRegistration.close();
+            }
+
+            @Override
+            public boolean createToast(Class<? extends ToastType> type, int doneness) {
+                return consumer.createToast(type, doneness);
+            }
+        }
+
+        return new AutoCloseableToastConsumer();
+    }
+}
diff --git a/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/config/yang/config/toaster_consumer/impl/ToasterConsumerModuleFactory.java b/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/config/yang/config/toaster_consumer/impl/ToasterConsumerModuleFactory.java
new file mode 100644 (file)
index 0000000..f804894
--- /dev/null
@@ -0,0 +1,19 @@
+/**
+* Generated file
+
+* Generated from: yang module name: toaster-consumer-impl  yang module local name: toaster-consumer-impl
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Wed Feb 05 11:31:30 CET 2014
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.controller.config.yang.config.toaster_consumer.impl;
+
+/**
+*
+*/
+public class ToasterConsumerModuleFactory extends org.opendaylight.controller.config.yang.config.toaster_consumer.impl.AbstractToasterConsumerModuleFactory
+{
+
+
+}
index 87e5787ef5c9f63df75c95344ae4ac64e608b76a..5a4b45c71e7ec2d6a09f1557d109b273d19da690 100644 (file)
@@ -7,33 +7,27 @@
  */
 package org.opendaylight.controller.sample.toaster.provider.impl;
 
-import java.util.Hashtable;
 import java.util.concurrent.ExecutionException;
 
-import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareConsumer;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
-import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer;
+import org.opendaylight.controller.config.yang.config.toaster_consumer.impl.ToasterConsumerRuntimeMXBean;
 import org.opendaylight.controller.sal.binding.api.NotificationListener;
-import org.opendaylight.controller.sal.binding.api.NotificationService;
 import org.opendaylight.controller.sample.toaster.provider.api.ToastConsumer;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.MakeToastInputBuilder;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastDone;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastType;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.*;
 import org.opendaylight.yangtools.yang.common.RpcResult;
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class ToastConsumerImpl extends AbstractBindingAwareConsumer implements BundleActivator, BindingAwareConsumer, ToastConsumer,
-        NotificationListener<ToastDone> {
+public class ToastConsumerImpl implements
+        ToastConsumer,
+        NotificationListener<ToastDone>,ToasterConsumerRuntimeMXBean {
 
     private static final Logger log = LoggerFactory.getLogger(ToastConsumerImpl.class);
 
     private ToasterService toaster;
 
-    private ConsumerContext session;
+    public ToastConsumerImpl(ToasterService toaster) {
+        this.toaster = toaster;
+    }
 
     @Override
     public boolean createToast(Class<? extends ToastType> type, int doneness) {
@@ -42,45 +36,28 @@ public class ToastConsumerImpl extends AbstractBindingAwareConsumer implements B
         toastInput.setToasterToastType(type);
 
         try {
-            RpcResult<Void> result = getToastService().makeToast(toastInput.build()).get();
+            RpcResult<Void> result = toaster.makeToast(toastInput.build()).get();
 
             if (result.isSuccessful()) {
-                log.trace("Toast was successfuly finished");
+                log.trace("Toast was successfully finished");
             } else {
-                log.warn("Toast was not successfuly finished");
+                log.warn("Toast was not successfully finished");
             }
             return result.isSuccessful();
         } catch (InterruptedException | ExecutionException e) {
-            log.warn("Error occured during toast creation");
+            log.warn("Error occurred during toast creation");
         }
         return false;
 
     }
 
-    @Override
-    @Deprecated
-    protected void startImpl(BundleContext context) {
-        context.registerService(ToastConsumer.class, this, new Hashtable<String,String>());
-    }
-
-    @Override
-    public void onSessionInitialized(ConsumerContext session) {
-        this.session = session;
-        NotificationService notificationService = session.getSALService(NotificationService.class);
-        notificationService.registerNotificationListener(ToastDone.class, this);
-    }
-
     @Override
     public void onNotification(ToastDone notification) {
         log.trace("ToastDone Notification Received: {} ",notification.getToastStatus());
-
     }
 
-    private ToasterService getToastService() {
-        if (toaster == null) {
-            toaster = session.getRpcService(ToasterService.class);
-        }
-        return toaster;
+    @Override
+    public Boolean makeHashBrownToast(Integer doneness) {
+        return createToast(HashBrown.class, doneness);
     }
-
 }
diff --git a/opendaylight/md-sal/samples/toaster-consumer/src/main/yang/toaster-consumer-impl.yang b/opendaylight/md-sal/samples/toaster-consumer/src/main/yang/toaster-consumer-impl.yang
new file mode 100644 (file)
index 0000000..8bc1a5c
--- /dev/null
@@ -0,0 +1,81 @@
+// vi: set smarttab et sw=4 tabstop=4:
+module toaster-consumer-impl {
+
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer:impl";
+    prefix "toaster-consumer-impl";
+
+    import config { prefix config; revision-date 2013-04-05; }
+    import rpc-context { prefix rpcx; revision-date 2013-06-17; }
+
+    import toaster-consumer { prefix toaster-consumer; revision-date 2014-01-31; }
+    import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28; }
+
+    description
+        "This module contains the base YANG definitions for
+        toaster-consumer impl implementation.";
+
+    revision "2014-01-31" {
+        description
+            "Initial revision.";
+    }
+
+    // This is the definition of a service implementation
+    identity toaster-consumer-impl {
+            base config:module-type;
+            config:provided-service toaster-consumer:toaster-consumer;
+            config:java-name-prefix ToasterConsumer;
+    }
+
+    augment "/config:modules/config:module/config:configuration" {
+        case toaster-consumer-impl {
+            when "/config:modules/config:module/config:type = 'toaster-consumer-impl'";
+
+            container rpc-registry {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity mdsal:binding-rpc-registry;
+                    }
+                }
+            }
+
+            container notification-service {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity mdsal:binding-notification-service;
+                    }
+                }
+            }
+
+        }
+    }
+
+    augment "/config:modules/config:module/config:state" {
+        case toaster-consumer-impl {
+            when "/config:modules/config:module/config:type = 'toaster-consumer-impl'";
+            rpcx:rpc-context-instance "make-hash-brown-toast-rpc";
+        }
+    }
+
+    identity make-hash-brown-toast-rpc;
+
+    rpc make-hash-brown-toast {
+        input {
+            uses rpcx:rpc-context-ref {
+                refine context-instance {
+                    rpcx:rpc-context-instance make-hash-brown-toast-rpc;
+                }
+            }
+            leaf doneness {
+                type uint16;
+            }
+        }
+        output {
+            leaf result {
+                type boolean;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/samples/toaster-consumer/src/main/yang/toaster-consumer.yang b/opendaylight/md-sal/samples/toaster-consumer/src/main/yang/toaster-consumer.yang
new file mode 100644 (file)
index 0000000..c050ee8
--- /dev/null
@@ -0,0 +1,26 @@
+// vi: set smarttab et sw=4 tabstop=4:
+module toaster-consumer {
+
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer";
+    prefix "toaster-consumer";
+
+    import config { prefix config; revision-date 2013-04-05; }
+
+    description
+        "This module contains the base YANG definitions for
+        toaster-consumer services.";
+
+    revision "2014-01-31" {
+        description
+            "Initial revision.";
+    }
+
+    // This is the definition of a service
+    identity toaster-consumer {
+
+        base "config:service-type";
+
+        config:java-class "org.opendaylight.controller.sample.toaster.provider.api.ToastConsumer";
+    }
+}
\ No newline at end of file
index a1925a53b505a616b1dc3cd6b6d99146a7fe97f7..d61393c22529573f03c76272064fda807d3c807a 100644 (file)
@@ -4,7 +4,7 @@
     <parent>
         <artifactId>sal-samples</artifactId>
         <groupId>org.opendaylight.controller.samples</groupId>
-        <version>1.0-SNAPSHOT</version>
+        <version>1.1-SNAPSHOT</version>
     </parent>
     <artifactId>sample-toaster-it</artifactId>
     <scm>
         <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
     </scm>
 
-    <properties>
-        <exam.version>3.0.0</exam.version>
-        <url.version>1.5.0</url.version>
-    </properties>
 
     <build>
         <plugins>
                     </execution>
                 </executions>
             </plugin>
-            <plugin>
-                <groupId>org.jacoco</groupId>
-                <artifactId>jacoco-maven-plugin</artifactId>
-                <configuration>
-                    <includes>org.opendaylight.controller.*</includes>
-                </configuration>
-                <executions>
-                    <execution>
-                        <id>pre-test</id>
-                        <goals>
-                            <goal>prepare-agent</goal>
-                        </goals>
-                    </execution>
-                    <execution>
-                        <id>post-test</id>
-                        <phase>test</phase>
-                        <goals>
-                            <goal>report</goal>
-                        </goals>
-                    </execution>
-                </executions>
-            </plugin>
         </plugins>
-        <pluginManagement>
-            <plugins>
-                <!--This plugin's configuration is used to store Eclipse 
-                    m2e settings only. It has no influence on the Maven build itself. -->
-                <plugin>
-                    <groupId>org.eclipse.m2e</groupId>
-                    <artifactId>lifecycle-mapping</artifactId>
-                    <version>1.0.0</version>
-                    <configuration>
-                        <lifecycleMappingMetadata>
-                            <pluginExecutions>
-                                <pluginExecution>
-                                    <pluginExecutionFilter>
-                                        <groupId>
-                                            org.ops4j.pax.exam
-                                        </groupId>
-                                        <artifactId>
-                                            maven-paxexam-plugin
-                                        </artifactId>
-                                        <versionRange>
-                                            [1.2.4,)
-                                        </versionRange>
-                                        <goals>
-                                            <goal>
-                                                generate-depends-file
-                                            </goal>
-                                        </goals>
-                                    </pluginExecutionFilter>
-                                    <action>
-                                        <ignore></ignore>
-                                    </action>
-                                </pluginExecution>
-                            </pluginExecutions>
-                        </lifecycleMappingMetadata>
-                    </configuration>
-                </plugin>
-            </plugins>
-        </pluginManagement>
     </build>
 
     <dependencies>
         <dependency>
-            <groupId>org.opendaylight.yangtools.thirdparty</groupId>
-            <artifactId>xtend-lib-osgi</artifactId>
-            <version>2.4.3</version>
-        </dependency>
-        <dependency>
-            <groupId>org.opendaylight.controller.samples</groupId>
-            <artifactId>sample-toaster</artifactId>
-            <version>1.0-SNAPSHOT</version>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-it</artifactId>
+            <version>1.1-SNAPSHOT</version>
         </dependency>
         <dependency>
             <groupId>org.opendaylight.controller.samples</groupId>
             <artifactId>sample-toaster-consumer</artifactId>
-            <version>1.0-SNAPSHOT</version>
+            <version>1.1-SNAPSHOT</version>
         </dependency>
         <dependency>
             <groupId>org.opendaylight.controller.samples</groupId>
             <artifactId>sample-toaster-provider</artifactId>
-            <version>1.0-SNAPSHOT</version>
+            <version>1.1-SNAPSHOT</version>
         </dependency>
         <dependency>
-            <groupId>org.opendaylight.controller</groupId>
-            <artifactId>sal-binding-broker-impl</artifactId>
-            <version>1.0-SNAPSHOT</version>
+            <groupId>org.opendaylight.controller.samples</groupId>
+            <artifactId>sample-toaster</artifactId>
+            <version>1.1-SNAPSHOT</version>
         </dependency>
+
         <dependency>
-            <groupId>org.ops4j.pax.exam</groupId>
-            <artifactId>pax-exam-container-native</artifactId>
-            <version>${exam.version}</version>
-            <scope>test</scope>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
         </dependency>
         <dependency>
             <groupId>org.ops4j.pax.exam</groupId>
             <artifactId>pax-exam-junit4</artifactId>
             <version>${exam.version}</version>
-            <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.ops4j.pax.exam</groupId>
             <version>${exam.version}</version>
             <scope>test</scope>
         </dependency>
-
         <dependency>
-            <groupId>org.opendaylight.controller</groupId>
-            <artifactId>config-manager</artifactId>
-            <version>0.2.3-SNAPSHOT</version>
+            <groupId>org.ops4j.pax.exam</groupId>
+            <artifactId>pax-exam-container-native</artifactId>
+            <version>${exam.version}</version>
+            <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>equinoxSDK381</groupId>
             <version>3.8.1.v20120830-144521</version>
             <scope>test</scope>
         </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>log4j-over-slf4j</artifactId>
-            <version>1.7.2</version>
-        </dependency>
-        <dependency>
-            <groupId>ch.qos.logback</groupId>
-            <artifactId>logback-core</artifactId>
-            <version>1.0.9</version>
-        </dependency>
-        <dependency>
-            <groupId>ch.qos.logback</groupId>
-            <artifactId>logback-classic</artifactId>
-            <version>1.0.9</version>
-        </dependency>
-        <dependency>
-            <groupId>org.opendaylight.yangtools.thirdparty</groupId>
-            <artifactId>antlr4-runtime-osgi-nohead</artifactId>
-            <version>4.0</version>
-        </dependency>
     </dependencies>
 </project>
index a7e1e9b44522e4e465c5c474a2c302d3d82bb224..38a4dd46617405c148022d4622a3b200b9182b80 100644 (file)
  */
 package org.opendaylight.controller.sample.toaster.it;
 
+import static org.junit.Assert.assertEquals;
+import static org.opendaylight.controller.test.sal.binding.it.TestHelper.*;
+import static org.ops4j.pax.exam.CoreOptions.*;
+
+import javax.inject.Inject;
+import javax.management.JMX;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.config.yang.config.toaster_consumer.impl.ToasterConsumerRuntimeMXBean;
+import org.opendaylight.controller.config.yang.config.toaster_provider.impl.ToasterProviderRuntimeMXBean;
 import org.opendaylight.controller.sample.toaster.provider.api.ToastConsumer;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.HashBrown;
 import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.WhiteBread;
 import org.ops4j.pax.exam.Configuration;
 import org.ops4j.pax.exam.Option;
 import org.ops4j.pax.exam.junit.PaxExam;
-import org.osgi.framework.BundleContext;
-
-import javax.inject.Inject;
-
-import static org.junit.Assert.assertTrue;
-import static org.ops4j.pax.exam.CoreOptions.junitBundles;
-import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
-import static org.ops4j.pax.exam.CoreOptions.options;
-import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+import org.ops4j.pax.exam.options.DefaultCompositeOption;
+import org.ops4j.pax.exam.util.Filter;
 import org.ops4j.pax.exam.util.PathUtils;
 
+import java.lang.management.ManagementFactory;
+
 @RunWith(PaxExam.class)
 public class ToasterTest {
 
-    public static final String ODL = "org.opendaylight.controller";
-    public static final String YANG = "org.opendaylight.yangtools";
-    public static final String CONTROLLER = "org.opendaylight.controller";
-    public static final String YANGTOOLS = "org.opendaylight.yangtools";
-    
-    
-    public static final String SAMPLE = "org.opendaylight.controller.samples";
+    @Inject
+    @Filter(timeout=60*1000)
+    ToastConsumer toastConsumer;
 
-    @Test
-    public void properInitialized() throws Exception {
+    @Configuration
+    public Option[] config() {
+        return options(systemProperty("osgi.console").value("2401"), mavenBundle("org.slf4j", "slf4j-api")
+                .versionAsInProject(), //
+                          mavenBundle("org.slf4j", "log4j-over-slf4j").versionAsInProject(), //
+
+                                systemProperty("logback.configurationFile").value(
+                        "file:" + PathUtils.getBaseDir()
+                                + "/src/test/resources/logback.xml"),
+                mavenBundle("ch.qos.logback", "logback-core").versionAsInProject(), //
+                mavenBundle("ch.qos.logback", "logback-classic").versionAsInProject(), //
+                systemProperty("osgi.bundles.defaultStartLevel").value("4"),
 
-        Thread.sleep(500); // Waiting for services to get wired.
+                toasterBundles(),
+                mdSalCoreBundles(),
 
-        assertTrue(consumer.createToast(WhiteBread.class, 5));
+                bindingAwareSalBundles(),
+                configMinumumBundles(),
+                // BASE Models
+                baseModelBundles(),
+                flowCapableModelBundles(),
 
+                // Set fail if unresolved bundle present
+                systemProperty("pax.exam.osgi.unresolved.fail").value("true"),
+                junitAndMockitoBundles());
     }
 
-    @Inject
-    BindingAwareBroker broker;
+    private Option toasterBundles() {
+        return new DefaultCompositeOption(
+                mavenBundle("org.opendaylight.controller.samples", "sample-toaster-provider").versionAsInProject(),
+                mavenBundle("org.opendaylight.controller.samples", "sample-toaster-consumer").versionAsInProject(),
+                mavenBundle("org.opendaylight.controller.samples", "sample-toaster").versionAsInProject()
+        );
+    }
 
-    @Inject
-    ToastConsumer consumer;
+    @Test
+    public void testToaster() throws Exception {
 
-    @Inject
-    BundleContext ctx;
+        MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
+        ObjectName consumerOn = new ObjectName("org.opendaylight.controller:instanceName=toaster-consumer-impl,type=RuntimeBean,moduleFactoryName=toaster-consumer-impl");
+        ObjectName providerOn = new ObjectName("org.opendaylight.controller:instanceName=toaster-provider-impl,type=RuntimeBean,moduleFactoryName=toaster-provider-impl");
 
-    @Configuration
-    public Option[] config() {
-        return options(systemProperty("osgi.console").value("2401"), 
-                systemProperty("logback.configurationFile").value(
-                    "file:" + PathUtils.getBaseDir()
-                    + "/src/test/resources/logback.xml"),
-                mavenBundle("org.slf4j", "slf4j-api").versionAsInProject(), //
-                mavenBundle("org.slf4j", "log4j-over-slf4j").versionAsInProject(), //
-                mavenBundle("ch.qos.logback", "logback-core").versionAsInProject(), //
-                mavenBundle("ch.qos.logback", "logback-classic").versionAsInProject(), //
-                
-                mavenBundle(ODL, "sal-common").versionAsInProject(), //
-                mavenBundle(ODL, "sal-common-api").versionAsInProject(),//
-                mavenBundle(ODL, "sal-common-impl").versionAsInProject(), //
-                mavenBundle(ODL, "sal-common-util").versionAsInProject(), //
-                
-                mavenBundle(ODL, "config-api").versionAsInProject(), //
-                mavenBundle(ODL, "config-manager").versionAsInProject(), //
-                mavenBundle("commons-io", "commons-io").versionAsInProject(),
-                mavenBundle("org.apache.commons", "commons-lang3").versionAsInProject(),
-                
-                mavenBundle(CONTROLLER, "sal-binding-api").versionAsInProject(), //
-                mavenBundle(CONTROLLER, "sal-binding-config").versionAsInProject(),
-                mavenBundle(CONTROLLER, "sal-binding-broker-impl").versionAsInProject(), //
-                mavenBundle("org.javassist", "javassist").versionAsInProject(), //
-                mavenBundle(CONTROLLER, "sal-common-util").versionAsInProject(), //
-        
-                mavenBundle(YANGTOOLS, "yang-data-api").versionAsInProject(), //
-                mavenBundle(YANGTOOLS, "yang-data-impl").versionAsInProject(), //
-                mavenBundle(YANGTOOLS, "yang-model-api").versionAsInProject(), //
-                mavenBundle(YANGTOOLS, "yang-model-util").versionAsInProject(), //
-                mavenBundle(YANGTOOLS, "yang-parser-api").versionAsInProject(),
-                mavenBundle(YANGTOOLS, "yang-parser-impl").versionAsInProject(),
-                
-                
-                mavenBundle(YANGTOOLS, "binding-generator-spi").versionAsInProject(), //
-                mavenBundle(YANGTOOLS, "binding-model-api").versionAsInProject(), //
-                mavenBundle(YANGTOOLS, "binding-generator-util").versionAsInProject(),
-                mavenBundle(YANGTOOLS, "yang-parser-impl").versionAsInProject(),
-                mavenBundle(YANGTOOLS, "binding-type-provider").versionAsInProject(),
-                mavenBundle(YANGTOOLS, "binding-generator-api").versionAsInProject(),
-                mavenBundle(YANGTOOLS, "binding-generator-spi").versionAsInProject(),
-                mavenBundle(YANGTOOLS, "binding-generator-impl").versionAsInProject(),
-                
-                
-                mavenBundle(CONTROLLER, "sal-core-api").versionAsInProject().update(), //
-                mavenBundle(CONTROLLER, "sal-broker-impl").versionAsInProject(), //
-                mavenBundle(CONTROLLER, "sal-core-spi").versionAsInProject().update(), //
-                
-                mavenBundle(YANGTOOLS + ".thirdparty", "antlr4-runtime-osgi-nohead").versionAsInProject(), //
-                
-                mavenBundle(SAMPLE, "sample-toaster").versionAsInProject(), //
-                mavenBundle(SAMPLE, "sample-toaster-consumer").versionAsInProject(), //
-                mavenBundle(SAMPLE, "sample-toaster-provider").versionAsInProject(), //
-                mavenBundle(YANG, "concepts").versionAsInProject(),
-                mavenBundle(YANG, "yang-binding").versionAsInProject(), //
-                mavenBundle(YANG, "yang-common").versionAsInProject(), //
-                mavenBundle(YANG+".thirdparty", "xtend-lib-osgi").versionAsInProject(),
-                mavenBundle("com.google.guava", "guava").versionAsInProject(), //
-                mavenBundle("org.javassist", "javassist").versionAsInProject(),
-                junitBundles()
-                );
+        long toastsMade = (long) platformMBeanServer.getAttribute(providerOn, "ToastsMade");
+        assertEquals(0, toastsMade);
+
+        boolean toasts = true;
+
+        // Make toasts using OSGi service
+        toasts &= toastConsumer.createToast(HashBrown.class, 4);
+        toasts &= toastConsumer.createToast(WhiteBread.class, 8);
+
+        // Make toast using JMX/config-subsystem
+        toasts &= (Boolean)platformMBeanServer.invoke(consumerOn, "makeHashBrownToast", new Object[]{4}, new String[]{Integer.class.getName()});
+
+        Assert.assertTrue("Not all toasts done by " + toastConsumer, toasts);
+
+        // Verify toasts made count on provider via JMX/config-subsystem
+        toastsMade = (long) platformMBeanServer.getAttribute(providerOn, "ToastsMade");
+        assertEquals(3, toastsMade);
     }
 
 }
diff --git a/opendaylight/md-sal/samples/toaster-it/src/test/resources/controller.xml b/opendaylight/md-sal/samples/toaster-it/src/test/resources/controller.xml
new file mode 100644 (file)
index 0000000..7a282db
--- /dev/null
@@ -0,0 +1,250 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<persisted-snapshots>
+    <snapshots>
+        <snapshot>
+            <required-capabilities>
+                <capability>urn:opendaylight:l2:types?module=opendaylight-l2-types&amp;revision=2013-08-27</capability>
+                <capability>
+                    urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&amp;revision=2013-10-28
+                </capability>
+                <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom?module=opendaylight-md-sal-dom&amp;revision=2013-10-28</capability>
+                <capability>
+                    urn:opendaylight:params:xml:ns:yang:controller:config?module=config&amp;revision=2013-04-05
+                </capability>
+                <capability>urn:ietf:params:netconf:capability:candidate:1.0</capability>
+                <capability>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&amp;revision=2010-10-04</capability>
+                <capability>urn:ietf:params:xml:ns:yang:rpc-context?module=rpc-context&amp;revision=2013-06-17
+                </capability>
+                <capability>
+                    urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl?module=opendaylight-sal-binding-broker-impl&amp;revision=2013-10-28
+                </capability>
+                <capability>urn:ietf:params:xml:ns:yang:ietf-inet-types?module=ietf-inet-types&amp;revision=2010-09-24
+                </capability>
+                <capability>urn:ietf:params:netconf:capability:rollback-on-error:1.0</capability>
+                <capability>urn:ietf:params:xml:ns:yang:ietf-yang-types?module=ietf-yang-types&amp;revision=2010-09-24
+                </capability>
+                <capability>
+                    urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl?module=opendaylight-sal-dom-broker-impl&amp;revision=2013-10-28
+                </capability>
+                <capability>urn:opendaylight:params:xml:ns:yang:controller:logback:config?module=config-logging&amp;revision=2013-07-16</capability>
+                <capability>urn:opendaylight:yang:extension:yang-ext?module=yang-ext&amp;revision=2013-07-09
+                </capability>
+                <capability>
+                    urn:opendaylight:params:xml:ns:yang:controller:md:sal:common?module=opendaylight-md-sal-common&amp;revision=2013-10-28
+                </capability>
+                <capability>http://netconfcentral.org/ns/toaster?module=toaster&amp;revision=2009-11-20</capability>
+                <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer?module=toaster-consumer&amp;revision=2014-01-31</capability>
+                <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer:impl?module=toaster-consumer-impl&amp;revision=2014-01-31</capability>
+                <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider?module=toaster-provider&amp;revision=2014-01-31</capability>
+                <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider:impl?module=toaster-provider-impl&amp;revision=2014-01-31</capability>
+
+            </required-capabilities>
+            <configuration>
+
+                <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+                    <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+                        <module>
+                            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider:impl">
+                                prefix:toaster-provider-impl
+                            </type>
+                            <name>toaster-provider-impl</name>
+
+                            <rpc-registry>
+                                <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
+                                <name>binding-rpc-broker</name>
+                            </rpc-registry>
+
+                            <notification-service>
+                                <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
+                                    binding:binding-notification-service
+                                </type>
+                                <name>ref_binding-notification-broker</name>
+                            </notification-service>
+                        </module>
+
+                        <module>
+                            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer:impl">
+                                prefix:toaster-consumer-impl
+                            </type>
+                            <name>toaster-consumer-impl</name>
+
+                            <rpc-registry>
+                                <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
+                                <name>binding-rpc-broker</name>
+                            </rpc-registry>
+
+                            <notification-service>
+                                <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
+                                    binding:binding-notification-service
+                                </type>
+                                <name>ref_binding-notification-broker</name>
+                            </notification-service>
+                        </module>
+
+                        <module>
+                            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
+                                prefix:schema-service-singleton
+                            </type>
+                            <name>yang-schema-service</name>
+                        </module>
+                        <module>
+                            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
+                                prefix:hash-map-data-store
+                            </type>
+                            <name>hash-map-data-store</name>
+                        </module>
+                        <module>
+                            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
+                                prefix:dom-broker-impl
+                            </type>
+                            <name>dom-broker</name>
+                            <data-store xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
+                                <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">
+                                    dom:dom-data-store
+                                </type>
+                                <name>ref_hash-map-data-store</name>
+                            </data-store>
+                        </module>
+                        <module>
+                            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                                prefix:binding-broker-impl
+                            </type>
+                            <name>binding-broker-impl</name>
+                            <notification-service
+                                    xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                                <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
+                                    binding:binding-notification-service
+                                </type>
+                                <name>ref_binding-notification-broker</name>
+                            </notification-service>
+                            <data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                                <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
+                                    binding:binding-data-broker
+                                </type>
+                                <name>ref_binding-data-broker</name>
+                            </data-broker>
+                        </module>
+                        <module>
+                            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                                prefix:runtime-generated-mapping
+                            </type>
+                            <name>runtime-mapping-singleton</name>
+                        </module>
+                        <module>
+                            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                                prefix:binding-notification-broker
+                            </type>
+                            <name>binding-notification-broker</name>
+                        </module>
+                        <module>
+                            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                                prefix:binding-data-broker
+                            </type>
+                            <name>binding-data-broker</name>
+                            <dom-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                                <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">
+                                    dom:dom-broker-osgi-registry
+                                </type>
+                                <name>ref_dom-broker</name>
+                            </dom-broker>
+                            <mapping-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                                <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                                    binding:binding-dom-mapping-service
+                                </type>
+                                <name>ref_runtime-mapping-singleton</name>
+                            </mapping-service>
+                        </module>
+                    </modules>
+
+                    <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+                        <service>
+                            <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">
+                                dom:schema-service
+                            </type>
+                            <instance>
+                                <name>ref_yang-schema-service</name>
+                                <provider>
+                                    /config/modules/module[name='schema-service-singleton']/instance[name='yang-schema-service']
+                                </provider>
+                            </instance>
+                        </service>
+                        <service>
+                            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
+                                binding:binding-notification-service
+                            </type>
+                            <instance>
+                                <name>ref_binding-notification-broker</name>
+                                <provider>
+                                    /config/modules/module[name='binding-notification-broker']/instance[name='binding-notification-broker']
+                                </provider>
+                            </instance>
+                        </service>
+                        <service>
+                            <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">
+                                dom:dom-data-store
+                            </type>
+                            <instance>
+                                <name>ref_hash-map-data-store</name>
+                                <provider>
+                                    /config/modules/module[name='hash-map-data-store']/instance[name='hash-map-data-store']
+                                </provider>
+                            </instance>
+                        </service>
+                        <service>
+                            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
+                            <instance>
+                                <name>binding-rpc-broker</name>
+                                <provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
+                            </instance>
+                        </service>
+                        <service>
+                            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
+                                binding:binding-broker-osgi-registry
+                            </type>
+                            <instance>
+                                <name>ref_binding-broker-impl</name>
+                                <provider>
+                                    /config/modules/module[name='binding-broker-impl']/instance[name='binding-broker-impl']
+                                </provider>
+                            </instance>
+                        </service>
+                        <service>
+                            <type xmlns:binding-impl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                                binding-impl:binding-dom-mapping-service
+                            </type>
+                            <instance>
+                                <name>ref_runtime-mapping-singleton</name>
+                                <provider>
+                                    /config/modules/module[name='runtime-generated-mapping']/instance[name='runtime-mapping-singleton']
+                                </provider>
+                            </instance>
+                        </service>
+                        <service>
+                            <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">
+                                dom:dom-broker-osgi-registry
+                            </type>
+                            <instance>
+                                <name>ref_dom-broker</name>
+                                <provider>/config/modules/module[name='dom-broker-impl']/instance[name='dom-broker']
+                                </provider>
+                            </instance>
+                        </service>
+                        <service>
+                            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
+                                binding:binding-data-broker
+                            </type>
+                            <instance>
+                                <name>ref_binding-data-broker</name>
+                                <provider>
+                                    /config/modules/module[name='binding-data-broker']/instance[name='binding-data-broker']
+                                </provider>
+                            </instance>
+                        </service>
+                    </services>
+                </data>
+
+            </configuration>
+        </snapshot>
+
+    </snapshots>
+</persisted-snapshots>
index 2d63ce57448f88b77a39b1bcb0525b9721c08370..f904f9726efce6c236526f318654fab49a81f49a 100644 (file)
@@ -7,7 +7,10 @@
     </encoder>
   </appender>
 
-  <root level="error">
+
+  <logger name="org.opendaylight.yangtools.yang.parser" level="ERROR"/>
+
+  <root level="debug">
     <appender-ref ref="STDOUT" />
   </root>
 </configuration>
index ca1e3b468941af54cd4fd0b9e6e68b5c45e9ed52..1a540fe9497fc51e4bb651fc7ea73f37bae69dc1 100644 (file)
   </scm>
 
 
+    <properties>
+        <jmxGeneratorPath>${project.build.directory}/generated-sources/config</jmxGeneratorPath>
+        <sal-binding-api.version>1.1-SNAPSHOT</sal-binding-api.version>
+    </properties>
+
     <build>
         <plugins>
             <plugin>
                 <artifactId>maven-bundle-plugin</artifactId>
                 <configuration>
                     <instructions>
-                        <Bundle-Activator>org.opendaylight.controller.sample.toaster.provider.ToasterProvider</Bundle-Activator>
+                        <Export-Package>
+                            org.opendaylight.controller.config.yang.toaster_provider,
+                        </Export-Package>
+                        <Import-Package>*</Import-Package>
                     </instructions>
                 </configuration>
             </plugin>
+            <plugin>
+                <groupId>org.opendaylight.yangtools</groupId>
+                <artifactId>yang-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>config</id>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>
+                                        org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+                                    </codeGeneratorClass>
+                                    <outputBaseDir>${jmxGeneratorPath}</outputBaseDir>
+                                    <additionalConfiguration>
+                                        <namespaceToPackage1>
+                                            urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang
+                                        </namespaceToPackage1>
+                                    </additionalConfiguration>
+                                </generator>
+                            </codeGenerators>
+                            <inspectDependencies>true</inspectDependencies>
+                        </configuration>
+                    </execution>
+                </executions>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.controller</groupId>
+                        <artifactId>yang-jmx-generator-plugin</artifactId>
+                        <version>${config.version}</version>
+                    </dependency>
+                </dependencies>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <version>1.8</version>
+                <executions>
+                    <execution>
+                        <id>add-source</id>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>add-source</goal>
+                        </goals>
+                        <configuration>
+                            <sources>
+                                <source>${jmxGeneratorPath}</source>
+                            </sources>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
         </plugins>
     </build>
 
             <groupId>org.opendaylight.controller</groupId>
             <artifactId>sal-common-util</artifactId>
         </dependency>
+       <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-config</artifactId>
+        </dependency>
+       <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>config-api</artifactId>
+        </dependency>
     </dependencies>
 </project>
diff --git a/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/config/yang/config/toaster_provider/impl/ToasterProviderModule.java b/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/config/yang/config/toaster_provider/impl/ToasterProviderModule.java
new file mode 100644 (file)
index 0000000..1029105
--- /dev/null
@@ -0,0 +1,72 @@
+/**
+* Generated file
+
+* Generated from: yang module name: toaster-provider-impl  yang module local name: toaster-provider-impl
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Wed Feb 05 11:05:32 CET 2014
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.controller.config.yang.config.toaster_provider.impl;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sample.toaster.provider.OpendaylightToaster;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.Toaster;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterData;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService;
+
+/**
+*
+*/
+public final class ToasterProviderModule extends org.opendaylight.controller.config.yang.config.toaster_provider.impl.AbstractToasterProviderModule
+ {
+
+    public ToasterProviderModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public ToasterProviderModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
+            ToasterProviderModule oldModule, java.lang.AutoCloseable oldInstance) {
+
+        super(identifier, dependencyResolver, oldModule, oldInstance);
+    }
+
+    @Override
+    protected void customValidation() {
+        // No need to validate dependencies, since all dependencies have mandatory true flag in yang
+        // config-subsystem will perform the validation for dependencies
+    }
+
+    @Override
+    public java.lang.AutoCloseable createInstance() {
+        final OpendaylightToaster opendaylightToaster = new OpendaylightToaster();
+
+        // Register to md-sal
+        opendaylightToaster.setNotificationProvider(getNotificationServiceDependency());
+        final BindingAwareBroker.RpcRegistration<ToasterService> rpcRegistration = getRpcRegistryDependency()
+                .addRpcImplementation(ToasterService.class, opendaylightToaster);
+
+        // Register runtimeBean for toaster statistics via JMX
+        final ToasterProviderRuntimeRegistration runtimeReg = getRootRuntimeBeanRegistratorWrapper().register(
+                opendaylightToaster);
+
+        // Wrap toaster as AutoCloseable and close registrations to md-sal at
+        // close()
+        final class AutoCloseableToaster implements AutoCloseable, ToasterData {
+
+            @Override
+            public void close() throws Exception {
+                rpcRegistration.close();
+                runtimeReg.close();
+            }
+
+            @Override
+            public Toaster getToaster() {
+                return opendaylightToaster.getToaster();
+            }
+        }
+
+        return new AutoCloseableToaster();
+    }
+
+}
diff --git a/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/config/yang/config/toaster_provider/impl/ToasterProviderModuleFactory.java b/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/config/yang/config/toaster_provider/impl/ToasterProviderModuleFactory.java
new file mode 100644 (file)
index 0000000..53a5071
--- /dev/null
@@ -0,0 +1,19 @@
+/**
+* Generated file
+
+* Generated from: yang module name: toaster-provider-impl  yang module local name: toaster-provider-impl
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Wed Feb 05 11:05:32 CET 2014
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.controller.config.yang.config.toaster_provider.impl;
+
+/**
+*
+*/
+public class ToasterProviderModuleFactory extends org.opendaylight.controller.config.yang.config.toaster_provider.impl.AbstractToasterProviderModuleFactory
+{
+
+
+}
index c3b9716783ef0b940484d2b65d7e8ccc227b6e57..a484154edf1703819b9c7675ace6675b53992470 100644 (file)
@@ -13,7 +13,9 @@ import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicLong;
 
+import org.opendaylight.controller.config.yang.config.toaster_provider.impl.ToasterProviderRuntimeMXBean;
 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
 import org.opendaylight.controller.sal.common.util.Futures;
 import org.opendaylight.controller.sal.common.util.Rpcs;
@@ -31,7 +33,7 @@ import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class OpendaylightToaster implements ToasterData, ToasterService {
+public class OpendaylightToaster implements ToasterData, ToasterService, ToasterProviderRuntimeMXBean {
 
     private static final Logger log = LoggerFactory.getLogger(OpendaylightToaster.class);
 
@@ -102,6 +104,13 @@ public class OpendaylightToaster implements ToasterData, ToasterService {
         log.trace("Toast: {} doneness: {}", toastType, toastDoneness);
     }
 
+    private final AtomicLong toastsMade = new AtomicLong(0);
+
+    @Override
+    public Long getToastsMade() {
+        return toastsMade.get();
+    }
+
     private class MakeToastTask implements Callable<RpcResult<Void>> {
 
         final MakeToastInput toastRequest;
@@ -120,6 +129,9 @@ public class OpendaylightToaster implements ToasterData, ToasterService {
             log.trace("Toast Done");
             logToastInput(toastRequest);
             currentTask = null;
+
+            toastsMade.incrementAndGet();
+
             return Rpcs.<Void> getRpcResult(true, null, Collections.<RpcError> emptySet());
         }
     }
diff --git a/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/ToasterActivator.java b/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/ToasterActivator.java
deleted file mode 100644 (file)
index 7e6e7e5..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * Copyright (c) 2014 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.sample.toaster.provider;
-
-public class ToasterActivator {
-
-}
diff --git a/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/ToasterProvider.java b/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/ToasterProvider.java
deleted file mode 100644 (file)
index ae482ed..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2014 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.sample.toaster.provider;
-
-import java.util.Collection;
-import java.util.Collections;
-
-import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
-import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService;
-import org.opendaylight.yangtools.yang.binding.RpcService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class ToasterProvider extends AbstractBindingAwareProvider {
-    private static final Logger log = LoggerFactory.getLogger(ToasterProvider.class);
-
-    private ProviderContext providerContext;
-    private final OpendaylightToaster toaster;
-
-    public ToasterProvider() {
-        toaster = new OpendaylightToaster();
-    }
-
-    @Override
-    public void onSessionInitiated(ProviderContext session) {
-        log.info("Provider Session initialized");
-
-        this.providerContext = session;
-        toaster.setNotificationProvider(session.getSALService(NotificationProviderService.class));
-        providerContext.addRpcImplementation(ToasterService.class, toaster);
-    }
-
-    @Override
-    public Collection<? extends RpcService> getImplementations() {
-        return Collections.emptySet();
-    }
-
-    @Override
-    public Collection<? extends ProviderFunctionality> getFunctionality() {
-        return Collections.emptySet();
-    }
-}
diff --git a/opendaylight/md-sal/samples/toaster-provider/src/main/yang/toaster-provider-impl.yang b/opendaylight/md-sal/samples/toaster-provider/src/main/yang/toaster-provider-impl.yang
new file mode 100644 (file)
index 0000000..0be8874
--- /dev/null
@@ -0,0 +1,63 @@
+// vi: set smarttab et sw=4 tabstop=4:
+module toaster-provider-impl {
+
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider:impl";
+    prefix "toaster-provider-impl";
+
+    import config { prefix config; revision-date 2013-04-05; }
+    import toaster-provider { prefix toaster-provider; revision-date 2014-01-31; }
+    import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28; }
+
+    description
+        "This module contains the base YANG definitions for
+        toaster-provider impl implementation.";
+
+    revision "2014-01-31" {
+        description
+            "Initial revision.";
+    }
+
+    // This is the definition of a service implementation
+    identity toaster-provider-impl {
+            base config:module-type;
+            config:provided-service toaster-provider:toaster-provider;
+            config:java-name-prefix ToasterProvider;
+    }
+
+    augment "/config:modules/config:module/config:configuration" {
+        case toaster-provider-impl {
+            when "/config:modules/config:module/config:type = 'toaster-provider-impl'";
+
+            container rpc-registry {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity mdsal:binding-rpc-registry;
+                    }
+                }
+            }
+
+            container notification-service {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity mdsal:binding-notification-service;
+                    }
+                }
+            }
+
+        }
+    }
+
+    augment "/config:modules/config:module/config:state" {
+        case toaster-provider-impl {
+            when "/config:modules/config:module/config:type = 'toaster-provider-impl'";
+
+            leaf toasts-made {
+                type uint32;
+            }
+
+        }
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/samples/toaster-provider/src/main/yang/toaster-provider.yang b/opendaylight/md-sal/samples/toaster-provider/src/main/yang/toaster-provider.yang
new file mode 100644 (file)
index 0000000..a5fba07
--- /dev/null
@@ -0,0 +1,26 @@
+// vi: set smarttab et sw=4 tabstop=4:
+module toaster-provider {
+
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider";
+    prefix "toaster-provider";
+
+    import config { prefix config; revision-date 2013-04-05; }
+
+    description
+        "This module contains the base YANG definitions for
+        toaster-provider services.";
+
+    revision "2014-01-31" {
+        description
+            "Initial revision.";
+    }
+
+    // This is the definition of a service
+    identity toaster-provider {
+
+        base "config:service-type";
+
+        config:java-class "org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterData";
+    }
+}
\ No newline at end of file
index 599fd714b8448452cd7da82d7784247c2f9a48cc..ad6d814c1b106382a33a066e0572ae5bc4a6436b 100644 (file)
@@ -19,7 +19,6 @@
             <plugin>
                 <groupId>org.opendaylight.yangtools</groupId>
                 <artifactId>yang-maven-plugin</artifactId>
-                <version>${yangtools.version}</version>
                 <executions>
                     <execution>
                         <goals>
index daaf60c1d3662caaa7a5febdb8da90f43eca4e46..c0b9f68814141427098f92304f024021b74dcfb9 100644 (file)
@@ -44,7 +44,6 @@
             <groupId>org.opendaylight.controller</groupId>
             <artifactId>config-persister-file-xml-adapter</artifactId>
             <scope>test</scope>
-            <version>${config.version}</version>
         </dependency>
 
         <!-- test dependencies -->
@@ -71,7 +70,6 @@
         <dependency>
             <groupId>org.opendaylight.controller</groupId>
             <artifactId>config-persister-directory-xml-adapter</artifactId>
-            <version>${config.version}</version>
             <scope>test</scope>
         </dependency>
     </dependencies>
index 959e2ff144810c2017131e8041229e86b1cabd64..eb975216e25f65f25124074be05d63071e1a8da7 100644 (file)
@@ -14,6 +14,7 @@ import static org.junit.Assert.assertEquals;
 import org.junit.Test;
 import org.opendaylight.controller.netconf.util.messages.NetconfMessageHeader;
 
+@Deprecated
 public class MessageHeaderTest {
     @Test
     public void testFromBytes() {
index 5df329def023f2c5216b08a3f9a7bbef29bccc23..d623dd979646e8f724f7abdefc9ce287a528a9fa 100644 (file)
             <groupId>io.netty</groupId>
             <artifactId>netty-handler</artifactId>
         </dependency>
-        <!--dependency>
-            <groupId>com.siemens.ct.exi</groupId>
-            <artifactId>exificient</artifactId>
-        </dependency-->
         <dependency>
             <groupId>org.opendaylight.controller.thirdparty</groupId>
             <artifactId>ganymed</artifactId>
index 7e4b9b9aa49ca5dd5d611f97878772cc0c987448..4928ddef3b0296b8525531791dfe4272064dfaa1 100644 (file)
@@ -454,7 +454,8 @@ public class FlowProgrammerNorthbound {
                     .build();
         }
         handleResourceCongruence(name, flowConfig.getName());
-        handleResourceCongruence(nodeId, flowConfig.getNode().getNodeIDString());
+        handleResourceCongruence(nodeType, flowConfig.getNode().getType());
+        handleResourceCongruence(nodeId, flowConfig.getNode().getID() == null ? null : flowConfig.getNode().getNodeIDString());
         handleDefaultDisabled(containerName);
 
         IForwardingRulesManager frm = getForwardingRulesManagerService(containerName);
index 07c08129db09cc96dbe8d75d8ded82e9d4b1792e..4a6a291e6a0a1518c68ee181c771139be5146ec5 100644 (file)
@@ -269,7 +269,7 @@ public class Activator extends ComponentActivatorAbstractBase {
             c.add(createServiceDependency()
                     .setService(IFlowProgrammerNotifier.class)
                     .setCallbacks("setFlowProgrammerNotifier",
-                            "unsetsetFlowProgrammerNotifier")
+                            "unsetFlowProgrammerNotifier")
                     .setRequired(false));
 
             c.add(createServiceDependency()
index ba2394131d84cb962696d2e955d4bbeb0866f277..3a4a192fc9b86c3df90576b393f7c23222974899 100644 (file)
@@ -19,6 +19,7 @@ package org.opendaylight.controller.sal.core;
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
 
@@ -65,11 +66,9 @@ public class Path implements Serializable {
             for (int i = 0; i < edges.size() - 1; i++) {
                 Edge current = edges.get(i);
                 Edge next = edges.get(i + 1);
-                if (!current.getHeadNodeConnector().getNode()
-                        .equals(
-                                next.getTailNodeConnector()
-                                        .getNode())) {
+                if (!current.getHeadNodeConnector().getNode().equals(next.getTailNodeConnector().getNode())) {
                     sequential = false;
+                    break;
                 }
             }
         } else if (edges.size() == 0) {
@@ -155,10 +154,10 @@ public class Path implements Serializable {
      * getter method for the Path
      *
      *
-     * @return Return the list of edges that constitue the Path
+     * @return Return the list of edges that constitute the Path
      */
     public List<Edge> getEdges() {
-        return this.edges;
+        return (edges == null) ? Collections.<Edge>emptyList() : new ArrayList<Edge>(edges);
     }
 
     @Override
@@ -171,18 +170,23 @@ public class Path implements Serializable {
 
     @Override
     public boolean equals(Object obj) {
-        if (this == obj)
+        if (this == obj) {
             return true;
-        if (obj == null)
+        }
+        if (obj == null) {
             return false;
-        if (getClass() != obj.getClass())
+        }
+        if (getClass() != obj.getClass()) {
             return false;
+        }
         Path other = (Path) obj;
         if (edges == null) {
-            if (other.edges != null)
+            if (other.edges != null) {
                 return false;
-        } else if (!edges.equals(other.edges))
+            }
+        } else if (!edges.equals(other.edges)) {
             return false;
+        }
         return true;
     }
 
index 142842ef90209baa56bf09b610a5f0a16b103521..21664cde6a6243ed6878e77136ca051003899245 100644 (file)
     <sonar.jacoco.itReportPath>../implementation/target/jacoco-it.exec</sonar.jacoco.itReportPath>
   </properties>
   <build>
-    <pluginManagement>
-      <plugins>
-        <plugin>
-          <groupId>org.jacoco</groupId>
-          <artifactId>jacoco-maven-plugin</artifactId>
-          <version>0.5.3.201107060350</version>
-        </plugin>
-      </plugins>
-    </pluginManagement>
     <plugins>
       <plugin>
         <groupId>org.jacoco</groupId>
         <artifactId>jacoco-maven-plugin</artifactId>
-        <version>${jacoco.version}</version>
         <configuration>
           <destFile>../implementation/target/jacoco-it.exec</destFile>
           <includes>org.opendaylight.controller.*</includes>
index 22ceeb419ba1cc9f484743d8f869c526de6e70ce..daee7a33a8ecab7d10d925e5162817736c880030 100644 (file)
       <plugin>
         <groupId>org.jacoco</groupId>
         <artifactId>jacoco-maven-plugin</artifactId>
-        <version>${jacoco.version}</version>
         <configuration>
           <destFile>../implementation/target/jacoco-it.exec</destFile>
           <includes>org.opendaylight.controller.*</includes>
index 0a36cbdb1ea65437e652a18ba6eea2dc80c85c6f..a72138548a80f0c71fc93368aa96fd33ef9ddefc 100644 (file)
     <sonar.jacoco.itReportPath>../implementaiton/target/jacoco-it.exec</sonar.jacoco.itReportPath>
   </properties>
   <build>
-    <pluginManagement>
-      <plugins>
-        <plugin>
-          <groupId>org.jacoco</groupId>
-          <artifactId>jacoco-maven-plugin</artifactId>
-          <version>0.5.3.201107060350</version>
-        </plugin>
-      </plugins>
-    </pluginManagement>
     <plugins>
       <plugin>
         <groupId>org.jacoco</groupId>
         <artifactId>jacoco-maven-plugin</artifactId>
-        <version>0.5.3.201107060350</version>
         <configuration>
           <destFile>../implementation/target/jacoco-it.exec</destFile>
           <includes>org.opendaylight.controller.*</includes>
diff --git a/third-party/com.siemens.ct.exi/pom.xml b/third-party/com.siemens.ct.exi/pom.xml
deleted file mode 100644 (file)
index 7a4f32f..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-  <!-- Get some common settings for the project we are using it in -->
-  <parent>
-    <groupId>org.opendaylight.controller</groupId>
-    <artifactId>commons.thirdparty</artifactId>
-    <version>1.1.1-SNAPSHOT</version>
-    <relativePath>../commons/thirdparty</relativePath>
-  </parent>
-  <scm>
-    <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
-    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
-    <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:Main</url>
-    <tag>HEAD</tag>
-  </scm>
-
-  <modelVersion>4.0.0</modelVersion>
-  <groupId>org.opendaylight.controller.thirdparty</groupId>
-  <artifactId>exificient</artifactId>
-  <version>0.9.2-SNAPSHOT</version>
-  <packaging>bundle</packaging>
-  <build>
-    <plugins>
-      <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <version>2.3.6</version>
-        <extensions>true</extensions>
-        <configuration>
-          <instructions>
-            <Embed-Dependency>*;scope=!provided;type=!pom;inline=false</Embed-Dependency>
-            <Embed-Transitive>false</Embed-Transitive>
-            <Export-Package>
-              com.siemens.ct.exi.*,
-            </Export-Package>
-            <Import-Package>
-                javax.xml.namespace,
-                javax.xml.parsers,
-                javax.xml.stream,
-                javax.xml.stream.events,
-                javax.xml.transform.sax,
-                org.apache.xerces.impl.xs,
-                org.apache.xerces.impl.xs.models,
-                org.apache.xerces.xni,
-                org.apache.xerces.xni.grammars,
-                org.apache.xerces.xni.parser,
-                org.apache.xerces.xs,
-                org.w3c.dom,
-                org.xml.sax,
-                org.xml.sax.ext,
-                org.xml.sax.helpers
-            </Import-Package>
-          </instructions>
-          <manifestLocation>${project.basedir}/META-INF</manifestLocation>
-        </configuration>
-      </plugin>
-    </plugins>
-  </build>
-
-
-  <dependencies>
-    <dependency>
-        <groupId>com.siemens.ct.exi</groupId>
-        <artifactId>exificient</artifactId>
-        <version>0.9.2</version>
-    </dependency>
-  </dependencies>
-
-</project>